justmotes commited on
Commit
5827883
·
1 Parent(s): 0daa7b7

UI: Major overhaul with structured layout and premium styling

Browse files
Files changed (1) hide show
  1. app.py +104 -59
app.py CHANGED
@@ -2,6 +2,7 @@ import gradio as gr
2
  import pandas as pd
3
  import os
4
  import time
 
5
  from src.vector_db import UnifiedQdrant
6
  from src.router import LearnedRouter
7
  from src.comparison import ComparisonEngine
@@ -11,10 +12,9 @@ from config import COLLECTION_NAME, NUM_CLUSTERS, FRESHNESS_SHARD_ID, MRL_DIMS
11
  print("Initializing dashVectorspace App...")
12
 
13
  # 1. Initialize DB
14
- # Note: In a real HF Space, secrets are in os.environ
15
  db = UnifiedQdrant(
16
  collection_name=COLLECTION_NAME,
17
- vector_size=384, # Assuming MiniLM for demo
18
  num_clusters=NUM_CLUSTERS,
19
  freshness_shard_id=FRESHNESS_SHARD_ID
20
  )
@@ -27,11 +27,7 @@ if os.path.exists(ROUTER_PATH):
27
  else:
28
  print("WARNING: Router model not found. Creating a DUMMY router for demo UI.")
29
  router = LearnedRouter(model_type="lightgbm", n_clusters=NUM_CLUSTERS, mrl_dims=MRL_DIMS)
30
- # We can't really predict without training, but let's mock it or fail gracefully.
31
- # For the UI to load, we need an object.
32
- # If we try to predict, it will crash if not trained.
33
- # Let's mock the predict method if not trained.
34
- router.predict = lambda x: (0, 0.99) # Mock prediction: Cluster 0, High Confidence
35
 
36
  # 3. Initialize Engine
37
  engine = ComparisonEngine(db, router, embedding_model_name="minilm")
@@ -41,86 +37,135 @@ def run_comparison(query):
41
  if not query:
42
  return "Please enter a query.", None, None, None, None
43
 
44
- # Run Direct Search
45
  res_direct = engine.direct_search(query)
46
-
47
- # Run xVector Search
48
  res_xvector = engine.xvector_search(query)
49
 
50
- # Format Results
51
  def format_results(res_dict):
52
  points = res_dict["results"]
53
- text_res = ""
54
  for p in points:
55
- # Payload might be dict or object depending on client version/mock
56
  payload = p.payload
57
  text = payload.get("text", "No text") if payload else "No text"
58
  score = p.score
59
- text_res += f"- [{score:.4f}] {text[:100]}...\n"
60
- return text_res
 
 
 
 
 
 
 
61
 
62
  out_direct = format_results(res_direct)
63
  out_xvector = format_results(res_xvector)
64
 
65
- # Metrics
66
- metrics_df = pd.DataFrame({
67
- "Metric": ["Latency (ms)", "Shards Searched"],
68
- "Brute Force": [res_direct["latency_ms"], res_direct["shards_searched"]],
69
- "xVector": [res_xvector["latency_ms"], res_xvector["shards_searched"]]
70
- })
 
 
 
 
 
 
71
 
72
- # Compute Savings
73
  savings = (1 - (res_xvector["shards_searched"] / res_direct["shards_searched"])) * 100
74
- savings_text = f"Compute Savings: {savings:.1f}%"
 
 
 
 
 
 
75
 
76
  # Telemetry
77
- telemetry = f"""
78
- **Search Mode:** {res_xvector['mode']}
79
- **Router Confidence:** {res_xvector.get('confidence', 0):.4f}
80
- **Target Cluster:** {res_xvector.get('target_cluster', 'N/A')}
81
- **Shards Scanned:** {res_xvector['shards_searched']} vs {res_direct['shards_searched']}
82
- """
83
 
84
- return out_direct, out_xvector, metrics_df, savings_text, telemetry
 
 
 
 
 
 
 
 
85
 
86
  # --- Gradio Layout ---
87
- with gr.Blocks(title="dashVectorspace: Learned Hybrid Retrieval", theme=gr.themes.Soft()) as demo:
88
- gr.Markdown("# 🚀 dashVectorspace: Learned Hybrid Retrieval Engine")
89
- gr.Markdown("Comparing **Brute Force Vector Search** vs **xVector (Learned Router + Custom Sharding)**.")
90
 
91
- with gr.Row():
92
- query_input = gr.Textbox(label="Enter your query", placeholder="e.g., What is the impact of AI on healthcare?", lines=2)
93
- submit_btn = gr.Button("🚀 Run Comparison", variant="primary")
94
-
95
- with gr.Row():
96
- with gr.Column(scale=1):
97
- gr.Markdown("### 🐢 Brute Force (Standard)")
98
- out_baseline = gr.Textbox(label="Results", lines=10)
99
 
100
- with gr.Column(scale=1):
101
- gr.Markdown("### ⚡ xVector (Optimized)")
102
- out_optimized = gr.Textbox(label="Results", lines=10)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
103
 
104
- with gr.Row():
105
- with gr.Column():
106
- metrics_plot = gr.BarPlot(
107
- x="Metric",
108
- y="Brute Force",
109
- title="Performance Comparison",
110
- tooltip=["Metric", "Brute Force", "xVector"],
111
- # Gradio BarPlot expects long format usually, but let's try simple DF display first if BarPlot is complex
112
- )
113
- # Actually, let's use a simple DataFrame for metrics first, it's cleaner.
114
- metrics_table = gr.Dataframe(label="Performance Metrics")
 
115
 
116
- with gr.Column():
117
- savings_display = gr.Markdown("### Compute Savings: --%")
118
- telemetry_display = gr.Markdown("### Telemetry\nWaiting for query...")
 
 
 
 
119
 
 
120
  submit_btn.click(
121
  run_comparison,
122
  inputs=[query_input],
123
- outputs=[out_baseline, out_optimized, metrics_table, savings_display, telemetry_display]
 
 
 
 
 
 
 
124
  )
125
 
126
  if __name__ == "__main__":
 
2
  import pandas as pd
3
  import os
4
  import time
5
+ import json
6
  from src.vector_db import UnifiedQdrant
7
  from src.router import LearnedRouter
8
  from src.comparison import ComparisonEngine
 
12
  print("Initializing dashVectorspace App...")
13
 
14
  # 1. Initialize DB
 
15
  db = UnifiedQdrant(
16
  collection_name=COLLECTION_NAME,
17
+ vector_size=384,
18
  num_clusters=NUM_CLUSTERS,
19
  freshness_shard_id=FRESHNESS_SHARD_ID
20
  )
 
27
  else:
28
  print("WARNING: Router model not found. Creating a DUMMY router for demo UI.")
29
  router = LearnedRouter(model_type="lightgbm", n_clusters=NUM_CLUSTERS, mrl_dims=MRL_DIMS)
30
+ router.predict = lambda x: (0, 0.99)
 
 
 
 
31
 
32
  # 3. Initialize Engine
33
  engine = ComparisonEngine(db, router, embedding_model_name="minilm")
 
37
  if not query:
38
  return "Please enter a query.", None, None, None, None
39
 
 
40
  res_direct = engine.direct_search(query)
 
 
41
  res_xvector = engine.xvector_search(query)
42
 
 
43
  def format_results(res_dict):
44
  points = res_dict["results"]
45
+ html = "<div style='display: flex; flex-direction: column; gap: 10px;'>"
46
  for p in points:
 
47
  payload = p.payload
48
  text = payload.get("text", "No text") if payload else "No text"
49
  score = p.score
50
+ # Card style for results
51
+ html += f"""
52
+ <div style="padding: 10px; border-radius: 8px; background: rgba(255,255,255,0.05); border: 1px solid rgba(255,255,255,0.1);">
53
+ <div style="font-size: 0.8em; color: #aaa; margin-bottom: 4px;">Score: {score:.4f}</div>
54
+ <div style="font-size: 0.95em;">{text[:200]}...</div>
55
+ </div>
56
+ """
57
+ html += "</div>"
58
+ return html
59
 
60
  out_direct = format_results(res_direct)
61
  out_xvector = format_results(res_xvector)
62
 
63
+ # Metrics for JSON
64
+ metrics_data = {
65
+ "Brute Force": {
66
+ "Latency": f"{res_direct['latency_ms']:.2f} ms",
67
+ "Shards Searched": res_direct['shards_searched']
68
+ },
69
+ "xVector": {
70
+ "Latency": f"{res_xvector['latency_ms']:.2f} ms",
71
+ "Shards Searched": res_xvector['shards_searched'],
72
+ "Mode": res_xvector['mode']
73
+ }
74
+ }
75
 
76
+ # Savings
77
  savings = (1 - (res_xvector["shards_searched"] / res_direct["shards_searched"])) * 100
78
+ savings_html = f"""
79
+ <div style="text-align: center; padding: 20px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); border-radius: 12px; color: white;">
80
+ <div style="font-size: 1.2em; opacity: 0.9;">Compute Savings</div>
81
+ <div style="font-size: 3em; font-weight: bold;">{savings:.1f}%</div>
82
+ <div style="font-size: 0.9em; opacity: 0.8;">{res_xvector['shards_searched']} shards vs {res_direct['shards_searched']}</div>
83
+ </div>
84
+ """
85
 
86
  # Telemetry
87
+ telemetry_data = {
88
+ "Router Confidence": f"{res_xvector.get('confidence', 0):.4f}",
89
+ "Target Cluster": int(res_xvector.get('target_cluster', -1)),
90
+ "Search Mode": res_xvector['mode']
91
+ }
 
92
 
93
+ return out_direct, out_xvector, metrics_data, savings_html, telemetry_data
94
+
95
+ # --- Custom CSS ---
96
+ custom_css = """
97
+ body { background-color: #0b0f19; color: #e0e0e0; }
98
+ .gradio-container { font-family: 'Inter', sans-serif; }
99
+ h1 { background: -webkit-linear-gradient(45deg, #667eea, #764ba2); -webkit-background-clip: text; -webkit-text-fill-color: transparent; }
100
+ .result-box { border: 1px solid #333; border-radius: 8px; padding: 10px; }
101
+ """
102
 
103
  # --- Gradio Layout ---
104
+ with gr.Blocks(title="dashVectorspace", theme=gr.themes.Soft(primary_hue="indigo", secondary_hue="slate"), css=custom_css) as demo:
 
 
105
 
106
+ with gr.Column(elem_id="main-container"):
107
+ # Header
108
+ gr.HTML("""
109
+ <div style="text-align: center; margin-bottom: 30px;">
110
+ <h1 style="font-size: 3em; margin-bottom: 10px;">🚀 dashVectorspace</h1>
111
+ <p style="font-size: 1.2em; color: #888;">Production-Grade Learned Hybrid Retrieval Engine</p>
112
+ </div>
113
+ """)
114
 
115
+ # Input Section
116
+ with gr.Row(variant="panel"):
117
+ with gr.Column(scale=4):
118
+ query_input = gr.Textbox(
119
+ label="Search Query",
120
+ placeholder="Ask a complex question (e.g., 'How does AI impact healthcare efficiency?')",
121
+ lines=1,
122
+ show_label=False,
123
+ container=False,
124
+ scale=4
125
+ )
126
+ with gr.Column(scale=1):
127
+ submit_btn = gr.Button("🔍 Search", variant="primary", scale=1)
128
+
129
+ # Results Section
130
+ with gr.Row():
131
+ # Left: Brute Force
132
+ with gr.Column():
133
+ gr.Markdown("### 🐢 Brute Force (Baseline)")
134
+ out_baseline = gr.HTML(label="Results")
135
 
136
+ # Right: xVector
137
+ with gr.Column():
138
+ gr.Markdown("### ⚡ xVector (Optimized)")
139
+ out_optimized = gr.HTML(label="Results")
140
+
141
+ gr.Markdown("---")
142
+
143
+ # Metrics Section
144
+ with gr.Row():
145
+ with gr.Column(scale=1):
146
+ gr.Markdown("### 📊 Performance Metrics")
147
+ metrics_display = gr.JSON(label="Detailed Metrics")
148
 
149
+ with gr.Column(scale=1):
150
+ gr.Markdown("### 💰 Efficiency")
151
+ savings_display = gr.HTML()
152
+
153
+ # Telemetry (Accordion)
154
+ with gr.Accordion("🛠️ System Telemetry (Debug Info)", open=False):
155
+ telemetry_display = gr.JSON(label="Router Decisions")
156
 
157
+ # Event Listener
158
  submit_btn.click(
159
  run_comparison,
160
  inputs=[query_input],
161
+ outputs=[out_baseline, out_optimized, metrics_display, savings_display, telemetry_display]
162
+ )
163
+
164
+ # Allow Enter key to submit
165
+ query_input.submit(
166
+ run_comparison,
167
+ inputs=[query_input],
168
+ outputs=[out_baseline, out_optimized, metrics_display, savings_display, telemetry_display]
169
  )
170
 
171
  if __name__ == "__main__":