Files
kit/internal/models/generate_models.go
T
Ed Zynda 63704f55b5 godoc
2025-11-12 16:48:46 +03:00

227 lines
6.2 KiB
Go

//go:build ignore
package main
import (
"encoding/json"
"fmt"
"io"
"net/http"
"os"
"text/template"
"time"
)
// ModelInfo represents information about a specific model.
// This struct is used during code generation to parse model data
// from the models.dev API and generate the static Go code.
type ModelInfo struct {
// ID is the unique identifier for the model
ID string `json:"id"`
// Name is the human-readable name of the model
Name string `json:"name"`
// Attachment indicates whether the model supports file attachments
Attachment bool `json:"attachment"`
// Reasoning indicates whether this is a reasoning/chain-of-thought model
Reasoning bool `json:"reasoning"`
// Temperature indicates whether the model supports temperature parameter
Temperature bool `json:"temperature"`
// Cost contains the pricing information for the model
Cost Cost `json:"cost"`
// Limit contains the context and output token limits
Limit Limit `json:"limit"`
}
// Cost represents the pricing information for a model.
// Used during code generation to parse pricing data from models.dev.
type Cost struct {
// Input is the cost per million input tokens
Input float64 `json:"input"`
// Output is the cost per million output tokens
Output float64 `json:"output"`
// CacheRead is the cost per million cached read tokens (optional)
CacheRead *float64 `json:"cache_read,omitempty"`
// CacheWrite is the cost per million cached write tokens (optional)
CacheWrite *float64 `json:"cache_write,omitempty"`
}
// Limit represents the context and output limits for a model.
// Used during code generation to parse token limit data from models.dev.
type Limit struct {
// Context is the maximum number of input tokens
Context int `json:"context"`
// Output is the maximum number of output tokens
Output int `json:"output"`
}
// ProviderInfo represents information about a model provider.
// Used during code generation to parse provider data from models.dev
// and generate the static provider registry.
type ProviderInfo struct {
// ID is the unique identifier for the provider
ID string `json:"id"`
// Env lists the environment variables for API credentials
Env []string `json:"env"`
// NPM is the NPM package name (for reference)
NPM string `json:"npm"`
// Name is the human-readable provider name
Name string `json:"name"`
// Models maps model IDs to their information
Models map[string]ModelInfo `json:"models"`
}
const codeTemplate = `// Code generated by go generate; DO NOT EDIT.
// Generated at: {{.Timestamp}}
package models
// ModelInfo represents information about a specific model
type ModelInfo struct {
ID string
Name string
Attachment bool
Reasoning bool
Temperature bool
Cost Cost
Limit Limit
}
// Cost represents the pricing information for a model
type Cost struct {
Input float64
Output float64
CacheRead *float64
CacheWrite *float64
}
// Limit represents the context and output limits for a model
type Limit struct {
Context int
Output int
}
// ProviderInfo represents information about a model provider
type ProviderInfo struct {
ID string
Env []string
NPM string
Name string
Models map[string]ModelInfo
}
// GetModelsData returns the static models data from models.dev
func GetModelsData() map[string]ProviderInfo {
return map[string]ProviderInfo{
{{- range $providerID, $provider := .Providers}}
"{{$providerID}}": {
ID: "{{$provider.ID}}",
Env: []string{ {{- range $i, $env := $provider.Env}}{{if $i}}, {{end}}"{{$env}}"{{end}} },
NPM: "{{$provider.NPM}}",
Name: "{{$provider.Name}}",
Models: map[string]ModelInfo{
{{- range $modelID, $model := $provider.Models}}
"{{$modelID}}": {
ID: "{{$model.ID}}",
Name: "{{$model.Name}}",
Attachment: {{$model.Attachment}},
Reasoning: {{$model.Reasoning}},
Temperature: {{$model.Temperature}},
Cost: Cost{
Input: {{$model.Cost.Input}},
Output: {{$model.Cost.Output}},
{{- if $model.Cost.CacheRead}}
CacheRead: &[]float64{{"{"}}{{$model.Cost.CacheRead}}{{"}"}}[0],
{{- else}}
CacheRead: nil,
{{- end}}
{{- if $model.Cost.CacheWrite}}
CacheWrite: &[]float64{{"{"}}{{$model.Cost.CacheWrite}}{{"}"}}[0],
{{- else}}
CacheWrite: nil,
{{- end}}
},
Limit: Limit{
Context: {{$model.Limit.Context}},
Output: {{$model.Limit.Output}},
},
},
{{- end}}
},
},
{{- end}}
}
}
`
func main() {
fmt.Println("Fetching models data from models.dev...")
// Fetch data from API
resp, err := http.Get("https://models.dev/api.json")
if err != nil {
fmt.Fprintf(os.Stderr, "Error fetching data: %v\n", err)
os.Exit(1)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
fmt.Fprintf(os.Stderr, "API returned status %d\n", resp.StatusCode)
os.Exit(1)
}
body, err := io.ReadAll(resp.Body)
if err != nil {
fmt.Fprintf(os.Stderr, "Error reading response: %v\n", err)
os.Exit(1)
}
// Parse JSON
var providers map[string]ProviderInfo
if err := json.Unmarshal(body, &providers); err != nil {
fmt.Fprintf(os.Stderr, "Error parsing JSON: %v\n", err)
os.Exit(1)
}
// Fix Google provider environment variables to match our implementation
if googleProvider, exists := providers["google"]; exists {
googleProvider.Env = []string{"GOOGLE_API_KEY", "GEMINI_API_KEY", "GOOGLE_GENERATIVE_AI_API_KEY"}
providers["google"] = googleProvider
}
// Generate Go code
tmpl, err := template.New("models").Parse(codeTemplate)
if err != nil {
fmt.Fprintf(os.Stderr, "Error parsing template: %v\n", err)
os.Exit(1)
}
// Create output file
file, err := os.Create("models_data.go")
if err != nil {
fmt.Fprintf(os.Stderr, "Error creating output file: %v\n", err)
os.Exit(1)
}
defer file.Close()
// Execute template
data := struct {
Providers map[string]ProviderInfo
Timestamp string
}{
Providers: providers,
Timestamp: time.Now().Format(time.RFC3339),
}
if err := tmpl.Execute(file, data); err != nil {
fmt.Fprintf(os.Stderr, "Error executing template: %v\n", err)
os.Exit(1)
}
fmt.Printf("Generated models_data.go with %d providers\n", len(providers))
// Print summary
for providerID, provider := range providers {
fmt.Printf(" %s: %d models\n", providerID, len(provider.Models))
}
}