apix/backend/routers/history.py
Khoa.vo 0ef7e5475c
Some checks are pending
CI / build (18.x) (push) Waiting to run
CI / build (20.x) (push) Waiting to run
v3.0.0: Add FastAPI backend
- Add Python FastAPI backend with Pydantic validation
- Port WhiskClient and MetaAIClient to Python
- Create API routers for all endpoints
- Add Swagger/ReDoc documentation at /docs
- Update Dockerfile for multi-service container
- Add lib/api.ts frontend client
- Update README for V3
2026-01-13 07:46:32 +07:00

164 lines
4.4 KiB
Python

"""
History Router - Upload history management
Note: This is a simplified version. The original Next.js version
stores history in memory/file. For FastAPI, we'll use a simple
JSON file approach similar to prompts.
"""
from fastapi import APIRouter, HTTPException, UploadFile, File, Form
from models.responses import HistoryResponse, HistoryItem, ErrorResponse
from services.whisk_client import WhiskClient
from pathlib import Path
import json
import uuid
import base64
from typing import Optional
from datetime import datetime
router = APIRouter(prefix="/history", tags=["History"])
# History storage
HISTORY_FILE = Path(__file__).parent.parent.parent / "data" / "history.json"
def load_history() -> list:
"""Load history from JSON file"""
try:
if HISTORY_FILE.exists():
return json.loads(HISTORY_FILE.read_text())
except:
pass
return []
def save_history(history: list) -> None:
"""Save history to JSON file"""
HISTORY_FILE.parent.mkdir(parents=True, exist_ok=True)
HISTORY_FILE.write_text(json.dumps(history, indent=2))
@router.get(
"",
response_model=HistoryResponse,
responses={500: {"model": ErrorResponse}}
)
async def get_history(category: Optional[str] = None):
"""
Get upload history.
- **category**: Optional filter by category (subject, scene, style)
"""
try:
history = load_history()
if category:
history = [h for h in history if h.get("category") == category]
return HistoryResponse(history=[HistoryItem(**h) for h in history])
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@router.post(
"",
response_model=HistoryItem,
responses={
400: {"model": ErrorResponse},
500: {"model": ErrorResponse}
}
)
async def upload_to_history(
file: UploadFile = File(...),
category: str = Form(default="subject"),
cookies: Optional[str] = Form(default=None)
):
"""
Upload an image to history.
- **file**: Image file to upload
- **category**: Category (subject, scene, style)
- **cookies**: Optional Whisk cookies to also upload to Whisk
"""
try:
# Read file
content = await file.read()
base64_data = base64.b64encode(content).decode('utf-8')
mime_type = file.content_type or 'image/png'
# Upload to Whisk if cookies provided
media_id = None
if cookies:
try:
client = WhiskClient(cookies)
media_id = await client.upload_reference_image(base64_data, mime_type, category)
except Exception as e:
print(f"[History] Whisk upload failed: {e}")
# Create history item
new_item = {
"id": str(uuid.uuid4()),
"url": f"data:{mime_type};base64,{base64_data}",
"originalName": file.filename or "upload.png",
"category": category,
"mediaId": media_id,
"createdAt": int(datetime.now().timestamp() * 1000)
}
# Save to history
history = load_history()
history.insert(0, new_item) # Add to beginning
save_history(history)
return HistoryItem(**new_item)
except Exception as e:
print(f"Upload error: {e}")
raise HTTPException(status_code=500, detail=str(e))
@router.delete(
"/{item_id}",
responses={
404: {"model": ErrorResponse},
500: {"model": ErrorResponse}
}
)
async def delete_history_item(item_id: str):
"""
Delete an item from history.
- **item_id**: ID of the history item to delete
"""
try:
history = load_history()
original_len = len(history)
history = [h for h in history if h.get("id") != item_id]
if len(history) == original_len:
raise HTTPException(status_code=404, detail="Item not found")
save_history(history)
return {"success": True, "deleted": item_id}
except HTTPException:
raise
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@router.delete(
"",
responses={500: {"model": ErrorResponse}}
)
async def clear_history():
"""
Clear all history items.
"""
try:
save_history([])
return {"success": True, "message": "History cleared"}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))