22
33import { useState , useEffect , useRef , useCallback } from "react" ;
44import { 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" ;
66import { PlaceholdersAndVanishInput } from "@/components/ui/placeholders-and-vanish-input" ;
77import { TextGenerateEffect } from "@/components/ui/enhanced-text-generate-effect" ;
88import { 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