gbrabbit's picture
Auto commit at 23-2025-08 10:05:36
84635f1
"""
OCR (Image OCR, LaTeX-OCR) router for Lily LLM API
"""
from fastapi import APIRouter, HTTPException, UploadFile, File, Form
from typing import Optional
import logging
import time
import os
import uuid
from ...models.schemas import DocumentUploadResponse, RAGResponse
logger = logging.getLogger(__name__)
router = APIRouter()
# ============================================================================
# 이미지 OCR 전용 API 엔드포인트
# ============================================================================
@router.post("/image-ocr/upload", response_model=DocumentUploadResponse)
async def upload_image_document(
file: UploadFile = File(...),
user_id: str = Form("default_user"),
document_id: Optional[str] = Form(None)
):
"""이미지 OCR 전용 문서 업로드"""
start_time = time.time()
try:
# 문서 ID 생성 (제공되지 않은 경우)
if not document_id:
document_id = str(uuid.uuid4())[:8]
# 임시 파일 저장
temp_file_path = f"./temp_image_{document_id}_{file.filename}"
with open(temp_file_path, "wb") as f:
content = await file.read()
f.write(content)
# 이미지 OCR 처리 및 벡터 스토어에 저장
try:
from lily_llm_core.image_rag_processor import image_rag_processor
result = image_rag_processor.process_and_store_image_document(
user_id, document_id, temp_file_path
)
except ImportError:
result = {
"success": False,
"error": "Image RAG processor not available"
}
# 임시 파일 삭제
if os.path.exists(temp_file_path):
os.remove(temp_file_path)
processing_time = time.time() - start_time
logger.info(f"🖼️ 이미지 OCR 문서 업로드 완료 ({processing_time:.2f}초): {file.filename}")
return DocumentUploadResponse(
success=result["success"],
document_id=document_id,
message=result.get("message", ""),
chunks=result.get("chunks"),
latex_count=result.get("latex_count"),
error=result.get("error"),
auto_response=result.get("auto_response", "")
)
except Exception as e:
logger.error(f"❌ 이미지 OCR 문서 업로드 실패: {e}")
return DocumentUploadResponse(
success=False,
document_id=document_id if 'document_id' in locals() else "unknown",
message="이미지 OCR 문서 업로드 중 오류가 발생했습니다.",
error=str(e)
)
@router.post("/image-ocr/generate", response_model=RAGResponse)
async def generate_image_ocr_response(
query: str = Form(...),
user_id: str = Form("default_user"),
document_id: str = Form(...)
):
"""이미지 OCR 기반 RAG 응답 생성"""
start_time = time.time()
try:
# 이미지 OCR RAG 응답 생성
try:
from lily_llm_core.image_rag_processor import image_rag_processor
result = image_rag_processor.generate_image_rag_response(
user_id, document_id, query
)
except ImportError:
result = {
"success": False,
"response": "Image RAG processor not available",
"context": "",
"sources": [],
"search_results": 0
}
processing_time = time.time() - start_time
result["processing_time"] = processing_time
logger.info(f"🖼️ 이미지 OCR RAG 응답 생성 완료 ({processing_time:.2f}초)")
return result
except Exception as e:
logger.error(f"❌ 이미지 OCR RAG 응답 생성 실패: {e}")
return RAGResponse(
success=False,
response=f"이미지 OCR RAG 응답 생성 중 오류가 발생했습니다: {str(e)}",
context="",
sources=[],
search_results=0,
processing_time=time.time() - start_time
)
@router.get("/image-ocr/document/{user_id}/{document_id}")
async def get_image_document_info(user_id: str, document_id: str):
"""이미지 OCR 문서 정보 조회"""
try:
try:
from lily_llm_core.image_rag_processor import image_rag_processor
result = image_rag_processor.get_image_document_info(user_id, document_id)
except ImportError:
result = {
"success": False,
"error": "Image RAG processor not available"
}
return result
except Exception as e:
logger.error(f"❌ 이미지 OCR 문서 정보 조회 실패: {e}")
return {
"success": False,
"error": str(e)
}
@router.delete("/image-ocr/document/{user_id}/{document_id}")
async def delete_image_document(user_id: str, document_id: str):
"""이미지 OCR 문서 삭제"""
try:
# 벡터 스토어에서 문서 삭제
try:
from lily_llm_core.vector_store_manager import vector_store_manager
success = vector_store_manager.delete_document(user_id, document_id)
except ImportError:
success = False
if success:
return {
"success": True,
"message": "이미지 OCR 문서가 삭제되었습니다."
}
else:
return {
"success": False,
"error": "이미지 OCR 문서 삭제에 실패했습니다."
}
except Exception as e:
logger.error(f"❌ 이미지 OCR 문서 삭제 실패: {e}")
return {
"success": False,
"error": str(e)
}
# ============================================================================
# LaTeX-OCR 전용 API 엔드포인트
# ============================================================================
@router.post("/latex-ocr/upload", response_model=DocumentUploadResponse)
async def upload_latex_document(
file: UploadFile = File(...),
user_id: str = Form("default_user"),
document_id: Optional[str] = Form(None)
):
"""LaTeX-OCR 전용 문서 업로드"""
start_time = time.time()
try:
# 문서 ID 생성 (제공되지 않은 경우)
if not document_id:
document_id = str(uuid.uuid4())[:8]
# 임시 파일 저장
temp_file_path = f"./temp_latex_{document_id}_{file.filename}"
with open(temp_file_path, "wb") as f:
content = await file.read()
f.write(content)
# LaTeX-OCR 처리 및 벡터 스토어에 저장
try:
from lily_llm_core.latex_rag_processor import latex_rag_processor
result = latex_rag_processor.process_and_store_latex_document(
user_id, document_id, temp_file_path
)
except ImportError:
result = {
"success": False,
"error": "LaTeX RAG processor not available"
}
# 임시 파일 삭제
if os.path.exists(temp_file_path):
os.remove(temp_file_path)
processing_time = time.time() - start_time
logger.info(f"🧮 LaTeX-OCR 문서 업로드 완료 ({processing_time:.2f}초): {file.filename}")
return DocumentUploadResponse(
success=result["success"],
document_id=document_id,
message=result.get("message", ""),
chunks=result.get("chunks"),
latex_count=result.get("latex_count"),
error=result.get("error"),
auto_response=result.get("auto_response", "")
)
except Exception as e:
logger.error(f"❌ LaTeX-OCR 문서 업로드 실패: {e}")
return DocumentUploadResponse(
success=False,
document_id=document_id if 'document_id' in locals() else "unknown",
message="LaTeX-OCR 문서 업로드 중 오류가 발생했습니다.",
error=str(e)
)
@router.post("/latex-ocr/generate", response_model=RAGResponse)
async def generate_latex_ocr_response(
query: str = Form(...),
user_id: str = Form("default_user"),
document_id: str = Form(...)
):
"""LaTeX-OCR 기반 RAG 응답 생성"""
start_time = time.time()
try:
# LaTeX-OCR RAG 응답 생성
try:
from lily_llm_core.latex_rag_processor import latex_rag_processor
result = latex_rag_processor.generate_latex_rag_response(
user_id, document_id, query
)
except ImportError:
result = {
"success": False,
"response": "LaTeX RAG processor not available",
"context": "",
"sources": [],
"search_results": 0
}
processing_time = time.time() - start_time
result["processing_time"] = processing_time
logger.info(f"🧮 LaTeX-OCR RAG 응답 생성 완료 ({processing_time:.2f}초)")
return result
except Exception as e:
logger.error(f"❌ LaTeX-OCR RAG 응답 생성 실패: {e}")
return RAGResponse(
success=False,
response=f"LaTeX-OCR RAG 응답 생성 중 오류가 발생했습니다: {str(e)}",
context="",
sources=[],
search_results=0,
processing_time=time.time() - start_time
)
@router.get("/latex-ocr/document/{user_id}/{document_id}")
async def get_latex_document_info(user_id: str, document_id: str):
"""LaTeX-OCR 문서 정보 조회"""
try:
try:
from lily_llm_core.latex_rag_processor import latex_rag_processor
result = latex_rag_processor.get_latex_document_info(user_id, document_id)
except ImportError:
result = {
"success": False,
"error": "LaTeX RAG processor not available"
}
return result
except Exception as e:
logger.error(f"❌ LaTeX-OCR 문서 정보 조회 실패: {e}")
return {
"success": False,
"error": str(e)
}
@router.delete("/latex-ocr/document/{user_id}/{document_id}")
async def delete_latex_document(user_id: str, document_id: str):
"""LaTeX-OCR 문서 삭제"""
try:
# 벡터 스토어에서 문서 삭제
try:
from lily_llm_core.vector_store_manager import vector_store_manager
success = vector_store_manager.delete_document(user_id, document_id)
except ImportError:
success = False
if success:
return {
"success": True,
"message": "LaTeX-OCR 문서가 삭제되었습니다."
}
else:
return {
"success": False,
"error": "LaTeX-OCR 문서 삭제에 실패했습니다."
}
except Exception as e:
logger.error(f"❌ LaTeX-OCR 문서 삭제 실패: {e}")
return {
"success": False,
"error": str(e)
}
# ============================================================================
# LaTeX-OCR + FAISS 통합 시스템 엔드포인트 (현재 비활성화)
# ============================================================================
@router.post("/latex-ocr-faiss/process", response_model=DocumentUploadResponse)
async def process_pdf_with_latex_faiss(
file: UploadFile = File(...),
user_id: str = Form("default_user"),
system_type: str = Form("simple") # "simple" 또는 "integrated"
):
"""PDF에서 LaTeX 수식 추출 및 FAISS 저장 (현재 비활성화)"""
try:
# 파일 저장
from pathlib import Path
upload_dir = Path("uploads/latex_ocr_faiss")
upload_dir.mkdir(parents=True, exist_ok=True)
file_path = upload_dir / f"{user_id}_{file.filename}"
with open(file_path, "wb") as f:
content = await file.read()
f.write(content)
# 현재 비활성화된 기능
return DocumentUploadResponse(
success=False,
document_id="",
message="LaTeX-OCR + FAISS 기능이 현재 비활성화되어 있습니다",
error="삭제된 모듈로 인해 기능이 비활성화됨"
)
except Exception as e:
logger.error(f"LaTeX-OCR + FAISS 처리 오류: {e}")
return DocumentUploadResponse(
success=False,
document_id="",
message="처리 중 오류가 발생했습니다",
error=f"처리 중 오류가 발생했습니다: {str(e)}"
)
@router.post("/latex-ocr-faiss/search", response_model=RAGResponse)
async def search_latex_formulas(
query: str = Form(...),
user_id: str = Form("default_user"),
document_path: Optional[str] = Form(None),
system_type: str = Form("simple"),
k: int = Form(5)
):
"""저장된 LaTeX 수식 검색 (현재 비활성화)"""
try:
# 현재 비활성화된 기능
return RAGResponse(
success=False,
response="LaTeX-OCR + FAISS 검색 기능이 현재 비활성화되어 있습니다",
context="",
sources=[],
search_results=0,
processing_time=0.0,
error="삭제된 모듈로 인해 기능이 비활성화됨"
)
except Exception as e:
logger.error(f"LaTeX 수식 검색 오류: {e}")
return RAGResponse(
success=False,
response="검색 중 오류가 발생했습니다.",
context="",
sources=[],
search_results=0,
processing_time=0.0,
error=str(e)
)
@router.get("/latex-ocr-faiss/status")
async def get_latex_ocr_faiss_status():
"""LaTeX-OCR + FAISS 시스템 상태 확인 (현재 비활성화)"""
try:
return {
"simple_system_initialized": False,
"integrated_system_initialized": False,
"status": "disabled",
"message": "LaTeX-OCR + FAISS 기능이 현재 비활성화되어 있습니다"
}
except Exception as e:
logger.error(f"상태 확인 오류: {e}")
return {"status": "error", "error": str(e)}