{% extends "admin_base.html" %} {% block extra_head %} {{ super() }} {% endblock %} {% block admin_content %}
Map any requested model name onto a provider and target model, each with its own pricing economy and an optional vision model for image to text merging. Image routes use a flat per-image price. Unmapped requests fall through to the default upstream unchanged.
{% if tab == 'models' %}Each source model maps to a provider and target model with its own economy. Chat uses cache-hit, cache-miss and output prices (USD per 1M tokens); embeddings use the input price; image routes use the input price as a flat USD per image; a vision model adds input and output pricing for the image description merge. An optional fallback model is retried once, automatically, whenever this route fails after its own retries are exhausted.
| Source | Provider | Target | Kind | Vision | Economy | Actions |
|---|---|---|---|---|---|---|
| No model routes. Requests fall through to the default upstream. | ||||||
| {{ m.source_model }} | {{ m.provider or "default" }} | {{ m.target_model }} |
{{ m.kind }} |
{% if m.vision_model %}
{{ m.vision_provider or m.provider or "default" }}/{{ m.vision_model }}
{% else %}
-
{% endif %}
|
{% if m.context_tier_threshold_tokens %}tiered{% endif %} {% if m.off_peak_start_minute is not none %}off-peak{% endif %} {% if m.kind == 'image' and m.price_input_per_m %}${{ m.price_input_per_m }}/img{% endif %} {% if m.fallback_model %}fallback: {{ m.fallback_model }}{% endif %} {% if not m.context_tier_threshold_tokens and m.off_peak_start_minute is none and not (m.kind == 'image' and m.price_input_per_m) and not m.fallback_model %}-{% endif %} | Edit |
Named upstreams reused across model routes. A model route with a blank provider uses the default below.
{{ default_provider.model }} at {{ default_provider.base_url }},
embed {{ default_provider.embed_model }},
image {{ default_provider.image_model }},
vision {{ default_provider.vision_model }}
| Name | Base URL | Active | Client profile | Actions |
|---|---|---|---|---|
| No extra providers. Model routes with a blank provider use the default. | ||||
| {{ p.name }} | {{ p.base_url }} |
{{ "yes" if p.is_active else "no" }} | {{ p.client_profile or "generic" }} | Edit |
Rolling 24h USD caps on /openai/v1/*. A rule scopes by any combination of role, specific user, and app label (the X-App-Reference header); the most specific active match wins, and a rule that omits a dimension pools spend across everyone matching it. With no matching rule, the global defaults below apply per caller. A limit of 0 means unlimited.
{{ "$%.2f/24h"|format(quota_defaults.user) if quota_defaults.user else "unlimited" }},
admin {{ "$%.2f/24h"|format(quota_defaults.admin) if quota_defaults.admin else "unlimited" }},
guest {{ "$%.2f/24h"|format(quota_defaults.guest) if quota_defaults.guest else "unlimited" }},
internal {{ "$%.2f/24h"|format(quota_defaults.internal) if quota_defaults.internal else "unlimited" }},
access key {{ "$%.2f/24h"|format(quota_defaults.key) if quota_defaults.key else "unlimited" }}
| Scope | Limit / 24h | Spent 24h | Active | Label | Actions |
|---|---|---|---|---|---|
| No quota rules. Every caller is capped by the global defaults above. | |||||
role={{ r.owner_kind or "any" }}, user={{ r.owner_id or "any" }}, app={{ r.app_reference or "any" }} |
{{ "$%.2f"|format(r.limit_usd) if r.limit_usd else "unlimited" }} | ${{ "%.4f"|format(r.spent_24h_usd) }} | {{ "yes" if r.is_active else "no" }} | {{ r.label }} | Edit |
Request volume, latency, and per-model reliability, computed from the gateway usage ledger you already record - no separate data collection.
| Model | Provider | Requests | Success | Avg latency | Avg tok/s | Weight | Circuit | Prompt tok | Completion tok |
|---|---|---|---|---|---|---|---|---|---|
| Loading... | |||||||||
| When | Model | Provider | Endpoint | Status | Reason | Fell back to |
|---|---|---|---|---|---|---|
| Loading... | ||||||