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