Caleb Fahlgren commited on
Commit
32e1a9b
1 Parent(s): eb17fc6

add finetune growth chart

Browse files
README.md CHANGED
@@ -4,4 +4,3 @@
4
  - [Dataset](https://huggingface.co/datasets/cfahlgren1/hub-stats) updated on HuggingFace
5
 
6
  ![HF Stats](./stats.png)
7
-
 
4
  - [Dataset](https://huggingface.co/datasets/cfahlgren1/hub-stats) updated on HuggingFace
5
 
6
  ![HF Stats](./stats.png)
 
app/page.tsx CHANGED
@@ -2,77 +2,64 @@
2
 
3
  import { useEffect, useState } from "react"
4
  import * as duckdb from "@duckdb/duckdb-wasm"
 
5
 
6
- import {
7
- CREATE_VIEWS_QUERY,
8
- FETCH_CHART_DATA_QUERY,
9
- FETCH_DATASET_LICENSE_DATA_QUERY,
10
- FETCH_MODEL_LICENSE_DATA_QUERY,
11
- FETCH_SPACE_SDK_DATA_QUERY,
12
- } from "@/lib/queries"
13
- import { AreaChartStacked, ChartDataPoint } from "@/components/area-chart"
14
  import { CustomPieChart } from "@/components/pie-chart"
 
 
15
 
16
  export default function IndexPage() {
17
  const [conn, setConn] = useState<duckdb.AsyncDuckDBConnection | null>(null)
18
  const [chartData, setChartData] = useState<ChartDataPoint[]>([])
19
- const [modelLicenseData, setModelLicenseData] = useState<
20
- Array<{ name: string; value: number; fill: string }>
21
- >([])
22
- const [datasetLicenseData, setDatasetLicenseData] = useState<
23
- Array<{ name: string; value: number; fill: string }>
24
- >([])
25
- const [spaceSdkData, setSpaceSdkData] = useState<
26
- Array<{ name: string; value: number; fill: string }>
27
- >([])
28
 
29
  useEffect(() => {
30
- const initDB = async () => {
31
- const CDN_BASE = `https://cdn.jsdelivr.net/npm/@duckdb/duckdb-wasm@next`
32
-
33
- const JSDELIVR_BUNDLES = {
34
- mvp: {
35
- mainModule: `${CDN_BASE}/dist/duckdb-mvp.wasm`,
36
- mainWorker: `${CDN_BASE}/dist/duckdb-browser-mvp.worker.js`,
37
- },
38
- eh: {
39
- mainModule: `${CDN_BASE}/dist/duckdb-eh.wasm`,
40
- mainWorker: `${CDN_BASE}/dist/duckdb-browser-eh.worker.js`,
41
- },
42
- }
43
-
44
- const bundle = await duckdb.selectBundle(JSDELIVR_BUNDLES)
45
- const worker_url = URL.createObjectURL(
46
- new Blob([`importScripts("${bundle.mainWorker}");`], {
47
- type: "text/javascript",
48
- })
49
- )
50
-
51
- const worker = new Worker(worker_url)
52
- const logger = new duckdb.ConsoleLogger()
53
- const db = new duckdb.AsyncDuckDB(logger, worker)
54
- await db.instantiate(bundle.mainModule)
55
-
56
- const connection = await db.connect()
57
-
58
- await connection.query(CREATE_VIEWS_QUERY)
59
-
60
- setConn(connection)
61
- await fetchChartData(connection)
62
- }
63
-
64
  initDB()
 
 
65
 
66
- // Clean up the connection when the component unmounts
67
- return () => {
68
- if (conn) {
69
- conn.close()
70
- }
 
 
 
 
 
 
 
71
  }
72
- }, [])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
73
 
74
  const fetchChartData = async (connection: duckdb.AsyncDuckDBConnection) => {
75
- // Use the imported query
76
  const result = await connection.query(FETCH_CHART_DATA_QUERY)
77
 
78
  const data: ChartDataPoint[] = result.toArray().map((row) => ({
@@ -116,47 +103,98 @@ export default function IndexPage() {
116
  )
117
  }
118
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
119
  return (
120
  <section className="container grid items-center gap-6 pb-8 pt-6 md:py-10">
121
- <div className="flex flex-col gap-4">
122
- <h1 className="text-3xl text-center font-extrabold leading-tight tracking-tighter md:text-4xl">
123
- Hugging Face Hub Stats
124
- </h1>
125
- </div>
126
  <div className="flex flex-col gap-4 max-w-6xl mt-10 w-full mx-auto">
127
- {chartData.length > 0 ? (
128
- <AreaChartStacked data={chartData} />
129
- ) : (
130
- <p>Loading...</p>
131
- )}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
132
  </div>
133
- {modelLicenseData.length > 0 &&
134
- datasetLicenseData.length > 0 &&
135
- spaceSdkData.length > 0 && (
136
- <div className="flex flex-wrap gap-8 max-w-6xl mt-10 w-full mx-auto">
137
- <div className="flex-1 min-w-[300px]">
138
- <CustomPieChart
139
- title="Model Licenses"
140
- data={modelLicenseData}
141
- dataKey="value"
142
- />
143
- </div>
144
- <div className="flex-1 min-w-[300px]">
145
- <CustomPieChart
146
- title="Dataset Licenses"
147
- data={datasetLicenseData}
148
- dataKey="value"
149
- />
150
- </div>
151
- <div className="flex-1 min-w-[300px]">
152
- <CustomPieChart
153
- title="Space SDKs"
154
- data={spaceSdkData}
155
- dataKey="value"
156
- />
157
- </div>
158
- </div>
159
- )}
 
 
 
 
 
 
 
160
  </section>
161
  )
162
  }
 
2
 
3
  import { useEffect, useState } from "react"
4
  import * as duckdb from "@duckdb/duckdb-wasm"
5
+ import { Loader2 } from "lucide-react"
6
 
7
+ import { CREATE_VIEWS_QUERY, FETCH_CHART_DATA_QUERY, FETCH_DATASET_LICENSE_DATA_QUERY, FETCH_FINETUNE_MODEL_GROWTH_QUERY, FETCH_MODEL_LICENSE_DATA_QUERY, FETCH_SPACE_SDK_DATA_QUERY } from "@/lib/queries"
8
+ import { AreaChartStacked, ChartDataPoint } from "@/components/area-chart-stacked"
 
 
 
 
 
 
9
  import { CustomPieChart } from "@/components/pie-chart"
10
+ import { SimpleArea } from "@/components/simple-area"
11
+ import { Button } from "@/components/ui/button"
12
 
13
  export default function IndexPage() {
14
  const [conn, setConn] = useState<duckdb.AsyncDuckDBConnection | null>(null)
15
  const [chartData, setChartData] = useState<ChartDataPoint[]>([])
16
+ const [modelLicenseData, setModelLicenseData] = useState<Array<{ name: string; value: number; fill: string }>>([])
17
+ const [datasetLicenseData, setDatasetLicenseData] = useState<Array<{ name: string; value: number; fill: string }>>([])
18
+ const [spaceSdkData, setSpaceSdkData] = useState<Array<{ name: string; value: number; fill: string }>>([])
19
+ const [baseModel, setBaseModel] = useState("meta-llama/Meta-Llama-3-8B")
20
+ const [finetuneModelGrowthData, setFinetuneModelGrowthData] = useState<Array<{ date: Date; count: number }>>([])
21
+ const [isLoading, setIsLoading] = useState(false)
 
 
 
22
 
23
  useEffect(() => {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24
  initDB()
25
+ return () => { if (conn) conn.close() }
26
+ }, [])
27
 
28
+ const initDB = async () => {
29
+ const CDN_BASE = `https://cdn.jsdelivr.net/npm/@duckdb/duckdb-wasm@next`
30
+
31
+ const JSDELIVR_BUNDLES = {
32
+ mvp: {
33
+ mainModule: `${CDN_BASE}/dist/duckdb-mvp.wasm`,
34
+ mainWorker: `${CDN_BASE}/dist/duckdb-browser-mvp.worker.js`,
35
+ },
36
+ eh: {
37
+ mainModule: `${CDN_BASE}/dist/duckdb-eh.wasm`,
38
+ mainWorker: `${CDN_BASE}/dist/duckdb-browser-eh.worker.js`,
39
+ },
40
  }
41
+
42
+ const bundle = await duckdb.selectBundle(JSDELIVR_BUNDLES)
43
+ const worker_url = URL.createObjectURL(
44
+ new Blob([`importScripts("${bundle.mainWorker}");`], {
45
+ type: "text/javascript",
46
+ })
47
+ )
48
+
49
+ const worker = new Worker(worker_url)
50
+ const logger = new duckdb.ConsoleLogger()
51
+ const db = new duckdb.AsyncDuckDB(logger, worker)
52
+ await db.instantiate(bundle.mainModule)
53
+
54
+ const connection = await db.connect()
55
+
56
+ await connection.query(CREATE_VIEWS_QUERY)
57
+
58
+ setConn(connection)
59
+ await fetchChartData(connection)
60
+ }
61
 
62
  const fetchChartData = async (connection: duckdb.AsyncDuckDBConnection) => {
 
63
  const result = await connection.query(FETCH_CHART_DATA_QUERY)
64
 
65
  const data: ChartDataPoint[] = result.toArray().map((row) => ({
 
103
  )
104
  }
105
 
106
+ const handleBaseModelSubmit = async (e: React.FormEvent) => {
107
+ e.preventDefault()
108
+ if (!conn) {
109
+ console.warn("Database connection not established")
110
+ return
111
+ }
112
+
113
+ setIsLoading(true)
114
+ try {
115
+ console.log("Fetching finetune model growth data for", baseModel)
116
+ const result = await conn.query(FETCH_FINETUNE_MODEL_GROWTH_QUERY(baseModel))
117
+ console.log("Received Result")
118
+ const data = result.toArray().map((row: { date: Date; count: bigint }) => ({
119
+ date: new Date(row.date),
120
+ count: parseInt(row.count.toString())
121
+ }))
122
+ console.log("Setting finetune model growth data", data)
123
+ setFinetuneModelGrowthData(data)
124
+ } catch (error) {
125
+ console.error("Error executing query:", error)
126
+ } finally {
127
+ setIsLoading(false)
128
+ }
129
+ }
130
+
131
  return (
132
  <section className="container grid items-center gap-6 pb-8 pt-6 md:py-10">
133
+ <h1 className="text-3xl text-center font-extrabold leading-tight tracking-tighter md:text-4xl">
134
+ Hugging Face Hub Stats
135
+ </h1>
136
+
 
137
  <div className="flex flex-col gap-4 max-w-6xl mt-10 w-full mx-auto">
138
+ <AreaChartStacked data={chartData} />
139
+ </div>
140
+
141
+ <div className="flex flex-wrap gap-8 max-w-6xl mt-10 w-full mx-auto">
142
+ <div className="flex-1 min-w-[300px]">
143
+ <CustomPieChart
144
+ title="Model Licenses"
145
+ data={modelLicenseData}
146
+ dataKey="value"
147
+ />
148
+ </div>
149
+ <div className="flex-1 min-w-[300px]">
150
+ <CustomPieChart
151
+ title="Dataset Licenses"
152
+ data={datasetLicenseData}
153
+ dataKey="value"
154
+ />
155
+ </div>
156
+ <div className="flex-1 min-w-[300px]">
157
+ <CustomPieChart
158
+ title="Space SDKs"
159
+ data={spaceSdkData}
160
+ dataKey="value"
161
+ />
162
+ </div>
163
  </div>
164
+
165
+ <div className="flex flex-col items-center gap-4 max-w-6xl mt-10 w-full mx-auto">
166
+ <h2 className="text-4xl font-bold text-center">Finetuned Model Growth</h2>
167
+ <p className="text-center mb-4">Find how many finetuned models have been created for your favorite model</p>
168
+ <form onSubmit={handleBaseModelSubmit} className="flex flex-col gap-2 w-full max-w-sm">
169
+ <input
170
+ type="text"
171
+ value={baseModel}
172
+ onChange={(e) => setBaseModel(e.target.value)}
173
+ placeholder="Base Model Name"
174
+ className="px-4 w-full py-2 border rounded"
175
+ />
176
+ <Button type="submit" disabled={isLoading} className="w-full">
177
+ {isLoading ? (
178
+ <>
179
+ <Loader2 className="mr-2 h-4 w-4 animate-spin" />
180
+ Loading
181
+ </>
182
+ ) : (
183
+ "Submit"
184
+ )}
185
+ </Button>
186
+ </form>
187
+ </div>
188
+
189
+ {finetuneModelGrowthData.length > 0 && (
190
+ <div className="flex flex-col gap-4 max-w-4xl mt-10 w-full mx-auto">
191
+ <SimpleArea
192
+ title="Finetune Model Growth"
193
+ description={`Showing the growth of finetune models over time for ${baseModel || "your favorite model."}`}
194
+ data={finetuneModelGrowthData}
195
+ />
196
+ </div>
197
+ )}
198
  </section>
199
  )
200
  }
components/{area-chart.tsx → area-chart-stacked.tsx} RENAMED
@@ -60,62 +60,68 @@ export function AreaChartStacked({ data }: AreaChartStackedProps) {
60
  </CardDescription>
61
  </CardHeader>
62
  <CardContent>
63
- <ChartContainer config={chartConfig}>
64
- <AreaChart
65
- accessibilityLayer
66
- data={sortedData}
67
- margin={{
68
- left: 12,
69
- right: 12,
70
- }}
71
- >
72
- <CartesianGrid vertical={false} />
73
- <XAxis
74
- dataKey="month"
75
- tickLine={false}
76
- axisLine={false}
77
- tickMargin={8}
78
- tickFormatter={(value) => {
79
- const date = new Date(value)
80
- return date.toLocaleString("default", {
81
- month: "short",
82
- year: "numeric",
83
- })
84
  }}
85
- />
86
- <ChartTooltip
87
- cursor={true}
88
- content={<ChartTooltipContent indicator="line" hideLabel />}
89
- />
90
- <Area
91
- dataKey="spaces"
92
- type="natural"
93
- fill="hsl(var(--chart-3))"
94
- fillOpacity={0.4}
95
- stroke="hsl(var(--chart-3))"
96
- stackId="a"
97
- />
98
- <Area
99
- dataKey="datasets"
100
- type="natural"
101
- fill="hsl(var(--chart-2))"
102
- fillOpacity={0.2}
103
- stroke="hsl(var(--chart-2))"
104
- stackId="a"
105
- />
106
- <Area
107
- dataKey="models"
108
- type="natural"
109
- fill="hsl(var(--chart-1))"
110
- fillOpacity={0.4}
111
- stroke="hsl(var(--chart-1))"
112
- stackId="a"
113
- />
114
- <ChartLegend
115
- content={<ChartLegendContent className="text-white" />}
116
- />
117
- </AreaChart>
118
- </ChartContainer>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
119
  </CardContent>
120
  </Card>
121
  )
 
60
  </CardDescription>
61
  </CardHeader>
62
  <CardContent>
63
+ {data.length > 0 ? (
64
+ <ChartContainer config={chartConfig}>
65
+ <AreaChart
66
+ accessibilityLayer
67
+ data={sortedData}
68
+ margin={{
69
+ left: 12,
70
+ right: 12,
 
 
 
 
 
 
 
 
 
 
 
 
 
71
  }}
72
+ >
73
+ <CartesianGrid vertical={false} />
74
+ <XAxis
75
+ dataKey="month"
76
+ tickLine={false}
77
+ axisLine={false}
78
+ tickMargin={8}
79
+ tickFormatter={(value) => {
80
+ const date = new Date(value)
81
+ return date.toLocaleString("default", {
82
+ month: "short",
83
+ year: "numeric",
84
+ })
85
+ }}
86
+ />
87
+ <ChartTooltip
88
+ cursor={true}
89
+ content={<ChartTooltipContent indicator="line" hideLabel />}
90
+ />
91
+ <Area
92
+ dataKey="spaces"
93
+ type="natural"
94
+ fill="hsl(var(--chart-3))"
95
+ fillOpacity={0.4}
96
+ stroke="hsl(var(--chart-3))"
97
+ stackId="a"
98
+ />
99
+ <Area
100
+ dataKey="datasets"
101
+ type="natural"
102
+ fill="hsl(var(--chart-2))"
103
+ fillOpacity={0.2}
104
+ stroke="hsl(var(--chart-2))"
105
+ stackId="a"
106
+ />
107
+ <Area
108
+ dataKey="models"
109
+ type="natural"
110
+ fill="hsl(var(--chart-1))"
111
+ fillOpacity={0.4}
112
+ stroke="hsl(var(--chart-1))"
113
+ stackId="a"
114
+ />
115
+ <ChartLegend
116
+ content={<ChartLegendContent className="text-white" />}
117
+ />
118
+ </AreaChart>
119
+ </ChartContainer>
120
+ ) : (
121
+ <div className="flex items-center justify-center h-[300px] text-[var(--card-text)]">
122
+ Loading...
123
+ </div>
124
+ )}
125
  </CardContent>
126
  </Card>
127
  )
components/pie-chart.tsx CHANGED
@@ -69,31 +69,37 @@ export function CustomPieChart({
69
  )}
70
  </CardHeader>
71
  <CardContent className="flex-1 pb-0">
72
- <ChartContainer
73
- config={chartConfig}
74
- className="mx-auto aspect-square max-h-[500px]"
75
- >
76
- <PieChart>
77
- <ChartTooltip
78
- cursor={false}
79
- content={<ChartTooltipContent hideIndicator hideLabel />}
80
- />
81
- <Pie data={chartData} dataKey={dataKey} nameKey="name">
82
- {chartData.map((entry, index) => (
83
- <Cell
84
- key={`cell-${index}`}
85
- fill={chartColors[index % chartColors.length]}
86
- />
87
- ))}
88
- <LabelList
89
- dataKey="name"
90
- className="fill-background"
91
- stroke="none"
92
- fontSize={12}
93
  />
94
- </Pie>
95
- </PieChart>
96
- </ChartContainer>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
97
  </CardContent>
98
  </Card>
99
  )
 
69
  )}
70
  </CardHeader>
71
  <CardContent className="flex-1 pb-0">
72
+ {data.length > 0 ? (
73
+ <ChartContainer
74
+ config={chartConfig}
75
+ className="mx-auto aspect-square max-h-[500px]"
76
+ >
77
+ <PieChart>
78
+ <ChartTooltip
79
+ cursor={false}
80
+ content={<ChartTooltipContent hideIndicator hideLabel />}
 
 
 
 
 
 
 
 
 
 
 
 
81
  />
82
+ <Pie data={chartData} dataKey={dataKey} nameKey="name">
83
+ {chartData.map((entry, index) => (
84
+ <Cell
85
+ key={`cell-${index}`}
86
+ fill={chartColors[index % chartColors.length]}
87
+ />
88
+ ))}
89
+ <LabelList
90
+ dataKey="name"
91
+ className="fill-background"
92
+ stroke="none"
93
+ fontSize={12}
94
+ />
95
+ </Pie>
96
+ </PieChart>
97
+ </ChartContainer>
98
+ ) : (
99
+ <div className="flex items-center justify-center h-[300px] text-[var(--card-text)]">
100
+ Loading...
101
+ </div>
102
+ )}
103
  </CardContent>
104
  </Card>
105
  )
components/simple-area.tsx ADDED
@@ -0,0 +1,97 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ "use client"
2
+
3
+ import { Area, AreaChart, CartesianGrid, XAxis } from "recharts"
4
+
5
+ import {
6
+ Card,
7
+ CardContent,
8
+ CardDescription,
9
+ CardHeader,
10
+ CardTitle,
11
+ } from "@/components/ui/card"
12
+ import {
13
+ ChartConfig,
14
+ ChartContainer,
15
+ ChartTooltip,
16
+ ChartTooltipContent,
17
+ } from "@/components/ui/chart"
18
+
19
+ interface SimpleAreaProps {
20
+ title: string
21
+ description: string
22
+ data: Array<{ date: Date; count: number }>
23
+ }
24
+
25
+ export function SimpleArea({ title, description, data }: SimpleAreaProps) {
26
+ const chartConfig = {
27
+ count: {
28
+ label: "Total",
29
+ color: "hsl(var(--chart-1))",
30
+ },
31
+ } satisfies ChartConfig
32
+
33
+ const formattedData = data.map(item => ({
34
+ label: item.date.toISOString().split('T')[0],
35
+ count: item.count
36
+ }))
37
+
38
+ const total = data.length > 0 ? data[data.length - 1].count : 0
39
+
40
+ return (
41
+ <Card className="bg-[var(--card-background)]">
42
+ <CardHeader className="flex flex-row items-center justify-between">
43
+ <div>
44
+ <CardTitle className="text-[var(--card-text)]">{title}</CardTitle>
45
+ <CardDescription className="text-[var(--card-text)]">
46
+ {description}
47
+ </CardDescription>
48
+ </div>
49
+ <div className="text-right">
50
+ <span className="text-xs text-white">Total</span>
51
+ <p className="text-2xl font-bold text-white">{total.toLocaleString()}</p>
52
+ </div>
53
+ </CardHeader>
54
+ <CardContent>
55
+ {data.length > 0 ? (
56
+ <ChartContainer config={chartConfig}>
57
+ <AreaChart
58
+ accessibilityLayer
59
+ data={formattedData}
60
+ margin={{
61
+ left: 12,
62
+ right: 12,
63
+ }}
64
+ >
65
+ <CartesianGrid vertical={false} />
66
+ <XAxis
67
+ dataKey="label"
68
+ tickLine={false}
69
+ axisLine={false}
70
+ tickMargin={8}
71
+ tickFormatter={(value) => {
72
+ const date = new Date(value);
73
+ return `${date.getMonth() + 1}/${date.getDate()}`;
74
+ }}
75
+ />
76
+ <ChartTooltip
77
+ cursor={false}
78
+ content={<ChartTooltipContent indicator="line" />}
79
+ />
80
+ <Area
81
+ dataKey="count"
82
+ type="natural"
83
+ fill="hsl(var(--chart-1))"
84
+ fillOpacity={0.4}
85
+ stroke="hsl(var(--chart-1))"
86
+ />
87
+ </AreaChart>
88
+ </ChartContainer>
89
+ ) : (
90
+ <div className="flex items-center justify-center h-[300px] text-[var(--card-text)]">
91
+ Loading...
92
+ </div>
93
+ )}
94
+ </CardContent>
95
+ </Card>
96
+ )
97
+ }
lib/queries.ts CHANGED
@@ -41,3 +41,29 @@ export const FETCH_SPACE_SDK_DATA_QUERY = `
41
  FROM spaces
42
  GROUP BY sdk;
43
  `
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41
  FROM spaces
42
  GROUP BY sdk;
43
  `
44
+
45
+ export const FETCH_FINETUNE_MODEL_GROWTH_QUERY = (baseModel: string) => `
46
+ WITH RECURSIVE month_series AS (
47
+ SELECT DATE_TRUNC('month', MIN(CAST(createdAt AS TIMESTAMP))) AS month
48
+ FROM models, UNNEST(tags) AS t(tag)
49
+ WHERE tag = 'base_model:${baseModel}'
50
+
51
+ UNION ALL
52
+
53
+ SELECT month + INTERVAL 1 MONTH
54
+ FROM month_series
55
+ WHERE month < DATE_TRUNC('month', CURRENT_DATE)
56
+ ),
57
+ finetuned_models AS (
58
+ SELECT DATE_TRUNC('month', CAST(createdAt AS TIMESTAMP)) AS creation_month
59
+ FROM models, UNNEST(tags) AS t(tag)
60
+ WHERE tag = 'base_model:${baseModel}'
61
+ )
62
+ SELECT
63
+ strftime(ms.month, '%Y-%m') as date,
64
+ COALESCE(SUM(COUNT(fm.creation_month)) OVER (ORDER BY ms.month), 0) AS count
65
+ FROM month_series ms
66
+ LEFT JOIN finetuned_models fm ON ms.month = fm.creation_month
67
+ GROUP BY ms.month
68
+ ORDER BY ms.month
69
+ `