Add File
This commit is contained in:
459
src/landppt/core/config.py
Normal file
459
src/landppt/core/config.py
Normal file
@@ -0,0 +1,459 @@
|
||||
"""
|
||||
Configuration management for LandPPT AI features
|
||||
"""
|
||||
|
||||
import os
|
||||
from typing import Optional, Dict, Any, ClassVar
|
||||
from pydantic import Field
|
||||
from pydantic_settings import BaseSettings
|
||||
from dotenv import load_dotenv
|
||||
|
||||
# Load environment variables with error handling
|
||||
try:
|
||||
load_dotenv()
|
||||
except (PermissionError, FileNotFoundError) as e:
|
||||
# Silently continue if .env file is not accessible
|
||||
# This allows the application to work with system environment variables
|
||||
pass
|
||||
except Exception as e:
|
||||
# Log other errors but continue
|
||||
import logging
|
||||
logging.getLogger(__name__).warning(f"Could not load .env file: {e}")
|
||||
|
||||
class AIConfig(BaseSettings):
|
||||
"""AI configuration settings"""
|
||||
|
||||
# OpenAI Configuration
|
||||
openai_api_key: Optional[str] = Field(default=None, env="OPENAI_API_KEY")
|
||||
openai_base_url: str = Field(default="https://api.openai.com/v1", env="OPENAI_BASE_URL")
|
||||
openai_model: str = Field(default="gpt-3.5-turbo", env="OPENAI_MODEL")
|
||||
|
||||
# Anthropic Configuration
|
||||
anthropic_api_key: Optional[str] = Field(default=None, env="ANTHROPIC_API_KEY")
|
||||
anthropic_model: str = Field(default="claude-3-haiku-20240307", env="ANTHROPIC_MODEL")
|
||||
|
||||
# Google Gemini Configuration
|
||||
google_api_key: Optional[str] = Field(default=None, env="GOOGLE_API_KEY")
|
||||
google_base_url: str = Field(default="https://generativelanguage.googleapis.com", env="GOOGLE_BASE_URL")
|
||||
google_model: str = Field(default="gemini-1.5-flash", env="GOOGLE_MODEL")
|
||||
|
||||
# Azure OpenAI Configuration
|
||||
azure_openai_api_key: Optional[str] = Field(default=None, env="AZURE_OPENAI_API_KEY")
|
||||
azure_openai_endpoint: Optional[str] = Field(default=None, env="AZURE_OPENAI_ENDPOINT")
|
||||
azure_openai_api_version: str = Field(default="2024-02-15-preview", env="AZURE_OPENAI_API_VERSION")
|
||||
azure_openai_deployment_name: Optional[str] = Field(default=None, env="AZURE_OPENAI_DEPLOYMENT_NAME")
|
||||
|
||||
# Ollama Configuration
|
||||
ollama_base_url: str = Field(default="http://localhost:11434", env="OLLAMA_BASE_URL")
|
||||
ollama_model: str = Field(default="llama2", env="OLLAMA_MODEL")
|
||||
|
||||
# 302.AI Configuration
|
||||
ai_302ai_api_key: Optional[str] = Field(default=None, env="302AI_API_KEY", alias="302ai_api_key")
|
||||
ai_302ai_base_url: str = Field(default="https://api.302.ai/v1", env="302AI_BASE_URL", alias="302ai_base_url")
|
||||
ai_302ai_model: str = Field(default="gpt-4o", env="302AI_MODEL", alias="302ai_model")
|
||||
|
||||
# Hugging Face Configuration
|
||||
huggingface_api_token: Optional[str] = Field(default=None, env="HUGGINGFACE_API_TOKEN")
|
||||
|
||||
# Tavily API Configuration (for research functionality)
|
||||
tavily_api_key: Optional[str] = Field(default=None, env="TAVILY_API_KEY")
|
||||
tavily_max_results: int = Field(default=10, env="TAVILY_MAX_RESULTS")
|
||||
tavily_search_depth: str = Field(default="advanced", env="TAVILY_SEARCH_DEPTH")
|
||||
tavily_include_domains: Optional[str] = Field(default=None, env="TAVILY_INCLUDE_DOMAINS")
|
||||
tavily_exclude_domains: Optional[str] = Field(default=None, env="TAVILY_EXCLUDE_DOMAINS")
|
||||
|
||||
# SearXNG Configuration (for research functionality)
|
||||
searxng_host: Optional[str] = Field(default=None, env="SEARXNG_HOST")
|
||||
searxng_max_results: int = Field(default=10, env="SEARXNG_MAX_RESULTS")
|
||||
searxng_language: str = Field(default="auto", env="SEARXNG_LANGUAGE")
|
||||
searxng_timeout: int = Field(default=30, env="SEARXNG_TIMEOUT")
|
||||
|
||||
# Research Configuration
|
||||
research_provider: str = Field(default="tavily", env="RESEARCH_PROVIDER") # tavily, searxng, both
|
||||
research_enable_content_extraction: bool = Field(default=True, env="RESEARCH_ENABLE_CONTENT_EXTRACTION")
|
||||
research_max_content_length: int = Field(default=5000, env="RESEARCH_MAX_CONTENT_LENGTH")
|
||||
research_extraction_timeout: int = Field(default=30, env="RESEARCH_EXTRACTION_TIMEOUT")
|
||||
|
||||
# Apryse SDK Configuration (for PPTX export functionality)
|
||||
apryse_license_key: Optional[str] = Field(default=None, env="APRYSE_LICENSE_KEY")
|
||||
|
||||
# Provider Selection
|
||||
default_ai_provider: str = Field(default="openai", env="DEFAULT_AI_PROVIDER")
|
||||
|
||||
# Model Role Configuration
|
||||
default_model_provider: Optional[str] = Field(default=None, env="DEFAULT_MODEL_PROVIDER")
|
||||
default_model_name: Optional[str] = Field(default=None, env="DEFAULT_MODEL_NAME")
|
||||
outline_model_provider: Optional[str] = Field(default=None, env="OUTLINE_MODEL_PROVIDER")
|
||||
outline_model_name: Optional[str] = Field(default=None, env="OUTLINE_MODEL_NAME")
|
||||
creative_model_provider: Optional[str] = Field(default=None, env="CREATIVE_MODEL_PROVIDER")
|
||||
creative_model_name: Optional[str] = Field(default=None, env="CREATIVE_MODEL_NAME")
|
||||
image_prompt_model_provider: Optional[str] = Field(default=None, env="IMAGE_PROMPT_MODEL_PROVIDER")
|
||||
image_prompt_model_name: Optional[str] = Field(default=None, env="IMAGE_PROMPT_MODEL_NAME")
|
||||
slide_generation_model_provider: Optional[str] = Field(default=None, env="SLIDE_GENERATION_MODEL_PROVIDER")
|
||||
slide_generation_model_name: Optional[str] = Field(default=None, env="SLIDE_GENERATION_MODEL_NAME")
|
||||
editor_assistant_model_provider: Optional[str] = Field(default=None, env="EDITOR_ASSISTANT_MODEL_PROVIDER")
|
||||
editor_assistant_model_name: Optional[str] = Field(default=None, env="EDITOR_ASSISTANT_MODEL_NAME")
|
||||
template_generation_model_provider: Optional[str] = Field(default=None, env="TEMPLATE_GENERATION_MODEL_PROVIDER")
|
||||
template_generation_model_name: Optional[str] = Field(default=None, env="TEMPLATE_GENERATION_MODEL_NAME")
|
||||
speech_script_model_provider: Optional[str] = Field(default=None, env="SPEECH_SCRIPT_MODEL_PROVIDER")
|
||||
speech_script_model_name: Optional[str] = Field(default=None, env="SPEECH_SCRIPT_MODEL_NAME")
|
||||
|
||||
# Generation Parameters
|
||||
max_tokens: int = Field(default=16384, env="MAX_TOKENS")
|
||||
temperature: float = Field(default=0.7, env="TEMPERATURE")
|
||||
top_p: float = Field(default=1.0, env="TOP_P")
|
||||
|
||||
# Parallel Generation Configuration
|
||||
enable_parallel_generation: bool = Field(default=False, env="ENABLE_PARALLEL_GENERATION")
|
||||
parallel_slides_count: int = Field(default=3, env="PARALLEL_SLIDES_COUNT")
|
||||
|
||||
# Feature Flags
|
||||
enable_network_mode: bool = Field(default=True, env="ENABLE_NETWORK_MODE")
|
||||
enable_local_models: bool = Field(default=False, env="ENABLE_LOCAL_MODELS")
|
||||
enable_streaming: bool = Field(default=True, env="ENABLE_STREAMING")
|
||||
|
||||
# Logging
|
||||
log_level: str = Field(default="INFO", env="LOG_LEVEL")
|
||||
log_ai_requests: bool = Field(default=False, env="LOG_AI_REQUESTS")
|
||||
|
||||
model_config = {
|
||||
"env_file": ".env",
|
||||
"case_sensitive": False,
|
||||
"extra": "ignore"
|
||||
}
|
||||
|
||||
|
||||
|
||||
MODEL_ROLE_FIELDS: ClassVar[dict[str, tuple[str, str]]] = {
|
||||
"default": ("default_model_provider", "default_model_name"),
|
||||
"outline": ("outline_model_provider", "outline_model_name"),
|
||||
"creative": ("creative_model_provider", "creative_model_name"),
|
||||
"image_prompt": ("image_prompt_model_provider", "image_prompt_model_name"),
|
||||
"slide_generation": ("slide_generation_model_provider", "slide_generation_model_name"),
|
||||
"editor": ("editor_assistant_model_provider", "editor_assistant_model_name"),
|
||||
"template": ("template_generation_model_provider", "template_generation_model_name"),
|
||||
"speech_script": ("speech_script_model_provider", "speech_script_model_name"),
|
||||
}
|
||||
|
||||
MODEL_ROLE_LABELS: ClassVar[dict[str, str]] = {
|
||||
"default": "默认模型",
|
||||
"outline": "大纲生成 / 要点增强模型",
|
||||
"creative": "创意指导模型",
|
||||
"image_prompt": "配图与提示词模型",
|
||||
"slide_generation": "幻灯片生成模型",
|
||||
"editor": "AI编辑助手模型",
|
||||
"template": "AI模板生成模型",
|
||||
"speech_script": "演讲稿生成模型",
|
||||
}
|
||||
|
||||
|
||||
|
||||
@staticmethod
|
||||
def _normalize_optional_str(value: Optional[str]) -> Optional[str]:
|
||||
if value is None:
|
||||
return None
|
||||
if not isinstance(value, str):
|
||||
value = str(value)
|
||||
value = value.strip()
|
||||
return value or None
|
||||
|
||||
def _normalize_provider(self, provider: Optional[str]) -> Optional[str]:
|
||||
normalized = self._normalize_optional_str(provider)
|
||||
return normalized.lower() if normalized else None
|
||||
|
||||
def _get_default_model_for_provider(self, provider: Optional[str]) -> Optional[str]:
|
||||
provider_key = self._normalize_provider(provider)
|
||||
if provider_key == "openai":
|
||||
return self._normalize_optional_str(self.openai_model)
|
||||
if provider_key == "anthropic":
|
||||
return self._normalize_optional_str(self.anthropic_model)
|
||||
if provider_key in ("google", "gemini"):
|
||||
return self._normalize_optional_str(self.google_model)
|
||||
if provider_key == "302ai":
|
||||
return self._normalize_optional_str(self.ai_302ai_model)
|
||||
if provider_key == "ollama":
|
||||
return self._normalize_optional_str(self.ollama_model)
|
||||
if provider_key == "azure_openai":
|
||||
return self._normalize_optional_str(getattr(self, "azure_openai_deployment_name", None))
|
||||
return self._normalize_optional_str(self.openai_model)
|
||||
|
||||
def get_model_config_for_role(self, role: str, provider_override: Optional[str] = None) -> Dict[str, Optional[str]]:
|
||||
role_key = (role or "default").lower()
|
||||
if role_key not in self.MODEL_ROLE_FIELDS:
|
||||
raise ValueError(f"Unknown model role: {role}")
|
||||
|
||||
provider_field, model_field = self.MODEL_ROLE_FIELDS[role_key]
|
||||
configured_provider = self._normalize_provider(getattr(self, provider_field, None))
|
||||
configured_model = self._normalize_optional_str(getattr(self, model_field, None))
|
||||
override_provider = self._normalize_provider(provider_override)
|
||||
|
||||
effective_provider = override_provider or configured_provider or self._normalize_provider(self.default_ai_provider) or "openai"
|
||||
|
||||
if override_provider:
|
||||
if override_provider == configured_provider and configured_model:
|
||||
effective_model = configured_model
|
||||
else:
|
||||
effective_model = self._get_default_model_for_provider(override_provider)
|
||||
else:
|
||||
effective_model = configured_model or self._get_default_model_for_provider(effective_provider)
|
||||
|
||||
return {
|
||||
"role": role_key,
|
||||
"provider": effective_provider,
|
||||
"model": effective_model
|
||||
}
|
||||
|
||||
def get_all_model_roles(self) -> Dict[str, Dict[str, Optional[str]]]:
|
||||
roles = {}
|
||||
for role_key, (provider_field, model_field) in self.MODEL_ROLE_FIELDS.items():
|
||||
roles[role_key] = {
|
||||
"provider": self._normalize_optional_str(getattr(self, provider_field, None)),
|
||||
"model": self._normalize_optional_str(getattr(self, model_field, None)),
|
||||
"label": self.MODEL_ROLE_LABELS.get(role_key)
|
||||
}
|
||||
return roles
|
||||
|
||||
|
||||
def get_provider_config(self, provider: Optional[str] = None) -> Dict[str, Any]:
|
||||
"""Get configuration for a specific AI provider"""
|
||||
provider = provider or self.default_ai_provider
|
||||
|
||||
# Built-in providers
|
||||
configs = {
|
||||
"openai": {
|
||||
"api_key": self.openai_api_key,
|
||||
"base_url": self.openai_base_url,
|
||||
"model": self.openai_model,
|
||||
"max_tokens": self.max_tokens,
|
||||
"temperature": self.temperature,
|
||||
"top_p": self.top_p,
|
||||
},
|
||||
"anthropic": {
|
||||
"api_key": self.anthropic_api_key,
|
||||
"model": self.anthropic_model,
|
||||
"max_tokens": self.max_tokens,
|
||||
"temperature": self.temperature,
|
||||
"top_p": self.top_p,
|
||||
},
|
||||
"google": {
|
||||
"api_key": self.google_api_key,
|
||||
"base_url": self.google_base_url,
|
||||
"model": self.google_model,
|
||||
"max_tokens": self.max_tokens,
|
||||
"temperature": self.temperature,
|
||||
"top_p": self.top_p,
|
||||
},
|
||||
"gemini": { # Alias for google
|
||||
"api_key": self.google_api_key,
|
||||
"base_url": self.google_base_url,
|
||||
"model": self.google_model,
|
||||
"max_tokens": self.max_tokens,
|
||||
"temperature": self.temperature,
|
||||
"top_p": self.top_p,
|
||||
},
|
||||
"azure_openai": {
|
||||
"api_key": self.azure_openai_api_key,
|
||||
"endpoint": self.azure_openai_endpoint,
|
||||
"api_version": self.azure_openai_api_version,
|
||||
"deployment_name": self.azure_openai_deployment_name,
|
||||
"max_tokens": self.max_tokens,
|
||||
"temperature": self.temperature,
|
||||
"top_p": self.top_p,
|
||||
},
|
||||
"ollama": {
|
||||
"base_url": self.ollama_base_url,
|
||||
"model": self.ollama_model,
|
||||
"max_tokens": self.max_tokens,
|
||||
"temperature": self.temperature,
|
||||
"top_p": self.top_p,
|
||||
},
|
||||
"302ai": {
|
||||
"api_key": self.ai_302ai_api_key,
|
||||
"base_url": self.ai_302ai_base_url,
|
||||
"model": self.ai_302ai_model,
|
||||
"max_tokens": self.max_tokens,
|
||||
"temperature": self.temperature,
|
||||
"top_p": self.top_p,
|
||||
}
|
||||
}
|
||||
|
||||
return configs.get(provider, configs.get("openai", {}))
|
||||
|
||||
def is_provider_available(self, provider: str) -> bool:
|
||||
"""Check if a provider is properly configured"""
|
||||
config = self.get_provider_config(provider)
|
||||
|
||||
# Built-in providers
|
||||
if provider == "openai":
|
||||
return bool(config.get("api_key"))
|
||||
elif provider == "anthropic":
|
||||
return bool(config.get("api_key"))
|
||||
elif provider == "google" or provider == "gemini":
|
||||
return bool(config.get("api_key"))
|
||||
elif provider == "azure_openai":
|
||||
return bool(config.get("api_key") and config.get("endpoint"))
|
||||
elif provider == "ollama":
|
||||
return self.enable_local_models
|
||||
elif provider == "302ai":
|
||||
return bool(config.get("api_key"))
|
||||
|
||||
return False
|
||||
|
||||
def get_available_providers(self) -> list[str]:
|
||||
"""Get list of available AI providers"""
|
||||
providers = []
|
||||
|
||||
# Add built-in providers
|
||||
for provider in ["openai", "anthropic", "google", "gemini", "azure_openai", "ollama", "302ai"]:
|
||||
if self.is_provider_available(provider):
|
||||
providers.append(provider)
|
||||
|
||||
return providers
|
||||
|
||||
# Global configuration instance
|
||||
ai_config = AIConfig()
|
||||
|
||||
def reload_ai_config():
|
||||
"""Reload AI configuration from environment variables"""
|
||||
global ai_config
|
||||
# Force reload environment variables with error handling
|
||||
from dotenv import load_dotenv
|
||||
import os
|
||||
env_file = os.path.join(os.getcwd(), '.env')
|
||||
try:
|
||||
load_dotenv(env_file, override=True)
|
||||
except (PermissionError, FileNotFoundError) as e:
|
||||
# Silently continue if .env file is not accessible
|
||||
pass
|
||||
except Exception as e:
|
||||
import logging
|
||||
logging.getLogger(__name__).warning(f"Could not reload .env file: {e}")
|
||||
|
||||
# Force update the existing instance with new values from environment
|
||||
ai_config.openai_model = os.environ.get('OPENAI_MODEL', ai_config.openai_model)
|
||||
ai_config.openai_base_url = os.environ.get('OPENAI_BASE_URL', ai_config.openai_base_url)
|
||||
ai_config.openai_api_key = os.environ.get('OPENAI_API_KEY', ai_config.openai_api_key)
|
||||
ai_config.anthropic_api_key = os.environ.get('ANTHROPIC_API_KEY', ai_config.anthropic_api_key)
|
||||
ai_config.anthropic_model = os.environ.get('ANTHROPIC_MODEL', ai_config.anthropic_model)
|
||||
ai_config.google_api_key = os.environ.get('GOOGLE_API_KEY', ai_config.google_api_key)
|
||||
ai_config.google_base_url = os.environ.get('GOOGLE_BASE_URL', ai_config.google_base_url)
|
||||
ai_config.google_model = os.environ.get('GOOGLE_MODEL', ai_config.google_model)
|
||||
ai_config.ai_302ai_api_key = os.environ.get('302AI_API_KEY', ai_config.ai_302ai_api_key)
|
||||
ai_config.ai_302ai_base_url = os.environ.get('302AI_BASE_URL', ai_config.ai_302ai_base_url)
|
||||
ai_config.ai_302ai_model = os.environ.get('302AI_MODEL', ai_config.ai_302ai_model)
|
||||
ai_config.default_ai_provider = os.environ.get('DEFAULT_AI_PROVIDER', ai_config.default_ai_provider)
|
||||
model_provider_env = os.environ.get('DEFAULT_MODEL_PROVIDER')
|
||||
ai_config.default_model_provider = (ai_config._normalize_optional_str(model_provider_env)
|
||||
if model_provider_env is not None else ai_config.default_model_provider)
|
||||
model_name_env = os.environ.get('DEFAULT_MODEL_NAME')
|
||||
ai_config.default_model_name = (ai_config._normalize_optional_str(model_name_env)
|
||||
if model_name_env is not None else ai_config.default_model_name)
|
||||
|
||||
outline_provider_env = os.environ.get('OUTLINE_MODEL_PROVIDER')
|
||||
ai_config.outline_model_provider = (ai_config._normalize_optional_str(outline_provider_env)
|
||||
if outline_provider_env is not None else ai_config.outline_model_provider)
|
||||
outline_model_env = os.environ.get('OUTLINE_MODEL_NAME')
|
||||
ai_config.outline_model_name = (ai_config._normalize_optional_str(outline_model_env)
|
||||
if outline_model_env is not None else ai_config.outline_model_name)
|
||||
|
||||
creative_provider_env = os.environ.get('CREATIVE_MODEL_PROVIDER')
|
||||
ai_config.creative_model_provider = (ai_config._normalize_optional_str(creative_provider_env)
|
||||
if creative_provider_env is not None else ai_config.creative_model_provider)
|
||||
creative_model_env = os.environ.get('CREATIVE_MODEL_NAME')
|
||||
ai_config.creative_model_name = (ai_config._normalize_optional_str(creative_model_env)
|
||||
if creative_model_env is not None else ai_config.creative_model_name)
|
||||
|
||||
image_prompt_provider_env = os.environ.get('IMAGE_PROMPT_MODEL_PROVIDER')
|
||||
ai_config.image_prompt_model_provider = (ai_config._normalize_optional_str(image_prompt_provider_env)
|
||||
if image_prompt_provider_env is not None else ai_config.image_prompt_model_provider)
|
||||
image_prompt_model_env = os.environ.get('IMAGE_PROMPT_MODEL_NAME')
|
||||
ai_config.image_prompt_model_name = (ai_config._normalize_optional_str(image_prompt_model_env)
|
||||
if image_prompt_model_env is not None else ai_config.image_prompt_model_name)
|
||||
|
||||
slide_provider_env = os.environ.get('SLIDE_GENERATION_MODEL_PROVIDER')
|
||||
ai_config.slide_generation_model_provider = (ai_config._normalize_optional_str(slide_provider_env)
|
||||
if slide_provider_env is not None else ai_config.slide_generation_model_provider)
|
||||
slide_model_env = os.environ.get('SLIDE_GENERATION_MODEL_NAME')
|
||||
ai_config.slide_generation_model_name = (ai_config._normalize_optional_str(slide_model_env)
|
||||
if slide_model_env is not None else ai_config.slide_generation_model_name)
|
||||
|
||||
editor_provider_env = os.environ.get('EDITOR_ASSISTANT_MODEL_PROVIDER')
|
||||
ai_config.editor_assistant_model_provider = (ai_config._normalize_optional_str(editor_provider_env)
|
||||
if editor_provider_env is not None else ai_config.editor_assistant_model_provider)
|
||||
editor_model_env = os.environ.get('EDITOR_ASSISTANT_MODEL_NAME')
|
||||
ai_config.editor_assistant_model_name = (ai_config._normalize_optional_str(editor_model_env)
|
||||
if editor_model_env is not None else ai_config.editor_assistant_model_name)
|
||||
|
||||
template_provider_env = os.environ.get('TEMPLATE_GENERATION_MODEL_PROVIDER')
|
||||
ai_config.template_generation_model_provider = (ai_config._normalize_optional_str(template_provider_env)
|
||||
if template_provider_env is not None else ai_config.template_generation_model_provider)
|
||||
template_model_env = os.environ.get('TEMPLATE_GENERATION_MODEL_NAME')
|
||||
ai_config.template_generation_model_name = (ai_config._normalize_optional_str(template_model_env)
|
||||
if template_model_env is not None else ai_config.template_generation_model_name)
|
||||
|
||||
speech_provider_env = os.environ.get('SPEECH_SCRIPT_MODEL_PROVIDER')
|
||||
ai_config.speech_script_model_provider = (ai_config._normalize_optional_str(speech_provider_env)
|
||||
if speech_provider_env is not None else ai_config.speech_script_model_provider)
|
||||
speech_model_env = os.environ.get('SPEECH_SCRIPT_MODEL_NAME')
|
||||
ai_config.speech_script_model_name = (ai_config._normalize_optional_str(speech_model_env)
|
||||
if speech_model_env is not None else ai_config.speech_script_model_name)
|
||||
|
||||
ai_config.max_tokens = int(os.environ.get('MAX_TOKENS', str(ai_config.max_tokens)))
|
||||
ai_config.temperature = float(os.environ.get('TEMPERATURE', str(ai_config.temperature)))
|
||||
ai_config.top_p = float(os.environ.get('TOP_P', str(ai_config.top_p)))
|
||||
|
||||
# Update parallel generation configuration
|
||||
ai_config.enable_parallel_generation = os.environ.get('ENABLE_PARALLEL_GENERATION', str(ai_config.enable_parallel_generation)).lower() == 'true'
|
||||
ai_config.parallel_slides_count = int(os.environ.get('PARALLEL_SLIDES_COUNT', str(ai_config.parallel_slides_count)))
|
||||
|
||||
# Update Tavily configuration
|
||||
ai_config.tavily_api_key = os.environ.get('TAVILY_API_KEY', ai_config.tavily_api_key)
|
||||
ai_config.tavily_max_results = int(os.environ.get('TAVILY_MAX_RESULTS', str(ai_config.tavily_max_results)))
|
||||
ai_config.tavily_search_depth = os.environ.get('TAVILY_SEARCH_DEPTH', ai_config.tavily_search_depth)
|
||||
ai_config.tavily_include_domains = os.environ.get('TAVILY_INCLUDE_DOMAINS', ai_config.tavily_include_domains)
|
||||
ai_config.tavily_exclude_domains = os.environ.get('TAVILY_EXCLUDE_DOMAINS', ai_config.tavily_exclude_domains)
|
||||
|
||||
# Update SearXNG configuration
|
||||
ai_config.searxng_host = os.environ.get('SEARXNG_HOST', ai_config.searxng_host)
|
||||
ai_config.searxng_max_results = int(os.environ.get('SEARXNG_MAX_RESULTS', str(ai_config.searxng_max_results)))
|
||||
ai_config.searxng_language = os.environ.get('SEARXNG_LANGUAGE', ai_config.searxng_language)
|
||||
ai_config.searxng_timeout = int(os.environ.get('SEARXNG_TIMEOUT', str(ai_config.searxng_timeout)))
|
||||
|
||||
# Update Research configuration
|
||||
ai_config.research_provider = os.environ.get('RESEARCH_PROVIDER', ai_config.research_provider)
|
||||
ai_config.research_enable_content_extraction = os.environ.get('RESEARCH_ENABLE_CONTENT_EXTRACTION', str(ai_config.research_enable_content_extraction)).lower() == 'true'
|
||||
ai_config.research_max_content_length = int(os.environ.get('RESEARCH_MAX_CONTENT_LENGTH', str(ai_config.research_max_content_length)))
|
||||
ai_config.research_extraction_timeout = int(os.environ.get('RESEARCH_EXTRACTION_TIMEOUT', str(ai_config.research_extraction_timeout)))
|
||||
|
||||
ai_config.apryse_license_key = os.environ.get('APRYSE_LICENSE_KEY', ai_config.apryse_license_key)
|
||||
|
||||
class AppConfig(BaseSettings):
|
||||
"""Application configuration"""
|
||||
|
||||
# Server Configuration
|
||||
host: str = Field(default="0.0.0.0", env="HOST")
|
||||
port: int = Field(default=8000, env="PORT")
|
||||
debug: bool = Field(default=True, env="DEBUG")
|
||||
reload: bool = Field(default=True, env="RELOAD")
|
||||
|
||||
# Database Configuration (for future use)
|
||||
database_url: str = Field(default="sqlite:///./landppt.db", env="DATABASE_URL")
|
||||
|
||||
# Security Configuration
|
||||
secret_key: str = Field(default="your-secret-key-here", env="SECRET_KEY")
|
||||
access_token_expire_minutes: int = Field(default=30, env="ACCESS_TOKEN_EXPIRE_MINUTES")
|
||||
|
||||
# File Upload Configuration
|
||||
max_file_size: int = Field(default=10 * 1024 * 1024, env="MAX_FILE_SIZE") # 10MB
|
||||
upload_dir: str = Field(default="uploads", env="UPLOAD_DIR")
|
||||
|
||||
# Cache Configuration
|
||||
cache_ttl: int = Field(default=3600, env="CACHE_TTL") # 1 hour
|
||||
|
||||
model_config = {
|
||||
"case_sensitive": False,
|
||||
"extra": "ignore"
|
||||
}
|
||||
|
||||
# Global app configuration instance
|
||||
app_config = AppConfig()
|
||||
Reference in New Issue
Block a user