Spaces:
Running
Running
| import os | |
| import gc | |
| import glob | |
| import time | |
| import logging | |
| from typing import List, Union, Optional, Literal | |
| from fastapi import FastAPI, Depends, HTTPException, Header, status | |
| from fastapi.responses import JSONResponse, FileResponse | |
| from pydantic import BaseModel, Field | |
| from llama_cpp import Llama | |
| logging.basicConfig(level=logging.INFO) | |
| logger = logging.getLogger(__name__) | |
| # 🔒 SEGURANÇA: Falha imediata se API_KEY não estiver configurada | |
| API_KEY = os.getenv("API_KEY") | |
| if not API_KEY: | |
| raise RuntimeError( | |
| "❌ SECURITY ERROR: API_KEY environment variable is not set!\n" | |
| "Please configure the API_KEY secret in your Hugging Face Space:\n" | |
| "Settings → Variables and Secrets → Add secret\n" | |
| "Name: API_KEY | Value: [your-secure-key]" | |
| ) | |
| MODEL_PATH = glob.glob("/app/model/*.gguf")[0] | |
| logger.info(f"Carregando modelo: {MODEL_PATH}") | |
| load_start = time.time() | |
| llm = Llama( | |
| model_path=MODEL_PATH, | |
| n_ctx=512, | |
| n_threads=2, | |
| n_batch=512, | |
| embedding=True, | |
| verbose=False | |
| ) | |
| load_time = time.time() - load_start | |
| logger.info(f"🚀 Model loaded in {load_time:.2f}s") | |
| app = FastAPI(title="Embedding Engine (GGUF Q8_0)") | |
| async def root(): | |
| return FileResponse("index.html") | |
| class EmbeddingRequest(BaseModel): | |
| input: Union[str, List[str]] | |
| model: str = "LiquidAI/LFM2.5-Embedding-350M" | |
| input_type: Optional[Literal["query", "document"]] = Field( | |
| default="document", | |
| alias="inputType" | |
| ) | |
| model_config = {"populate_by_name": True} | |
| class EmbeddingObject(BaseModel): | |
| object: str = "embedding" | |
| embedding: List[float] | |
| index: int | |
| class EmbeddingResponse(BaseModel): | |
| object: str = "list" | |
| data: List[EmbeddingObject] | |
| model: str | |
| usage: dict | |
| def verify_api_key(authorization: str = Header(None)): | |
| if not authorization or not authorization.startswith("Bearer "): | |
| raise HTTPException( | |
| status_code=status.HTTP_401_UNAUTHORIZED, | |
| detail="Invalid or missing Authorization header", | |
| headers={"WWW-Authenticate": "Bearer"}, | |
| ) | |
| token = authorization.replace("Bearer ", "") | |
| if token != API_KEY: | |
| raise HTTPException( | |
| status_code=status.HTTP_401_UNAUTHORIZED, | |
| detail="Invalid API key", | |
| headers={"WWW-Authenticate": "Bearer"}, | |
| ) | |
| async def create_embeddings( | |
| request: EmbeddingRequest, | |
| _: str = Depends(verify_api_key) | |
| ): | |
| req_start = time.time() | |
| inputs = request.input if isinstance(request.input, list) else [request.input] | |
| if request.input_type == "query": | |
| inputs = [f"query: {text}" for text in inputs] | |
| else: | |
| inputs = [f"document: {text}" for text in inputs] | |
| prep_time = time.time() - req_start | |
| logger.info(f"📝 Prep time: {prep_time:.3f}s | Input count: {len(inputs)} | First input length: {len(inputs[0])} chars") | |
| try: | |
| infer_start = time.time() | |
| response = llm.create_embedding(input=inputs) | |
| infer_time = time.time() - infer_start | |
| logger.info(f"🧠 Inference time: {infer_time:.3f}s") | |
| response["model"] = request.model | |
| total_time = time.time() - req_start | |
| logger.info(f"✅ Total request time: {total_time:.3f}s") | |
| return JSONResponse(content=response) | |
| except Exception as e: | |
| logger.error(f"Embedding error: {str(e)}") | |
| raise HTTPException(status_code=500, detail="Embedding generation failed") | |
| finally: | |
| gc.collect() |