Feat: openrouter fetch/update free model list
This commit is contained in:
		| @@ -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
									
								
							
							
						
						
									
										64
									
								
								llmapi/or.go
									
									
									
									
									
										Normal 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 | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
		Reference in New Issue
	
	Block a user
	 Grail Finder
					Grail Finder