gkdivya commited on
Commit
684f84d
·
verified ·
1 Parent(s): 44e120e

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +184 -0
app.py ADDED
@@ -0,0 +1,184 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import requests
3
+ import json
4
+ import pandas as pd
5
+ from difflib import get_close_matches
6
+
7
+ KYS_SAMPLE = "https://kys.udiseplus.gov.in/webapp/api/search-schools?searchType=3&searchParam={udise}"
8
+
9
+
10
+ def call_kys_by_udise(udise_code):
11
+ url = KYS_SAMPLE.format(udise=udise_code)
12
+ try:
13
+ resp = requests.get(url, timeout=10)
14
+ resp.raise_for_status()
15
+ data = resp.json()
16
+ return {"ok": True, "url": url, "data": data}
17
+ except Exception as e:
18
+ return {"ok": False, "error": str(e), "url": url}
19
+
20
+
21
+ def call_tavily(tavily_url, api_key, payload_text):
22
+ headers = {"Accept": "application/json"}
23
+ if api_key:
24
+ headers["Authorization"] = api_key
25
+ body = {"query": payload_text}
26
+ try:
27
+ resp = requests.post(tavily_url, json=body, headers=headers, timeout=12)
28
+ resp.raise_for_status()
29
+ return {"ok": True, "url": tavily_url, "status_code": resp.status_code, "data": resp.json()}
30
+ except Exception as e:
31
+ # fallback to GET
32
+ try:
33
+ params = {"q": payload_text}
34
+ resp = requests.get(tavily_url, params=params, headers=headers, timeout=12)
35
+ resp.raise_for_status()
36
+ return {"ok": True, "url": resp.url, "status_code": resp.status_code, "data": resp.json()}
37
+ except Exception as e2:
38
+ return {"ok": False, "error": f"POST failed: {e}; GET failed: {e2}"}
39
+
40
+
41
+ def extract_udise_candidates_from_tavily(tavily_json):
42
+ # Heuristic: walk the JSON and collect strings that look like UDISE (digits, length 6-14)
43
+ found = set()
44
+
45
+ def walk(obj):
46
+ if isinstance(obj, dict):
47
+ for v in obj.values():
48
+ walk(v)
49
+ elif isinstance(obj, list):
50
+ for item in obj:
51
+ walk(item)
52
+ elif isinstance(obj, str):
53
+ s = obj.strip()
54
+ tokens = s.replace('-', ' ').split()
55
+ for t in tokens:
56
+ if t.isdigit() and 6 <= len(t) <= 14:
57
+ found.add(t)
58
+
59
+ walk(tavily_json)
60
+ return sorted(list(found))
61
+
62
+
63
+ def json_to_table(obj):
64
+ # Try to convert a JSON object/array to pandas DataFrame for display
65
+ try:
66
+ if isinstance(obj, list):
67
+ df = pd.json_normalize(obj)
68
+ return df
69
+ if isinstance(obj, dict):
70
+ # Often tavily returns {"results": [...]}
71
+ if "results" in obj and isinstance(obj["results"], list):
72
+ return pd.json_normalize(obj["results"])
73
+ # common patterns: top-level list wrapped in data or hits
74
+ for k in ("data", "hits", "items", "results"):
75
+ if k in obj and isinstance(obj[k], list):
76
+ return pd.json_normalize(obj[k])
77
+ # fallback: flatten dict to single-row table
78
+ return pd.json_normalize([obj])
79
+ except Exception:
80
+ pass
81
+ return pd.DataFrame()
82
+
83
+
84
+ def to_table_from_kys(kys_json):
85
+ try:
86
+ items = kys_json.get("data") if isinstance(kys_json, dict) else kys_json
87
+ if isinstance(items, dict) and "data" in items:
88
+ items = items["data"]
89
+ if not items:
90
+ return pd.DataFrame()
91
+ df = pd.json_normalize(items)
92
+ return df
93
+ except Exception:
94
+ return pd.DataFrame()
95
+
96
+
97
+ def search_workflow(school_name_or_udise, tavily_url, tavily_key, use_tavily, use_kys):
98
+ out = {"kys": None, "tavily": None, "suggestions": []}
99
+
100
+ if use_tavily and tavily_url:
101
+ tavily_res = call_tavily(tavily_url, tavily_key, school_name_or_udise or "")
102
+ out["tavily"] = tavily_res
103
+ if tavily_res.get("ok"):
104
+ candidates = extract_udise_candidates_from_tavily(tavily_res["data"])
105
+ out["suggestions"] = candidates
106
+ else:
107
+ out["tavily"] = {"ok": False, "error": "Tavily disabled or no URL provided"}
108
+
109
+ # If user provided a numeric UDISE directly and KYS requested, do KYS
110
+ if use_kys and school_name_or_udise and school_name_or_udise.strip().isdigit() and 6 <= len(school_name_or_udise.strip()) <= 14:
111
+ kys_res = call_kys_by_udise(school_name_or_udise.strip())
112
+ out["kys"] = kys_res
113
+
114
+ return out
115
+
116
+
117
+ with gr.Blocks() as demo:
118
+ gr.Markdown("# Tavily + KYS Search (Hugging Face Space)
119
+
120
+ Enter a school name or a UDISE code and call KYS (UDISE) or your Tavily search endpoint.
121
+ ")
122
+
123
+ with gr.Row():
124
+ inp = gr.Textbox(label="School name or UDISE code", placeholder="e.g. 123456789012 or 'Govt High School...'", lines=1)
125
+ tavily_url = gr.Textbox(label="Tavily endpoint URL (POST/GET)", placeholder="https://your-tavily.example/api/search")
126
+ tavily_key = gr.Textbox(label="Tavily API Key / Authorization (optional)", placeholder="Bearer ... or APIKEY ...")
127
+
128
+ with gr.Row():
129
+ use_tavily = gr.Checkbox(value=True, label="Call Tavily")
130
+ use_kys = gr.Checkbox(value=True, label="Call KYS by UDISE")
131
+
132
+ run = gr.Button("Search Tavily")
133
+
134
+ output_json = gr.JSON(label="Raw Tavily Output (JSON)")
135
+ tavily_table = gr.DataFrame(headers=None, label="Tavily results (table)")
136
+
137
+ gr.Markdown("### UDISE candidates found in Tavily results
138
+ The dropdown will list all numeric tokens resembling UDISE codes found in Tavily's response. Choose any candidate (or edit the UDISE field) and click 'Lookup UDISE' to call KYS.")
139
+ suggestions_dropdown = gr.Dropdown(choices=[], label="UDISE candidates (from Tavily)")
140
+ udise_input = gr.Textbox(label="UDISE to lookup (editable)", placeholder="Pick a candidate or type a UDISE code...", lines=1)
141
+ lookup_btn = gr.Button("Lookup UDISE (Call KYS)")
142
+
143
+ kys_output_json = gr.JSON(label="KYS Raw Output")
144
+ kys_table = gr.DataFrame(headers=None, label="KYS results (table)")
145
+
146
+ def on_run(school, turl, tkey, utav, ukys):
147
+ res = search_workflow(school, turl, tkey, utav, ukys)
148
+ # Prepare tavily table
149
+ tav_df = pd.DataFrame()
150
+ if res.get("tavily") and res["tavily"].get("ok"):
151
+ tav_df = json_to_table(res["tavily"]["data"])
152
+ # suggestions for dropdown
153
+ suggestions = res.get("suggestions", [])
154
+ return res.get("tavily"), tav_df, suggestions
155
+
156
+ run.click(on_run, inputs=[inp, tavily_url, tavily_key, use_tavily, use_kys], outputs=[output_json, tavily_table, suggestions_dropdown])
157
+
158
+ # When user selects a suggestion, populate the editable UDISE textbox
159
+ def on_select_suggestion(choice):
160
+ return choice or ""
161
+
162
+ suggestions_dropdown.change(on_select_suggestion, inputs=[suggestions_dropdown], outputs=[udise_input])
163
+
164
+ # Lookup button handler: call KYS for whatever is in udise_input
165
+ def on_lookup_udise(udise_code):
166
+ if not udise_code or not udise_code.strip().isdigit():
167
+ return {"ok": False, "error": "Provide a numeric UDISE code (6-14 digits)."}, pd.DataFrame()
168
+ kys_res = call_kys_by_udise(udise_code.strip())
169
+ df = pd.DataFrame()
170
+ if kys_res.get("ok"):
171
+ df = to_table_from_kys(kys_res["data"]) if kys_res.get("data") else pd.DataFrame()
172
+ return kys_res, df
173
+
174
+ lookup_btn.click(on_lookup_udise, inputs=[udise_input], outputs=[kys_output_json, kys_table])
175
+
176
+ gr.Markdown("---
177
+ **Notes:**
178
+ - Tavily results are attempted to be flattened into a table for easy scanning; complex nested structures will be shown as JSON above.
179
+ - The UDISE candidates dropdown contains numeric tokens heuristically detected in the Tavily response; you can select one to fill the UDISE field, edit it, or type a different code.
180
+ - The 'Search Tavily' button only queries Tavily and fills the table + suggestions; use 'Lookup UDISE' to call KYS for the chosen code.
181
+ ")
182
+
183
+ if __name__ == "__main__":
184
+ demo.launch()