Files
Edu/services/ai/src/ai/config.py
SpecialX 1dcdcf23fd feat(ai): python graphql federation subgraph with strawberry
- strawberry-graphql[asgi] dependency added

- GeneratedReport and LessonPlanStatus @key types with resolve_reference

- RouterAuthMiddleware validates Router-Authorization header on /graphql

- GraphQL endpoint mounted at /graphql in FastAPI app

- WorkflowStateStore injected for lesson plan status resolution
2026-07-15 00:56:37 +08:00

109 lines
3.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""配置管理pydantic-settings12-factor 合规)."""
from pydantic_settings import BaseSettings
class Settings(BaseSettings):
"""应用配置.
配置优先级:环境变量 > .env 文件 > 默认值.
"""
# 服务
service_name: str = "ai"
http_port: int = 3008
grpc_port: int = 50058
dev_mode: bool = False
# 可观测性
otel_endpoint: str = "http://localhost:4318"
log_level: str = "info"
# LLM Provider 配置
openai_api_key: str = ""
openai_base_url: str = "https://api.openai.com/v1"
anthropic_api_key: str = ""
anthropic_base_url: str = "https://api.anthropic.com"
baichuan_api_key: str = ""
baichuan_base_url: str = "https://api.baichuan-ai.com/v1"
ollama_base_url: str = "" # 本地 Ollama如 http://localhost:11434
# Provider 优先级(按顺序 failover
llm_provider_priority: str = "openai,anthropic,baichuan,local_ollama"
# LLM 调用参数
llm_timeout_seconds: float = 30.0
llm_stream_connect_timeout: float = 30.0
llm_stream_read_timeout: float = 60.0
llm_max_retries: int = 3
# 默认模型
default_chat_model: str = "gpt-4o-mini"
default_question_model: str = "gpt-4o-mini"
# Redis限流 + 缓存 + 工作流状态)
redis_url: str = "redis://localhost:6379/0"
redis_rate_limit_user_per_min: int = 10
redis_rate_limit_ip_per_min: int = 30
redis_rate_limit_school_per_min: int = 100
# Kafka用量事件发布派生数据豁免 Outbox
kafka_bootstrap_servers: str = "localhost:9092"
kafka_ai_usage_topic: str = "edu.ai.usage"
kafka_producer_transactional_id: str = "ai-service-producer"
# 下游 gRPC
content_grpc_endpoint: str = "localhost:50054"
data_ana_grpc_endpoint: str = "localhost:50055"
iam_grpc_endpoint: str = "localhost:50052"
# GraphQL Federation 2 子图v2.1 ADR-036 Router-Authorization 信任凭证)
router_auth_secret: str = ""
# 备课工作流
workflow_ttl_seconds: int = 86400 # 24h
workflow_max_retries: int = 3
# 评估
evaluation_pass_threshold: float = 0.7
evaluation_excellent_threshold: float = 0.85
# 配额(月度 token 预算)
default_school_monthly_budget: int = 1_000_000
default_teacher_monthly_budget: int = 100_000
model_config = {"env_file": ".env", "env_prefix": "", "extra": "ignore"}
@property
def is_dev(self) -> bool:
"""是否处于开发模式."""
return self.dev_mode
@property
def llm_available(self) -> bool:
"""LLM 是否可用(至少一个 provider 配置了 API key."""
return bool(
self.openai_api_key
or self.anthropic_api_key
or self.baichuan_api_key
or self.ollama_base_url,
)
@property
def provider_priority_list(self) -> list[str]:
"""Provider 优先级列表."""
return [p.strip() for p in self.llm_provider_priority.split(",") if p.strip()]
@property
def providers_status(self) -> dict[str, bool]:
"""各 Provider 配置状态."""
return {
"openai": bool(self.openai_api_key),
"anthropic": bool(self.anthropic_api_key),
"baichuan": bool(self.baichuan_api_key),
"local_ollama": bool(self.ollama_base_url),
}
settings = Settings()