diff --git a/.env b/.env index a2b9dd7..79d7395 100644 --- a/.env +++ b/.env @@ -10,4 +10,6 @@ MINIO_SECRET_KEY=SuperSecretPassword123! MINIO_BUCKET=filam3d MINIO_SECURE=false AI_PROXY_URL=http://82.22.174.14:8001 -AI_PROXY_SALT=AbVJUkwTPcUWJWhPzmjXb5p4SYyKmYC5m1uVW7Dhi7o \ No newline at end of file +AI_PROXY_SALT=AbVJUkwTPcUWJWhPzmjXb5p4SYyKmYC5m1uVW7Dhi7o +QWEN_API_KEY=sk-991942d15b424cc89513498bb2946045 +QWEN_MODEL=qwen3.5-plus \ No newline at end of file diff --git a/backend/app/config.py b/backend/app/config.py index b0e4643..3670a3a 100644 --- a/backend/app/config.py +++ b/backend/app/config.py @@ -4,6 +4,9 @@ from pydantic_settings import BaseSettings class Settings(BaseSettings): DATABASE_URL: str = "postgresql+asyncpg://print3d:P3D_PASSWORD@31.59.58.220:5432/print3d" GOOGLE_API_KEY: str = "" + QWEN_API_KEY: str = "" + QWEN_MODEL: str = "qwen-plus" + QWEN_BASE_URL: str = "https://dashscope.aliyuncs.com/compatible-mode/v1" AI_PROXY_URL: str = "http://82.22.174.14:8001" AI_PROXY_SALT: str = "change_me_in_production" TELEGRAM_BOT_TOKEN: str = "" diff --git a/backend/app/services/ai_advisor.py b/backend/app/services/ai_advisor.py index c5f8469..0c88216 100644 --- a/backend/app/services/ai_advisor.py +++ b/backend/app/services/ai_advisor.py @@ -75,25 +75,32 @@ async def _call_via_proxy(proxy_url: str, proxy_salt: str, messages: list[dict]) async def _call_direct(api_key: str, system: str, user_message: str) -> str: - """Call Google GenAI directly via REST (no SDK dependency).""" - url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key={api_key}" + """Call Qwen via OpenAI-compatible DashScope API.""" + url = f"{settings.QWEN_BASE_URL.rstrip('/')}/chat/completions" + headers = { + "Authorization": f"Bearer {api_key}", + "Content-Type": "application/json", + } payload = { - "system_instruction": {"parts": [{"text": system}]}, - "contents": [{"role": "user", "parts": [{"text": user_message}]}], - "generationConfig": {"temperature": 0.3, "maxOutputTokens": 1024}, + "model": settings.QWEN_MODEL, + "messages": [ + {"role": "system", "content": system}, + {"role": "user", "content": user_message}, + ], + "temperature": 0.3, + "max_tokens": 1024, } async with httpx.AsyncClient(timeout=60.0) as client: - resp = await client.post(url, json=payload) + resp = await client.post(url, json=payload, headers=headers) if resp.status_code != 200: - logger.error("Google API error %d: %s", resp.status_code, resp.text[:500]) - raise ValueError(f"Google API ошибка: {resp.status_code}") + logger.error("Qwen API error %d: %s", resp.status_code, resp.text[:500]) + raise ValueError(f"Qwen API ошибка: {resp.status_code}") data = resp.json() - candidates = data.get("candidates", []) - if not candidates: - raise ValueError("Google API вернул пустой ответ") - parts = candidates[0].get("content", {}).get("parts", []) - return parts[0].get("text", "") if parts else "" + choices = data.get("choices", []) + if not choices: + raise ValueError("Qwen API вернул пустой ответ") + return choices[0].get("message", {}).get("content", "") def _parse_json_response(text: str) -> dict: @@ -122,7 +129,7 @@ async def get_material_recommendation( use_proxy = True proxy_url = settings.AI_PROXY_URL proxy_salt = settings.AI_PROXY_SALT - direct_api_key = settings.GOOGLE_API_KEY + direct_api_key = settings.QWEN_API_KEY if db: use_proxy_str = await _get_setting(db, "ai_use_proxy", "true") @@ -153,9 +160,9 @@ async def get_material_recommendation( messages = [{"role": "user", "content": system + "\n\n" + user_message}] response_text = await _call_via_proxy(proxy_url, proxy_salt, messages) else: - logger.info("Mode: DIRECT (Google API)") + logger.info("Mode: DIRECT (Qwen API, model=%s)", settings.QWEN_MODEL) if not direct_api_key: - raise ValueError("Google API Key не настроен") + raise ValueError("Qwen API Key не настроен (QWEN_API_KEY)") response_text = await _call_direct(direct_api_key, system, user_message) elapsed = time.time() - start_time diff --git a/frontend/src/views/admin/AdminSettings.vue b/frontend/src/views/admin/AdminSettings.vue index 37872db..25d66b3 100644 --- a/frontend/src/views/admin/AdminSettings.vue +++ b/frontend/src/views/admin/AdminSettings.vue @@ -116,7 +116,7 @@ const settingsGroups = [ { key: 'ai_use_proxy', label: 'Использовать AI-прокси (true/false)', placeholder: 'true' }, { key: 'ai_proxy_url', label: 'URL прокси', placeholder: 'http://82.22.174.14:8001' }, { key: 'ai_proxy_salt', label: 'Секретная соль прокси', placeholder: '' }, - { key: 'ai_direct_api_key', label: 'Google API Key (прямое подключение)', placeholder: '' }, + { key: 'ai_direct_api_key', label: 'Qwen API Key (DashScope)', placeholder: '' }, ], }, {