Demon Lord Vinsen
logout fcm
57b3c7e
Raw
History Blame Contribute Delete
4.14 kB
# app/main.py
import asyncio
import uvicorn
from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import HTMLResponse
from pydantic import BaseModel
# Schemas
from app.models import ChatRequest, RegisterRequest, ScheduleRequest
# Services
from app.services.chat_service import process_chat_message
from app.services.scheduler_service import (
scheduler,
schedule_new_reminder,
send_proactive_message_task,
device_tokens,
cancel_reminder,
)
app = FastAPI(title="Mini-chan Tsundere API (Proactive Text Assistant)")
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
@app.on_event("startup")
async def startup_event():
scheduler.start()
print("Scheduler sudah hidup, siap menerima jadwal, Baka!")
@app.on_event("shutdown")
async def shutdown_event():
scheduler.shutdown()
print("Scheduler dimatikan. Hmph.")
@app.get("/", include_in_schema=False)
def root():
return HTMLResponse(
"""
<style>
body{font-family:ui-sans-serif,system-ui;max-width:720px;margin:48px auto;padding:0 16px}
a{color:#6b46c1;text-decoration:none}
.badge{display:inline-block;background:#ede9fe;color:#5b21b6;padding:4px 8px;border-radius:999px;font-size:12px;margin-left:8px}
code{background:#111827;color:#e5e7eb;padding:2px 6px;border-radius:6px}
</style>
<h2>🤖 Mini-chan Tsundere API <span class="badge">Running</span></h2>
<p>Hmph… aku udah hidup di Hugging Face Spaces. Baka 😤</p>
<p>• Buka <a href="/docs">/docs</a> buat Swagger UI.<br/>
• Healthcheck: <code>GET /health</code><br/>
• Endpoints utama: <code>/chat</code>, <code>/register-device</code>, dan <code>/schedule</code></p>
""",
status_code=200,
)
@app.get("/health", tags=["Health"])
def health():
return {"status": "ok"}
@app.post("/chat", tags=["Chat"])
async def handle_chat_endpoint(request: ChatRequest):
response_text = await process_chat_message(request)
return {"response": response_text}
@app.post("/register-device", tags=["Scheduler"])
async def register_device(request: RegisterRequest):
if not request.fcm_token:
return {"error": "FCM token tidak boleh kosong, Baka!"}
device_tokens.add(request.fcm_token)
print(f"Device baru tercatat: {request.fcm_token}")
return {"message": "Hmph, yaudah, devicemu aku catat. Jangan aneh-aneh."}
@app.post("/schedule", tags=["Scheduler"])
async def schedule_reminder_endpoint(request: ScheduleRequest):
user_id = request.user_id.strip()
task = request.task.strip()
if not user_id:
raise HTTPException(
status_code=400,
detail="user_id tidak boleh kosong."
)
if not task:
raise HTTPException(
status_code=400,
detail="Task tidak boleh kosong."
)
job_id = schedule_new_reminder(
user_id=user_id,
task=task,
remind_at=request.remind_at_utc
)
return {
"message": (
f"Cih, yaudah aku ingetin nanti jam "
f"{request.remind_at_utc.isoformat()}."
),
"job_id": job_id,
}
@app.get("/debug/jobs", tags=["Debug"])
async def list_jobs():
jobs = []
for job in scheduler.get_jobs():
jobs.append({
"id": job.id,
"next_run_time": str(job.next_run_time),
"func": str(job.func_ref),
})
return {"jobs": jobs}
class DebugSendNow(BaseModel):
user_id: str
task: str
@app.post("/debug/send-now", tags=["Debug"])
async def debug_send_now(body: DebugSendNow):
asyncio.create_task(
send_proactive_message_task(
body.user_id,
body.task
)
)
return {
"message": "Mini-chan mencoba mengirim sekarang."
}
@app.post("/debug/cancel/{job_id}", tags=["Debug"])
async def debug_cancel(job_id: str):
ok = cancel_reminder(job_id)
return {"cancelled": ok, "job_id": job_id}