51 lines
1.7 KiB
TypeScript
51 lines
1.7 KiB
TypeScript
import { useEffect, useState } from "react";
|
|
import type { SettingsResponse } from "@helios/shared";
|
|
import { api } from "../api";
|
|
|
|
export function Settings() {
|
|
const [current, setCurrent] = useState<SettingsResponse | null>(null);
|
|
const [llmBaseUrl, setLlmBaseUrl] = useState("");
|
|
const [llmModel, setLlmModel] = useState("");
|
|
const [llmKey, setLlmKey] = useState("");
|
|
const [status, setStatus] = useState<string | null>(null);
|
|
|
|
useEffect(() => {
|
|
api.getSettings().then((s) => {
|
|
setCurrent(s);
|
|
setLlmBaseUrl(s.llmBaseUrl);
|
|
setLlmModel(s.llmModel);
|
|
});
|
|
}, []);
|
|
|
|
const save = async (e: React.FormEvent) => {
|
|
e.preventDefault();
|
|
setStatus(null);
|
|
try {
|
|
await api.putSettings({ llmBaseUrl, llmModel, ...(llmKey ? { llmKey } : {}) });
|
|
setLlmKey("");
|
|
setCurrent(await api.getSettings());
|
|
setStatus("Saved");
|
|
} catch (err) {
|
|
setStatus(err instanceof Error ? err.message : "failed");
|
|
}
|
|
};
|
|
|
|
if (!current) return <p>Loading…</p>;
|
|
return (
|
|
<section>
|
|
<h2>AI provider</h2>
|
|
<p>Any OpenAI-compatible endpoint. OpenRouter by default; point at Ollama for a fully local setup.</p>
|
|
<form onSubmit={save}>
|
|
<label>Base URL <input value={llmBaseUrl} onChange={(e) => setLlmBaseUrl(e.target.value)} /></label>
|
|
<label>Model <input value={llmModel} onChange={(e) => setLlmModel(e.target.value)} /></label>
|
|
<label>
|
|
API key{current.llmKeyMasked ? ` (saved: ${current.llmKeyMasked})` : ""}
|
|
<input type="password" value={llmKey} onChange={(e) => setLlmKey(e.target.value)} placeholder="paste to replace" />
|
|
</label>
|
|
<button type="submit">Save</button>
|
|
</form>
|
|
{status && <p>{status}</p>}
|
|
</section>
|
|
);
|
|
}
|