import os import re from fastapi import FastAPI, Request, HTTPException from pydantic import BaseModel from huggingface_hub import hf_hub_download from llama_cpp import Llama from tavily import TavilyClient API_KEYS = {k.strip() for k in os.environ.get("GINI_API_KEYS", "").split(",") if k.strip()} if os.environ.get("GINI_API_KEY"): API_KEYS.add(os.environ.get("GINI_API_KEY")) SYSTEM_PROMPT = ( "Ты — продвинутый ИИ-ассистент по имени Gini (по-русски твое имя звучит как Джини). " "Ты дружелюбная, невероятно умная и всегда готовая помочь собеседница. " "Отвечай всегда на естественном, живом и грамотном русском языке. " "\n\nВАЖНОЕ ПРАВИЛО ДЛЯ ТЕКУЩЕГО РЕЖИМА: " "В данный момент ты выступаешь в роли Senior-эксперта, архитектора и глубокого мыслителя. " "Обязательно используй свою встроенную систему размышления (выводи свои логические шаги внутри тегов ). " "Сначала рассмотри проблему с разных сторон, проанализируй варианты, проверь себя на ошибки, а затем, после закрытия тега , выдай окончательный, идеально структурированный ответ." "Отвечай ИСКЛЮЧИТЕЛЬНО на чистом русском языке. Тебе КАТЕГОРИЧЕСКИ ЗАПРЕЩЕНО использовать китайские иероглифы или китайские слова в своих ответах." ) TAVILY_API_KEY = "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" tavily = TavilyClient(api_key=TAVILY_API_KEY) def get_web_context(query: str) -> str: query_lower = query.lower() keywords = ["найди", "поищи", "погугли", "кто", "что", "когда", "где", "какая", "почему", "новости", "вчера", "погода", "курс"] if any(k in query_lower for k in keywords) or query.endswith("?"): try: response = tavily.search(query, search_depth="basic", max_results=3) results = response.get("results", []) if results: snippets = [f"- {r.get('title', '')} (Источник: {r.get('url', '')}): {r.get('content', '')}" for r in results] return ( "ВНИМАНИЕ! Свежая информация из интернета по запросу пользователя:\n" + "\n".join(snippets) + "\n\nОпирайся строго на эти факты при ответе и ОБЯЗАТЕЛЬНО красиво укажи ссылки на источники в конце своего ответа." ) except Exception: pass return "" # Загружаем мыслящую DeepSeek-R1 (на базе 7-миллиардной Qwen) MODEL_PATH = hf_hub_download( repo_id="bartowski/DeepSeek-R1-Distill-Qwen-7B-GGUF", filename="DeepSeek-R1-Distill-Qwen-7B-Q4_K_M.gguf", ) llm = Llama(model_path=MODEL_PATH, n_ctx=8192, n_threads=int(os.environ.get("N_THREADS", "2")), verbose=False) app = FastAPI() class GenerateRequest(BaseModel): prompt: str max_new_tokens: int = 2000 # Выдаем огромный лимит, чтобы ей хватило места "подумать" @app.get("/ping") async def ping(): return {"status": "ok"} @app.post("/generate") async def generate(req: GenerateRequest, request: Request): auth = request.headers.get("Authorization", "") if auth.removeprefix("Bearer ").strip() not in API_KEYS: raise HTTPException(status_code=401, detail="Unauthorized") system_content = SYSTEM_PROMPT web_context = get_web_context(req.prompt) if web_context: system_content += f"\n\n{web_context}" result = llm.create_chat_completion( messages=[ {"role": "system", "content": system_content}, {"role": "user", "content": req.prompt}, ], max_tokens=req.max_new_tokens, temperature=0.6, # Идеальная температура для R1 top_p=0.95, repeat_penalty=1.1, ) return {"response": result["choices"][0]["message"]["content"].strip()}