rishik1111 commited on
Commit
e64b489
·
1 Parent(s): c8bb2b9

Render full retro Command Center UI with base64 assets in Streamlit

Browse files
Files changed (1) hide show
  1. streamlit_app.py +70 -116
streamlit_app.py CHANGED
@@ -1,137 +1,91 @@
1
  """
2
- Streamlit Native UI for VECTOR: Voice-Enabled Indic RAG.
3
- Optimized for instant Streamlit Cloud health check (<1s boot time).
4
  """
5
- import asyncio
6
- import json
 
7
  import os
8
- import tempfile
9
  import streamlit as st
 
10
 
11
- # Disable heavy network/ONNX downloads at boot to prevent Streamlit health check timeout
12
- os.environ["ENABLE_PROMPT_GUARD"] = "false"
13
- os.environ["ENABLE_CONTEXT_CHUNK_SCAN"] = "false"
14
-
15
- # Page setup
16
  st.set_page_config(
17
- page_title="⚡ VECTOR — Voice Indic RAG",
18
  page_icon="⚡",
19
  layout="wide",
 
20
  )
21
 
22
- # Custom retro-tropical styling
23
  st.markdown("""
24
  <style>
25
- .stApp {
26
- background-color: #0b0f19;
27
- color: #e2e8f0;
28
- }
29
- .main-title {
30
- font-family: monospace;
31
- font-size: 2.2rem;
32
- font-weight: bold;
33
- color: #38bdf8;
34
- text-shadow: 0 0 10px rgba(56, 189, 248, 0.4);
35
  }
36
- .sub-title {
37
- color: #94a3b8;
38
- font-size: 1rem;
39
- margin-bottom: 20px;
40
  }
41
  </style>
42
  """, unsafe_allow_html=True)
43
 
44
- st.markdown('<div class="main-title">⚡ VECTOR Command Center</div>', unsafe_allow_html=True)
45
- st.markdown('<div class="sub-title">Voice-Enabled Indic Multilingual Retrieval-Augmented Generation</div>', unsafe_allow_html=True)
46
-
47
- # Layout
48
- col1, col2 = st.columns([1, 1])
 
49
 
50
- with col1:
51
- st.subheader("🔍 Query Input")
52
-
53
- input_mode = st.radio("Select Input Mode", ["Text Query", "Audio File Upload"], horizontal=True)
54
-
55
- language_hint = st.selectbox(
56
- "Language Hint",
57
- options=["auto", "en", "hi", "mr"],
58
- format_func=lambda x: {"auto": "Auto-Detect", "en": "English (en)", "hi": "Hindi (hi)", "mr": "Marathi (mr)"}[x]
59
- )
60
 
61
- cross_lingual = st.checkbox("Enable Cross-Lingual Vector Search", value=False)
62
- bypass_cache = st.checkbox("Bypass Semantic Answer Cache", value=False)
63
-
64
- query_text = ""
65
- audio_path = None
66
-
67
- if input_mode == "Text Query":
68
- query_text = st.text_area(
69
- "Enter your question:",
70
- placeholder="e.g., What are the key features of the Manhattan Project?",
71
- height=120
72
- )
73
- else:
74
- uploaded_audio = st.file_uploader("Upload Audio File (.wav, .mp3, .m4a)", type=["wav", "mp3", "m4a"])
75
- if uploaded_audio:
76
- with tempfile.NamedTemporaryFile(delete=False, suffix=".wav") as tmp:
77
- tmp.write(uploaded_audio.read())
78
- audio_path = tmp.name
79
- st.audio(uploaded_audio)
80
 
81
- submit_btn = st.button("🚀 Run RAG Pipeline", type="primary", use_container_width=True)
 
 
 
 
 
 
 
 
 
 
 
82
 
83
- with col2:
84
- st.subheader("📊 Output & JSON Telemetry")
85
-
86
- if submit_btn:
87
- if not query_text and not audio_path:
88
- st.warning("Please enter a text query or upload an audio file.")
89
- else:
90
- with st.spinner("Loading models & processing RAG pipeline..."):
91
- try:
92
- from rag_pipeline.orchestrator import get_orchestrator
93
- from rag_pipeline.schemas import QueryRequest
94
-
95
- orchestrator = get_orchestrator()
96
-
97
- req = QueryRequest(
98
- text=query_text.strip() if query_text else None,
99
- audio_path=audio_path,
100
- language_hint=language_hint,
101
- cross_lingual=cross_lingual,
102
- bypass_cache=bypass_cache
103
- )
104
-
105
- response = asyncio.run(orchestrator.execute(req))
106
-
107
- # Display Answer
108
- st.markdown("### 💬 Answer")
109
- if response.answer_source == "declined":
110
- st.error(response.answer)
111
- else:
112
- st.success(response.answer)
113
-
114
- # Telemetry Metrics
115
- m1, m2, m3 = st.columns(3)
116
- m1.metric("Target Language", response.language_detected.upper())
117
- m2.metric("Answer Source", response.answer_source)
118
- m3.metric("Total Latency", f"{response.total_ms:.1f} ms")
119
-
120
- # Retrieved Chunks
121
- with st.expander("📚 Retrieved Knowledge Chunks", expanded=True):
122
- for i, chunk in enumerate(response.retrieved_chunks):
123
- st.markdown(f"**Chunk #{i+1}** `[{chunk.source_lang.upper()}]` (Score: `{chunk.final_score:.4f}`)")
124
- st.info(chunk.text)
125
-
126
- # Full JSON Response
127
- with st.expander("🛠️ Full Raw JSON Response", expanded=True):
128
- st.json(response.model_dump())
129
-
130
- except Exception as ex:
131
- st.error(f"Error executing pipeline: {ex}")
132
- finally:
133
- if audio_path and os.path.exists(audio_path):
134
- try:
135
- os.remove(audio_path)
136
- except Exception:
137
- pass
 
1
  """
2
+ Streamlit App to render the full retro-tropical Command Center UI (web_ui/index.html)
3
+ with base64 embedded assets and backend FastAPI support.
4
  """
5
+ import base64
6
+ from pathlib import Path
7
+ import threading
8
  import os
9
+ import uvicorn
10
  import streamlit as st
11
+ import streamlit.components.v1 as components
12
 
13
+ # Streamlit Page Config
 
 
 
 
14
  st.set_page_config(
15
+ page_title="⚡ VECTOR 2026 — Voice Indic RAG Engine",
16
  page_icon="⚡",
17
  layout="wide",
18
+ initial_sidebar_state="collapsed"
19
  )
20
 
21
+ # Hide Streamlit header/footer padding for full-screen UI experience
22
  st.markdown("""
23
  <style>
24
+ #MainMenu {visibility: hidden;}
25
+ footer {visibility: hidden;}
26
+ header {visibility: hidden;}
27
+ .block-container {
28
+ padding-top: 0rem;
29
+ padding-bottom: 0rem;
30
+ padding-left: 0rem;
31
+ padding-right: 0rem;
32
+ max-width: 100%;
 
33
  }
34
+ iframe {
35
+ border: none !important;
36
+ width: 100% !important;
 
37
  }
38
  </style>
39
  """, unsafe_allow_html=True)
40
 
41
+ # Helper to read file as base64
42
+ def get_base64_image(file_path: Path) -> str:
43
+ if file_path.exists():
44
+ with open(file_path, "rb") as f:
45
+ return f"data:image/png;base64,{base64.b64encode(f.read()).decode('utf-8')}"
46
+ return ""
47
 
48
+ # Load and prepare full HTML string
49
+ @st.cache_data
50
+ def get_prepared_html() -> str:
51
+ web_ui_dir = Path(__file__).parent / "web_ui"
52
+ index_file = web_ui_dir / "index.html"
 
 
 
 
 
53
 
54
+ if not index_file.exists():
55
+ return "<h1>Error: web_ui/index.html not found</h1>"
56
+
57
+ with open(index_file, "r", encoding="utf-8") as f:
58
+ html = f.read()
59
+
60
+ # Replace relative PNG images with inline base64
61
+ for img_name in ["ironman.png", "thor.png", "cap.png", "spider_gwen.png", "spider_gwen_clean.png", "spider_gwen_cutout.png", "bg_beach.png"]:
62
+ b64_data = get_base64_image(web_ui_dir / img_name)
63
+ if b64_data:
64
+ html = html.replace(f'"{img_name}"', f'"{b64_data}"')
65
+ html = html.replace(f"'{img_name}'", f"'{b64_data}'")
66
+ html = html.replace(f'src="/{img_name}"', f'src="{b64_data}"')
67
+
68
+ return html
 
 
 
 
69
 
70
+ # Start background FastAPI server for /query, /languages, /health endpoints
71
+ @st.cache_resource
72
+ def start_fastapi_backend():
73
+ def _run():
74
+ import main
75
+ # Disable heavy startup preloads in background thread
76
+ os.environ["ENABLE_PROMPT_GUARD"] = "false"
77
+ uvicorn.run(main.app, host="0.0.0.0", port=7860, log_level="warning")
78
+
79
+ thread = threading.Thread(target=_run, daemon=True)
80
+ thread.start()
81
+ return True
82
 
83
+ # Initialize backend
84
+ try:
85
+ start_fastapi_backend()
86
+ except Exception:
87
+ pass
88
+
89
+ # Render Full Command Center UI
90
+ prepared_html = get_prepared_html()
91
+ components.html(prepared_html, height=1200, scrolling=True)