Aadhavan12344 commited on
Commit
eac94ac
·
verified ·
1 Parent(s): b9a3bc6

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +206 -0
app.py ADDED
@@ -0,0 +1,206 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # ============================================================
2
+ # ⚡ Semantic Intent Router (MiniLM)
3
+ # Zero-shot • No training • Sub-second • HF Free CPU
4
+ # ============================================================
5
+
6
+ import json
7
+ import time
8
+ import math
9
+ from typing import Dict, List, Any
10
+
11
+ import torch
12
+ import gradio as gr
13
+ from sentence_transformers import SentenceTransformer, util
14
+
15
+ # ============================================================
16
+ # CONFIG
17
+ # ============================================================
18
+
19
+ MODEL_NAME = "sentence-transformers/all-MiniLM-L6-v2"
20
+ MIN_SCORE = 0.05
21
+ MAX_EXAMPLES = 20
22
+
23
+ # ============================================================
24
+ # LOAD MODEL
25
+ # ============================================================
26
+
27
+ print("Loading MiniLM model...")
28
+ model = SentenceTransformer(MODEL_NAME, device="cpu")
29
+ print("Model loaded")
30
+
31
+ # ============================================================
32
+ # HELPERS
33
+ # ============================================================
34
+
35
+ def softmax(scores: Dict[str, float]) -> Dict[str, float]:
36
+ if not scores:
37
+ return {}
38
+
39
+ max_val = max(scores.values())
40
+ exp_scores = {k: math.exp(v - max_val) for k, v in scores.items()}
41
+ total = sum(exp_scores.values())
42
+
43
+ return {k: v / total for k, v in exp_scores.items()}
44
+
45
+
46
+ def parse_labels(raw: Any) -> Dict[str, List[str]]:
47
+ """
48
+ Accepts dict (Gradio JSON) or JSON string.
49
+ Returns clean label -> examples mapping.
50
+ """
51
+
52
+ if isinstance(raw, str):
53
+ try:
54
+ raw = json.loads(raw)
55
+ except Exception as e:
56
+ return {"__error__": f"Invalid JSON: {e}"}
57
+
58
+ if not isinstance(raw, dict):
59
+ return {"__error__": "Labels must be a JSON object"}
60
+
61
+ cleaned = {}
62
+
63
+ for label, examples in raw.items():
64
+ if not isinstance(label, str):
65
+ continue
66
+ if not isinstance(examples, list):
67
+ continue
68
+
69
+ ex = [
70
+ str(x).strip()
71
+ for x in examples
72
+ if isinstance(x, (str, int, float)) and str(x).strip()
73
+ ][:MAX_EXAMPLES]
74
+
75
+ if ex:
76
+ cleaned[label] = ex
77
+
78
+ if not cleaned:
79
+ return {"__error__": "No valid labels found"}
80
+
81
+ return cleaned
82
+
83
+
84
+ # ============================================================
85
+ # CLASSIFIER CORE
86
+ # ============================================================
87
+
88
+ def classify(text: str, raw_labels: Any) -> Dict[str, Any]:
89
+ start = time.time()
90
+
91
+ if not text or not text.strip():
92
+ return {"error": "Empty input"}
93
+
94
+ labels = parse_labels(raw_labels)
95
+ if "__error__" in labels:
96
+ return {"error": labels["__error__"]}
97
+
98
+ text_emb = model.encode(text, convert_to_tensor=True)
99
+
100
+ scores = {}
101
+
102
+ for label, examples in labels.items():
103
+ example_embs = model.encode(examples, convert_to_tensor=True)
104
+ sims = util.cos_sim(text_emb, example_embs)[0]
105
+ score = float(torch.max(sims).item())
106
+
107
+ if score >= MIN_SCORE:
108
+ scores[label] = score
109
+
110
+ if not scores:
111
+ return {
112
+ "text": text,
113
+ "top_intent": None,
114
+ "scores": {},
115
+ "latency_ms": round((time.time() - start) * 1000, 2),
116
+ }
117
+
118
+ scores = softmax(scores)
119
+ top_intent = max(scores, key=scores.get)
120
+
121
+ return {
122
+ "text": text,
123
+ "top_intent": top_intent,
124
+ "scores": dict(sorted(scores.items(), key=lambda x: -x[1])),
125
+ "latency_ms": round((time.time() - start) * 1000, 2),
126
+ }
127
+
128
+
129
+ # ============================================================
130
+ # DEFAULT LABELS
131
+ # ============================================================
132
+
133
+ DEFAULT_LABELS = {
134
+ "chat": [
135
+ "say hello",
136
+ "casual talk",
137
+ "how are you"
138
+ ],
139
+ "image_generation": [
140
+ "generate an image",
141
+ "draw a picture",
142
+ "create artwork"
143
+ ],
144
+ "action": [
145
+ "set a timer",
146
+ "create a reminder"
147
+ ],
148
+ "code": [
149
+ "write code",
150
+ "debug program"
151
+ ],
152
+ "search": [
153
+ "search online",
154
+ "find information"
155
+ ]
156
+ }
157
+
158
+ # ============================================================
159
+ # GRADIO UI
160
+ # ============================================================
161
+
162
+ with gr.Blocks(title="⚡ Semantic Intent Router") as demo:
163
+ gr.Markdown(
164
+ "# ⚡ Semantic Intent Router\n"
165
+ "MiniLM semantic classifier · No training · Sub-second\n\n"
166
+ "• Edit labels freely\n"
167
+ "• Add examples per label\n"
168
+ "• Used for MPC / system-prompt routing\n"
169
+ )
170
+
171
+ user_input = gr.Textbox(
172
+ label="User Input",
173
+ placeholder="Type anything…",
174
+ lines=2
175
+ )
176
+
177
+ labels_input = gr.JSON(
178
+ label="Labels & Examples (editable)",
179
+ value=DEFAULT_LABELS
180
+ )
181
+
182
+ output = gr.JSON(label="Routing Result")
183
+
184
+ classify_btn = gr.Button("Classify", variant="primary")
185
+
186
+ classify_btn.click(
187
+ fn=classify,
188
+ inputs=[user_input, labels_input],
189
+ outputs=output
190
+ )
191
+
192
+ gr.Markdown(
193
+ "### API Usage\n"
194
+ "POST to this Space endpoint with:\n\n"
195
+ "`{\"data\": [\"your text\", {\"label\": [\"example\"]}]}`\n"
196
+ )
197
+
198
+ # ============================================================
199
+ # LAUNCH
200
+ # ============================================================
201
+
202
+ if __name__ == "__main__":
203
+ demo.launch(
204
+ share=True,
205
+ enable_queue=False
206
+ )