Reubencf's picture
Deploy: Godot Web build + HF Inference NPC dialogue (drop AWS)
7b3900c verified
Raw
History Blame Contribute Delete
2.77 kB
import os
import time
import mimetypes
from dotenv import load_dotenv
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse, RedirectResponse
from fastapi.staticfiles import StaticFiles
from huggingface_hub import InferenceClient
load_dotenv()
HF_TOKEN = os.getenv("HF_TOKEN")
MODEL_ID = os.getenv("MODEL_ID", "Qwen/Qwen2.5-1.5B-Instruct")
GAME_DIR = "game"
MAX_TOKENS = 80
TEMPERATURE = 0.5
TOP_P = 0.85
client = InferenceClient(token=HF_TOKEN) if HF_TOKEN else None
mimetypes.add_type("application/wasm", ".wasm")
mimetypes.add_type("application/octet-stream", ".pck")
def generate_reply(prompt: str) -> str:
"""Generate short NPC dialogue for the Godot game."""
if client is None:
time.sleep(0.2)
return "The air is calm today. Bring what you find, and we will make it useful."
start_time = time.time()
completion = client.chat.completions.create(
model=MODEL_ID,
messages=[
{
"role": "system",
"content": (
"You are an NPC in the post-nuclear RPG Shadows of Tomorrow. "
"Answer in plain text only, with 1 or 2 short natural sentences."
),
},
{"role": "user", "content": prompt},
],
max_tokens=MAX_TOKENS,
temperature=TEMPERATURE,
top_p=TOP_P,
)
print(f"HF inference model={MODEL_ID} took={time.time() - start_time:.2f}s")
return completion.choices[0].message.content.strip()
app = FastAPI()
@app.get("/", include_in_schema=False)
async def root():
"""Make the Space open straight into the fullscreen Godot web export."""
return RedirectResponse(url="/game/index.html", status_code=307)
@app.get("/healthz")
async def healthz():
return {"ok": True, "model": MODEL_ID}
@app.post("/ai-response")
async def ai_response(request: Request):
"""Contract used by Godot: {"prompt": str} -> {"output": str}."""
try:
data = await request.json()
except Exception:
return JSONResponse({"error": "Invalid JSON body"}, status_code=400)
prompt = (data or {}).get("prompt")
if not prompt:
return JSONResponse({"error": "Missing 'prompt' in request body"}, status_code=400)
try:
return {"output": generate_reply(prompt)}
except Exception as e:
print(f"Inference error: {e}")
return JSONResponse({"error": str(e)}, status_code=500)
if os.path.isdir(GAME_DIR):
app.mount("/game", StaticFiles(directory=GAME_DIR, html=True), name="game")
else:
print(f"WARNING: '{GAME_DIR}/' not found. Export the Godot Web build before deploying.")
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=7860)