Feat: openrouter fetch/update free model list

This commit is contained in:
Grail Finder
2025-08-03 17:37:34 +03:00
parent ab60476688
commit 4fed716f8c
4 changed files with 118 additions and 0 deletions

View File

@@ -95,3 +95,52 @@ func (b *Bot) ToPlayer() *models.Player {
IsBot: true,
}
}
type ORModel struct {
ID string `json:"id"`
CanonicalSlug string `json:"canonical_slug"`
HuggingFaceID string `json:"hugging_face_id"`
Name string `json:"name"`
Created int `json:"created"`
Description string `json:"description"`
ContextLength int `json:"context_length"`
Architecture struct {
Modality string `json:"modality"`
InputModalities []string `json:"input_modalities"`
OutputModalities []string `json:"output_modalities"`
Tokenizer string `json:"tokenizer"`
InstructType any `json:"instruct_type"`
} `json:"architecture"`
Pricing struct {
Prompt string `json:"prompt"`
Completion string `json:"completion"`
Request string `json:"request"`
Image string `json:"image"`
Audio string `json:"audio"`
WebSearch string `json:"web_search"`
InternalReasoning string `json:"internal_reasoning"`
} `json:"pricing,omitempty"`
TopProvider struct {
ContextLength int `json:"context_length"`
MaxCompletionTokens int `json:"max_completion_tokens"`
IsModerated bool `json:"is_moderated"`
} `json:"top_provider"`
PerRequestLimits any `json:"per_request_limits"`
SupportedParameters []string `json:"supported_parameters"`
}
// https://openrouter.ai/api/v1/models
type ORModels struct {
Data []ORModel `json:"data"`
}
func (orm *ORModels) ListFree() []string {
resp := []string{}
for _, model := range orm.Data {
if model.Pricing.Prompt == "0" && model.Pricing.Request == "0" &&
model.Pricing.Completion == "0" {
resp = append(resp, model.ID)
}
}
return resp
}

64
llmapi/or.go Normal file
View File

@@ -0,0 +1,64 @@
package llmapi
import (
"context"
"encoding/json"
"fmt"
"log/slog"
"net/http"
"time"
)
var (
ormodelsLink = "https://openrouter.ai/api/v1/models"
ORFreeModels = []string{
"google/gemini-2.0-flash-exp:free",
"deepseek/deepseek-chat-v3-0324:free",
"mistralai/mistral-small-3.2-24b-instruct:free",
"qwen/qwen3-14b:free",
"google/gemma-3-27b-it:free",
"meta-llama/llama-3.3-70b-instruct:free",
}
)
func ListORModels() ([]string, error) {
resp, err := http.Get(ormodelsLink)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
err := fmt.Errorf("failed to fetch or models; status: %s", resp.Status)
return nil, err
}
data := &ORModels{}
if err := json.NewDecoder(resp.Body).Decode(data); err != nil {
return nil, err
}
freeModels := data.ListFree()
return freeModels, nil
}
func ORModelListUpdateTicker(ctx context.Context) {
ticker := time.NewTicker(time.Hour * 2)
freeModels, err := ListORModels()
slog.Info("updated free models list", "list", freeModels)
if err != nil {
slog.Error("failed to update free models list", "list", freeModels)
}
for {
select {
case <-ctx.Done():
return
case <-ticker.C:
freeModels, err := ListORModels()
slog.Info("updated free models list", "list", freeModels)
if err != nil {
slog.Error("failed to update free models list", "list", freeModels)
// log
continue
}
ORFreeModels = freeModels
}
}
}

View File

@@ -5,6 +5,7 @@ import (
"gralias/config"
"gralias/crons"
"gralias/handlers"
"gralias/llmapi"
"gralias/repos"
"gralias/telemetry"
"log/slog"
@@ -22,6 +23,7 @@ var cfg *config.Config
func init() {
cfg = config.LoadConfigOrDefault("")
go llmapi.ORModelListUpdateTicker(context.Background())
}
// GzipFileServer serves pre-compressed .gz files if available

View File

@@ -36,6 +36,9 @@
- player stats: played games, lost, won, rating elo, opened opposite words, opened white words, opened black words. +
- at the end of the game, all colors should be revealed;
- tracing;
====
- action history to bot (not json); basic stuff: what words were previously given as clue and guessed (maybe what team bot is on);
- automate getting list of free and non-thinking openrouter models;
#### sse points
- clue sse update;