11import axios from 'axios' ;
2-
3- // Helper function to track events using MatomoManager instance
4- function trackMatomoEvent ( category : string , action : string , name ?: string ) {
5- try {
6- if ( typeof window !== 'undefined' && ( window as any ) . _matomoManagerInstance ) {
7- ( window as any ) . _matomoManagerInstance . trackEvent ( category , action , name )
8- }
9- } catch ( error ) {
10- // Silent fail for tracking
11- }
12- }
2+ import { Registry } from '@remix-project/remix-lib' ;
3+ import { trackMatomoEvent } from '@remix-api'
134
145// default Ollama ports to check (11434 is the legacy/standard port)
156const OLLAMA_PORTS = [ 11434 , 11435 , 11436 ] ;
167const OLLAMA_BASE_HOST = 'http://localhost' ;
8+ const DEFAULT_OLLAMA_HOST = 'http://localhost:11434' ;
179
1810let discoveredOllamaHost : string | null = null ;
1911
12+ function getConfiguredOllamaEndpoint ( ) : string | null {
13+ const filemanager = Registry . getInstance ( ) . get ( 'filemanager' ) . api ;
14+ try {
15+ const config = Registry . getInstance ( ) . get ( 'config' ) . api
16+ const configuredEndpoint = config . get ( 'settings/ollama-endpoint' ) ;
17+ if ( configuredEndpoint && configuredEndpoint !== DEFAULT_OLLAMA_HOST ) {
18+ trackMatomoEvent ( filemanager , { category : 'ai' , action : 'remixAI' , name : 'ollama_using_configured_endpoint' , value : configuredEndpoint } ) ;
19+ return configuredEndpoint ;
20+ }
21+ } catch ( error ) {
22+ trackMatomoEvent ( filemanager , { category : 'ai' , action : 'remixAI' , name : 'ollama_config_access_failed' , value : error . message || 'unknown' } ) ;
23+ }
24+ return null ;
25+ }
26+
2027export async function discoverOllamaHost ( ) : Promise < string | null > {
28+ const filemanager = Registry . getInstance ( ) . get ( 'filemanager' ) . api ;
2129 if ( discoveredOllamaHost ) {
22- trackMatomoEvent ( 'ai' , 'remixAI' , `ollama_host_cache_hit:${ discoveredOllamaHost } ` ) ;
30+ trackMatomoEvent ( filemanager , { category : 'ai' , action : 'remixAI' , name : `ollama_host_cache_hit:${ discoveredOllamaHost } ` } )
2331 return discoveredOllamaHost ;
2432 }
2533
34+ // First, try to use the configured endpoint from settings
35+ const configuredEndpoint = getConfiguredOllamaEndpoint ( ) ;
36+ if ( configuredEndpoint ) {
37+ try {
38+ const res = await axios . get ( `${ configuredEndpoint } /api/tags` , { timeout : 2000 } ) ;
39+ if ( res . status === 200 ) {
40+ discoveredOllamaHost = configuredEndpoint ;
41+ trackMatomoEvent ( filemanager , { category : 'ai' , action : 'remixAI' , name : 'ollama_configured_endpoint_success' , value : configuredEndpoint } ) ;
42+ return configuredEndpoint ;
43+ }
44+ return null ;
45+ } catch ( error ) {
46+ trackMatomoEvent ( filemanager , { category : 'ai' , action : 'remixAI' , name : 'ollama_configured_endpoint_failed' , value : `${ configuredEndpoint } :${ error . message || 'unknown' } ` } ) ;
47+ // Fall back to discovery if configured endpoint fails
48+ return null ;
49+ }
50+ }
51+
52+ // Fall back to port discovery if no configured endpoint
2653 for ( const port of OLLAMA_PORTS ) {
2754 const host = `${ OLLAMA_BASE_HOST } :${ port } ` ;
28- trackMatomoEvent ( 'ai' , 'remixAI' , `ollama_port_check:${ port } ` ) ;
55+ trackMatomoEvent ( filemanager , { category : 'ai' , action : 'remixAI' , name : `ollama_port_check:${ port } ` } ) ;
2956 try {
3057 const res = await axios . get ( `${ host } /api/tags` , { timeout : 2000 } ) ;
3158 if ( res . status === 200 ) {
3259 discoveredOllamaHost = host ;
33- trackMatomoEvent ( 'ai' , 'remixAI' , `ollama_host_discovered_success:${ host } ` ) ;
60+ trackMatomoEvent ( filemanager , { category : 'ai' , action : 'remixAI' , name : `ollama_host_discovered_success:${ host } ` } ) ;
3461 return host ;
3562 }
3663 } catch ( error ) {
37- trackMatomoEvent ( 'ai' , 'remixAI' , `ollama_port_connection_failed:${ port } :${ error . message || 'unknown' } ` ) ;
64+ trackMatomoEvent ( filemanager , { category : 'ai' , action : 'remixAI' , name : `ollama_port_connection_failed:${ port } :${ error . message || 'unknown' } ` } ) ;
3865 continue ; // next port
3966 }
4067 }
41- trackMatomoEvent ( 'ai' , 'remixAI' , 'ollama_host_discovery_failed:no_ports_available' ) ;
68+ trackMatomoEvent ( filemanager , { category : 'ai' , action : 'remixAI' , name : 'ollama_host_discovery_failed:no_ports_available' } ) ;
4269 return null ;
4370}
4471
4572export async function isOllamaAvailable ( ) : Promise < boolean > {
46- trackMatomoEvent ( 'ai' , 'remixAI' , 'ollama_availability_check:checking' ) ;
73+ const filemanager = Registry . getInstance ( ) . get ( 'filemanager' ) . api ;
74+ trackMatomoEvent ( filemanager , { category : 'ai' , action : 'remixAI' , name : 'ollama_availability_check:checking' } ) ;
4775 const host = await discoverOllamaHost ( ) ;
4876 const isAvailable = host !== null ;
49- trackMatomoEvent ( 'ai' , 'remixAI' , `ollama_availability_result:available:${ isAvailable } ` ) ;
77+ trackMatomoEvent ( filemanager , { category : 'ai' , action : 'remixAI' , name : `ollama_availability_result:available:${ isAvailable } ` } ) ;
5078 return isAvailable ;
5179}
5280
5381export async function listModels ( ) : Promise < string [ ] > {
54- trackMatomoEvent ( 'ai' , 'remixAI' , 'ollama_list_models_start:fetching' ) ;
82+ const filemanager = Registry . getInstance ( ) . get ( 'filemanager' ) . api ;
83+ trackMatomoEvent ( filemanager , { category : 'ai' , action : 'remixAI' , name : 'ollama_list_models_start:fetching' } ) ;
5584 const host = await discoverOllamaHost ( ) ;
5685 if ( ! host ) {
57- trackMatomoEvent ( 'ai' , 'remixAI' , 'ollama_list_models_failed:no_host' ) ;
86+ trackMatomoEvent ( filemanager , { category : 'ai' , action : 'remixAI' , name : 'ollama_list_models_failed:no_host' } ) ;
5887 throw new Error ( 'Ollama is not available' ) ;
5988 }
6089
@@ -71,26 +100,35 @@ export function getOllamaHost(): string | null {
71100}
72101
73102export function resetOllamaHost ( ) : void {
74- trackMatomoEvent ( 'ai' , 'remixAI' , `ollama_reset_host:${ discoveredOllamaHost || 'null' } ` ) ;
103+ const fileManager = Registry . getInstance ( ) . get ( 'filemanager' ) . api ;
104+ trackMatomoEvent ( fileManager , { category : 'ai' , action : 'remixAI' , name : `ollama_reset_host:${ discoveredOllamaHost || 'null' } ` } ) ;
75105 discoveredOllamaHost = null ;
76106}
77107
108+ export function resetOllamaHostOnSettingsChange ( ) : void {
109+ const fileManager = Registry . getInstance ( ) . get ( 'filemanager' ) . api ;
110+ // This function should be called when Ollama settings are updated
111+ resetOllamaHost ( ) ;
112+ trackMatomoEvent ( fileManager , { category : 'ai' , action : 'remixAI' , name : 'ollama_reset_on_settings_change' } ) ;
113+ }
114+
78115export async function pullModel ( modelName : string ) : Promise < void > {
116+ const filemanager = Registry . getInstance ( ) . get ( 'filemanager' ) . api ;
79117 // in case the user wants to pull a model from registry
80- trackMatomoEvent ( 'ai' , 'remixAI' , `ollama_pull_model_start:${ modelName } ` ) ;
118+ trackMatomoEvent ( filemanager , { category : 'ai' , action : 'remixAI' , name : `ollama_pull_model_start:${ modelName } ` } ) ;
81119 const host = await discoverOllamaHost ( ) ;
82120 if ( ! host ) {
83- trackMatomoEvent ( 'ai' , 'remixAI' , `ollama_pull_model_failed:${ modelName } |no_host` ) ;
121+ trackMatomoEvent ( filemanager , { category : 'ai' , action : 'remixAI' , name : `ollama_pull_model_failed:${ modelName } |no_host` } ) ;
84122 throw new Error ( 'Ollama is not available' ) ;
85123 }
86124
87125 try {
88126 const startTime = Date . now ( ) ;
89127 await axios . post ( `${ host } /api/pull` , { name : modelName } ) ;
90128 const duration = Date . now ( ) - startTime ;
91- trackMatomoEvent ( 'ai' , 'remixAI' , `ollama_pull_model_success:${ modelName } |duration:${ duration } ms` ) ;
129+ trackMatomoEvent ( filemanager , { category : 'ai' , action : 'remixAI' , name : `ollama_pull_model_success:${ modelName } |duration:${ duration } ms` } ) ;
92130 } catch ( error ) {
93- trackMatomoEvent ( 'ai' , 'remixAI' , `ollama_pull_model_error:${ modelName } |${ error . message || 'unknown' } ` ) ;
131+ trackMatomoEvent ( filemanager , { category : 'ai' , action : 'remixAI' , name : `ollama_pull_model_error:${ modelName } |${ error . message || 'unknown' } ` } ) ;
94132 console . error ( 'Error pulling model:' , error ) ;
95133 throw new Error ( `Failed to pull model: ${ modelName } ` ) ;
96134 }
@@ -106,7 +144,8 @@ export async function validateModel(modelName: string): Promise<boolean> {
106144}
107145
108146export async function getBestAvailableModel ( ) : Promise < string | null > {
109- trackMatomoEvent ( 'ai' , 'remixAI' , 'ollama_get_best' ) ;
147+ const filemanager = Registry . getInstance ( ) . get ( 'filemanager' ) . api ;
148+ trackMatomoEvent ( filemanager , { category : 'ai' , action : 'remixAI' , name : 'ollama_get_best' } ) ;
110149 try {
111150 const models = await listModels ( ) ;
112151 if ( models . length === 0 ) return null ;
@@ -125,7 +164,7 @@ export async function getBestAvailableModel(): Promise<string | null> {
125164 // TODO get model stats and get best model
126165 return models [ 0 ] ;
127166 } catch ( error ) {
128- trackMatomoEvent ( 'ai' , 'remixAI' , `ollama_get_best_model_error:${ error . message || 'unknown' } ` ) ;
167+ trackMatomoEvent ( filemanager , { category : 'ai' , action : 'remixAI' , name : `ollama_get_best_model_error:${ error . message || 'unknown' } ` } ) ;
129168 console . error ( 'Error getting best available model:' , error ) ;
130169 return null ;
131170 }
0 commit comments