PureVersation / api.py
github-actions[bot]
Automated deployment to Hugging Face
93bdcc9
Raw
History Blame Contribute Delete
5.5 kB
import os
import pandas as pd
from datetime import datetime
from fastapi import FastAPI, HTTPException, BackgroundTasks
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
from openai import AsyncOpenAI
from dotenv import load_dotenv
load_dotenv()
app = FastAPI(title="PurePolyglot Hybrid Backend", version="1.0.0")
# Enable CORS for the Vite SPA
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# Attempt Qwen first, fallback to Groq
QWEN_API_KEY = os.getenv("QWEN_API_KEY")
QWEN_BASE_URL = os.getenv("QWEN_BASE_URL", "https://dashscope-intl.aliyuncs.com/compatible-mode/v1")
QWEN_MODEL_NAME = os.getenv("QWEN_MODEL_NAME", "qwen3-coder-80b-instruct")
GROQ_API_KEY = os.getenv("GROQ_API_KEY")
if QWEN_API_KEY and QWEN_API_KEY != "your-api-key-here":
client = AsyncOpenAI(api_key=QWEN_API_KEY, base_url=QWEN_BASE_URL)
MODEL_NAME = QWEN_MODEL_NAME
NODE_TYPE = "Qwen Hybrid Node"
elif GROQ_API_KEY:
client = AsyncOpenAI(api_key=GROQ_API_KEY, base_url="https://api.groq.com/openai/v1")
MODEL_NAME = "llama-3.3-70b-versatile"
NODE_TYPE = "Groq Hybrid Node"
else:
client = None
MODEL_NAME = None
NODE_TYPE = "Offline"
class TranslationRequest(BaseModel):
text: str
source_language: str = "Unknown"
source_dialect: str = "Standard"
target_language: str
target_dialect: str
user_key: str = "Polyglot Player"
class TranslationResponse(BaseModel):
original_text: str
translated_text: str
target_dialect: str
node: str
def log_to_pending_queue(request: TranslationRequest, translation: str):
"""Background task to log translations to pending_approvals.csv"""
pending_file = "/app/pending_approvals.csv" if os.path.exists("/app") else "pending_approvals.csv"
new_entry = {
"User": request.user_key,
"Data_Origin": "Game: Polyglot Chat",
"Utterance": request.text,
"Dialect": request.target_dialect,
"Clarification": translation,
"Clarification_Source": NODE_TYPE,
"Tone": "Neutral / Conversational",
"Context": f"Translated from {request.source_language} ({request.source_dialect})",
"Pragmatic_Analysis": "",
"Audio": "",
"Timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
"Chain_ID": "",
"Approvers": "",
"Language": request.target_language
}
try:
if os.path.exists(pending_file):
df = pd.read_csv(pending_file)
else:
df = pd.DataFrame(columns=new_entry.keys())
df = pd.concat([df, pd.DataFrame([new_entry])], ignore_index=True)
df.to_csv(pending_file, index=False)
print(f"✅ Logged to {pending_file} for peer review.")
# Sync to Hugging Face PureChain_Dataset if HF_TOKEN is present
from huggingface_hub import HfApi
hf_token = os.environ.get("HF_TOKEN")
if hf_token:
api = HfApi(token=hf_token)
api.upload_file(
path_or_fileobj=pending_file,
path_in_repo="pending_approvals.csv",
repo_id="toecm/PureChain_Dataset",
repo_type="dataset",
commit_message="🔄 Auto-sync: Polyglot Chat text translation added to pending approvals queue"
)
print("☁️ Synced Polyglot Chat text translation entry to HF PureChain_Dataset.")
except Exception as e:
print(f"Failed to save translation to pending queue: {e}")
@app.post("/api/translate", response_model=TranslationResponse)
async def translate_text(request: TranslationRequest, background_tasks: BackgroundTasks):
if not client:
raise HTTPException(status_code=500, detail="No LLM API key configured (neither Qwen nor Groq).")
system_prompt = (
f"You are an expert polyglot interpreter specializing in deep cultural and linguistic dialects.\n"
f"Translate the following text from {request.source_language} ({request.source_dialect}) "
f"into {request.target_language} ({request.target_dialect}).\n"
f"Output ONLY the raw translated string. Do not include quotes, explanations, or thinking traces."
)
try:
response = await client.chat.completions.create(
model=MODEL_NAME,
messages=[
{"role": "system", "content": system_prompt},
{"role": "user", "content": request.text}
],
temperature=0.3,
max_tokens=256
)
translated_text = response.choices[0].message.content.strip()
# Log to CSV in the background
background_tasks.add_task(log_to_pending_queue, request, translated_text)
return TranslationResponse(
original_text=request.text,
translated_text=translated_text,
target_dialect=f"{request.target_language} ({request.target_dialect})",
node=NODE_TYPE
)
except Exception as e:
print(f"Error calling {NODE_TYPE} API: {e}")
raise HTTPException(status_code=500, detail=str(e))
@app.get("/")
async def root():
return {"message": f"PurePolyglot Hybrid Backend Online ({NODE_TYPE})"}
if __name__ == "__main__":
import uvicorn
uvicorn.run("api:app", host="0.0.0.0", port=8000, reload=True)