models.ts 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. import { Global } from "../global"
  2. import { Log } from "../util/log"
  3. import path from "path"
  4. import z from "zod/v4"
  5. import { data } from "./models-macro" with { type: "macro" }
  6. import { Installation } from "../installation"
  7. export namespace ModelsDev {
  8. const log = Log.create({ service: "models.dev" })
  9. const filepath = path.join(Global.Path.cache, "models.json")
  10. export const Model = z
  11. .object({
  12. id: z.string(),
  13. name: z.string(),
  14. release_date: z.string(),
  15. attachment: z.boolean(),
  16. reasoning: z.boolean(),
  17. temperature: z.boolean(),
  18. tool_call: z.boolean(),
  19. cost: z.object({
  20. input: z.number(),
  21. output: z.number(),
  22. cache_read: z.number().optional(),
  23. cache_write: z.number().optional(),
  24. }),
  25. limit: z.object({
  26. context: z.number(),
  27. output: z.number(),
  28. }),
  29. modalities: z
  30. .object({
  31. input: z.array(z.enum(["text", "audio", "image", "video", "pdf"])),
  32. output: z.array(z.enum(["text", "audio", "image", "video", "pdf"])),
  33. })
  34. .optional(),
  35. experimental: z.boolean().optional(),
  36. status: z.enum(["alpha", "beta"]).optional(),
  37. options: z.record(z.string(), z.any()),
  38. provider: z.object({ npm: z.string() }).optional(),
  39. })
  40. .meta({
  41. ref: "Model",
  42. })
  43. export type Model = z.infer<typeof Model>
  44. export const Provider = z
  45. .object({
  46. api: z.string().optional(),
  47. name: z.string(),
  48. env: z.array(z.string()),
  49. id: z.string(),
  50. npm: z.string().optional(),
  51. models: z.record(z.string(), Model),
  52. })
  53. .meta({
  54. ref: "Provider",
  55. })
  56. export type Provider = z.infer<typeof Provider>
  57. export async function get() {
  58. refresh()
  59. const file = Bun.file(filepath)
  60. const result = await file.json().catch(() => {})
  61. if (result) return result as Record<string, Provider>
  62. const json = await data()
  63. return JSON.parse(json) as Record<string, Provider>
  64. }
  65. export async function refresh() {
  66. const file = Bun.file(filepath)
  67. log.info("refreshing", {
  68. file,
  69. })
  70. const result = await fetch("https://models.dev/api.json", {
  71. headers: {
  72. "User-Agent": Installation.USER_AGENT,
  73. },
  74. signal: AbortSignal.timeout(10 * 1000),
  75. }).catch((e) => {
  76. log.error("Failed to fetch models.dev", {
  77. error: e,
  78. })
  79. })
  80. if (result && result.ok) await Bun.write(file, await result.text())
  81. }
  82. }
  83. setInterval(() => ModelsDev.refresh(), 60 * 1000 * 60).unref()