Class: Labimotion::AiModels
- Inherits:
-
Object
- Object
- Labimotion::AiModels
- Defined in:
- lib/labimotion/libs/ai_models.rb
Overview
Fetches the LIVE model catalogue from an OpenAI-compatible AI provider (the KIT KI-Toolbox, https://ki-toolbox.scc.kit.edu, by default) using the user's OWN API key. "My LabIMotion" offers the result in its model dropdown, so a user does not depend on the static pick-list in config/labimotion_ai.yml (:models), which goes stale whenever the provider changes its line-up.
Only a PERSONAL key is ever used here: the shared server key must never be sent to a user-supplied provider URL, and a keyless user's choice is restricted to the admin allowlist anyway (Chemotion::ProfileAPI#labimotion_ai_admin_model_ids), so there would be nothing for them to pick out of a live list.
Endpoint resolution mirrors Labimotion::AiTemplate: a personal :base_url (and :api_path) is honored only alongside a personal key and is SSRF-validated by Labimotion::AiEgressGuard before any request; otherwise the server-wide config applies.
Defined Under Namespace
Classes: Error
Constant Summary collapse
- DEFAULT_BASE_URL =
'https://ki-toolbox.scc.kit.edu'- DEFAULT_API_PATH =
'/api/v1/chat/completions'- FALLBACK_PATHS =
List endpoints tried after the one derived from the configured chat-completions path: Open WebUI (what KI-Toolbox runs) serves /api/models, the OpenAI standard is /v1/models. The first that answers with a usable list wins.
['/api/models', '/v1/models', '/api/v1/models'].freeze
- REQUEST_TIMEOUT =
20- NON_CHAT_PATTERN =
Model ids/names that are not chat models. KI-Toolbox lists embedding, reranking, speech and image models next to the chat ones; offering those in the dropdown would only produce puzzling failures when a template is generated.
/ embed | rerank | whisper | \btts\b | \bstt\b | flux | stable-?diffusion | dall-?e | \bbge\b | moderation /xi- UNAUTHORIZED_CODES =
A provider answering these has a working endpoint but not the caller's key.
[401, 403].freeze
- MISSING_KEY_ERROR =
'Add your personal API key first — the model list is fetched with your own key.'
Instance Method Summary collapse
-
#call ⇒ Hash
{ models: [{ id:, label: }], endpoint: String }.
-
#initialize(api_key:, base_url: nil, api_path: nil) ⇒ AiModels
constructor
A new instance of AiModels.
Constructor Details
#initialize(api_key:, base_url: nil, api_path: nil) ⇒ AiModels
Returns a new instance of AiModels.
51 52 53 54 55 |
# File 'lib/labimotion/libs/ai_models.rb', line 51 def initialize(api_key:, base_url: nil, api_path: nil) @api_key = api_key.to_s.strip @base_url_override = base_url.to_s.strip.presence @api_path_override = api_path.to_s.strip.presence end |
Instance Method Details
#call ⇒ Hash
Returns { models: [{ id:, label: }], endpoint: String }.
59 60 61 62 63 64 65 66 67 68 69 70 71 |
# File 'lib/labimotion/libs/ai_models.rb', line 59 def call raise Error, MISSING_KEY_ERROR if @api_key.blank? statuses = {} candidate_paths.each do |path| url = "#{base_url}#{path}" response = get(url) statuses[path] = response&.code models = parse_models(response) return { models: models, endpoint: url } if models.present? end raise Error, (statuses) end |