Kethan Dosapati commited on
Commit
caa70b1
Β·
1 Parent(s): 4d002be

Add initial implementation of Yantrabodha Article API with FastAPI and Supabase integration

Browse files
Dockerfile ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Hugging Face Spaces β€” FastAPI app (Yantrabodha API)
2
+ # Runs from repo root; app code lives in api/
3
+
4
+ FROM python:3.12-slim
5
+
6
+ RUN useradd -m -u 1000 user
7
+ USER user
8
+ ENV HOME=/home/user PATH=/home/user/.local/bin:$PATH
9
+ WORKDIR $HOME/app
10
+
11
+ COPY --chown=user api/requirements.txt .
12
+ RUN pip install --no-cache-dir -r requirements.txt
13
+
14
+ COPY --chown=user api/ .
15
+
16
+ # HF Spaces expose port 7860 by default
17
+ EXPOSE 7860
18
+ CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "7860"]
api/.env ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ # Supabase β€” Project Settings β†’ API
2
+ SUPABASE_URL=https://kdtbcdsugebjjxtufsiy.supabase.co
3
+ SUPABASE_SERVICE_KEY=sb_publishable__iDn02CEPpNdGShqBinK0Q_7tgniGQf
api/database.py ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ """Supabase client singleton."""
2
+ import os
3
+
4
+ from supabase import create_client, Client
5
+
6
+ SUPABASE_URL = os.environ["SUPABASE_URL"]
7
+ SUPABASE_SERVICE_KEY = os.environ["SUPABASE_SERVICE_KEY"]
8
+
9
+ supabase: Client = create_client(SUPABASE_URL, SUPABASE_SERVICE_KEY)
api/endpoints/__init__.py ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ """API endpoint routers."""
2
+ from .match import router as match_router
3
+ from .post import router as post_router
4
+
5
+ __all__ = ["post_router", "match_router"]
api/endpoints/match.py ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """MATCH endpoint β€” full-text search across articles."""
2
+ from typing import Optional
3
+
4
+ from fastapi import APIRouter, Query
5
+
6
+ from database import supabase
7
+
8
+ router = APIRouter(tags=["match"])
9
+
10
+
11
+ @router.get("")
12
+ def match_articles(
13
+ q: str = Query(..., min_length=1, description="Search query"),
14
+ language: Optional[str] = Query(None, description="Filter by language"),
15
+ type: Optional[str] = Query(None, description="Filter by type"),
16
+ limit: int = Query(5, ge=1, le=50, description="Max results"),
17
+ ):
18
+ """Full-text search across article titles and bodies."""
19
+ query = (
20
+ supabase.table("articles")
21
+ .select("id, title, body, language, tags, type, contributing_agent, confidence, created_at")
22
+ .text_search("fts", q, config="english")
23
+ .limit(limit)
24
+ )
25
+ if language:
26
+ query = query.eq("language", language)
27
+ if type:
28
+ query = query.eq("type", type)
29
+ result = query.execute()
30
+ return result.data
api/endpoints/post.py ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """POST endpoint β€” submit a new article."""
2
+ from fastapi import APIRouter, HTTPException
3
+
4
+ from database import supabase
5
+ from models import ArticleIn, ArticleOut
6
+
7
+ router = APIRouter(tags=["post"])
8
+
9
+
10
+ @router.post("", response_model=ArticleOut, status_code=201)
11
+ def create_article(article: ArticleIn):
12
+ """Insert a new article into the knowledge base."""
13
+ result = (
14
+ supabase.table("articles")
15
+ .insert(article.model_dump())
16
+ .execute()
17
+ )
18
+ if not result.data:
19
+ raise HTTPException(status_code=500, detail="Failed to insert article")
20
+ row = result.data[0]
21
+ return ArticleOut(id=row["id"], title=row["title"], created_at=row["created_at"])
api/main.py ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Yantrabodha Article API
3
+ =======================
4
+ FastAPI app backed by Supabase (Postgres). Endpoints:
5
+ - POST /post β€” submit a new article
6
+ - GET /match β€” full-text search across articles
7
+
8
+ Environment variables:
9
+ SUPABASE_URL β€” from Supabase Project Settings β†’ API
10
+ SUPABASE_SERVICE_KEY β€” service role key (bypasses RLS)
11
+ """
12
+
13
+ from fastapi import FastAPI
14
+
15
+ from database import supabase # noqa: F401 β€” ensure DB is loaded
16
+ from endpoints.match import router as match_router
17
+ from endpoints.post import router as post_router
18
+
19
+ app = FastAPI(title="Yantrabodha API", version="1.0.0")
20
+
21
+ app.include_router(post_router, prefix="/post")
22
+ app.include_router(match_router, prefix="/match")
api/models.py ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Shared Pydantic models for the API."""
2
+ from typing import Optional
3
+
4
+ from pydantic import BaseModel
5
+
6
+
7
+ class ArticleIn(BaseModel):
8
+ title: str
9
+ body: str
10
+ language: str = "general"
11
+ tags: list[str] = []
12
+ type: str = "error"
13
+ contributing_agent: Optional[str] = None
14
+ confidence: str = "medium"
15
+
16
+
17
+ class ArticleOut(BaseModel):
18
+ id: str
19
+ title: str
20
+ created_at: str
api/requirements.txt ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ fastapi
2
+ uvicorn
3
+ supabase
4
+ pydantic