ambrosfitz commited on
Commit
d04fe9b
Β·
verified Β·
1 Parent(s): 4bd9b26

Create gradio.app

Browse files
Files changed (1) hide show
  1. gradio.app +215 -0
gradio.app ADDED
@@ -0,0 +1,215 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import requests
3
+ import json
4
+ import os
5
+ from typing import List, Tuple
6
+
7
+ # --- Configuration ---
8
+ API_URL = "https://monocopter.net"
9
+ API_TOKEN = os.getenv("API_TOKEN", "")
10
+
11
+ HEADERS = {
12
+ "Authorization": f"Bearer {API_TOKEN}",
13
+ "Content-Type": "application/json"
14
+ }
15
+
16
+ # --- Core API Functions ---
17
+ def query_rag_system(query: str, max_cards: int = 5) -> dict:
18
+ """Query the RAG system with a historical question."""
19
+ try:
20
+ payload = {"query": query, "max_cards": max_cards, "include_sources": True}
21
+ response = requests.post(f"{API_URL}/query", json=payload, headers=HEADERS)
22
+ return response.json()
23
+ except Exception as e:
24
+ return {"error": str(e)}
25
+
26
+ def search_cards_semantic(query: str, max_cards: int = 5) -> dict:
27
+ """Perform semantic search on cards."""
28
+ try:
29
+ payload = {"query": query, "max_cards": max_cards}
30
+ response = requests.post(f"{API_URL}/search", json=payload, headers=HEADERS)
31
+ return response.json()
32
+ except Exception as e:
33
+ return {"error": str(e)}
34
+
35
+ # --- Chatbot Functions ---
36
+ def format_rag_response(result: dict) -> str:
37
+ """Format the RAG response for display in the chatbot."""
38
+ if "error" in result:
39
+ return f"❌ **Error**: {result['error']}"
40
+
41
+ answer = result.get("answer", "I couldn't generate an answer for your question.")
42
+ cards_used = result.get("cards_used", [])
43
+ sources = result.get("sources", [])
44
+ processing_time = result.get("processing_time", 0)
45
+
46
+ # Build formatted response
47
+ response = f"**Answer:**\n{answer}\n\n"
48
+
49
+ if sources:
50
+ response += f"**πŸ“š Sources ({len(sources)} documents):**\n"
51
+ for i, source in enumerate(sources[:3], 1): # Limit to top 3 sources
52
+ response += f"{i}. {source}\n"
53
+ if len(sources) > 3:
54
+ response += f"... and {len(sources) - 3} more sources\n"
55
+ response += "\n"
56
+
57
+ if cards_used:
58
+ response += f"**πŸ—ƒοΈ Retrieved {len(cards_used)} relevant cards** | "
59
+ response += f"**⏱️ {processing_time:.2f}s**"
60
+
61
+ return response
62
+
63
+ def format_search_response(result: dict) -> str:
64
+ """Format the search response for display."""
65
+ if "error" in result:
66
+ return f"❌ **Error**: {result['error']}"
67
+
68
+ cards = result.get("cards", [])
69
+ if not cards:
70
+ return "πŸ” No relevant historical information found for your search."
71
+
72
+ response = f"πŸ” **Found {len(cards)} relevant historical entries:**\n\n"
73
+
74
+ for i, card in enumerate(cards[:3], 1): # Show top 3 results
75
+ title = card.get('title', 'Untitled')
76
+ summary = card.get('summary', 'No summary available')
77
+ relevance = card.get('relevance_score', 0)
78
+
79
+ # Truncate summary if too long
80
+ if len(summary) > 200:
81
+ summary = summary[:200] + "..."
82
+
83
+ response += f"**{i}. {title}** (Relevance: {relevance:.3f})\n{summary}\n\n"
84
+
85
+ if len(cards) > 3:
86
+ response += f"*... and {len(cards) - 3} more results*\n"
87
+
88
+ processing_time = result.get("processing_time", 0)
89
+ response += f"⏱️ Search completed in {processing_time:.2f}s"
90
+
91
+ return response
92
+
93
+ def chatbot_respond(message: str, history: List[Tuple[str, str]], search_mode: bool) -> Tuple[str, List[Tuple[str, str]]]:
94
+ """Main chatbot response function."""
95
+ if not message.strip():
96
+ return "", history
97
+
98
+ # Determine max cards based on query complexity
99
+ max_cards = 3 if len(message.split()) < 5 else 5
100
+
101
+ if search_mode:
102
+ # Use semantic search for browsing/exploring
103
+ result = search_cards_semantic(message, max_cards)
104
+ response = format_search_response(result)
105
+ else:
106
+ # Use RAG for question-answering
107
+ result = query_rag_system(message, max_cards)
108
+ response = format_rag_response(result)
109
+
110
+ # Add to history
111
+ history.append((message, response))
112
+ return "", history
113
+
114
+ def clear_chat():
115
+ """Clear the chat history."""
116
+ return [], ""
117
+
118
+ # --- Gradio Interface ---
119
+ def create_interface():
120
+ with gr.Blocks(
121
+ title="Historical Knowledge Assistant",
122
+ theme=gr.themes.Soft(),
123
+ css="""
124
+ .chat-container { max-height: 600px; overflow-y: auto; }
125
+ .examples { margin: 10px 0; }
126
+ """
127
+ ) as demo:
128
+
129
+ gr.Markdown("""
130
+ # πŸ›οΈ Historical Knowledge Assistant
131
+ Ask questions about historical events, people, and concepts. Powered by your Rolodex RAG database.
132
+ """)
133
+
134
+ with gr.Row():
135
+ with gr.Column(scale=4):
136
+ chatbot = gr.Chatbot(
137
+ label="Historical Q&A",
138
+ height=500,
139
+ show_copy_button=True,
140
+ container=True,
141
+ elem_classes=["chat-container"]
142
+ )
143
+
144
+ with gr.Row():
145
+ msg_input = gr.Textbox(
146
+ placeholder="Ask about historical events, people, or concepts...",
147
+ label="Your Question",
148
+ lines=2,
149
+ scale=4
150
+ )
151
+
152
+ with gr.Row():
153
+ send_btn = gr.Button("πŸ’¬ Ask", variant="primary", scale=1)
154
+ clear_btn = gr.Button("πŸ—‘οΈ Clear", variant="secondary", scale=1)
155
+
156
+ with gr.Column(scale=1):
157
+ search_mode = gr.Checkbox(
158
+ label="πŸ” Search Mode",
159
+ value=False,
160
+ info="Toggle between Q&A (off) and Search (on)"
161
+ )
162
+
163
+ gr.Markdown("""
164
+ ### πŸ’‘ Example Questions
165
+ **Question & Answer Mode:**
166
+ - What caused the American Revolution?
167
+ - How did colonial resistance evolve?
168
+ - Who were key figures in Bacon's Rebellion?
169
+
170
+ **Search Mode:**
171
+ - colonial resistance
172
+ - Boston Massacre
173
+ - taxation without representation
174
+
175
+ ### ℹ️ Tips
176
+ - **Q&A Mode**: Ask complete questions for detailed answers
177
+ - **Search Mode**: Use keywords to explore topics
178
+ - Sources and processing time shown with each response
179
+ """, elem_classes=["examples"])
180
+
181
+ # Event handlers
182
+ msg_input.submit(
183
+ chatbot_respond,
184
+ inputs=[msg_input, chatbot, search_mode],
185
+ outputs=[msg_input, chatbot]
186
+ )
187
+
188
+ send_btn.click(
189
+ chatbot_respond,
190
+ inputs=[msg_input, chatbot, search_mode],
191
+ outputs=[msg_input, chatbot]
192
+ )
193
+
194
+ clear_btn.click(
195
+ clear_chat,
196
+ outputs=[chatbot, msg_input]
197
+ )
198
+
199
+ return demo
200
+
201
+ # --- Launch Configuration ---
202
+ if __name__ == "__main__":
203
+ print("πŸš€ Launching Historical Knowledge Assistant...")
204
+ print(f"🌐 API URL: {API_URL}")
205
+ print(f"πŸ”‘ Using API token: {API_TOKEN[:10]}...")
206
+
207
+ demo = create_interface()
208
+
209
+ # For Hugging Face Spaces deployment
210
+ demo.launch(
211
+ share=False, # Set to True for temporary sharing
212
+ server_name="0.0.0.0", # Required for HF Spaces
213
+ server_port=7860, # Standard port for HF Spaces
214
+ show_error=True
215
+ )