26
26
def _attempt_dependency_installation ():
27
27
"""Attempt to install missing dependencies automatically."""
28
28
global _dependency_install_attempted
29
-
29
+
30
30
if _dependency_install_attempted :
31
31
return False # Don't try multiple times
32
-
32
+
33
33
_dependency_install_attempted = True
34
-
34
+
35
35
try :
36
36
FreeCAD .Console .PrintMessage ("FreeCAD AI: Attempting automatic dependency installation...\n " )
37
-
37
+
38
38
# Try to import and use the dependency manager
39
39
try :
40
40
from utils .dependency_manager import DependencyManager
41
-
41
+
42
42
def progress_callback (message ):
43
43
FreeCAD .Console .PrintMessage (f"FreeCAD AI: { message } \n " )
44
-
44
+
45
45
manager = DependencyManager (progress_callback )
46
-
46
+
47
47
# Check for missing critical dependencies and sub-dependencies
48
48
critical_missing = manager .get_critical_missing_dependencies ()
49
-
49
+
50
50
if critical_missing :
51
51
FreeCAD .Console .PrintMessage (f"FreeCAD AI: Installing critical dependencies: { ', ' .join (critical_missing )} \n " )
52
-
52
+
53
53
# Special handling for aiohttp and its sub-dependencies
54
54
if "aiohttp" in critical_missing :
55
55
FreeCAD .Console .PrintMessage ("FreeCAD AI: Checking aiohttp sub-dependencies...\n " )
56
-
56
+
57
57
# Check sub-dependencies
58
58
sub_deps = manager .check_sub_dependencies ("aiohttp" )
59
59
missing_sub_deps = [dep for dep , available in sub_deps .items () if not available ]
60
-
60
+
61
61
if missing_sub_deps :
62
62
FreeCAD .Console .PrintMessage (f"FreeCAD AI: Missing sub-dependencies: { ', ' .join (missing_sub_deps )} \n " )
63
-
63
+
64
64
# Try to install critical dependencies with sub-dependency support
65
65
success = manager .install_missing_dependencies (critical_only = True )
66
-
66
+
67
67
if success :
68
68
FreeCAD .Console .PrintMessage ("FreeCAD AI: ✅ Critical dependencies installed successfully\n " )
69
-
69
+
70
70
# Verify sub-dependencies were installed correctly
71
71
if "aiohttp" in critical_missing and manager .check_dependency ("aiohttp" ):
72
72
sub_deps_after = manager .check_sub_dependencies ("aiohttp" )
73
73
still_missing = [dep for dep , available in sub_deps_after .items () if not available ]
74
-
74
+
75
75
if still_missing :
76
76
FreeCAD .Console .PrintWarning (f"FreeCAD AI: ⚠️ Some sub-dependencies still missing: { ', ' .join (still_missing )} \n " )
77
77
FreeCAD .Console .PrintMessage ("FreeCAD AI: Attempting to install missing sub-dependencies individually...\n " )
78
-
78
+
79
79
# Try to install missing sub-dependencies individually
80
80
for sub_dep in still_missing :
81
81
if manager .install_dependency (sub_dep ):
@@ -84,38 +84,38 @@ def progress_callback(message):
84
84
FreeCAD .Console .PrintWarning (f"FreeCAD AI: ❌ Failed to install sub-dependency { sub_dep } \n " )
85
85
else :
86
86
FreeCAD .Console .PrintMessage ("FreeCAD AI: ✅ All aiohttp sub-dependencies verified\n " )
87
-
87
+
88
88
FreeCAD .Console .PrintMessage ("FreeCAD AI: Please restart FreeCAD to use the new dependencies\n " )
89
89
return True
90
90
else :
91
91
FreeCAD .Console .PrintWarning ("FreeCAD AI: ❌ Failed to install some critical dependencies\n " )
92
92
return False
93
93
else :
94
94
FreeCAD .Console .PrintMessage ("FreeCAD AI: All critical dependencies are already available\n " )
95
-
95
+
96
96
# Even if main dependencies are available, check sub-dependencies
97
97
if manager .check_dependency ("aiohttp" ):
98
98
sub_deps = manager .check_sub_dependencies ("aiohttp" )
99
99
missing_sub_deps = [dep for dep , available in sub_deps .items () if not available ]
100
-
100
+
101
101
if missing_sub_deps :
102
102
FreeCAD .Console .PrintMessage (f"FreeCAD AI: Installing missing aiohttp sub-dependencies: { ', ' .join (missing_sub_deps )} \n " )
103
-
103
+
104
104
for sub_dep in missing_sub_deps :
105
105
if manager .install_dependency (sub_dep ):
106
106
FreeCAD .Console .PrintMessage (f"FreeCAD AI: ✅ Sub-dependency { sub_dep } installed\n " )
107
107
else :
108
108
FreeCAD .Console .PrintWarning (f"FreeCAD AI: ❌ Failed to install sub-dependency { sub_dep } \n " )
109
-
109
+
110
110
return True
111
-
111
+
112
112
except ImportError as e :
113
113
FreeCAD .Console .PrintWarning (f"FreeCAD AI: Could not import dependency manager: { e } \n " )
114
114
return False
115
115
except Exception as e :
116
116
FreeCAD .Console .PrintError (f"FreeCAD AI: Dependency installation failed: { e } \n " )
117
117
return False
118
-
118
+
119
119
except Exception as e :
120
120
FreeCAD .Console .PrintError (f"FreeCAD AI: Automatic dependency installation error: { e } \n " )
121
121
return False
@@ -173,32 +173,30 @@ def _show_dependency_guidance(missing_dependency, provider_name):
173
173
FreeCAD .Console .PrintMessage ("=" * 60 + "\n " )
174
174
175
175
176
-
177
176
def _show_sub_dependency_guidance (main_dependency , missing_sub_dependency , provider_name ):
178
177
"""Show user-friendly guidance for installing missing sub-dependencies."""
179
178
FreeCAD .Console .PrintMessage ("=" * 60 + "\n " )
180
179
FreeCAD .Console .PrintMessage ("FreeCAD AI: SUB-DEPENDENCY INSTALLATION GUIDE\n " )
181
180
FreeCAD .Console .PrintMessage ("=" * 60 + "\n " )
182
-
181
+
183
182
FreeCAD .Console .PrintMessage (f"The { provider_name } provider requires '{ missing_sub_dependency } ', which is a sub-dependency of '{ main_dependency } '.\n " )
184
183
FreeCAD .Console .PrintMessage (f"This usually means { main_dependency } was installed without its required sub-dependencies.\n " )
185
-
184
+
186
185
FreeCAD .Console .PrintMessage ("\n 📋 INSTALLATION OPTIONS:\n " )
187
186
FreeCAD .Console .PrintMessage ("\n 1. 🔧 Use the FreeCAD AI Dependencies Tab:\n " )
188
187
FreeCAD .Console .PrintMessage (" - Open the FreeCAD AI interface\n " )
189
188
FreeCAD .Console .PrintMessage (" - Go to the 'Dependencies' or 'Settings' tab\n " )
190
189
FreeCAD .Console .PrintMessage (" - Click 'Install Missing Dependencies'\n " )
191
- FreeCAD .Console .PrintMessage (" - This will install both main and sub-dependencies\n " )
192
-
190
+
193
191
FreeCAD .Console .PrintMessage ("\n 2. 🐍 Manual Installation via FreeCAD Python Console:\n " )
194
192
FreeCAD .Console .PrintMessage (" Copy and paste this into the FreeCAD Python console:\n " )
195
193
FreeCAD .Console .PrintMessage (" " + "-" * 50 + "\n " )
196
-
194
+
197
195
# Generate installation script for sub-dependency
198
196
try :
199
197
from utils .dependency_manager import DependencyManager
200
198
manager = DependencyManager ()
201
-
199
+
202
200
# Create script for both main dependency and sub-dependency
203
201
FreeCAD .Console .PrintMessage (" exec('''\n " )
204
202
FreeCAD .Console .PrintMessage (" import subprocess, sys, os\n " )
@@ -214,27 +212,28 @@ def _show_sub_dependency_guidance(main_dependency, missing_sub_dependency, provi
214
212
FreeCAD .Console .PrintMessage (" import subprocess, sys\n " )
215
213
FreeCAD .Console .PrintMessage (f" subprocess.run([sys.executable, '-m', 'pip', 'install', '{ missing_sub_dependency } '])\n " )
216
214
FreeCAD .Console .PrintMessage (f" subprocess.run([sys.executable, '-m', 'pip', 'install', '--upgrade', '{ main_dependency } '])\n " )
217
-
215
+
218
216
FreeCAD .Console .PrintMessage (" " + "-" * 50 + "\n " )
219
-
217
+
220
218
FreeCAD .Console .PrintMessage ("\n 3. 💻 System Package Manager:\n " )
221
219
if main_dependency == "aiohttp" :
222
220
FreeCAD .Console .PrintMessage (" Ubuntu/Debian: sudo apt install python3-aiohttp python3-multidict python3-yarl\n " )
223
221
FreeCAD .Console .PrintMessage (" Fedora: sudo dnf install python3-aiohttp python3-multidict python3-yarl\n " )
224
222
FreeCAD .Console .PrintMessage (" macOS: pip3 install aiohttp[speedups]\n " )
225
223
else :
226
224
FreeCAD .Console .PrintMessage (f" Install both: pip3 install { missing_sub_dependency } { main_dependency } \n " )
227
-
225
+
228
226
FreeCAD .Console .PrintMessage ("\n 4. 🔄 Restart FreeCAD:\n " )
229
227
FreeCAD .Console .PrintMessage (" After installation, restart FreeCAD to use the new dependencies\n " )
230
-
228
+
231
229
FreeCAD .Console .PrintMessage ("\n 💡 TROUBLESHOOTING:\n " )
232
230
FreeCAD .Console .PrintMessage (" - Sub-dependencies are often missed when using --no-deps flag\n " )
233
231
FreeCAD .Console .PrintMessage (" - Try reinstalling the main dependency without --no-deps\n " )
234
232
FreeCAD .Console .PrintMessage (" - Check that your pip version is up to date\n " )
235
-
233
+
236
234
FreeCAD .Console .PrintMessage ("=" * 60 + "\n " )
237
235
236
+
238
237
def _lazy_import_provider (provider_name : str , module_name : str , class_name : str ):
239
238
"""Lazy import a provider with enhanced dependency management and error handling."""
240
239
if provider_name in _providers :
@@ -250,15 +249,15 @@ def _lazy_import_provider(provider_name: str, module_name: str, class_name: str)
250
249
_providers [provider_name ] = provider_class
251
250
FreeCAD .Console .PrintMessage (f"FreeCAD AI: ✅ { provider_name } provider loaded successfully\n " )
252
251
return provider_class
253
-
252
+
254
253
except ImportError as e :
255
254
error_msg = f"Failed to import { provider_name } : { str (e )} "
256
255
_provider_errors [provider_name ] = error_msg
257
-
256
+
258
257
# Enhanced sub-dependency detection
259
258
missing_dependency = None
260
259
missing_sub_dependency = None
261
-
260
+
262
261
if "aiohttp" in str (e ):
263
262
missing_dependency = "aiohttp"
264
263
elif "multidict" in str (e ):
@@ -274,21 +273,21 @@ def _lazy_import_provider(provider_name: str, module_name: str, class_name: str)
274
273
missing_dependency = "requests"
275
274
elif "mcp" in str (e ):
276
275
missing_dependency = "mcp"
277
-
276
+
278
277
if missing_dependency :
279
278
if missing_sub_dependency :
280
279
FreeCAD .Console .PrintWarning (f"FreeCAD AI: ❌ { provider_name } provider unavailable - missing '{ missing_sub_dependency } ' sub-dependency\n " )
281
280
FreeCAD .Console .PrintWarning (f"FreeCAD AI: This is a sub-dependency of '{ missing_dependency } ' that wasn't installed properly\n " )
282
281
else :
283
282
FreeCAD .Console .PrintWarning (f"FreeCAD AI: ❌ { provider_name } provider unavailable - missing '{ missing_dependency } ' dependency\n " )
284
-
283
+
285
284
# Attempt automatic installation with sub-dependency handling
286
285
if not _dependency_install_attempted :
287
286
if missing_sub_dependency :
288
287
FreeCAD .Console .PrintMessage (f"FreeCAD AI: Attempting to install { missing_dependency } with sub-dependencies...\n " )
289
288
else :
290
289
FreeCAD .Console .PrintMessage (f"FreeCAD AI: Attempting to install { missing_dependency } automatically...\n " )
291
-
290
+
292
291
if _attempt_dependency_installation ():
293
292
FreeCAD .Console .PrintMessage (f"FreeCAD AI: ✅ Dependencies installed - restart FreeCAD to use { provider_name } \n " )
294
293
else :
@@ -304,9 +303,9 @@ def _lazy_import_provider(provider_name: str, module_name: str, class_name: str)
304
303
_show_dependency_guidance (missing_dependency , provider_name )
305
304
else :
306
305
FreeCAD .Console .PrintWarning (f"FreeCAD AI: ❌ { provider_name } provider import failed: { error_msg } \n " )
307
-
306
+
308
307
return None
309
-
308
+
310
309
except Exception as e :
311
310
error_msg = f"Error loading { provider_name } : { str (e )} "
312
311
_provider_errors [provider_name ] = error_msg
@@ -344,24 +343,23 @@ def get_available_providers() -> Dict[str, Any]:
344
343
"OpenRouter" : get_openrouter_provider (),
345
344
}
346
345
347
-
348
346
# Enhanced availability summary with sub-dependency information
349
347
available_count = sum (1 for p in providers .values () if p is not None )
350
348
total_count = len (providers )
351
349
352
350
if available_count == 0 :
353
351
FreeCAD .Console .PrintWarning (f"FreeCAD AI: ⚠️ No AI providers available ({ available_count } /{ total_count } )\n " )
354
352
FreeCAD .Console .PrintWarning ("FreeCAD AI: Install missing dependencies to enable AI providers\n " )
355
-
353
+
356
354
# Check if it's a sub-dependency issue
357
355
try :
358
356
from utils .dependency_manager import DependencyManager
359
357
manager = DependencyManager ()
360
-
358
+
361
359
if manager .check_dependency ("aiohttp" ):
362
360
sub_deps = manager .check_sub_dependencies ("aiohttp" )
363
361
missing_sub_deps = [dep for dep , available in sub_deps .items () if not available ]
364
-
362
+
365
363
if missing_sub_deps :
366
364
FreeCAD .Console .PrintWarning (f"FreeCAD AI: ⚠️ aiohttp is installed but missing sub-dependencies: { ', ' .join (missing_sub_deps )} \n " )
367
365
FreeCAD .Console .PrintWarning ("FreeCAD AI: Use Dependencies tab to fix sub-dependency issues\n " )
@@ -370,7 +368,7 @@ def get_available_providers() -> Dict[str, Any]:
370
368
371
369
elif available_count < total_count :
372
370
FreeCAD .Console .PrintMessage (f"FreeCAD AI: ⚠️ Partial AI provider availability ({ available_count } /{ total_count } )\n " )
373
-
371
+
374
372
# Show which providers are missing and why
375
373
for provider_name , provider_class in providers .items ():
376
374
if provider_class is None and provider_name in _provider_errors :
@@ -379,10 +377,9 @@ def get_available_providers() -> Dict[str, Any]:
379
377
FreeCAD .Console .PrintMessage (f"FreeCAD AI: ⚠️ { provider_name } : Missing sub-dependency\n " )
380
378
else :
381
379
FreeCAD .Console .PrintMessage (f"FreeCAD AI: ⚠️ { provider_name } : Missing main dependency\n " )
382
-
383
380
else :
384
381
FreeCAD .Console .PrintMessage (f"FreeCAD AI: ✅ All AI providers available ({ available_count } /{ total_count } )\n " )
385
-
382
+
386
383
return providers
387
384
388
385
@@ -407,7 +404,7 @@ def check_dependencies() -> Dict[str, bool]:
407
404
# Try to use the enhanced dependency manager
408
405
409
406
from utils .dependency_manager import check_dependencies as enhanced_check
410
-
407
+
411
408
dependencies = enhanced_check ()
412
409
413
410
# Log dependency status
@@ -444,7 +441,6 @@ def install_missing_dependencies():
444
441
# Try to use the dependency manager
445
442
446
443
from utils .dependency_manager import auto_install_dependencies
447
-
448
444
449
445
def progress_callback (message ):
450
446
FreeCAD .Console .PrintMessage (f"FreeCAD AI: { message } \n " )
0 commit comments