Nottybro commited on
Commit
30c982b
·
verified ·
1 Parent(s): c612e6c

deploy: app.py

Browse files
Files changed (1) hide show
  1. app.py +82 -0
app.py ADDED
@@ -0,0 +1,82 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI, HTTPException, Header
2
+ from fastapi.middleware.cors import CORSMiddleware
3
+ from pydantic import BaseModel
4
+ from typing import Optional, List
5
+ from contextlib import asynccontextmanager
6
+ import os
7
+
8
+ from auth import verify_api_key
9
+ from credits import check_and_deduct_credits
10
+ from acra import run_acra_pipeline
11
+ from classifier_inference import warm_up
12
+
13
+ @asynccontextmanager
14
+ async def lifespan(app: FastAPI):
15
+ print("Loading ACRA classifier...")
16
+ warm_up()
17
+ print("Ready ✓")
18
+ yield
19
+
20
+ app = FastAPI(
21
+ title="ACRA API",
22
+ description="Adaptive Contextual Retrieval Architecture — by NurricAI",
23
+ version="1.0.0",
24
+ lifespan=lifespan
25
+ )
26
+ app.add_middleware(CORSMiddleware, allow_origins=["*"],
27
+ allow_methods=["*"], allow_headers=["*"])
28
+
29
+ class IngestRequest(BaseModel):
30
+ texts: List[str]
31
+ metadata: Optional[List[dict]] = None
32
+ namespace: Optional[str] = "default"
33
+
34
+ class QueryRequest(BaseModel):
35
+ query: str
36
+ namespace: Optional[str] = "default"
37
+ top_k: Optional[int] = 5
38
+ rerank: Optional[bool] = True
39
+
40
+ class QueryResponse(BaseModel):
41
+ answer: str
42
+ sources: List[dict]
43
+ credits_used: int
44
+ credits_remaining: int
45
+
46
+ @app.get("/")
47
+ def root():
48
+ return {"status": "ACRA API is live 🚀", "docs": "/docs"}
49
+
50
+ @app.get("/health")
51
+ def health():
52
+ return {"status": "ok"}
53
+
54
+ @app.post("/v1/ingest")
55
+ async def ingest(body: IngestRequest,
56
+ x_api_key: str = Header(..., alias="X-API-Key")):
57
+ user = await verify_api_key(x_api_key)
58
+ cost = max(1, len(body.texts) // 10)
59
+ remaining = await check_and_deduct_credits(user["id"], cost)
60
+ inserted = await run_acra_pipeline(
61
+ mode="ingest", texts=body.texts,
62
+ metadata=body.metadata or [{} for _ in body.texts],
63
+ namespace=body.namespace, user_id=user["id"])
64
+ return {"status": "success", "chunks_indexed": inserted,
65
+ "credits_used": cost, "credits_remaining": remaining}
66
+
67
+ @app.post("/v1/query", response_model=QueryResponse)
68
+ async def query(body: QueryRequest,
69
+ x_api_key: str = Header(..., alias="X-API-Key")):
70
+ user = await verify_api_key(x_api_key)
71
+ remaining = await check_and_deduct_credits(user["id"], 1)
72
+ result = await run_acra_pipeline(
73
+ mode="query", query=body.query, namespace=body.namespace,
74
+ top_k=body.top_k, rerank=body.rerank, user_id=user["id"])
75
+ return QueryResponse(answer=result["answer"], sources=result["sources"],
76
+ credits_used=1, credits_remaining=remaining)
77
+
78
+ @app.get("/v1/usage")
79
+ async def usage(x_api_key: str = Header(..., alias="X-API-Key")):
80
+ user = await verify_api_key(x_api_key)
81
+ return {"plan": user["plan"], "credits_remaining": user["credits_remaining"],
82
+ "credits_reset": user["credits_reset_at"]}