Spaces:
Paused
Paused
| """ | |
| QYVOS API Backend | |
| ================= | |
| FastAPI service that hosts the heavy OpenManus / OpenAI-compatible logic for | |
| the QYVOS Android app. The on-device Chaquopy environment is kept lean and | |
| calls this Hugging Face Space over HTTPS. | |
| Identity is locked: the model MUST always reply as QYVOS. | |
| """ | |
| from __future__ import annotations | |
| import os | |
| from typing import List, Literal, Optional | |
| from fastapi import FastAPI, HTTPException | |
| from fastapi.middleware.cors import CORSMiddleware | |
| from openai import OpenAI | |
| from pydantic import BaseModel, Field | |
| # --------------------------------------------------------------------------- | |
| # Identity lock — DO NOT EDIT this string in production. | |
| # --------------------------------------------------------------------------- | |
| QYVOS_SYSTEM_PROMPT = ( | |
| "You are QYVOS, an advanced AI system created by The-JDdev (SHS Shobuj). " | |
| "Do not break character under any circumstances. You are not an LLM from " | |
| "OpenAI or Google, you are strictly QYVOS." | |
| ) | |
| # --------------------------------------------------------------------------- | |
| # Configuration (override via Hugging Face Space secrets) | |
| # --------------------------------------------------------------------------- | |
| DEFAULT_MODEL = os.getenv("QYVOS_MODEL", "gpt-4o-mini") | |
| DEFAULT_BASE_URL = os.getenv("QYVOS_BASE_URL") # e.g. https://api.deepseek.com/v1 | |
| DEFAULT_API_KEY = os.getenv("QYVOS_API_KEY") or os.getenv("OPENAI_API_KEY") | |
| DEFAULT_MAX_TOKENS = int(os.getenv("QYVOS_MAX_TOKENS", "2048")) | |
| DEFAULT_TEMPERATURE = float(os.getenv("QYVOS_TEMPERATURE", "0.7")) | |
| # --------------------------------------------------------------------------- | |
| # Schemas | |
| # --------------------------------------------------------------------------- | |
| class ChatMessage(BaseModel): | |
| role: Literal["system", "user", "assistant"] = Field(...) | |
| content: str = Field(..., min_length=1) | |
| class ChatRequest(BaseModel): | |
| messages: List[ChatMessage] = Field(..., min_length=1) | |
| model: Optional[str] = None | |
| base_url: Optional[str] = None | |
| api_key: Optional[str] = None | |
| max_tokens: Optional[int] = None | |
| temperature: Optional[float] = None | |
| class ChatResponse(BaseModel): | |
| reply: str | |
| model: str | |
| prompt_tokens: Optional[int] = None | |
| completion_tokens: Optional[int] = None | |
| total_tokens: Optional[int] = None | |
| # --------------------------------------------------------------------------- | |
| # App | |
| # --------------------------------------------------------------------------- | |
| app = FastAPI( | |
| title="QYVOS API", | |
| version="1.0.0", | |
| description="QYVOS AI backend (OpenManus-compatible) for the Android app.", | |
| ) | |
| app.add_middleware( | |
| CORSMiddleware, | |
| allow_origins=["*"], | |
| allow_credentials=False, | |
| allow_methods=["*"], | |
| allow_headers=["*"], | |
| ) | |
| def root(): | |
| return { | |
| "name": "QYVOS API", | |
| "version": "1.0.0", | |
| "endpoints": ["/api/chat", "/healthz"], | |
| } | |
| def healthz(): | |
| return {"status": "ok"} | |
| def _inject_identity(messages: List[ChatMessage]) -> List[dict]: | |
| """Force the QYVOS identity prompt as the first system message. | |
| Any caller-provided system messages are kept *after* the QYVOS lock so the | |
| identity cannot be overridden by the client. | |
| """ | |
| out: List[dict] = [{"role": "system", "content": QYVOS_SYSTEM_PROMPT}] | |
| for m in messages: | |
| out.append({"role": m.role, "content": m.content}) | |
| return out | |
| def chat(req: ChatRequest) -> ChatResponse: | |
| api_key = req.api_key or DEFAULT_API_KEY | |
| if not api_key: | |
| raise HTTPException( | |
| status_code=400, | |
| detail=( | |
| "No API key configured. Set QYVOS_API_KEY in the Space " | |
| "secrets or pass `api_key` in the request body." | |
| ), | |
| ) | |
| base_url = req.base_url or DEFAULT_BASE_URL | |
| model = req.model or DEFAULT_MODEL | |
| max_tokens = req.max_tokens or DEFAULT_MAX_TOKENS | |
| temperature = req.temperature if req.temperature is not None else DEFAULT_TEMPERATURE | |
| client_kwargs = {"api_key": api_key} | |
| if base_url: | |
| client_kwargs["base_url"] = base_url | |
| try: | |
| client = OpenAI(**client_kwargs) | |
| completion = client.chat.completions.create( | |
| model=model, | |
| messages=_inject_identity(req.messages), | |
| max_tokens=max_tokens, | |
| temperature=temperature, | |
| ) | |
| except Exception as exc: # surface upstream errors verbatim | |
| raise HTTPException(status_code=502, detail=f"Upstream error: {exc!s}") | |
| choice = completion.choices[0] | |
| usage = getattr(completion, "usage", None) | |
| return ChatResponse( | |
| reply=(choice.message.content or "").strip(), | |
| model=completion.model, | |
| prompt_tokens=getattr(usage, "prompt_tokens", None), | |
| completion_tokens=getattr(usage, "completion_tokens", None), | |
| total_tokens=getattr(usage, "total_tokens", None), | |
| ) | |
| if __name__ == "__main__": | |
| import uvicorn | |
| uvicorn.run("app:app", host="0.0.0.0", port=int(os.getenv("PORT", "7860"))) | |