- Add ActionBar component with expandable toolbar for mobile - Add @mention functionality with autocomplete dropdown - Add browser notification system (push, sound, vibration) - Add NotificationSettings modal for user preferences - Add mention badges on room list cards - Add ReportPreview with Markdown rendering and copy/download - Add message copy functionality with hover actions - Add backend mentions field to messages with Alembic migration - Add lots field to rooms, remove templates - Optimize WebSocket database session handling - Various UX polish (animations, accessibility) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
113 lines
3.6 KiB
Python
113 lines
3.6 KiB
Python
"""Main FastAPI application
|
|
|
|
生產線異常即時反應系統 (Task Reporter)
|
|
"""
|
|
import os
|
|
from pathlib import Path
|
|
from fastapi import FastAPI
|
|
from fastapi.middleware.cors import CORSMiddleware
|
|
from fastapi.staticfiles import StaticFiles
|
|
from fastapi.responses import FileResponse
|
|
from app.core.config import get_settings
|
|
from app.modules.auth import router as auth_router
|
|
from app.modules.auth.users_router import router as users_router
|
|
from app.modules.auth.middleware import auth_middleware
|
|
from app.modules.chat_room import router as chat_room_router
|
|
from app.modules.realtime import router as realtime_router
|
|
from app.modules.file_storage import router as file_storage_router
|
|
from app.modules.report_generation import router as report_generation_router
|
|
from app.modules.report_generation import health_router as report_health_router
|
|
|
|
# Frontend build directory
|
|
FRONTEND_DIR = Path(__file__).parent.parent / "frontend" / "dist"
|
|
|
|
settings = get_settings()
|
|
|
|
# Database tables are managed by Alembic migrations
|
|
# Run: alembic upgrade head
|
|
|
|
# Initialize FastAPI app
|
|
app = FastAPI(
|
|
title="Task Reporter API",
|
|
description="Production Line Incident Response System - 生產線異常即時反應系統",
|
|
version="1.0.0",
|
|
debug=settings.DEBUG,
|
|
)
|
|
|
|
# CORS middleware - origins configured via CORS_ORIGINS environment variable
|
|
app.add_middleware(
|
|
CORSMiddleware,
|
|
allow_origins=settings.get_cors_origins(),
|
|
allow_credentials=True,
|
|
allow_methods=["*"],
|
|
allow_headers=["*"],
|
|
)
|
|
|
|
# Authentication middleware (applies to all /api routes except login/logout)
|
|
app.middleware("http")(auth_middleware)
|
|
|
|
# Include routers
|
|
app.include_router(auth_router)
|
|
app.include_router(users_router)
|
|
app.include_router(chat_room_router)
|
|
app.include_router(realtime_router)
|
|
app.include_router(file_storage_router)
|
|
app.include_router(report_generation_router)
|
|
app.include_router(report_health_router)
|
|
|
|
|
|
@app.on_event("startup")
|
|
async def startup_event():
|
|
"""Initialize application on startup"""
|
|
from app.core.minio_client import initialize_bucket
|
|
import logging
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
# Initialize MinIO bucket
|
|
try:
|
|
if initialize_bucket():
|
|
logger.info("MinIO bucket initialized successfully")
|
|
else:
|
|
logger.warning("MinIO bucket initialization failed - file uploads may not work")
|
|
except Exception as e:
|
|
logger.warning(f"MinIO connection failed: {e} - file uploads will be unavailable")
|
|
|
|
# Check DIFY API Key configuration
|
|
if not settings.DIFY_API_KEY:
|
|
logger.warning("DIFY_API_KEY not configured - AI report generation will be unavailable")
|
|
|
|
|
|
@app.get("/api/health")
|
|
async def health_check():
|
|
"""Health check for monitoring"""
|
|
return {
|
|
"status": "healthy",
|
|
"service": "Task Reporter API",
|
|
"version": "1.0.0",
|
|
}
|
|
|
|
|
|
# Serve frontend static files (only if build exists)
|
|
if FRONTEND_DIR.exists():
|
|
# Mount static assets (JS, CSS, images)
|
|
app.mount("/assets", StaticFiles(directory=FRONTEND_DIR / "assets"), name="static")
|
|
|
|
@app.get("/{full_path:path}")
|
|
async def serve_spa(full_path: str):
|
|
"""Serve the React SPA for all non-API routes"""
|
|
# Try to serve the exact file if it exists
|
|
file_path = FRONTEND_DIR / full_path
|
|
if file_path.exists() and file_path.is_file():
|
|
return FileResponse(file_path)
|
|
# Otherwise serve index.html for client-side routing
|
|
return FileResponse(FRONTEND_DIR / "index.html")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
import uvicorn
|
|
|
|
uvicorn.run(
|
|
"app.main:app", host=settings.HOST, port=settings.PORT, reload=settings.DEBUG, log_level="info"
|
|
)
|