ktejeshnaidu commited on
Commit
8cbbd4c
Β·
verified Β·
1 Parent(s): f166caf

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +110 -90
app.py CHANGED
@@ -1,17 +1,13 @@
1
  """
2
- DocuMind - Unified FastAPI + Streamlit App for HuggingFace Spaces
3
- Combines backend API and frontend UI in a single process
4
  """
5
 
6
  import streamlit as st
7
  import requests
8
  import json
9
  import os
10
- import subprocess
11
  import time
12
- import sys
13
- from threading import Thread
14
- from pathlib import Path
15
 
16
  # ============================================================================
17
  # STREAMLIT CONFIG (Must be first)
@@ -25,43 +21,49 @@ st.set_page_config(
25
  )
26
 
27
  # ============================================================================
28
- # BACKEND STARTUP
29
  # ============================================================================
30
 
31
- @st.cache_resource
32
- def start_backend_server():
33
- """Start FastAPI backend in a separate thread"""
34
-
35
- def run_server():
36
- # Import FastAPI backend components
37
- from main import app as fastapi_app
38
- import uvicorn
39
-
40
- # Run uvicorn server
41
- uvicorn.run(
42
- fastapi_app,
43
- host="127.0.0.1",
44
- port=8000,
45
- log_level="warning",
46
- access_log=False
47
- )
48
-
49
- # Start backend in daemon thread
50
- backend_thread = Thread(target=run_server, daemon=True)
51
- backend_thread.start()
52
-
53
- # Give backend time to start
54
- time.sleep(2)
55
-
56
- return "Backend started"
57
 
58
- # Start backend
59
- try:
60
- start_backend_server()
61
- API_URL = "http://127.0.0.1:8000"
62
- except Exception as e:
63
- st.error(f"Failed to start backend: {e}")
64
- st.stop()
 
 
 
 
 
 
 
 
 
 
 
 
 
65
 
66
  # ============================================================================
67
  # STREAMLIT FRONTEND UI
@@ -71,6 +73,24 @@ st.title("🧠 DocuMind")
71
  st.markdown("**Enterprise Document Intelligence Chatbot**")
72
  st.markdown("---")
73
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
74
  # --- Sidebar for Document Upload ---
75
  with st.sidebar:
76
  st.header("🏒 Document Knowledge Base")
@@ -81,35 +101,31 @@ with st.sidebar:
81
  if uploaded_file and st.button("Ingest Document", key="ingest_btn"):
82
  with st.spinner("Ingesting document (creating chunks & embeddings)..."):
83
  files = {"file": (uploaded_file.name, uploaded_file.getvalue())}
84
- try:
85
- res = requests.post(f"{API_URL}/ingest", files=files, timeout=30)
86
- if res.status_code == 200:
87
- st.success(f"βœ… {uploaded_file.name} ingested successfully!")
88
- else:
89
- st.error(f"❌ Failed to ingest: {res.text}")
90
- except requests.exceptions.ConnectionError:
91
- st.error("⚠️ Backend is not running. Please refresh the page.")
92
- except Exception as e:
93
- st.error(f"⚠️ Error: {str(e)}")
94
 
95
  st.divider()
96
 
97
  st.subheader("πŸ“„ Indexed Documents")
98
- try:
99
- res = requests.get(f"{API_URL}/sources", timeout=10)
100
- if res.status_code == 200:
101
- documents = res.json().get("documents", [])
102
- if documents:
103
- for doc in documents:
104
- st.markdown(f"- `{doc}`")
105
- else:
106
- st.info("No documents indexed yet.")
107
  else:
108
- st.warning("Could not fetch documents list")
109
- except requests.exceptions.ConnectionError:
110
- st.warning("⚠️ Could not connect to backend")
111
- except Exception as e:
112
- st.warning(f"⚠️ Error: {str(e)}")
113
 
114
  # --- Main Chat Interface ---
115
  st.subheader("πŸ’¬ Chat with Your Documents")
@@ -128,7 +144,11 @@ for msg in st.session_state.messages:
128
  score = src.get('score', 0)
129
  st.caption(f"**Source {idx+1}** [Relevance: {score:.2%}]")
130
  st.markdown(f"**From:** `{src.get('source', 'Unknown')}`")
131
- st.markdown(f"> {src.get('content', '')[:500]}...")
 
 
 
 
132
 
133
  # Chat input
134
  user_input = st.chat_input("Ask a question about your documents...")
@@ -147,16 +167,20 @@ if user_input:
147
  full_response = ""
148
  sources = []
149
 
150
- try:
151
- with requests.post(
152
- f"{API_URL}/query",
153
- json={"question": user_input},
154
- stream=True,
155
- timeout=60
156
- ) as r:
157
- r.raise_for_status()
158
-
159
- for line in r.iter_lines():
 
 
 
 
160
  if line:
161
  try:
162
  decoded_line = line.decode('utf-8')
@@ -179,20 +203,16 @@ if user_input:
179
  score = src.get('score', 0)
180
  st.caption(f"**Source {idx+1}** [Relevance: {score:.2%}]")
181
  st.markdown(f"**From:** `{src.get('source', 'Unknown')}`")
182
- st.markdown(f"> {src.get('content', '')[:500]}...")
183
-
184
- except requests.exceptions.Timeout:
185
- error_msg = "⏱️ Request timed out. Please try a shorter question."
186
- st.error(error_msg)
187
- full_response = error_msg
188
- except requests.exceptions.ConnectionError:
189
- error_msg = "⚠️ Backend connection failed. Please refresh the page."
190
- st.error(error_msg)
191
- full_response = error_msg
192
- except Exception as e:
193
- error_msg = f"❌ Error: {str(e)}"
194
- st.error(error_msg)
195
- full_response = error_msg
196
 
197
  # Save assistant message
198
  st.session_state.messages.append({
@@ -204,7 +224,7 @@ if user_input:
204
  # Footer
205
  st.divider()
206
  st.markdown(
207
- "<div style='text-align: center; color: gray; font-size: 0.8em;'>"
208
  "DocuMind - Enterprise RAG Chatbot | "
209
  "<a href='https://github.com/TejeshNaiduKona/DocuMind' target='_blank'>GitHub</a>"
210
  "</div>",
 
1
  """
2
+ DocuMind - Streamlit Frontend for HuggingFace Spaces
3
+ Simplified version that works with existing FastAPI backend
4
  """
5
 
6
  import streamlit as st
7
  import requests
8
  import json
9
  import os
 
10
  import time
 
 
 
11
 
12
  # ============================================================================
13
  # STREAMLIT CONFIG (Must be first)
 
21
  )
22
 
23
  # ============================================================================
24
+ # API CONFIGURATION
25
  # ============================================================================
26
 
27
+ # Use localhost for internal communication
28
+ API_URL = "http://127.0.0.1:8000"
29
+ API_TIMEOUT = 30 # seconds
30
+
31
+ # ============================================================================
32
+ # UTILITY FUNCTIONS
33
+ # ============================================================================
34
+
35
+ def check_backend_health(retries=5):
36
+ """Check if backend API is running"""
37
+ for attempt in range(retries):
38
+ try:
39
+ response = requests.get(f"{API_URL}/docs", timeout=5)
40
+ if response.status_code == 200:
41
+ return True
42
+ except:
43
+ if attempt < retries - 1:
44
+ time.sleep(1)
45
+ return False
 
 
 
 
 
 
 
46
 
47
+ def safe_api_call(method, endpoint, **kwargs):
48
+ """Safely call API with error handling"""
49
+ try:
50
+ url = f"{API_URL}{endpoint}"
51
+ kwargs.setdefault('timeout', API_TIMEOUT)
52
+
53
+ if method == "GET":
54
+ response = requests.get(url, **kwargs)
55
+ elif method == "POST":
56
+ response = requests.post(url, **kwargs)
57
+ else:
58
+ return None, "Invalid method"
59
+
60
+ return response, None
61
+ except requests.exceptions.Timeout:
62
+ return None, "⏱️ Request timed out"
63
+ except requests.exceptions.ConnectionError:
64
+ return None, "⚠️ Backend not responding"
65
+ except Exception as e:
66
+ return None, f"❌ Error: {str(e)}"
67
 
68
  # ============================================================================
69
  # STREAMLIT FRONTEND UI
 
73
  st.markdown("**Enterprise Document Intelligence Chatbot**")
74
  st.markdown("---")
75
 
76
+ # Health check on load
77
+ if "backend_checked" not in st.session_state:
78
+ st.session_state.backend_checked = False
79
+ st.session_state.backend_healthy = False
80
+
81
+ if not st.session_state.backend_checked:
82
+ with st.spinner("πŸ”„ Starting backend..."):
83
+ time.sleep(2) # Give backend time to start
84
+ st.session_state.backend_healthy = check_backend_health()
85
+ st.session_state.backend_checked = True
86
+
87
+ # Show status
88
+ if not st.session_state.backend_healthy:
89
+ st.warning(
90
+ "⚠️ Backend is starting up. This may take 30-60 seconds on first load. "
91
+ "Please refresh the page if you see this message for more than 1 minute."
92
+ )
93
+
94
  # --- Sidebar for Document Upload ---
95
  with st.sidebar:
96
  st.header("🏒 Document Knowledge Base")
 
101
  if uploaded_file and st.button("Ingest Document", key="ingest_btn"):
102
  with st.spinner("Ingesting document (creating chunks & embeddings)..."):
103
  files = {"file": (uploaded_file.name, uploaded_file.getvalue())}
104
+ response, error = safe_api_call("POST", "/ingest", files=files)
105
+
106
+ if error:
107
+ st.error(error)
108
+ elif response and response.status_code == 200:
109
+ st.success(f"βœ… {uploaded_file.name} ingested successfully!")
110
+ else:
111
+ st.error(f"❌ Failed to ingest: {response.text if response else 'Unknown error'}")
 
 
112
 
113
  st.divider()
114
 
115
  st.subheader("πŸ“„ Indexed Documents")
116
+ response, error = safe_api_call("GET", "/sources")
117
+
118
+ if error:
119
+ st.warning(f"Could not fetch documents: {error}")
120
+ elif response and response.status_code == 200:
121
+ documents = response.json().get("documents", [])
122
+ if documents:
123
+ for doc in documents:
124
+ st.markdown(f"- `{doc}`")
125
  else:
126
+ st.info("No documents indexed yet.")
127
+ else:
128
+ st.info("Backend not ready yet...")
 
 
129
 
130
  # --- Main Chat Interface ---
131
  st.subheader("πŸ’¬ Chat with Your Documents")
 
144
  score = src.get('score', 0)
145
  st.caption(f"**Source {idx+1}** [Relevance: {score:.2%}]")
146
  st.markdown(f"**From:** `{src.get('source', 'Unknown')}`")
147
+ content = src.get('content', '')
148
+ if len(content) > 500:
149
+ st.markdown(f"> {content[:500]}...")
150
+ else:
151
+ st.markdown(f"> {content}")
152
 
153
  # Chat input
154
  user_input = st.chat_input("Ask a question about your documents...")
 
167
  full_response = ""
168
  sources = []
169
 
170
+ response, error = safe_api_call(
171
+ "POST",
172
+ "/query",
173
+ json={"question": user_input},
174
+ stream=True
175
+ )
176
+
177
+ if error:
178
+ error_msg = error
179
+ st.error(error_msg)
180
+ full_response = error_msg
181
+ elif response:
182
+ try:
183
+ for line in response.iter_lines():
184
  if line:
185
  try:
186
  decoded_line = line.decode('utf-8')
 
203
  score = src.get('score', 0)
204
  st.caption(f"**Source {idx+1}** [Relevance: {score:.2%}]")
205
  st.markdown(f"**From:** `{src.get('source', 'Unknown')}`")
206
+ content = src.get('content', '')
207
+ if len(content) > 500:
208
+ st.markdown(f"> {content[:500]}...")
209
+ else:
210
+ st.markdown(f"> {content}")
211
+
212
+ except Exception as e:
213
+ error_msg = f"❌ Error processing response: {str(e)}"
214
+ st.error(error_msg)
215
+ full_response = error_msg
 
 
 
 
216
 
217
  # Save assistant message
218
  st.session_state.messages.append({
 
224
  # Footer
225
  st.divider()
226
  st.markdown(
227
+ "<div style='text-align: center; color: var(--color-text-secondary); font-size: 0.85em;'>"
228
  "DocuMind - Enterprise RAG Chatbot | "
229
  "<a href='https://github.com/TejeshNaiduKona/DocuMind' target='_blank'>GitHub</a>"
230
  "</div>",