Skip to content

Commit 4ca18b3

Browse files
committed
winidows specific fixes
1 parent 2d4ae87 commit 4ca18b3

3 files changed

Lines changed: 131 additions & 6 deletions

File tree

ollama-search

Lines changed: 0 additions & 1 deletion
This file was deleted.

src/app/services/ollamaService.ts

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,74 @@ export async function listOllamaModels(): Promise<string[]> {
161161
}
162162
}
163163

164+
// Add periodic model refresh and Windows-specific fixes
165+
export async function listOllamaModelsWithRetry(): Promise<string[]> {
166+
const maxRetries = 5; // Increased from 3 for Windows
167+
const retryDelay = 800; // Slightly reduced delay
168+
169+
for (let attempt = 1; attempt <= maxRetries; attempt++) {
170+
try {
171+
const models = await listOllamaModels();
172+
if (models.length > 0) {
173+
return models;
174+
}
175+
176+
// If no models found and not the last attempt, wait and retry
177+
if (attempt < maxRetries) {
178+
// On Windows, add a small random jitter to avoid timing issues
179+
const jitter = Math.random() * 200; // 0-200ms
180+
await new Promise(resolve => setTimeout(resolve, (retryDelay * attempt) + jitter));
181+
}
182+
} catch (error) {
183+
console.warn(`Model listing attempt ${attempt} failed:`, error);
184+
185+
// If not the last attempt, wait and retry
186+
if (attempt < maxRetries) {
187+
const jitter = Math.random() * 200; // 0-200ms
188+
await new Promise(resolve => setTimeout(resolve, (retryDelay * attempt) + jitter));
189+
}
190+
}
191+
}
192+
193+
return [];
194+
}
195+
196+
// Windows-specific model refresh with force reload
197+
export async function forceRefreshModels(): Promise<string[]> {
198+
try {
199+
// On Windows, sometimes we need to force a refresh of the Ollama connection
200+
// First, try to "wake up" Ollama by making a simple API call
201+
await fetch("http://localhost:11434/api/tags", {
202+
method: "GET",
203+
signal: AbortSignal.timeout(3000),
204+
}).catch(() => {}); // Ignore errors, this is just to wake up the service
205+
206+
// Wait a moment for the service to respond
207+
await new Promise(resolve => setTimeout(resolve, 500));
208+
209+
// Now try to get the models with retry logic
210+
const models = await listOllamaModelsWithRetry();
211+
212+
// If still no models on Windows, try one more aggressive approach
213+
if (models.length === 0) {
214+
try {
215+
// Try the backend command directly as a last resort
216+
const backendModels = await invoke('list_installed_models') as string[];
217+
if (backendModels && backendModels.length > 0) {
218+
return backendModels;
219+
}
220+
} catch (backendError) {
221+
console.warn('Backend fallback failed:', backendError);
222+
}
223+
}
224+
225+
return models;
226+
} catch (error) {
227+
console.error('Force refresh failed:', error);
228+
return [];
229+
}
230+
}
231+
164232
export interface OllamaStatus {
165233
isInstalled: boolean;
166234
isRunning: boolean;

src/components/Chat.tsx

Lines changed: 63 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import { useState, useEffect, useRef, useCallback } from "react";
44
import { useTheme } from "next-themes";
5-
import { askOllama, listOllamaModels, checkOllamaStatus, askOllamaVerbose, askOllamaStreaming, searchWeb, type OllamaStatus } from "@/app/services/ollamaService";
5+
import { askOllama, listOllamaModels, forceRefreshModels, checkOllamaStatus, askOllamaVerbose, askOllamaStreaming, searchWeb, type OllamaStatus } from "@/app/services/ollamaService";
66
import { PlaceholdersAndVanishInput } from "@/components/ui/placeholders-and-vanish-input";
77
import { TextGenerateEffect } from "@/components/ui/enhanced-text-generate-effect";
88
import { StreamingTextEffect } from "@/components/ui/streaming-text-effect";
@@ -170,19 +170,45 @@ export default function Chat() {
170170
};
171171
}, [clearConfirmation.isOpen, clearConfirmation.isClearing]);
172172

173-
const refreshModels = useCallback(async () => {
173+
const refreshModels = useCallback(async (forceRefresh: boolean = false) => {
174174
if (!ollamaStatus.isRunning) return;
175175

176176
setRefreshingModels(true);
177177
try {
178-
const availableModels = await listOllamaModels();
178+
// Use force refresh on Windows or when explicitly requested
179+
const isWindows = typeof navigator !== 'undefined' && navigator.userAgent.includes('Windows');
180+
const availableModels = forceRefresh || isWindows
181+
? await forceRefreshModels()
182+
: await listOllamaModels();
183+
179184
setModels(availableModels);
180185

181186
// Set default model if none selected or current model not available
182187
if (availableModels.length > 0) {
183188
if (!model || !availableModels.includes(model)) {
184189
setModel(availableModels[0]);
185190
}
191+
} else if (isWindows) {
192+
// On Windows, if we still don't have models, try multiple times with increasing delays
193+
const retryAttempts = [1000, 3000, 5000]; // 1s, 3s, 5s delays
194+
195+
for (let i = 0; i < retryAttempts.length; i++) {
196+
setTimeout(async () => {
197+
try {
198+
const retryModels = await forceRefreshModels();
199+
if (retryModels.length > 0) {
200+
setModels(retryModels);
201+
if (!model || !retryModels.includes(model)) {
202+
setModel(retryModels[0]);
203+
}
204+
// Success, exit early
205+
return;
206+
}
207+
} catch (error) {
208+
console.error(`Windows model retry ${i + 1} failed:`, error);
209+
}
210+
}, retryAttempts[i]);
211+
}
186212
}
187213
} catch (error) {
188214
console.error('Error loading models:', error);
@@ -192,6 +218,16 @@ export default function Chat() {
192218
}
193219
}, [ollamaStatus.isRunning, model]);
194220

221+
// Event handler wrapper for refresh button clicks
222+
const handleRefreshModels = useCallback(() => {
223+
refreshModels(false);
224+
}, [refreshModels]);
225+
226+
// Event handler wrapper for force refresh
227+
const handleForceRefreshModels = useCallback(() => {
228+
refreshModels(true);
229+
}, [refreshModels]);
230+
195231
useEffect(() => {
196232
// Check Ollama status first, then load models if available
197233
const checkStatus = async () => {
@@ -228,6 +264,28 @@ export default function Chat() {
228264
}
229265
}, [refreshModels]);
230266

267+
// Windows-specific: Periodic background model refresh
268+
useEffect(() => {
269+
const isWindows = typeof navigator !== 'undefined' && navigator.userAgent.includes('Windows');
270+
271+
if (!isWindows || !ollamaStatus.isRunning) return;
272+
273+
// Set up periodic refresh for Windows every 30 seconds
274+
const interval = setInterval(async () => {
275+
try {
276+
// Only refresh if we don't have models or there's been a long time since last refresh
277+
if (models.length === 0) {
278+
console.log('Windows: Background model refresh - no models detected');
279+
await refreshModels(true);
280+
}
281+
} catch (error) {
282+
console.error('Windows background model refresh failed:', error);
283+
}
284+
}, 30000); // 30 seconds
285+
286+
return () => clearInterval(interval);
287+
}, [ollamaStatus.isRunning, models.length, refreshModels]);
288+
231289
const createNewConversation = () => {
232290
const newConversation: Conversation = {
233291
id: Date.now().toString(),
@@ -921,7 +979,7 @@ export default function Chat() {
921979
<Button
922980
variant="ghost"
923981
size="sm"
924-
onClick={refreshModels}
982+
onClick={handleRefreshModels}
925983
disabled={!ollamaStatus.isRunning || refreshingModels}
926984
title="Refresh model list"
927985
>
@@ -974,7 +1032,7 @@ export default function Chat() {
9741032
</Button>
9751033
<Button
9761034
variant="outline"
977-
onClick={refreshModels}
1035+
onClick={handleRefreshModels}
9781036
disabled={refreshingModels}
9791037
>
9801038
{refreshingModels ? (

0 commit comments

Comments
 (0)