api 구축
This commit is contained in:
139
workspace/api.py
Normal file
139
workspace/api.py
Normal file
@@ -0,0 +1,139 @@
|
||||
# api.py
|
||||
|
||||
import asyncio
|
||||
import json # JSON 파싱을 위해 추가
|
||||
|
||||
from fastapi import APIRouter, FastAPI, File, HTTPException, UploadFile
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from routers import google_docai
|
||||
from utils.config import (
|
||||
CORS_ALLOW_CREDENTIALS,
|
||||
CORS_ALLOW_HEADERS,
|
||||
CORS_ALLOW_METHODS,
|
||||
CORS_ALLOW_ORIGINS,
|
||||
UPLOAD_DOCS_DIR,
|
||||
)
|
||||
|
||||
# 유틸리티 함수 임포트 (기존 코드 유지)
|
||||
from utils.file_utils import (
|
||||
create_essential_directories,
|
||||
create_key,
|
||||
save_uploaded_file,
|
||||
)
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
# CORS 설정 (기존 코드 유지)
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=CORS_ALLOW_ORIGINS,
|
||||
allow_credentials=CORS_ALLOW_CREDENTIALS,
|
||||
allow_methods=CORS_ALLOW_METHODS,
|
||||
allow_headers=CORS_ALLOW_HEADERS,
|
||||
)
|
||||
|
||||
|
||||
# 애플리케이션 시작 시 실행될 함수 (기존 코드 유지)
|
||||
@app.on_event("startup")
|
||||
async def startup_event():
|
||||
print("Starting up...")
|
||||
create_essential_directories()
|
||||
print("Essential directories created.")
|
||||
|
||||
|
||||
# --- Document AI 라우터 ---
|
||||
doc_ai_router = APIRouter(
|
||||
prefix="/docai",
|
||||
tags=["DocumentAI"],
|
||||
)
|
||||
|
||||
# Document AI 관련 설정값 (프로덕션에서는 환경 변수나 설정 파일에서 로드 권장)
|
||||
DOCAI_PROJECT_ID = "drawingpdfocr-461103"
|
||||
DOCAI_LOCATION = "us"
|
||||
DOCAI_PROCESSOR_ID = "b838676d4e3b4758" # 실제 사용자의 프로세서 ID
|
||||
|
||||
|
||||
async def run_sync_in_threadpool(func, *args, **kwargs):
|
||||
"""동기 함수를 별도의 스레드에서 실행하고 await 가능하게 만듭니다."""
|
||||
loop = asyncio.get_event_loop()
|
||||
if hasattr(asyncio, "to_thread"): # Python 3.9+
|
||||
return await asyncio.to_thread(func, *args, **kwargs)
|
||||
else: # Python < 3.9
|
||||
return await loop.run_in_executor(None, lambda: func(*args, **kwargs))
|
||||
|
||||
|
||||
@doc_ai_router.post("/process-document/")
|
||||
async def process_uploaded_document(file: UploadFile = File(...)):
|
||||
"""
|
||||
업로드된 파일을 Document AI로 처리하고, 추출된 엔티티 정보를 JSON으로 반환합니다.
|
||||
"""
|
||||
if not file.content_type:
|
||||
raise HTTPException(status_code=400, detail="File content type is missing.")
|
||||
|
||||
# 지원되는 MIME 타입 (예시, 필요에 따라 확장)
|
||||
allowed_mime_types = ["application/pdf", "image/jpeg", "image/png", "image/tiff"]
|
||||
if file.content_type not in allowed_mime_types:
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail=f"Unsupported file type: '{file.content_type}'. Supported: {', '.join(allowed_mime_types)}",
|
||||
)
|
||||
print(f"Received audio file for async processing: {file.filename}")
|
||||
file_id = str(create_key())
|
||||
|
||||
# 파일 저장 (유틸리티 함수 사용)
|
||||
try:
|
||||
file_path, file_content = save_uploaded_file(file, UPLOAD_DOCS_DIR, file_id)
|
||||
except HTTPException as e:
|
||||
raise e
|
||||
except Exception as e:
|
||||
raise HTTPException(
|
||||
status_code=500, detail=f"파일 저장 준비 중 오류 발생: {str(e)}"
|
||||
)
|
||||
|
||||
try:
|
||||
# Document AI 처리 (동기 함수를 비동기적으로 호출)
|
||||
document_result = await run_sync_in_threadpool(
|
||||
google_docai.process_document_from_content, # 수정된 함수 사용
|
||||
project_id=DOCAI_PROJECT_ID,
|
||||
location=DOCAI_LOCATION,
|
||||
processor_id=DOCAI_PROCESSOR_ID,
|
||||
file_content=file_content,
|
||||
mime_type=file.content_type,
|
||||
field_mask="text,entities", # 필요한 필드 마스크
|
||||
)
|
||||
print(document_result)
|
||||
if not document_result:
|
||||
# 이 경우는 process_document_from_content 함수 내부에서 예외가 발생하지 않고
|
||||
# None이나 빈 Document 객체를 반환했을 때를 대비 (일반적으론 예외 발생)
|
||||
raise HTTPException(
|
||||
status_code=500,
|
||||
detail="Failed to process document: No result from Document AI.",
|
||||
)
|
||||
|
||||
json_output_string = google_docai.extract_and_convert_to_json(document_result)
|
||||
|
||||
return json.loads(json_output_string)
|
||||
|
||||
except HTTPException as http_exc:
|
||||
# 이미 HTTPException으로 처리된 예외는 그대로 다시 발생시킴
|
||||
raise http_exc
|
||||
except Exception as e:
|
||||
# 기타 예외 처리 (로깅 권장)
|
||||
# import traceback
|
||||
# print(f"Error processing file: {e}\n{traceback.format_exc()}")
|
||||
raise HTTPException(
|
||||
status_code=500,
|
||||
detail=f"An error occurred during document processing: {str(e)}",
|
||||
)
|
||||
finally:
|
||||
await file.close() # 업로드된 파일 객체를 닫아 리소스 정리
|
||||
|
||||
|
||||
# app에 라우터 등록
|
||||
app.include_router(doc_ai_router)
|
||||
|
||||
|
||||
@app.get("/health/API")
|
||||
async def health_check():
|
||||
"""애플리케이션 상태 확인"""
|
||||
return {"status": "API ok"}
|
||||
Reference in New Issue
Block a user