@@ -45,6 +45,8 @@ def get_config_path():
4545 DEEPSEEK_API_KEY ,
4646 DEEPSEEK_MODEL ,
4747 POE_API_KEY ,
48+ NIM_API_KEY ,
49+ NIM_MODEL ,
4850 POE_MODEL ,
4951 MAX_TOKENS_PER_CHUNK ,
5052 OUTPUT_FILENAME_PATTERN
@@ -119,6 +121,8 @@ def get_available_models():
119121 return _get_deepseek_models (api_key )
120122 elif provider == 'poe' :
121123 return _get_poe_models (api_key )
124+ elif provider == 'nim' :
125+ return _get_nim_models (api_key )
122126 elif provider == 'openai' :
123127 # Get endpoint from request for LM Studio support
124128 if request .method == 'POST' :
@@ -158,12 +162,14 @@ def mask_api_key(key):
158162 "mistral_api_key" : mask_api_key (MISTRAL_API_KEY ),
159163 "deepseek_api_key" : mask_api_key (DEEPSEEK_API_KEY ),
160164 "poe_api_key" : mask_api_key (POE_API_KEY ),
165+ "nim_api_key" : mask_api_key (NIM_API_KEY ),
161166 "gemini_api_key_configured" : bool (GEMINI_API_KEY ),
162167 "openai_api_key_configured" : bool (OPENAI_API_KEY ),
163168 "openrouter_api_key_configured" : bool (OPENROUTER_API_KEY ),
164169 "mistral_api_key_configured" : bool (MISTRAL_API_KEY ),
165170 "deepseek_api_key_configured" : bool (DEEPSEEK_API_KEY ),
166171 "poe_api_key_configured" : bool (POE_API_KEY ),
172+ "nim_api_key_configured" : bool (NIM_API_KEY ),
167173 "output_filename_pattern" : OUTPUT_FILENAME_PATTERN
168174 }
169175
@@ -412,6 +418,95 @@ def _get_poe_models(provided_api_key=None):
412418 "error" : f"Error connecting to Poe API: { str (e )} "
413419 })
414420
421+ def _get_nim_models (provided_api_key = None ):
422+ """Get available models from NVIDIA NIM API"""
423+ from src .config import NIM_API_ENDPOINT
424+
425+ api_key = _resolve_api_key (provided_api_key , 'NIM_API_KEY' , NIM_API_KEY )
426+
427+ # Use NIM_MODEL from .env, fallback to meta/llama-3.1-8b-instruct
428+ default_model = NIM_MODEL if NIM_MODEL else "meta/llama-3.1-8b-instruct"
429+
430+ if not api_key :
431+ return jsonify ({
432+ "models" : [],
433+ "model_names" : [],
434+ "default" : default_model ,
435+ "status" : "api_key_missing" ,
436+ "count" : 0 ,
437+ "error" : "NVIDIA NIM API key is required. Get your key at https://build.nvidia.com/"
438+ })
439+
440+ try :
441+ # Determine base URL from endpoint
442+ base_url = NIM_API_ENDPOINT .replace ('/chat/completions' , '' ).rstrip ('/' )
443+ models_url = f"{ base_url } /models"
444+ headers = {'Authorization' : f'Bearer { api_key } ' }
445+
446+ response = requests .get (models_url , headers = headers , timeout = 10 )
447+
448+ if response .status_code == 200 :
449+ data = response .json ()
450+ models_data = data .get ('data' , [])
451+
452+ if models_data :
453+ # Filter and format models
454+ models = []
455+ for m in models_data :
456+ model_id = m .get ('id' , '' )
457+ # Skip embedding models and other non-chat models
458+ if 'embedding' in model_id .lower () or 'whisper' in model_id .lower ():
459+ continue
460+ models .append ({
461+ 'id' : model_id ,
462+ 'name' : model_id ,
463+ 'owned_by' : m .get ('owned_by' , 'nvidia' )
464+ })
465+
466+ # Sort models by name
467+ models .sort (key = lambda x : x ['name' ].lower ())
468+
469+ if models :
470+ model_ids = [m ['id' ] for m in models ]
471+ if default_model not in model_ids and model_ids :
472+ default_model = model_ids [0 ]
473+ return jsonify ({
474+ "models" : models ,
475+ "model_names" : model_ids ,
476+ "default" : default_model ,
477+ "status" : "nim_connected" ,
478+ "count" : len (models )
479+ })
480+
481+ # If API call failed, return empty with error
482+ return jsonify ({
483+ "models" : [],
484+ "model_names" : [],
485+ "default" : default_model ,
486+ "status" : "nim_error" ,
487+ "count" : 0 ,
488+ "error" : f"Failed to retrieve NVIDIA NIM models (HTTP { response .status_code } )"
489+ })
490+
491+ except requests .exceptions .ConnectionError :
492+ return jsonify ({
493+ "models" : [],
494+ "model_names" : [],
495+ "default" : default_model ,
496+ "status" : "nim_error" ,
497+ "count" : 0 ,
498+ "error" : "Could not connect to NVIDIA NIM API. Check your internet connection."
499+ })
500+ except Exception as e :
501+ return jsonify ({
502+ "models" : [],
503+ "model_names" : [],
504+ "default" : default_model ,
505+ "status" : "nim_error" ,
506+ "count" : 0 ,
507+ "error" : f"Error connecting to NVIDIA NIM API: { str (e )} "
508+ })
509+
415510 def _get_openai_models (provided_api_key = None , api_endpoint = None ):
416511 """Get available models from OpenAI-compatible API
417512
@@ -777,6 +872,8 @@ def save_settings():
777872 'DEEPSEEK_MODEL' ,
778873 'POE_API_KEY' ,
779874 'POE_MODEL' ,
875+ 'NIM_API_KEY' ,
876+ 'NIM_MODEL' ,
780877 'DEFAULT_MODEL' ,
781878 'LLM_PROVIDER' ,
782879 'API_ENDPOINT' ,
@@ -830,6 +927,7 @@ def get_settings():
830927 "mistral_api_key_configured" : bool (MISTRAL_API_KEY ),
831928 "deepseek_api_key_configured" : bool (DEEPSEEK_API_KEY ),
832929 "poe_api_key_configured" : bool (POE_API_KEY ),
930+ "nim_api_key_configured" : bool (NIM_API_KEY ),
833931 "default_model" : DEFAULT_MODEL or "" ,
834932 "llm_provider" : os .getenv ('LLM_PROVIDER' , 'ollama' ),
835933 "api_endpoint" : DEFAULT_OLLAMA_API_ENDPOINT or "" ,
0 commit comments