Fetch models from OpenAI API or any OpenAI-compatible endpoint. Returns a list of model options with label and value.
(api_key, api_url='')
| 852 | |
| 853 | |
| 854 | def _fetch_openai_models(api_key, api_url=''): |
| 855 | """ |
| 856 | Fetch models from OpenAI API or any OpenAI-compatible endpoint. |
| 857 | Returns a list of model options with label and value. |
| 858 | """ |
| 859 | import urllib.request |
| 860 | import urllib.error |
| 861 | from pgadmin.llm.utils import validate_api_url |
| 862 | |
| 863 | base_url = (api_url or 'https://api.openai.com/v1').rstrip('/') |
| 864 | |
| 865 | if not validate_api_url(base_url): |
| 866 | raise LLMApiError( |
| 867 | 'API URL is not in the allowed list. ' |
| 868 | 'Check the ALLOWED_LLM_API_URLS configuration.' |
| 869 | ) |
| 870 | |
| 871 | url = f'{base_url}/models' |
| 872 | |
| 873 | headers = { |
| 874 | 'Content-Type': 'application/json' |
| 875 | } |
| 876 | if api_key: |
| 877 | headers['Authorization'] = f'Bearer {api_key}' |
| 878 | |
| 879 | req = urllib.request.Request(url, headers=headers) |
| 880 | |
| 881 | try: |
| 882 | with urllib.request.urlopen( |
| 883 | req, timeout=30, context=SSL_CONTEXT |
| 884 | ) as response: |
| 885 | data = json.loads(response.read().decode('utf-8')) |
| 886 | except urllib.error.HTTPError as e: |
| 887 | if e.code == 401: |
| 888 | raise LLMApiError('Invalid API key') |
| 889 | raise LLMApiError(f'API error: {e.code}') |
| 890 | except urllib.error.URLError as e: |
| 891 | raise LLMApiError( |
| 892 | f'Cannot connect to OpenAI API: {e.reason}' |
| 893 | ) |
| 894 | |
| 895 | models = [] |
| 896 | seen = set() |
| 897 | |
| 898 | for model in data.get('data', []): |
| 899 | model_id = model.get('id', '') |
| 900 | |
| 901 | # Skip if already seen or empty |
| 902 | if not model_id or model_id in seen: |
| 903 | continue |
| 904 | seen.add(model_id) |
| 905 | |
| 906 | models.append({ |
| 907 | 'label': model_id, |
| 908 | 'value': model_id |
| 909 | }) |
| 910 | |
| 911 | if not models and api_url: |
no test coverage detected