fixes setup scripts

fixes to env handling in setup script plus other minor fixes
This commit is contained in:
Pavel
2026-01-12 23:48:52 +03:00
parent f1d714b5c1
commit 974d98b94b
5 changed files with 125 additions and 83 deletions

View File

@@ -6,6 +6,19 @@ from typing import Dict, List, Optional
logger = logging.getLogger(__name__)
def _is_valid_api_key(key: Optional[str]) -> bool:
"""
Check if an API key is valid (not None, not empty, not string 'None').
Handles Pydantic loading 'None' from .env as string "None".
"""
if key is None:
return False
if not isinstance(key, str):
return False
key_stripped = key.strip().lower()
return key_stripped != "" and key_stripped != "none"
class ModelProvider(str, Enum):
OPENAI = "openai"
AZURE_OPENAI = "azure_openai"
@@ -87,40 +100,53 @@ class ModelRegistry:
# Skip DocsGPT model if using custom OpenAI-compatible endpoint
if not settings.OPENAI_BASE_URL:
self._add_docsgpt_models(settings)
if settings.OPENAI_API_KEY or (
settings.LLM_PROVIDER == "openai" and settings.API_KEY
if (
_is_valid_api_key(settings.OPENAI_API_KEY)
or (settings.LLM_PROVIDER == "openai" and _is_valid_api_key(settings.API_KEY))
or settings.OPENAI_BASE_URL
):
self._add_openai_models(settings)
if settings.OPENAI_API_BASE or (
settings.LLM_PROVIDER == "azure_openai" and settings.API_KEY
settings.LLM_PROVIDER == "azure_openai" and _is_valid_api_key(settings.API_KEY)
):
self._add_azure_openai_models(settings)
if settings.ANTHROPIC_API_KEY or (
settings.LLM_PROVIDER == "anthropic" and settings.API_KEY
if _is_valid_api_key(settings.ANTHROPIC_API_KEY) or (
settings.LLM_PROVIDER == "anthropic" and _is_valid_api_key(settings.API_KEY)
):
self._add_anthropic_models(settings)
if settings.GOOGLE_API_KEY or (
settings.LLM_PROVIDER == "google" and settings.API_KEY
if _is_valid_api_key(settings.GOOGLE_API_KEY) or (
settings.LLM_PROVIDER == "google" and _is_valid_api_key(settings.API_KEY)
):
self._add_google_models(settings)
if settings.GROQ_API_KEY or (
settings.LLM_PROVIDER == "groq" and settings.API_KEY
if _is_valid_api_key(settings.GROQ_API_KEY) or (
settings.LLM_PROVIDER == "groq" and _is_valid_api_key(settings.API_KEY)
):
self._add_groq_models(settings)
if settings.HUGGINGFACE_API_KEY or (
settings.LLM_PROVIDER == "huggingface" and settings.API_KEY
if _is_valid_api_key(settings.HUGGINGFACE_API_KEY) or (
settings.LLM_PROVIDER == "huggingface" and _is_valid_api_key(settings.API_KEY)
):
self._add_huggingface_models(settings)
# Default model selection
if settings.LLM_NAME and settings.LLM_NAME in self.models:
self.default_model_id = settings.LLM_NAME
elif settings.LLM_PROVIDER and settings.API_KEY:
for model_id, model in self.models.items():
if model.provider.value == settings.LLM_PROVIDER:
self.default_model_id = model_id
if settings.LLM_NAME:
# Parse LLM_NAME (may be comma-separated)
model_names = self._parse_model_names(settings.LLM_NAME)
# First model in the list becomes default
for model_name in model_names:
if model_name in self.models:
self.default_model_id = model_name
break
else:
# Backward compat: try exact match if no parsed model found
if not self.default_model_id and settings.LLM_NAME in self.models:
self.default_model_id = settings.LLM_NAME
if not self.default_model_id:
if settings.LLM_PROVIDER and _is_valid_api_key(settings.API_KEY):
for model_id, model in self.models.items():
if model.provider.value == settings.LLM_PROVIDER:
self.default_model_id = model_id
break
if not self.default_model_id and self.models:
self.default_model_id = next(iter(self.models.keys()))
logger.info(
f"ModelRegistry loaded {len(self.models)} models, default: {self.default_model_id}"
@@ -132,29 +158,29 @@ class ModelRegistry:
create_custom_openai_model,
)
# Add standard OpenAI models if API key is present
if settings.OPENAI_API_KEY:
for model in OPENAI_MODELS:
self.models[model.id] = model
# Check if using local OpenAI-compatible endpoint (Ollama, LM Studio, etc.)
using_local_endpoint = bool(
settings.OPENAI_BASE_URL and settings.OPENAI_BASE_URL.strip()
)
# Add custom model if OPENAI_BASE_URL is configured with a custom LLM_NAME
if (
settings.LLM_PROVIDER == "openai"
and settings.OPENAI_BASE_URL
and settings.LLM_NAME
):
custom_model = create_custom_openai_model(
settings.LLM_NAME, settings.OPENAI_BASE_URL
)
self.models[settings.LLM_NAME] = custom_model
logger.info(
f"Registered custom OpenAI model: {settings.LLM_NAME} at {settings.OPENAI_BASE_URL}"
)
# Fallback: add all OpenAI models if none were added
if not any(m.provider.value == "openai" for m in self.models.values()):
for model in OPENAI_MODELS:
self.models[model.id] = model
if using_local_endpoint:
# When OPENAI_BASE_URL is set, ONLY register custom models from LLM_NAME
# Do NOT add standard OpenAI models (gpt-5.1, etc.)
if settings.LLM_NAME:
model_names = self._parse_model_names(settings.LLM_NAME)
for model_name in model_names:
custom_model = create_custom_openai_model(
model_name, settings.OPENAI_BASE_URL
)
self.models[model_name] = custom_model
logger.info(
f"Registered custom OpenAI model: {model_name} at {settings.OPENAI_BASE_URL}"
)
else:
# Standard OpenAI API usage - add standard models if API key is valid
if _is_valid_api_key(settings.OPENAI_API_KEY):
for model in OPENAI_MODELS:
self.models[model.id] = model
def _add_azure_openai_models(self, settings):
from application.core.model_configs import AZURE_OPENAI_MODELS
@@ -240,6 +266,15 @@ class ModelRegistry:
)
self.models[model_id] = model
def _parse_model_names(self, llm_name: str) -> List[str]:
"""
Parse LLM_NAME which may contain comma-separated model names.
E.g., 'deepseek-r1:1.5b,gemma:2b' -> ['deepseek-r1:1.5b', 'gemma:2b']
"""
if not llm_name:
return []
return [name.strip() for name in llm_name.split(",") if name.strip()]
def get_model(self, model_id: str) -> Optional[AvailableModel]:
return self.models.get(model_id)

View File

@@ -1,6 +1,6 @@
from typing import Any, Dict, Optional
from application.core.model_settings import ModelRegistry
from application.core.model_settings import ModelRegistry, _is_valid_api_key
def get_api_key_for_provider(provider: str) -> Optional[str]:
@@ -19,9 +19,11 @@ def get_api_key_for_provider(provider: str) -> Optional[str]:
}
provider_key = provider_key_map.get(provider)
if provider_key:
if provider_key and _is_valid_api_key(provider_key):
return provider_key
return settings.API_KEY
if _is_valid_api_key(settings.API_KEY):
return settings.API_KEY
return None
def get_all_available_models() -> Dict[str, Dict[str, Any]]:

View File

@@ -16,6 +16,8 @@ services:
backend:
user: root
image: arc53/docsgpt:develop
env_file:
- ../.env
environment:
- API_KEY=$API_KEY
- EMBEDDINGS_KEY=$API_KEY
@@ -41,6 +43,8 @@ services:
user: root
image: arc53/docsgpt:develop
command: celery -A application.app.celery worker -l INFO -B
env_file:
- ../.env
environment:
- API_KEY=$API_KEY
- EMBEDDINGS_KEY=$API_KEY
@@ -51,6 +55,7 @@ services:
- MONGO_URI=mongodb://mongo:27017/docsgpt
- API_URL=http://backend:7091
- CACHE_REDIS_URL=redis://redis:6379/2
- OPENAI_BASE_URL=$OPENAI_BASE_URL
volumes:
- ../application/indexes:/app/indexes
- ../application/inputs:/app/inputs

View File

@@ -398,9 +398,9 @@ function Serve-LocalOllama {
# Create .env file
"API_KEY=xxxx" | Out-File -FilePath $ENV_FILE -Encoding utf8 -Force
"LLM_PROVIDER=openai" | Add-Content -Path $ENV_FILE -Encoding utf8
"MODEL_NAME=$model_name" | Add-Content -Path $ENV_FILE -Encoding utf8
"LLM_NAME=$model_name" | Add-Content -Path $ENV_FILE -Encoding utf8
"VITE_API_STREAMING=true" | Add-Content -Path $ENV_FILE -Encoding utf8
"OPENAI_BASE_URL=http://host.docker.internal:11434/v1" | Add-Content -Path $ENV_FILE -Encoding utf8
"OPENAI_BASE_URL=http://ollama:11434/v1" | Add-Content -Path $ENV_FILE -Encoding utf8
"EMBEDDINGS_NAME=huggingface_sentence-transformers/all-mpnet-base-v2" | Add-Content -Path $ENV_FILE -Encoding utf8
Write-ColorText ".env file configured for Ollama ($($docker_compose_file_suffix.ToUpper()))." -ForegroundColor "Green"
@@ -495,49 +495,49 @@ function Connect-LocalInferenceEngine {
switch ($engine_choice) {
"1" { # LLaMa.cpp
$script:engine_name = "LLaMa.cpp"
$script:openai_base_url = "http://localhost:8000/v1"
$script:openai_base_url = "http://host.docker.internal:8000/v1"
Get-ModelName
break
}
"2" { # Ollama
$script:engine_name = "Ollama"
$script:openai_base_url = "http://localhost:11434/v1"
$script:openai_base_url = "http://host.docker.internal:11434/v1"
Get-ModelName
break
}
"3" { # TGI
$script:engine_name = "TGI"
$script:openai_base_url = "http://localhost:8080/v1"
$script:openai_base_url = "http://host.docker.internal:8080/v1"
Get-ModelName
break
}
"4" { # SGLang
$script:engine_name = "SGLang"
$script:openai_base_url = "http://localhost:30000/v1"
$script:openai_base_url = "http://host.docker.internal:30000/v1"
Get-ModelName
break
}
"5" { # vLLM
$script:engine_name = "vLLM"
$script:openai_base_url = "http://localhost:8000/v1"
$script:openai_base_url = "http://host.docker.internal:8000/v1"
Get-ModelName
break
}
"6" { # Aphrodite
$script:engine_name = "Aphrodite"
$script:openai_base_url = "http://localhost:2242/v1"
$script:openai_base_url = "http://host.docker.internal:2242/v1"
Get-ModelName
break
}
"7" { # FriendliAI
$script:engine_name = "FriendliAI"
$script:openai_base_url = "http://localhost:8997/v1"
$script:openai_base_url = "http://host.docker.internal:8997/v1"
Get-ModelName
break
}
"8" { # LMDeploy
$script:engine_name = "LMDeploy"
$script:openai_base_url = "http://localhost:23333/v1"
$script:openai_base_url = "http://host.docker.internal:23333/v1"
Get-ModelName
break
}
@@ -561,7 +561,7 @@ function Connect-LocalInferenceEngine {
# Create .env file
"API_KEY=None" | Out-File -FilePath $ENV_FILE -Encoding utf8 -Force
"LLM_PROVIDER=openai" | Add-Content -Path $ENV_FILE -Encoding utf8
"MODEL_NAME=$model_name" | Add-Content -Path $ENV_FILE -Encoding utf8
"LLM_NAME=$model_name" | Add-Content -Path $ENV_FILE -Encoding utf8
"VITE_API_STREAMING=true" | Add-Content -Path $ENV_FILE -Encoding utf8
"OPENAI_BASE_URL=$openai_base_url" | Add-Content -Path $ENV_FILE -Encoding utf8
"EMBEDDINGS_NAME=huggingface_sentence-transformers/all-mpnet-base-v2" | Add-Content -Path $ENV_FILE -Encoding utf8
@@ -694,7 +694,7 @@ function Connect-CloudAPIProvider {
# Create .env file
"API_KEY=$api_key" | Out-File -FilePath $ENV_FILE -Encoding utf8 -Force
"LLM_PROVIDER=$llm_name" | Add-Content -Path $ENV_FILE -Encoding utf8
"MODEL_NAME=$model_name" | Add-Content -Path $ENV_FILE -Encoding utf8
"LLM_NAME=$model_name" | Add-Content -Path $ENV_FILE -Encoding utf8
"VITE_API_STREAMING=true" | Add-Content -Path $ENV_FILE -Encoding utf8
Write-ColorText ".env file configured for $provider_name." -ForegroundColor "Green"

View File

@@ -173,8 +173,8 @@ prompt_ollama_options() {
# 1) Use DocsGPT Public API Endpoint (simple and free)
use_docs_public_api_endpoint() {
echo -e "\n${NC}Setting up DocsGPT Public API Endpoint...${NC}"
echo "LLM_PROVIDER=docsgpt" > .env
echo "VITE_API_STREAMING=true" >> .env
echo "LLM_PROVIDER=docsgpt" > "$ENV_FILE"
echo "VITE_API_STREAMING=true" >> "$ENV_FILE"
echo -e "${GREEN}.env file configured for DocsGPT Public API.${NC}"
check_and_start_docker
@@ -240,12 +240,12 @@ serve_local_ollama() {
echo -e "\n${NC}Configuring for Ollama ($(echo "$docker_compose_file_suffix" | tr '[:lower:]' '[:upper:]'))...${NC}" # Using tr for uppercase - more compatible
echo "API_KEY=xxxx" > .env # Placeholder API Key
echo "LLM_PROVIDER=openai" >> .env
echo "LLM_NAME=$model_name" >> .env
echo "VITE_API_STREAMING=true" >> .env
echo "OPENAI_BASE_URL=http://ollama:11434/v1" >> .env
echo "EMBEDDINGS_NAME=huggingface_sentence-transformers/all-mpnet-base-v2" >> .env
echo "API_KEY=xxxx" > "$ENV_FILE" # Placeholder API Key
echo "LLM_PROVIDER=openai" >> "$ENV_FILE"
echo "LLM_NAME=$model_name" >> "$ENV_FILE"
echo "VITE_API_STREAMING=true" >> "$ENV_FILE"
echo "OPENAI_BASE_URL=http://ollama:11434/v1" >> "$ENV_FILE"
echo "EMBEDDINGS_NAME=huggingface_sentence-transformers/all-mpnet-base-v2" >> "$ENV_FILE"
echo -e "${GREEN}.env file configured for Ollama ($(echo "$docker_compose_file_suffix" | tr '[:lower:]' '[:upper:]')${NC}${GREEN}).${NC}"
@@ -308,42 +308,42 @@ connect_local_inference_engine() {
case "$engine_choice" in
1) # LLaMa.cpp
engine_name="LLaMa.cpp"
openai_base_url="http://localhost:8000/v1"
openai_base_url="http://host.docker.internal:8000/v1"
get_model_name
break ;;
2) # Ollama
engine_name="Ollama"
openai_base_url="http://localhost:11434/v1"
openai_base_url="http://host.docker.internal:11434/v1"
get_model_name
break ;;
3) # TGI
engine_name="TGI"
openai_base_url="http://localhost:8080/v1"
openai_base_url="http://host.docker.internal:8080/v1"
get_model_name
break ;;
4) # SGLang
engine_name="SGLang"
openai_base_url="http://localhost:30000/v1"
openai_base_url="http://host.docker.internal:30000/v1"
get_model_name
break ;;
5) # vLLM
engine_name="vLLM"
openai_base_url="http://localhost:8000/v1"
openai_base_url="http://host.docker.internal:8000/v1"
get_model_name
break ;;
6) # Aphrodite
engine_name="Aphrodite"
openai_base_url="http://localhost:2242/v1"
openai_base_url="http://host.docker.internal:2242/v1"
get_model_name
break ;;
7) # FriendliAI
engine_name="FriendliAI"
openai_base_url="http://localhost:8997/v1"
openai_base_url="http://host.docker.internal:8997/v1"
get_model_name
break ;;
8) # LMDeploy
engine_name="LMDeploy"
openai_base_url="http://localhost:23333/v1"
openai_base_url="http://host.docker.internal:23333/v1"
get_model_name
break ;;
b|B) clear; return ;; # Back to Main Menu
@@ -352,19 +352,19 @@ connect_local_inference_engine() {
done
echo -e "\n${NC}Configuring for Local Inference Engine: ${BOLD}${engine_name}...${NC}"
echo "API_KEY=None" > .env
echo "LLM_PROVIDER=openai" >> .env
echo "LLM_NAME=$model_name" >> .env
echo "VITE_API_STREAMING=true" >> .env
echo "OPENAI_BASE_URL=$openai_base_url" >> .env
echo "EMBEDDINGS_NAME=huggingface_sentence-transformers/all-mpnet-base-v2" >> .env
echo "API_KEY=None" > "$ENV_FILE"
echo "LLM_PROVIDER=openai" >> "$ENV_FILE"
echo "LLM_NAME=$model_name" >> "$ENV_FILE"
echo "VITE_API_STREAMING=true" >> "$ENV_FILE"
echo "OPENAI_BASE_URL=$openai_base_url" >> "$ENV_FILE"
echo "EMBEDDINGS_NAME=huggingface_sentence-transformers/all-mpnet-base-v2" >> "$ENV_FILE"
echo -e "${GREEN}.env file configured for ${BOLD}${engine_name}${NC}${GREEN} with OpenAI API format.${NC}"
echo -e "${YELLOW}Note: MODEL_NAME is set to '${BOLD}$model_name${NC}${YELLOW}'. You can change it later in the .env file.${NC}"
check_and_start_docker
echo -e "\n${NC}Starting Docker Compose...${NC}"
docker compose --env-file "${ENV_FILE}" -f "${COMPOSE_FILE}" pull && docker compose -f "${COMPOSE_FILE}" up -d
docker compose --env-file "${ENV_FILE}" -f "${COMPOSE_FILE}" pull && docker compose --env-file "${ENV_FILE}" -f "${COMPOSE_FILE}" up -d
docker_compose_status=$?
echo "Docker Compose Exit Status: $docker_compose_status" # Debug output
@@ -444,10 +444,10 @@ connect_cloud_api_provider() {
done
echo -e "\n${NC}Configuring for Cloud API Provider: ${BOLD}${provider_name}...${NC}"
echo "API_KEY=$api_key" > .env
echo "LLM_PROVIDER=$llm_provider" >> .env
echo "LLM_NAME=$model_name" >> .env
echo "VITE_API_STREAMING=true" >> .env
echo "API_KEY=$api_key" > "$ENV_FILE"
echo "LLM_PROVIDER=$llm_provider" >> "$ENV_FILE"
echo "LLM_NAME=$model_name" >> "$ENV_FILE"
echo "VITE_API_STREAMING=true" >> "$ENV_FILE"
echo -e "${GREEN}.env file configured for ${BOLD}${provider_name}${NC}${GREEN}.${NC}"
check_and_start_docker