Skip to content

Commit f2e1983

Browse files
committed
chore: add gemini and claude to UI
1 parent 5b2fcde commit f2e1983

4 files changed

Lines changed: 124 additions & 9 deletions

File tree

api_server.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -578,6 +578,14 @@ def get_user_settings(user_id: str, _: str = Depends(verify_api_key)):
578578
"gpt-4",
579579
"gpt-4-turbo",
580580
"gpt-4o"
581+
],
582+
"gemini": [
583+
"gemini-1.5-flash",
584+
"gemini-1.5-pro"
585+
],
586+
"claude": [
587+
"claude-3-opus-20240229",
588+
"claude-3-5-sonnet-20240620"
581589
]
582590
}
583591
return {"settings": current_settings, "llm_options": llm_options}

engine/backends/ollama.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,8 @@ def stream_generator():
174174
resp = requests.post("http://localhost:11434/api/generate", json={"model": model, "prompt": text, "stream": False})
175175
if resp.status_code == 404:
176176
models_list = get_downloaded_models()
177+
if not models_list:
178+
return "[404] No models are available. Please download a model using Ollama CLI (e.g., 'ollama pull mistral') or configure a different AI API."
177179
models_str = "\n".join(f"- {m}" for m in models_list)
178180
return f"[404] Model '{model}' not available. Choose one of the downloaded models:\n{models_str}"
179181

tauri-ui/src/components/Settings.tsx

Lines changed: 98 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -263,10 +263,12 @@ export function Settings({ onClose }: SettingsProps) {
263263
>
264264
<option value="ollama">Ollama</option>
265265
<option value="openai">OpenAI</option>
266+
<option value="gemini">Gemini</option>
267+
<option value="claude">Claude</option>
266268
</select>
267269
</div>
268270

269-
{settingsForm.settings.llm_backend === 'ollama' ? (
271+
{settingsForm.settings.llm_backend === 'ollama' && (
270272
<div>
271273
<label
272274
htmlFor="ollama-model"
@@ -289,7 +291,9 @@ export function Settings({ onClose }: SettingsProps) {
289291
))}
290292
</select>
291293
</div>
292-
) : (
294+
)}
295+
296+
{settingsForm.settings.llm_backend === 'openai' && (
293297
<>
294298
<div>
295299
<label
@@ -335,6 +339,98 @@ export function Settings({ onClose }: SettingsProps) {
335339
</>
336340
)}
337341

342+
{settingsForm.settings.llm_backend === 'gemini' && (
343+
<>
344+
<div>
345+
<label
346+
htmlFor="gemini-model"
347+
className="block text-sm font-medium text-gray-700 mb-1"
348+
>
349+
Gemini Model
350+
</label>
351+
<select
352+
id="gemini-model"
353+
value={settingsForm.settings.gemini_model || ''}
354+
onChange={e =>
355+
handleChange('gemini_model', e.currentTarget.value)
356+
}
357+
className="w-full border border-gray-300 rounded-md px-3 py-2"
358+
>
359+
{(settings.llm_options.gemini || []).map(model => (
360+
<option key={model} value={model}>
361+
{model}
362+
</option>
363+
))}
364+
</select>
365+
</div>
366+
367+
<div>
368+
<label
369+
htmlFor="gemini-api-key"
370+
className="block text-sm font-medium text-gray-700 mb-1"
371+
>
372+
Gemini API Key
373+
</label>
374+
<input
375+
id="gemini-api-key"
376+
type="password"
377+
value={settingsForm.settings.gemini_api_key || ''}
378+
onChange={e =>
379+
handleChange('gemini_api_key', e.currentTarget.value)
380+
}
381+
className="w-full border border-gray-300 rounded-md px-3 py-2"
382+
placeholder="AIza..."
383+
/>
384+
</div>
385+
</>
386+
)}
387+
388+
{settingsForm.settings.llm_backend === 'claude' && (
389+
<>
390+
<div>
391+
<label
392+
htmlFor="claude-model"
393+
className="block text-sm font-medium text-gray-700 mb-1"
394+
>
395+
Claude Model
396+
</label>
397+
<select
398+
id="claude-model"
399+
value={settingsForm.settings.claude_model || ''}
400+
onChange={e =>
401+
handleChange('claude_model', e.currentTarget.value)
402+
}
403+
className="w-full border border-gray-300 rounded-md px-3 py-2"
404+
>
405+
{(settings.llm_options.claude || []).map(model => (
406+
<option key={model} value={model}>
407+
{model}
408+
</option>
409+
))}
410+
</select>
411+
</div>
412+
413+
<div>
414+
<label
415+
htmlFor="claude-api-key"
416+
className="block text-sm font-medium text-gray-700 mb-1"
417+
>
418+
Claude API Key
419+
</label>
420+
<input
421+
id="claude-api-key"
422+
type="password"
423+
value={settingsForm.settings.claude_api_key || ''}
424+
onChange={e =>
425+
handleChange('claude_api_key', e.currentTarget.value)
426+
}
427+
className="w-full border border-gray-300 rounded-md px-3 py-2"
428+
placeholder="sk-ant-..."
429+
/>
430+
</div>
431+
</>
432+
)}
433+
338434
<div className="flex items-center gap-2">
339435
<input
340436
type="checkbox"

tauri-ui/src/context/ChatContext.tsx

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,14 @@ export type SettingsType = {
1919
llm_backend: string;
2020
llm_model: string;
2121
openai_model: string;
22+
gemini_model?: string;
23+
claude_model?: string;
2224
voice: boolean;
2325
streaming: boolean;
2426
secured_streaming: boolean;
25-
openai_api_key: string;
27+
openai_api_key?: string;
28+
gemini_api_key?: string;
29+
claude_api_key?: string;
2630
}
2731

2832
export type AppSettings = {
@@ -71,6 +75,8 @@ export interface UserPrivacy {
7175
export interface LLMOptions {
7276
ollama: string[];
7377
openai: string[];
78+
gemini?: string[];
79+
claude?: string[];
7480
}
7581

7682
export interface UserSession {
@@ -311,18 +317,19 @@ export function ChatProvider({
311317

312318
const sendMessage = async (
313319
input: string,
314-
backend = 'ollama',
320+
backend?: string,
315321
mode?: string,
316322
project_path?: string
317323
) => {
324+
const effectiveBackend = backend ?? settings?.settings.llm_backend ?? 'ollama';
318325
const data = await fetchWithKey(`${BASE_URL}/query`, apiKey, setError, {
319326
method: 'POST',
320327
headers: {
321328
'Content-Type': 'application/json',
322329
},
323330
body: JSON.stringify({
324331
input,
325-
backend,
332+
backend: effectiveBackend,
326333
conversation_id: conversationId,
327334
mode,
328335
project_path
@@ -337,10 +344,11 @@ export function ChatProvider({
337344
const sendStreamingMessage = async (
338345
input: string,
339346
onToken: (token: string) => void,
340-
backend = 'ollama',
347+
backend?: string,
341348
mode?: string,
342349
project_path?: string
343350
) => {
351+
const effectiveBackend = backend ?? settings?.settings.llm_backend ?? 'ollama';
344352
const res = await fetch(`${BASE_URL}/query/stream`, {
345353
method: 'POST',
346354
headers: {
@@ -349,7 +357,7 @@ export function ChatProvider({
349357
},
350358
body: JSON.stringify({
351359
input,
352-
backend,
360+
backend: effectiveBackend,
353361
conversation_id: conversationId,
354362
mode,
355363
project_path
@@ -370,21 +378,22 @@ export function ChatProvider({
370378
const sendSecuredStreamingMessage = (
371379
input: string,
372380
onToken: (token: string) => void,
373-
backend = 'ollama',
381+
backend?: string,
374382
mode?: string,
375383
project_path?: string
376384
)=> {
377385
if (messages.length === 0) {
378386
addTemporaryConversation(input)
379387
}
388+
const effectiveBackend = backend ?? settings?.settings.llm_backend ?? 'ollama';
380389
return consumeEncryptedStream(
381390
`${BASE_URL}/query/secure_stream`,
382391
apiKey,
383392
conversationId,
384393
onToken,
385394
JSON.stringify({
386395
input,
387-
backend,
396+
backend: effectiveBackend,
388397
conversation_id: conversationId,
389398
mode,
390399
project_path

0 commit comments

Comments
 (0)