Skip to content

Commit 7b4d277

Browse files
committed
sync
1 parent 8de398d commit 7b4d277

File tree

3 files changed

+90
-29
lines changed

3 files changed

+90
-29
lines changed

app/schemas.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,14 @@ export const ModelSchema = z
2828

2929
// Define types based on schemas
3030
export type Provider = z.infer<typeof ProviderSchema>;
31-
export type Model = z.infer<typeof ModelSchema>;
31+
export type Model = z.infer<typeof ModelSchema>;
32+
33+
// Define the API data structure
34+
export interface ApiData {
35+
[providerId: string]: Provider & {
36+
id: string;
37+
models: {
38+
[modelId: string]: Model & { id: string };
39+
};
40+
};
41+
}

app/worker.tsx

Lines changed: 74 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,11 @@
11
import { Hono } from "hono";
22
import type { Fetcher } from "@cloudflare/workers-types";
3-
import type { Model } from "./schemas";
3+
import type { ApiData } from "./schemas";
44

55
interface Env {
66
ASSETS: Fetcher;
77
}
88

9-
// Define the API data structure
10-
interface ApiData {
11-
[providerId: string]: {
12-
name: string;
13-
models: {
14-
[modelId: string]: Model;
15-
};
16-
};
17-
}
18-
199
// Create a typed Hono app
2010
const app = new Hono<{ Bindings: Env }>();
2111

@@ -37,14 +27,61 @@ app.get("/", async (c) => {
3727
<html>
3828
<head>
3929
<title>API Data</title>
30+
<script
31+
dangerouslySetInnerHTML={{
32+
__html: `
33+
function filterTable() {
34+
const searchInput = document.getElementById('searchInput').value.toLowerCase();
35+
const rows = document.querySelectorAll('table tbody tr');
36+
37+
rows.forEach(row => {
38+
const provider = row.cells[0].textContent.toLowerCase();
39+
const providerId = row.cells[1].textContent.toLowerCase();
40+
const model = row.cells[2].textContent.toLowerCase();
41+
const modelId = row.cells[3].textContent.toLowerCase();
42+
43+
if (provider.includes(searchInput) || model.includes(searchInput) || providerId.includes(searchInput) || modelId.includes(searchInput)) {
44+
row.style.display = '';
45+
} else {
46+
row.style.display = 'none';
47+
}
48+
});
49+
}
50+
`,
51+
}}
52+
/>
53+
<style
54+
dangerouslySetInnerHTML={{
55+
__html: `
56+
.search-container {
57+
margin-bottom: 20px;
58+
}
59+
#searchInput {
60+
padding: 8px;
61+
width: 300px;
62+
font-size: 16px;
63+
}
64+
`,
65+
}}
66+
/>
4067
</head>
4168
<body>
4269
<h1>API Data</h1>
70+
<div class="search-container">
71+
<input
72+
type="text"
73+
id="searchInput"
74+
placeholder="Search by provider or model..."
75+
onkeyup="filterTable()"
76+
/>
77+
</div>
4378
<table border="1" cellpadding="5" cellspacing="0">
4479
<thead>
4580
<tr>
4681
<th>Provider</th>
82+
<th>Provider ID</th>
4783
<th>Model</th>
84+
<th>Model ID</th>
4885
<th>Attachment</th>
4986
<th>Reasoning</th>
5087
<th>Input Cost</th>
@@ -56,22 +93,32 @@ app.get("/", async (c) => {
5693
</tr>
5794
</thead>
5895
<tbody>
59-
{Object.entries(apiData).map(([providerId, provider]) =>
60-
Object.entries(provider.models).map(([modelId, model]) => (
61-
<tr key={`${providerId}-${modelId}`}>
62-
<td>{provider.name}</td>
63-
<td>{model.name}</td>
64-
<td>{model.attachment ? "Yes" : "No"}</td>
65-
<td>{model.reasoning ? "Yes" : "No"}</td>
66-
<td>${model.cost.input}</td>
67-
<td>${model.cost.output}</td>
68-
<td>${model.cost.inputCached}</td>
69-
<td>${model.cost.outputCached}</td>
70-
<td>{model.limit.context}</td>
71-
<td>{model.limit.output}</td>
72-
</tr>
73-
))
74-
)}
96+
{Object.entries(apiData)
97+
.sort(([, providerA], [, providerB]) =>
98+
providerA.name.localeCompare(providerB.name)
99+
)
100+
.flatMap(([providerId, provider]) =>
101+
Object.entries(provider.models)
102+
.sort(([, modelA], [, modelB]) =>
103+
modelA.name.localeCompare(modelB.name)
104+
)
105+
.map(([modelId, model]) => (
106+
<tr key={`${providerId}-${modelId}`}>
107+
<td>{provider.name}</td>
108+
<td>{providerId}</td>
109+
<td>{model.name}</td>
110+
<td>{modelId}</td>
111+
<td>{model.attachment ? "Yes" : "No"}</td>
112+
<td>{model.reasoning ? "Yes" : "No"}</td>
113+
<td>${model.cost.input}</td>
114+
<td>${model.cost.output}</td>
115+
<td>${model.cost.inputCached}</td>
116+
<td>${model.cost.outputCached}</td>
117+
<td>{model.limit.context}</td>
118+
<td>{model.limit.output}</td>
119+
</tr>
120+
))
121+
)}
75122
</tbody>
76123
</table>
77124
</body>

scripts/generate

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ async function build() {
2626
const providerContent = parse(await providerTomlFile.text());
2727
result[provider] = {
2828
...providerContent,
29+
id: provider,
2930
models: {},
3031
};
3132

@@ -43,7 +44,10 @@ async function build() {
4344

4445
// Use filename without extension as the model ID
4546
const modelId = modelFile.replace(/\.toml$/, "");
46-
result[provider].models[modelId] = modelContent;
47+
result[provider].models[modelId] = {
48+
...modelContent,
49+
id: modelId,
50+
};
4751
}
4852
}
4953

0 commit comments

Comments
 (0)