Files
test-mcp/server_test.py
Taehoon 533e4c073d
All checks were successful
Deploy Web Application / deploy (push) Successful in 6s
fix(playwright): resolve browser dependencies without sudo & cleanup unused files
- Copy necessary shared libraries (libnss, libasound, libsoftokn, etc.) from docker to libs/ to support headless chromium execution on host
- Update server and crawler configuration to support custom DB_PORT (3307)
- Remove unused databases, lockfiles, standalone helper scripts, and documentation files as requested
2026-06-23 17:36:18 +09:00

194 lines
6.9 KiB
Python

import os
import sys
import asyncio
import pymysql
from dotenv import load_dotenv
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_test 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
# --- 환경 설정 ---
load_dotenv()
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 (TEST MODE)")
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 데이터베이스(TEST) 연결을 반환"""
return pymysql.connect(
host=os.getenv('DB_HOST', 'localhost'),
port=int(os.getenv('DB_PORT', 3306)),
user=os.getenv('DB_USER', 'root'),
password=os.getenv('DB_PASSWORD', '45278434'),
database='PM_proto_test', # 테스트용 DB로 고정
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")
@app.get("/dashboard_test")
async def get_dashboard_test(request: Request):
# 테스트 환경에서는 dashboard_test.html을 우선적으로 반환
return templates.TemplateResponse("dashboard_test.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")
@app.get("/analysis_test")
async def get_analysis_test(request: Request):
# 테스트 환경에서는 analysis_test.html을 우선적으로 반환
return templates.TemplateResponse("analysis_test.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")
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8001)