1
0
mirror of https://github.com/coalaura/whiskr.git synced 2025-12-02 20:22:52 +00:00

add provider sorting

This commit is contained in:
Laura
2025-11-09 22:12:32 +01:00
parent adb8e82165
commit 1e7a711e36
6 changed files with 50 additions and 7 deletions

16
chat.go
View File

@@ -54,6 +54,7 @@ type Metadata struct {
type Request struct { type Request struct {
Prompt string `json:"prompt"` Prompt string `json:"prompt"`
Model string `json:"model"` Model string `json:"model"`
Provider string `json:"provider"`
Temperature float64 `json:"temperature"` Temperature float64 `json:"temperature"`
Iterations int64 `json:"iterations"` Iterations int64 `json:"iterations"`
Tools Tools `json:"tools"` Tools Tools `json:"tools"`
@@ -168,6 +169,21 @@ func (r *Request) Parse() (*openrouter.ChatCompletionRequest, error) {
} }
} }
switch r.Provider {
case "throughput":
request.Provider = &openrouter.ChatProvider{
Sort: openrouter.ProviderSortingThroughput,
}
case "latency":
request.Provider = &openrouter.ChatProvider{
Sort: openrouter.ProviderSortingLatency,
}
case "price":
request.Provider = &openrouter.ChatProvider{
Sort: openrouter.ProviderSortingPrice,
}
}
if model.JSON && r.Tools.JSON { if model.JSON && r.Tools.JSON {
request.ResponseFormat = &openrouter.ChatCompletionResponseFormat{ request.ResponseFormat = &openrouter.ChatCompletionResponseFormat{
Type: openrouter.ChatCompletionResponseFormatTypeJSONObject, Type: openrouter.ChatCompletionResponseFormatTypeJSONObject,

View File

@@ -518,8 +518,8 @@ body:not(.loading) #loading {
.message .time { .message .time {
font-family: "Comic Code", ui-monospace, "Cascadia Mono", "Segoe UI Mono", "Ubuntu Mono", "Roboto Mono", Menlo, Monaco, Consolas, monospace; font-family: "Comic Code", ui-monospace, "Cascadia Mono", "Segoe UI Mono", "Ubuntu Mono", "Roboto Mono", Menlo, Monaco, Consolas, monospace;
font-size: 11px; font-size: 10px;
line-height: 12px; line-height: 10px;
position: absolute; position: absolute;
top: 3px; top: 3px;
right: 3px; right: 3px;
@@ -1199,6 +1199,10 @@ label[for="iterations"] {
background-image: url(icons/iterations.svg); background-image: url(icons/iterations.svg);
} }
label[for="provider-sorting"] {
background-image: url(icons/provider.svg);
}
label[for="reasoning-effort"] { label[for="reasoning-effort"] {
background-image: url(icons/reasoning.svg); background-image: url(icons/reasoning.svg);
} }

View File

@@ -6,6 +6,7 @@
font-size: 14px; font-size: 14px;
white-space: nowrap; white-space: nowrap;
max-width: 160px; max-width: 160px;
min-width: 60px;
} }
.dropdown .selected { .dropdown .selected {

View File

@@ -47,7 +47,7 @@
<div id="header"> <div id="header">
<div id="role"> <div id="role">
<select title="Message role"> <select title="Message Role">
<option value="user" selected>User</option> <option value="user" selected>User</option>
<option value="assistant">Assistant</option> <option value="assistant">Assistant</option>
<option value="system">System</option> <option value="system">System</option>
@@ -73,6 +73,15 @@
<label for="model" title="Model"></label> <label for="model" title="Model"></label>
<select id="model" data-searchable></select> <select id="model" data-searchable></select>
</div> </div>
<div class="option">
<label for="provider-sorting" title="Provider Sorting"></label>
<select id="provider-sorting">
<option value="" selected title="Default sorting">-</option>
<option value="throughput" title="Sort by throughput">:turbo</option>
<option value="latency" title="Sort by latency">:quick</option>
<option value="price" title="Sort by price">:cheap</option>
</select>
</div>
<div class="option none"> <div class="option none">
<label for="reasoning-effort" title="Reasoning Effort"></label> <label for="reasoning-effort" title="Reasoning Effort"></label>
<select id="reasoning-effort"> <select id="reasoning-effort">

View File

@@ -25,11 +25,12 @@
$attachments = document.getElementById("attachments"), $attachments = document.getElementById("attachments"),
$role = document.getElementById("role").querySelector("select"), $role = document.getElementById("role").querySelector("select"),
$model = document.getElementById("model"), $model = document.getElementById("model"),
$providerSorting = document.getElementById("provider-sorting"),
$reasoningEffort = document.getElementById("reasoning-effort"),
$reasoningTokens = document.getElementById("reasoning-tokens"),
$prompt = document.getElementById("prompt"), $prompt = document.getElementById("prompt"),
$temperature = document.getElementById("temperature"), $temperature = document.getElementById("temperature"),
$iterations = document.getElementById("iterations"), $iterations = document.getElementById("iterations"),
$reasoningEffort = document.getElementById("reasoning-effort"),
$reasoningTokens = document.getElementById("reasoning-tokens"),
$json = document.getElementById("json"), $json = document.getElementById("json"),
$search = document.getElementById("search"), $search = document.getElementById("search"),
$upload = document.getElementById("upload"), $upload = document.getElementById("upload"),
@@ -1246,6 +1247,7 @@
return { return {
prompt: $prompt.value, prompt: $prompt.value,
model: $model.value, model: $model.value,
provider: $providerSorting.value,
temperature: temperature, temperature: temperature,
iterations: iterations, iterations: iterations,
tools: { tools: {
@@ -1641,7 +1643,7 @@
separator, separator,
`Created:\t\t${formatTimestamp(model.created)}`, `Created:\t\t${formatTimestamp(model.created)}`,
`Pricing/1M:\t${formatMoney(model.pricing.input)} In | ${formatMoney(model.pricing.output)} Out`, `Pricing/1M:\t${formatMoney(model.pricing.input)} In | ${formatMoney(model.pricing.output)} Out`,
model.pricing.image ? `Images:\t\t${formatMoney(model.pricing.image)} each` : null, model.pricing.image ? `Images/1K:\t${formatMoney(model.pricing.image * 1000)} Out` : null,
separator, separator,
stripMarkdown(model.description), stripMarkdown(model.description),
] ]
@@ -1696,6 +1698,7 @@
$prompt.value = loadValue("prompt", promptList.length ? promptList[0].key : ""); $prompt.value = loadValue("prompt", promptList.length ? promptList[0].key : "");
$temperature.value = loadValue("temperature", 0.85); $temperature.value = loadValue("temperature", 0.85);
$iterations.value = loadValue("iterations", 3); $iterations.value = loadValue("iterations", 3);
$providerSorting.value = loadValue("provider", "");
$reasoningEffort.value = loadValue("reasoning-effort", "medium"); $reasoningEffort.value = loadValue("reasoning-effort", "medium");
$reasoningTokens.value = loadValue("reasoning-tokens", 1024); $reasoningTokens.value = loadValue("reasoning-tokens", 1024);
@@ -2060,6 +2063,12 @@
$iterations.classList.toggle("invalid", Number.isNaN(iterations) || iterations < 1 || iterations > 50); $iterations.classList.toggle("invalid", Number.isNaN(iterations) || iterations < 1 || iterations > 50);
}); });
$providerSorting.addEventListener("change", () => {
const provider = $providerSorting.value;
storeValue("provider", provider);
});
$reasoningEffort.addEventListener("change", () => { $reasoningEffort.addEventListener("change", () => {
const effort = $reasoningEffort.value; const effort = $reasoningEffort.value;
@@ -2124,6 +2133,7 @@
attachments: attachments, attachments: attachments,
role: $role.value, role: $role.value,
model: $model.value, model: $model.value,
provider: $providerSorting.value,
prompt: $prompt.value, prompt: $prompt.value,
temperature: $temperature.value, temperature: $temperature.value,
iterations: $iterations.value, iterations: $iterations.value,
@@ -2343,6 +2353,7 @@
}); });
dropdown($role); dropdown($role);
dropdown($providerSorting);
dropdown($reasoningEffort); dropdown($reasoningEffort);
loadData().then(() => { loadData().then(() => {

View File

@@ -117,7 +117,9 @@ function formatMoney(num) {
if (num < 1) { if (num < 1) {
let decimals = 1; let decimals = 1;
if (num < 0.0001) { if (num < 0.00001) {
decimals = 4;
} else if (num < 0.0001) {
decimals = 3; decimals = 3;
} else if (num < 0.001) { } else if (num < 0.001) {
decimals = 2; decimals = 2;