This commit is contained in:
2026-07-09 02:52:54 +02:00
parent 818568c609
commit 48bb6c2ec2
95 changed files with 6115 additions and 267 deletions
+20 -10
View File
@@ -9,7 +9,7 @@
<h2>Gateway routing</h2>
<span class="admin-count" id="gw-count" role="status" aria-live="polite"></span>
</div>
<p class="gw-intro">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. Unmapped requests fall through to the default upstream unchanged.</p>
<p class="gw-intro">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.</p>
<section class="gw-section">
<div class="gw-section-head">
@@ -40,12 +40,12 @@
<div class="gw-section-head">
<h3>Model routes</h3>
</div>
<p class="gw-section-hint">Each source model maps to a provider and target model with its own economy (USD per 1M tokens). Chat uses cache-hit, cache-miss and output prices; embeddings use the input price; a vision model adds input and output pricing for the image description merge.</p>
<p class="gw-section-hint">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.</p>
<div class="admin-table-wrap">
<table class="admin-table">
<caption class="sr-only">Model routes</caption>
<thead>
<tr><th scope="col">Source</th><th scope="col">Provider</th><th scope="col">Target</th><th scope="col">Kind</th><th scope="col">Vision</th><th scope="col" class="gw-actions">Actions</th></tr>
<tr><th scope="col">Source</th><th scope="col">Provider</th><th scope="col">Target</th><th scope="col">Kind</th><th scope="col">Vision</th><th scope="col">Economy</th><th scope="col" class="gw-actions">Actions</th></tr>
</thead>
<tbody id="gw-models"></tbody>
</table>
@@ -55,15 +55,25 @@
<div class="gw-field"><label for="gw-model-source">Source model (requested)</label><input type="text" id="gw-model-source" name="source_model" placeholder="gpt-4o" required aria-required="true"></div>
<div class="gw-field"><label for="gw-model-provider">Provider</label><select id="gw-model-provider" name="provider" data-provider-select></select></div>
<div class="gw-field"><label for="gw-model-target">Target model (upstream)</label><input type="text" id="gw-model-target" name="target_model" placeholder="openai/gpt-4o" required aria-required="true"></div>
<div class="gw-field"><label for="gw-model-kind">Kind</label><select id="gw-model-kind" name="kind"><option value="chat">chat</option><option value="embed">embed</option></select></div>
<div class="gw-field"><label for="gw-model-vision-provider">Vision provider</label><select id="gw-model-vision-provider" name="vision_provider" data-provider-select></select></div>
<div class="gw-field"><label for="gw-model-vision-model">Vision model</label><input type="text" id="gw-model-vision-model" name="vision_model" placeholder="(optional) google/gemma-3-12b-it"></div>
<div class="gw-field"><label for="gw-model-kind">Kind</label><select id="gw-model-kind" name="kind"><option value="chat">chat</option><option value="embed">embed</option><option value="image">image</option></select></div>
<div class="gw-field" data-kind-field="chat"><label for="gw-model-vision-provider">Vision provider</label><select id="gw-model-vision-provider" name="vision_provider" data-provider-select></select></div>
<div class="gw-field" data-kind-field="chat"><label for="gw-model-vision-model">Vision model</label><input type="text" id="gw-model-vision-model" name="vision_model" placeholder="(optional) google/gemma-3-12b-it"></div>
<div class="gw-field"><label for="gw-model-context">Context window</label><input type="number" id="gw-model-context" name="context_window" min="0" value="0"></div>
<div class="gw-field"><label for="gw-model-active">Active</label><select id="gw-model-active" name="is_active"><option value="1">Yes</option><option value="0">No</option></select></div>
<div class="gw-field"><label for="gw-model-price-cache-hit">Price cache-hit / 1M ($)</label><input type="number" id="gw-model-price-cache-hit" name="price_cache_hit_per_m" min="0" step="0.0001" value="0"></div>
<div class="gw-field"><label for="gw-model-price-cache-miss">Price cache-miss / 1M ($)</label><input type="number" id="gw-model-price-cache-miss" name="price_cache_miss_per_m" min="0" step="0.0001" value="0"></div>
<div class="gw-field"><label for="gw-model-price-output">Price output / 1M ($)</label><input type="number" id="gw-model-price-output" name="price_output_per_m" min="0" step="0.0001" value="0"></div>
<div class="gw-field"><label for="gw-model-price-input">Price input / 1M ($) (embed/vision)</label><input type="number" id="gw-model-price-input" name="price_input_per_m" min="0" step="0.0001" value="0"></div>
<div class="gw-field" data-kind-field="chat"><label for="gw-model-price-cache-hit">Price cache-hit / 1M ($)</label><input type="number" id="gw-model-price-cache-hit" name="price_cache_hit_per_m" min="0" step="0.0001" value="0"></div>
<div class="gw-field" data-kind-field="chat"><label for="gw-model-price-cache-miss">Price cache-miss / 1M ($)</label><input type="number" id="gw-model-price-cache-miss" name="price_cache_miss_per_m" min="0" step="0.0001" value="0"></div>
<div class="gw-field" data-kind-field="chat"><label for="gw-model-price-output">Price output / 1M ($)</label><input type="number" id="gw-model-price-output" name="price_output_per_m" min="0" step="0.0001" value="0"></div>
<div class="gw-field" data-kind-field="embed chat"><label for="gw-model-price-input" id="gw-model-price-input-label">Price input / 1M ($) (embed/vision)</label><input type="number" id="gw-model-price-input" name="price_input_per_m" min="0" step="0.0001" value="0"></div>
<p class="gw-form-title gw-form-subtitle" data-kind-field="chat embed">Tiered / off-peak pricing (optional)</p>
<p class="gw-section-hint" data-kind-field="chat embed">Some providers charge a different rate once a request crosses a context-length threshold, or discount a fixed time-of-day window. Leave blank/zero to keep the flat rates above at all times.</p>
<div class="gw-field" data-kind-field="chat embed"><label for="gw-model-tier-threshold">Tier-2 threshold (input tokens)</label><input type="number" id="gw-model-tier-threshold" name="context_tier_threshold_tokens" min="0" value="0" title="0 disables tiered pricing"></div>
<div class="gw-field" data-kind-field="chat"><label for="gw-model-price-cache-hit-tier2">Tier-2 price cache-hit / 1M ($)</label><input type="number" id="gw-model-price-cache-hit-tier2" name="price_cache_hit_per_m_tier2" min="0" step="0.0001" placeholder="same as tier 1"></div>
<div class="gw-field" data-kind-field="chat"><label for="gw-model-price-cache-miss-tier2">Tier-2 price cache-miss / 1M ($)</label><input type="number" id="gw-model-price-cache-miss-tier2" name="price_cache_miss_per_m_tier2" min="0" step="0.0001" placeholder="same as tier 1"></div>
<div class="gw-field" data-kind-field="chat"><label for="gw-model-price-output-tier2">Tier-2 price output / 1M ($)</label><input type="number" id="gw-model-price-output-tier2" name="price_output_per_m_tier2" min="0" step="0.0001" placeholder="same as tier 1"></div>
<div class="gw-field" data-kind-field="chat embed"><label for="gw-model-price-input-tier2">Tier-2 price input / 1M ($) (embed/vision)</label><input type="number" id="gw-model-price-input-tier2" name="price_input_per_m_tier2" min="0" step="0.0001" placeholder="same as tier 1"></div>
<div class="gw-field" data-kind-field="chat embed image"><label for="gw-model-off-peak-start">Off-peak start (UTC)</label><input type="time" id="gw-model-off-peak-start" name="off_peak_start" title="Leave blank to disable off-peak discount"></div>
<div class="gw-field" data-kind-field="chat embed image"><label for="gw-model-off-peak-end">Off-peak end (UTC)</label><input type="time" id="gw-model-off-peak-end" name="off_peak_end" title="Leave blank to disable off-peak discount"></div>
<div class="gw-field" data-kind-field="chat embed image"><label for="gw-model-off-peak-discount">Off-peak discount (%)</label><input type="number" id="gw-model-off-peak-discount" name="off_peak_discount_pct" min="0" max="100" step="0.1" value="0"></div>
<div class="gw-form-actions"><button type="submit" class="admin-btn admin-btn-primary">Save model route</button></div>
</form>
</section>