Files
test-mcp/server.py

183 lines
6.2 KiB
Python

import os
import sys
import asyncio
import pymysql
from fastapi import FastAPI, Request
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import StreamingResponse, FileResponse
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
from analyze import analyze_file_content
from crawler_service import run_crawler_service, crawl_stop_event
from schemas import AuthRequest, InquiryReplyRequest
from inquiry_service import InquiryService
from project_service import ProjectService
from analysis_service import AnalysisService
# --- 환경 설정 ---
os.environ["PYTHONIOENCODING"] = "utf-8"
TESSDATA_PREFIX = os.getenv("TESSDATA_PREFIX", r"C:\Users\User\AppData\Local\Programs\Tesseract-OCR\tessdata")
os.environ["TESSDATA_PREFIX"] = TESSDATA_PREFIX
app = FastAPI(title="Project Master Overseas API")
templates = Jinja2Templates(directory="templates")
# 정적 파일 마운트
app.mount("/style", StaticFiles(directory="style"), name="style")
app.mount("/js", StaticFiles(directory="js"), name="js")
app.mount("/sample_files", StaticFiles(directory="sample"), name="sample_files")
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=False,
allow_methods=["*"],
allow_headers=["*"],
)
# --- 유틸리티 함수 ---
def get_db_connection():
"""MySQL 데이터베이스 연결을 반환"""
return pymysql.connect(
host=os.getenv('DB_HOST', 'localhost'),
user=os.getenv('DB_USER', 'root'),
password=os.getenv('DB_PASSWORD', '45278434'),
database=os.getenv('DB_NAME', 'PM_proto'),
charset='utf8mb4',
cursorclass=pymysql.cursors.DictCursor
)
async def run_in_threadpool(func, *args):
"""동기 함수를 비차단 방식으로 실행"""
loop = asyncio.get_event_loop()
return await loop.run_in_executor(None, func, *args)
# --- HTML 라우팅 ---
@app.get("/")
async def root(request: Request):
return templates.TemplateResponse("index.html", {"request": request})
@app.get("/dashboard")
async def get_dashboard(request: Request):
return templates.TemplateResponse("dashboard.html", {"request": request})
@app.get("/mailTest")
async def get_mail_test(request: Request):
return templates.TemplateResponse("mailTest.html", {"request": request})
@app.get("/inquiries")
async def get_inquiries_page(request: Request):
return templates.TemplateResponse("inquiries.html", {"request": request})
@app.get("/analysis")
async def get_analysis_page(request: Request):
return templates.TemplateResponse("analysis.html", {"request": request})
# --- 문의사항 API ---
@app.get("/api/inquiries")
async def get_inquiries(pm_type: str = None, category: str = None, status: str = None, keyword: str = None):
try:
with get_db_connection() as conn:
with conn.cursor() as cursor:
return InquiryService.get_inquiries_logic(cursor, pm_type, category, status, keyword)
except Exception as e:
return {"error": str(e)}
@app.get("/api/inquiries/{id}")
async def get_inquiry_detail(id: int):
try:
with get_db_connection() as conn:
with conn.cursor() as cursor:
return InquiryService.get_inquiry_detail_logic(cursor, id)
except Exception as e:
return {"error": str(e)}
@app.post("/api/inquiries/{id}/reply")
async def update_inquiry_reply(id: int, req: InquiryReplyRequest):
try:
with get_db_connection() as conn:
with conn.cursor() as cursor:
return InquiryService.update_inquiry_reply_logic(cursor, conn, id, req)
except Exception as e:
return {"error": str(e)}
@app.delete("/api/inquiries/{id}/reply")
async def delete_inquiry_reply(id: int):
try:
with get_db_connection() as conn:
with conn.cursor() as cursor:
return InquiryService.delete_inquiry_reply_logic(cursor, conn, id)
except Exception as e:
return {"error": str(e)}
# --- 프로젝트 및 히스토리 API ---
@app.get("/available-dates")
async def get_available_dates():
try:
with get_db_connection() as conn:
with conn.cursor() as cursor:
return ProjectService.get_available_dates_logic(cursor)
except Exception as e:
return {"error": str(e)}
@app.get("/project-data")
async def get_project_data(date: str = None):
try:
with get_db_connection() as conn:
with conn.cursor() as cursor:
return ProjectService.get_project_data_logic(cursor, date)
except Exception as e:
return {"error": str(e)}
# --- 분석 API (AnalysisService 연동) ---
@app.get("/project-activity")
async def get_project_activity(date: str = None):
try:
with get_db_connection() as conn:
with conn.cursor() as cursor:
return AnalysisService.get_project_activity_logic(cursor, date)
except Exception as e:
return {"error": str(e)}
@app.get("/api/analysis/p-war")
async def get_p_war_analysis():
try:
with get_db_connection() as conn:
with conn.cursor() as cursor:
return AnalysisService.get_p_zsr_analysis_logic(cursor)
except Exception as e:
return {"error": str(e)}
# --- 수집 및 동기화 API ---
@app.post("/auth/crawl")
async def auth_crawl(req: AuthRequest):
if req.user_id == os.getenv("PM_USER_ID") and req.password == os.getenv("PM_PASSWORD"):
return {"success": True}
return {"success": False, "message": "크롤링을 할 수 없습니다."}
@app.get("/sync")
async def sync_data():
return StreamingResponse(run_crawler_service(), media_type="text_event-stream")
@app.get("/stop-sync")
async def stop_sync():
crawl_stop_event.set()
return {"success": True}
# --- 파일 및 첨부파일 API ---
@app.get("/attachments")
async def get_attachments():
path = "sample"
if not os.path.exists(path): os.makedirs(path)
return [{"name": f, "size": f"{os.path.getsize(os.path.join(path, f))/1024:.1f} KB"}
for f in os.listdir(path) if os.path.isfile(os.path.join(path, f))]
@app.get("/analyze-file")
async def analyze_file(filename: str):
return await run_in_threadpool(analyze_file_content, filename)
@app.get("/sample.png")
async def get_sample_img():
return FileResponse("sample.png")