tanmay-bm commited on
Commit
71cd020
Β·
1 Parent(s): 6f30221

docs: update README and main.py to reflect two-tier architecture (v2.0.0)

Browse files
Files changed (2) hide show
  1. README.md +177 -5
  2. main.py +19 -12
README.md CHANGED
@@ -10,9 +10,181 @@ pinned: false
10
 
11
  # GCAS Excel Search Engine
12
 
13
- Natural-language search API over Gujarat College Admissions System (GCAS) data.
14
 
15
- **POST** `/search` β€” query in English, Hindi, or Gujarati
16
- **GET** `/health` β€” index status
17
- **GET** `/schema` β€” table schemas
18
- **GET** `/docs` β€” Swagger UI
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
 
11
  # GCAS Excel Search Engine
12
 
13
+ Natural-language search API over Gujarat College Admissions System (GCAS) data. Supports English, Hindi (Hinglish), and Gujarati queries.
14
 
15
+ ---
16
+
17
+ ## Architecture
18
+
19
+ The engine runs a **two-tier pipeline** β€” structured lookup first, semantic fallback second.
20
+
21
+ **Tier 1 β€” Structured in-memory lookup (~50–200 ms)**
22
+ Every query is parsed into a `QueryPlan` (college name, district, university, program, gender, category, medium, type, intent). Resolved entities are matched directly against the in-memory data store with O(n) row scanning. This handles ~95% of real queries with `confidence: high`.
23
+
24
+ **Tier 2 β€” FAISS semantic fallback**
25
+ Only triggered when Tier 1 produces zero candidates (vague / open-ended queries with no resolved entities). The query is embedded and compared against dense FAISS vectors built over all ~50k rows.
26
+
27
+ **LLM reranking** is an explicit opt-in (`use_llm_rerank: true`) β€” it is NOT part of the default path. Default is `false`.
28
+
29
+ ---
30
+
31
+ ## Endpoints
32
+
33
+ | Method | Path | Auth | Description |
34
+ |--------|------|------|-------------|
35
+ | `GET` | `/health` | No | Liveness check + index status |
36
+ | `GET` | `/schema` | No | Table names, columns, row counts |
37
+ | `POST` | `/search` | Bearer token | Natural-language search |
38
+ | `POST` | `/reindex` | Bearer token | Rebuild FAISS index from Excel folder |
39
+ | `GET` | `/docs` | No | Swagger UI (auto-generated) |
40
+ | `GET` | `/redoc` | No | ReDoc UI |
41
+
42
+ ---
43
+
44
+ ## POST /search
45
+
46
+ ### Request body
47
+
48
+ | Field | Type | Default | Description |
49
+ |-------|------|---------|-------------|
50
+ | `query` | string | *required* | Query in English, Hindi (Hinglish), or Gujarati |
51
+ | `top_k` | int | 10 | Max results (1–100). Actual count may be lower β€” the engine auto-caps based on intent (e.g. hostel β†’ 1, fees β†’ 8) |
52
+ | `tables` | list[str] | null | Restrict to specific table name(s). null = all tables |
53
+ | `use_llm_rerank` | bool | **false** | Opt-in LLM reranking pass (adds ~3–10s latency) |
54
+ | `llm_provider` | string | server default | `"openai"` or `"anthropic"` |
55
+ | `llm_model` | string | server default | Model name override |
56
+ | `api_key` | string | server default | API key override for chosen provider |
57
+
58
+ ### Response body
59
+
60
+ | Field | Type | Description |
61
+ |-------|------|-------------|
62
+ | `query` | string | Original query as submitted |
63
+ | `total_results` | int | Number of results returned |
64
+ | `results` | list[SearchResult] | Ranked result rows |
65
+ | `search_time_ms` | float | End-to-end latency |
66
+ | `reranked` | bool | Whether LLM reranking was applied |
67
+ | `detected_language` | string | `en` / `hi` / `gu` / `unknown` |
68
+ | `corrected_query` | string\|null | Query after alias resolution and entity correction |
69
+ | `entity_corrections` | list[EntityCorrection] | Spelling / ASR corrections applied |
70
+ | `confidence_level` | string | `high` (structured hit) / `medium` / `low` (FAISS fallback) |
71
+ | `detected_intent` | string | `fees` / `hostel` / `cutoff` / `facilities` / `courses` / `naac` / `contact` / `general` |
72
+ | `did_you_mean` | list[string] | Suggestions when confidence is low |
73
+
74
+ ### SearchResult fields
75
+
76
+ | Field | Type | Description |
77
+ |-------|------|-------------|
78
+ | `table` | string | Source table (Excel filename stem) |
79
+ | `row_index` | int | Original row index in the Excel file |
80
+ | `score` | float | Relevance score (higher = more relevant) |
81
+ | `llm_reason` | string\|null | LLM explanation (only when `reranked: true`) |
82
+ | `data` | object | Row data filtered to fields relevant to the detected intent |
83
+
84
+ `data` is **intent-filtered**: only the columns relevant to your query intent are returned, keeping responses compact. For example, a `fees` query returns fee columns only; a `hostel` query returns hostel-specific fields.
85
+
86
+ ---
87
+
88
+ ## Supported Query Types
89
+
90
+ The engine is designed around the full GCAS query taxonomy:
91
+
92
+ **College-level queries**
93
+ - "M N College ke baare mein sab batao"
94
+ - "GLS College contact number"
95
+ - "NAAC A grade colleges in Ahmedabad"
96
+ - "Government colleges in Rajkot district"
97
+ - "Grant-in-aid Gujarati medium arts colleges"
98
+
99
+ **Fees queries**
100
+ - "Gujarat Commerce College ki fees kitni hai?"
101
+ - "B.Com fees in Surat government colleges"
102
+ - "SC category ke liye engineering fees"
103
+ - "Girls ke liye medical college fees in Vadodara"
104
+
105
+ **Hostel queries**
106
+ - "M N College mein girls hostel hai kya?"
107
+ - "Rajkot mein boys hostel wale colleges"
108
+ - "Engineering colleges with hostel facility in Ahmedabad"
109
+
110
+ **Cutoff / admission queries**
111
+ - "IMN Law College ka cutoff kya hai?"
112
+ - "GTU ke under OBC category computer science cutoff"
113
+ - "Mehsana district mein arts college cutoff"
114
+
115
+ **Program / courses queries**
116
+ - "M N College mein evening batch hai kya?"
117
+ - "BCA kahan kahan milta hai Gujarat mein?"
118
+ - "Rajkot mein law college hai kya?"
119
+ - "LLB kitne saal ka course hai?"
120
+
121
+ **Infrastructure / facilities**
122
+ - "Anand district mein library wale colleges"
123
+ - "NAAC accredited self-financed colleges under GTU"
124
+
125
+ ---
126
+
127
+ ## Authentication
128
+
129
+ All `POST` endpoints require a Bearer token:
130
+
131
+ ```
132
+ Authorization: Bearer <API_SECRET_TOKEN>
133
+ ```
134
+
135
+ The token is configured via the `API_SECRET_TOKEN` environment variable on the server. If not set, the API runs open (dev mode).
136
+
137
+ ---
138
+
139
+ ## Example (curl)
140
+
141
+ ```bash
142
+ curl -X POST https://tanmay-bm-gsearch-api.hf.space/search \
143
+ -H "Authorization: Bearer <token>" \
144
+ -H "Content-Type: application/json" \
145
+ -d '{
146
+ "query": "GLS College ki fees kitni hai",
147
+ "top_k": 5
148
+ }'
149
+ ```
150
+
151
+ ```bash
152
+ # With LLM reranking (slower, ~3-10s extra)
153
+ curl -X POST https://tanmay-bm-gsearch-api.hf.space/search \
154
+ -H "Authorization: Bearer <token>" \
155
+ -H "Content-Type: application/json" \
156
+ -d '{
157
+ "query": "engineering colleges in Ahmedabad with hostel and NAAC A grade",
158
+ "top_k": 5,
159
+ "use_llm_rerank": true,
160
+ "llm_provider": "openai",
161
+ "api_key": "sk-..."
162
+ }'
163
+ ```
164
+
165
+ ---
166
+
167
+ ## Data Tables
168
+
169
+ | Table | Description |
170
+ |-------|-------------|
171
+ | `CollegeMaster` | College identity, type, district, university, NAAC grade, medium, gender |
172
+ | `CollegeIntakeMaster` | Programs offered, intake seats, fees by category |
173
+ | `CollegeInfrastructure` | Hostel, library, labs, sports, and other facilities |
174
+ | `CutOff_2025-26` | Admission cutoff ranks by program, round, and category |
175
+
176
+ ---
177
+
178
+ ## Multilingual Support
179
+
180
+ Queries can mix English, Hindi (Hinglish romanised), and Gujarati. The normaliser handles common transliterations:
181
+
182
+ | Input | Resolved |
183
+ |-------|----------|
184
+ | `ki fees kitni hai` | fees |
185
+ | `ke baare mein sab batao` | (removed) |
186
+ | `hostel milta hai kya` | hostel available |
187
+ | `kitne saal ka course` | how many years course |
188
+ | `kahan milta hai` | where available |
189
+
190
+ College names, district names, and university names are fuzzy-matched against the database vocabulary (edit distance + phonetic matching), so typos and ASR errors are automatically corrected.
main.py CHANGED
@@ -10,23 +10,28 @@ Endpoints
10
  POST /reindex – rebuild FAISS index from the Excel folder
11
  GET /docs – Swagger UI (auto-generated)
12
 
 
 
 
 
 
 
 
 
 
 
13
  Startup behaviour
14
  -----------------
15
- On first boot the server tries to load a persisted FAISS cache from
16
  ./index_cache/. If none exists it indexes the Excel files immediately
17
  (this takes ~1-3 min for ~50 k rows with the local embedding model).
18
 
19
  Usage example (curl)
20
  --------------------
21
  curl -X POST http://localhost:8000/search \
 
22
  -H 'Content-Type: application/json' \
23
- -d '{
24
- "query": "engineering colleges in Ahmedabad with hostel and NAAC A grade",
25
- "top_k": 5,
26
- "use_llm_rerank": true,
27
- "llm_provider": "openai",
28
- "api_key": "sk-..."
29
- }'
30
  """
31
  from __future__ import annotations
32
 
@@ -117,10 +122,12 @@ async def lifespan(app: FastAPI):
117
  app = FastAPI(
118
  title="GCAS Excel Search Engine",
119
  description=(
120
- "Natural-language search API over Gujarat College Admissions System (GCAS) "
121
- "Excel data. Hybrid pipeline: dense retrieval (FAISS) + LLM reranking."
 
 
122
  ),
123
- version="1.0.0",
124
  lifespan=lifespan,
125
  docs_url="/docs",
126
  redoc_url="/redoc",
@@ -198,7 +205,7 @@ def search(request: SearchRequest) -> SearchResponse:
198
  | `query` | string | *required* | Natural language query |
199
  | `top_k` | int | 10 | Max results to return (1–100) |
200
  | `tables` | list[str] | null | Restrict to specific table names |
201
- | `use_llm_rerank` | bool | true | Enable LLM reranking pass |
202
  | `llm_provider` | string | *(server default)* | `"openai"` or `"anthropic"` |
203
  | `llm_model` | string | *(server default)* | Model name |
204
  | `api_key` | string | *(server default)* | API key override |
 
10
  POST /reindex – rebuild FAISS index from the Excel folder
11
  GET /docs – Swagger UI (auto-generated)
12
 
13
+ Pipeline
14
+ --------
15
+ Tier 1: Structured in-memory lookup (~50–200 ms, confidence=high)
16
+ QueryPlan is built from the query (college, district, university,
17
+ program, gender, category, intent, etc.) and matched directly against
18
+ the data store via O(n) row scan.
19
+ Tier 2: FAISS semantic fallback (triggered only when Tier 1 returns [])
20
+ Query is embedded and compared against dense FAISS vectors (~50k rows).
21
+ LLM reranking: opt-in only (use_llm_rerank=true), not on by default.
22
+
23
  Startup behaviour
24
  -----------------
25
+ On first boot the server tries to load a persisted cache from
26
  ./index_cache/. If none exists it indexes the Excel files immediately
27
  (this takes ~1-3 min for ~50 k rows with the local embedding model).
28
 
29
  Usage example (curl)
30
  --------------------
31
  curl -X POST http://localhost:8000/search \
32
+ -H 'Authorization: Bearer <token>' \
33
  -H 'Content-Type: application/json' \
34
+ -d '{"query": "GLS College ki fees kitni hai", "top_k": 5}'
 
 
 
 
 
 
35
  """
36
  from __future__ import annotations
37
 
 
122
  app = FastAPI(
123
  title="GCAS Excel Search Engine",
124
  description=(
125
+ "Natural-language search API over Gujarat College Admissions System (GCAS) Excel data. "
126
+ "Two-tier pipeline: structured in-memory lookup (primary, ~50–200ms) + "
127
+ "FAISS semantic fallback. Supports English, Hindi (Hinglish), and Gujarati queries. "
128
+ "LLM reranking is opt-in only."
129
  ),
130
+ version="2.0.0",
131
  lifespan=lifespan,
132
  docs_url="/docs",
133
  redoc_url="/redoc",
 
205
  | `query` | string | *required* | Natural language query |
206
  | `top_k` | int | 10 | Max results to return (1–100) |
207
  | `tables` | list[str] | null | Restrict to specific table names |
208
+ | `use_llm_rerank` | bool | false | Opt-in LLM reranking (adds 3–10s latency) |
209
  | `llm_provider` | string | *(server default)* | `"openai"` or `"anthropic"` |
210
  | `llm_model` | string | *(server default)* | Model name |
211
  | `api_key` | string | *(server default)* | API key override |