can change openrouter model in UI

This commit is contained in:
DaKheera47
2025-12-15 16:12:15 +00:00
parent 4244c908e5
commit 04f771f289
11 changed files with 312 additions and 14 deletions
@@ -0,0 +1,140 @@
/**
* Settings page.
*/
import React, { useEffect, useMemo, useState } from "react"
import { toast } from "sonner"
import { Button } from "@/components/ui/button"
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
import { Input } from "@/components/ui/input"
import { Separator } from "@/components/ui/separator"
import type { AppSettings } from "../../shared/types"
import * as api from "../api"
export const SettingsPage: React.FC = () => {
const [settings, setSettings] = useState<AppSettings | null>(null)
const [modelDraft, setModelDraft] = useState("")
const [isSaving, setIsSaving] = useState(false)
const [isLoading, setIsLoading] = useState(true)
useEffect(() => {
let isMounted = true
setIsLoading(true)
api
.getSettings()
.then((data) => {
if (!isMounted) return
setSettings(data)
setModelDraft(data.overrideModel ?? "")
})
.catch((error) => {
const message = error instanceof Error ? error.message : "Failed to load settings"
toast.error(message)
})
.finally(() => {
if (!isMounted) return
setIsLoading(false)
})
return () => {
isMounted = false
}
}, [])
const effectiveModel = settings?.model ?? ""
const defaultModel = settings?.defaultModel ?? ""
const overrideModel = settings?.overrideModel
const canSave = useMemo(() => {
if (!settings) return false
const next = modelDraft.trim()
const current = (overrideModel ?? "").trim()
return next !== current
}, [modelDraft, overrideModel, settings])
const handleSave = async () => {
if (!settings) return
try {
setIsSaving(true)
const trimmed = modelDraft.trim()
const updated = await api.updateSettings({ model: trimmed.length > 0 ? trimmed : null })
setSettings(updated)
setModelDraft(updated.overrideModel ?? "")
toast.success("Settings saved")
} catch (error) {
const message = error instanceof Error ? error.message : "Failed to save settings"
toast.error(message)
} finally {
setIsSaving(false)
}
}
const handleReset = async () => {
try {
setIsSaving(true)
const updated = await api.updateSettings({ model: null })
setSettings(updated)
setModelDraft("")
toast.success("Reset to default")
} catch (error) {
const message = error instanceof Error ? error.message : "Failed to reset settings"
toast.error(message)
} finally {
setIsSaving(false)
}
}
return (
<main className="container mx-auto max-w-3xl space-y-6 px-4 py-6 pb-12">
<div className="space-y-1">
<h1 className="text-xl font-semibold tracking-tight">Settings</h1>
<p className="text-sm text-muted-foreground">Configure runtime behavior for this app.</p>
</div>
<Card>
<CardHeader>
<CardTitle className="text-base">Model</CardTitle>
</CardHeader>
<CardContent className="space-y-4">
<div className="space-y-2">
<div className="text-sm font-medium">Override model</div>
<Input
value={modelDraft}
onChange={(event) => setModelDraft(event.target.value)}
placeholder={defaultModel || "openai/gpt-4o-mini"}
disabled={isLoading || isSaving}
/>
<div className="text-xs text-muted-foreground">
Leave blank to use the default from server env (`MODEL`).
</div>
</div>
<Separator />
<div className="grid gap-2 text-sm sm:grid-cols-2">
<div>
<div className="text-xs text-muted-foreground">Effective</div>
<div className="break-words font-mono text-xs">{effectiveModel || "—"}</div>
</div>
<div>
<div className="text-xs text-muted-foreground">Default (env)</div>
<div className="break-words font-mono text-xs">{defaultModel || "—"}</div>
</div>
</div>
<div className="flex flex-wrap gap-2">
<Button onClick={handleSave} disabled={isLoading || isSaving || !canSave}>
{isSaving ? "Saving..." : "Save"}
</Button>
<Button variant="outline" onClick={handleReset} disabled={isLoading || isSaving || !settings}>
Reset to default
</Button>
</div>
</CardContent>
</Card>
</main>
)
}