| from fastapi import FastAPI, HTTPException, UploadFile, File, BackgroundTasks |
| from fastapi.middleware.cors import CORSMiddleware |
| from fastapi.responses import FileResponse |
| from pydantic import BaseModel |
| import os |
| import uuid |
| import subprocess |
| import logging |
|
|
| |
| app = FastAPI( |
| title="HF Utility API", |
| description="Fast APIs for Embedding and Docx to PDF conversion" |
| ) |
|
|
| |
| app.add_middleware( |
| CORSMiddleware, |
| allow_origins=["*"], |
| allow_credentials=True, |
| allow_methods=["*"], |
| allow_headers=["*"], |
| ) |
|
|
| |
| logging.basicConfig(level=logging.INFO) |
| logger = logging.getLogger(__name__) |
|
|
| |
| try: |
| from sentence_transformers import SentenceTransformer |
| |
| embedding_model = SentenceTransformer("all-MiniLM-L6-v2") |
| logger.info("SentenceTransformer model loaded successfully.") |
| except Exception as e: |
| logger.error(f"Failed to load embedding model: {e}") |
| embedding_model = None |
|
|
| class EmbedRequest(BaseModel): |
| text: str |
|
|
| @app.post("/api/embed") |
| async def embed_text(req: EmbedRequest): |
| if not embedding_model: |
| raise HTTPException(status_code=500, detail="Embedding model not initialized.") |
| |
| try: |
| |
| embedding = embedding_model.encode(req.text).tolist() |
| return {"embedding": embedding} |
| except Exception as e: |
| logger.error(f"Embedding error: {e}") |
| raise HTTPException(status_code=500, detail=str(e)) |
|
|
| def cleanup_files(*file_paths): |
| for path in file_paths: |
| if path and os.path.exists(path): |
| try: |
| os.remove(path) |
| logger.info(f"Cleaned up {path}") |
| except Exception as e: |
| logger.error(f"Failed to clean up {path}: {e}") |
|
|
| @app.post("/api/convert-docx") |
| async def convert_docx(background_tasks: BackgroundTasks, file: UploadFile = File(...)): |
| if not file.filename.endswith(".docx"): |
| raise HTTPException(status_code=400, detail="Only .docx files are supported.") |
| |
| |
| job_id = str(uuid.uuid4()) |
| upload_dir = "/tmp/hf_api_uploads" |
| |
| os.makedirs(upload_dir, exist_ok=True) |
| |
| |
| safe_filename = file.filename.replace(" ", "_") |
| |
| input_path = os.path.join(upload_dir, f"{job_id}_{safe_filename}") |
| output_filename = f"{job_id}_{safe_filename.replace('.docx', '.pdf')}" |
| output_path = os.path.join(upload_dir, output_filename) |
| |
| try: |
| |
| with open(input_path, "wb") as f: |
| content = await file.read() |
| f.write(content) |
| |
| logger.info(f"Saved docx to {input_path}. Starting conversion...") |
| |
| |
| command = [ |
| "libreoffice", |
| "--headless", |
| "--convert-to", "pdf", |
| "--outdir", upload_dir, |
| input_path |
| ] |
| |
| |
| process = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) |
| |
| if process.returncode != 0: |
| logger.error(f"LibreOffice error: {process.stderr}") |
| |
| cleanup_files(input_path) |
| raise HTTPException(status_code=500, detail="Failed to convert document.") |
| |
| logger.info(f"Successfully converted to {output_path}") |
| |
| |
| if not os.path.exists(output_path): |
| cleanup_files(input_path) |
| raise HTTPException(status_code=500, detail="Output PDF not found after conversion.") |
| |
| |
| background_tasks.add_task(cleanup_files, input_path, output_path) |
| |
| return FileResponse( |
| path=output_path, |
| filename=safe_filename.replace('.docx', '.pdf'), |
| media_type="application/pdf" |
| ) |
| |
| except HTTPException: |
| raise |
| except Exception as e: |
| logger.error(f"Conversion error: {e}") |
| cleanup_files(input_path, output_path) |
| raise HTTPException(status_code=500, detail=str(e)) |
|
|
| @app.get("/api/health") |
| async def health_check(): |
| return {"status": "healthy", "embedding_model_loaded": embedding_model is not None} |
|
|
| @app.get("/") |
| async def root(): |
| return {"message": "HF Utility API is running"} |