ssfinder-analyze / main.py
μ†μ„œν˜„
fix
251c4fb
import os
from fastapi import FastAPI, File, UploadFile, HTTPException, Body
from fastapi.middleware.cors import CORSMiddleware
import tempfile
from models.models import LostItemAnalyzer
from typing import Dict, Any
import base64
from PIL import Image
import io
# FastAPI μ• ν”Œλ¦¬μΌ€μ΄μ…˜ 생성
app = FastAPI(title="λΆ„μ‹€λ¬Ό 이미지 뢄석 API")
# CORS μ„€μ •
app.add_middleware(
CORSMiddleware,
allow_origins=["*"], # ν”„λ‘œλ•μ…˜μ—μ„œλŠ” νŠΉμ • λ„λ©”μΈμœΌλ‘œ μ œν•œν•˜μ„Έμš”
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# 뢄석기 μ΄ˆκΈ°ν™”
analyzer = LostItemAnalyzer()
# API 루트 경둜 ν•Έλ“€λŸ¬
@app.get("/")
async def root():
return {"message": "λΆ„μ‹€λ¬Ό 이미지 뢄석 APIκ°€ μ‹€ν–‰ μ€‘μž…λ‹ˆλ‹€."}
# 파일 μ—…λ‘œλ“œλ₯Ό ν†΅ν•œ 이미지 뢄석
@app.post("/api/analyze/upload")
async def analyze_image_upload(file: UploadFile = File(...)):
# 파일 ν™•μž₯자 검증
valid_extensions = ['.jpg', '.jpeg', '.png', '.bmp', '.gif']
file_ext = os.path.splitext(file.filename)[1].lower()
if file_ext not in valid_extensions:
raise HTTPException(
status_code=400,
detail=f"μ§€μ›λ˜μ§€ μ•ŠλŠ” 파일 ν˜•μ‹μž…λ‹ˆλ‹€. μ§€μ›λ˜λŠ” ν˜•μ‹: {', '.join(valid_extensions)}"
)
try:
# μž„μ‹œ 파일둜 μ €μž₯
with tempfile.NamedTemporaryFile(delete=False, suffix=os.path.splitext(file.filename)[1]) as temp:
temp_path = temp.name
content = await file.read()
temp.write(content)
# 이미지 뢄석
result = analyzer.analyze_lost_item(temp_path)
# μž„μ‹œ 파일 μ‚­μ œ
os.unlink(temp_path)
if result["success"]:
# ν•œκ΅­μ–΄ λ²ˆμ—­ 결과만 λ°˜ν™˜
ko_result = {
"status": "success",
"data": {
"title": result["data"]["translated"]["title"],
"category": result["data"]["translated"]["category"],
"color": result["data"]["translated"]["color"],
"material": result["data"]["translated"]["material"],
"brand": result["data"]["translated"]["brand"],
"description": result["data"]["translated"]["description"],
"distinctive_features": result["data"]["translated"]["distinctive_features"]
}
}
return ko_result
else:
raise HTTPException(status_code=500, detail=result["error"])
except Exception as e:
# μ˜ˆμ™Έ λ°œμƒ μ‹œ μž„μ‹œ 파일 μ‚­μ œ μ‹œλ„
try:
if 'temp_path' in locals() and os.path.exists(temp_path):
os.unlink(temp_path)
except:
pass
raise HTTPException(status_code=500, detail=f"이미지 뢄석 쀑 였λ₯˜ λ°œμƒ: {str(e)}")
# Base64 μΈμ½”λ”©λœ 이미지 뢄석 (Javaμ—μ„œ μ‚¬μš©ν•  μ—”λ“œν¬μΈνŠΈ)
# λ©”λͺ¨λ¦¬μ—μ„œ 직접 처리
@app.post("/api/analyze/base64")
async def analyze_image_base64(payload: Dict[str, Any] = Body(...)):
try:
if "image" not in payload:
raise HTTPException(status_code=400, detail="μš”μ²­μ— 'image' ν•„λ“œκ°€ ν•„μš”ν•©λ‹ˆλ‹€")
base64_str = payload["image"]
# Base64 λ¬Έμžμ—΄μ—μ„œ 헀더 제거 (μžˆμ„ 경우)
if "," in base64_str:
base64_str = base64_str.split(",")[1]
# Base64 λ””μ½”λ”©
image_data = base64.b64decode(base64_str)
image = Image.open(io.BytesIO(image_data))
# λ©”λͺ¨λ¦¬ λ‚΄ 이미지λ₯Ό λ°”μ΄νŠΈ 슀트림으둜 μ €μž₯
img_byte_arr = io.BytesIO()
image.save(img_byte_arr, format='JPEG')
img_byte_arr = img_byte_arr.getvalue()
# μž„μ‹œ 파일 경둜 동적 생성
temp_path = f"/tmp/uploads/temp_{os.getpid()}_{id(image)}.jpg"
# 이미지 μ €μž₯
with open(temp_path, 'wb') as f:
f.write(img_byte_arr)
# 이미지 뢄석
result = analyzer.analyze_lost_item(temp_path)
# μž„μ‹œ 파일 μ‚­μ œ
os.unlink(temp_path)
if result["success"]:
# ν•œκ΅­μ–΄ λ²ˆμ—­ 결과만 λ°˜ν™˜
ko_result = {
"status": "success",
"data": {
"title": result["data"]["translated"]["title"],
"category": result["data"]["translated"]["category"],
"color": result["data"]["translated"]["color"],
"material": result["data"]["translated"]["material"],
"brand": result["data"]["translated"]["brand"],
"description": result["data"]["translated"]["description"],
"distinctive_features": result["data"]["translated"]["distinctive_features"]
}
}
return ko_result
else:
raise HTTPException(status_code=500, detail=result["error"])
except HTTPException:
raise
except Exception as e:
raise HTTPException(status_code=500, detail=f"이미지 뢄석 쀑 였λ₯˜ λ°œμƒ: {str(e)}")
# API μƒνƒœ, ν™˜κ²½λ³€μˆ˜ 확인
@app.get("/api/status")
async def status():
return {
"status": "ok",
"papago_api": "active" if analyzer.translator.use_papago else "inactive",
"models_loaded": True
}
# 메인 μ‹€ν–‰ μ½”λ“œ (둜컬 ν…ŒμŠ€νŠΈμš©)
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=5001)