diff --git a/.env.example b/.env.example index 302ed5b..b2c97f7 100644 --- a/.env.example +++ b/.env.example @@ -7,3 +7,9 @@ NODE_ENV=development # AI — Anthropic Claude (единственный AI-провайдер). Бэкенд: ANTHROPIC_API_KEY # OPENAI_API_KEY не используется ANTHROPIC_API_KEY= + +# Прокси Anthropic через papa-app на Railway (если Anthropic блокирует с РФ IP) +# AI_PROXY_URL=https://papa-app-production.up.railway.app/api/proxy/anthropic +# AI_PROXY_SECRET=klg-refly-proxy-2026 +AI_PROXY_URL= +AI_PROXY_SECRET= diff --git a/backend/app/api/routes/ai_assistant.py b/backend/app/api/routes/ai_assistant.py index d5222c1..78a1cb0 100644 --- a/backend/app/api/routes/ai_assistant.py +++ b/backend/app/api/routes/ai_assistant.py @@ -21,8 +21,11 @@ class ChatResponse(BaseModel): @router.post("/chat", response_model=ChatResponse) async def ai_chat(req: ChatRequest, user=Depends(get_current_user)): api_key = getattr(settings, "ANTHROPIC_API_KEY", None) or "" - if not api_key or api_key == "": - raise HTTPException(400, "AI assistant not configured") + proxy_url = getattr(settings, "AI_PROXY_URL", "") or "" + proxy_secret = getattr(settings, "AI_PROXY_SECRET", "") or "" + if not proxy_url or not proxy_secret: + if not api_key or api_key == "": + raise HTTPException(400, "AI assistant not configured (set ANTHROPIC_API_KEY or AI_PROXY_URL+AI_PROXY_SECRET)") db = SessionLocal() try: @@ -52,21 +55,33 @@ async def ai_chat(req: ChatRequest, user=Depends(get_current_user)): Отвечай на русском языке. Будь конкретным и профессиональным. Используй авиационную терминологию где уместно.""" + payload = { + "model": getattr(settings, "ANTHROPIC_MODEL", "claude-sonnet-4-20250514"), + "max_tokens": 1024, + "system": system_prompt, + "messages": [{"role": "user", "content": req.message}], + } + async with httpx.AsyncClient(timeout=30.0) as client: - resp = await client.post( - "https://api.anthropic.com/v1/messages", - headers={ - "x-api-key": api_key, - "anthropic-version": "2023-06-01", - "content-type": "application/json", - }, - json={ - "model": getattr(settings, "ANTHROPIC_MODEL", "claude-sonnet-4-20250514"), - "max_tokens": 1024, - "system": system_prompt, - "messages": [{"role": "user", "content": req.message}], - }, - ) + if proxy_url and proxy_secret: + resp = await client.post( + proxy_url, + headers={ + "x-proxy-secret": proxy_secret, + "content-type": "application/json", + }, + json=payload, + ) + else: + resp = await client.post( + "https://api.anthropic.com/v1/messages", + headers={ + "x-api-key": api_key, + "anthropic-version": "2023-06-01", + "content-type": "application/json", + }, + json=payload, + ) if resp.status_code != 200: raise HTTPException(502, f"AI service error: {resp.status_code}") diff --git a/backend/app/core/config.py b/backend/app/core/config.py index be3df95..2a85938 100644 --- a/backend/app/core/config.py +++ b/backend/app/core/config.py @@ -67,6 +67,9 @@ class Settings(BaseSettings): # AI (Anthropic Claude) ANTHROPIC_API_KEY: str = "" ANTHROPIC_MODEL: str = "claude-sonnet-4-20250514" + # Прокси Anthropic через papa-app (Railway) — для обхода блокировки с российских IP + AI_PROXY_URL: str = "" + AI_PROXY_SECRET: str = "" @property def database_url(self) -> str: diff --git a/docker-compose.yml b/docker-compose.yml index 22b6d93..3940b10 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -95,6 +95,9 @@ services: FGIS_ORG_ID: ${FGIS_ORG_ID:-} FGIS_API_KEY: ${FGIS_API_KEY:-} FGIS_CERT_PATH: /etc/ssl/fgis/client.pem + # Прокси Anthropic через papa-app (Railway) — обход блокировки с российских IP + AI_PROXY_URL: ${AI_PROXY_URL:-} + AI_PROXY_SECRET: ${AI_PROXY_SECRET:-} ports: - "8000:8000" volumes: