Spaces:
Sleeping
Sleeping
File size: 11,300 Bytes
5d99375 | 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 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 | import gradio as gr
import requests
import numpy as np
import time
import json
import os
# Import the utilities with proper error handling
try:
from utils.encoding_input import encode_text
from utils.retrieve_n_rerank import retrieve_and_rerank
from utils.sentiment_analysis import get_sentiment
from utils.coherence_bbscore import coherence_report
from utils.loading_embeddings import get_vectorstore
from utils.model_generation import build_messages
except ImportError as e:
print(f"Import error: {e}")
print("Make sure you're running from the correct directory and all dependencies are installed.")
API_KEY = os.getenv("API_KEY", "sk-do-8Hjf0liuGQCoPwglilL49xiqrthMECwjGP_kAjPM53OTOFQczPyfPK8xJc")
MODEL = "llama3.3-70b-instruct"
# Global settings for sentiment and coherence analysis
ENABLE_SENTIMENT = True
ENABLE_COHERENCE = True
def chat_response(message, history):
"""
Generate response for chat interface.
Args:
message: Current user message
history: List of [user_message, bot_response] pairs
"""
try:
# Initialize vectorstore when needed
vectorstore = get_vectorstore()
# Retrieve and rerank documents
reranked_results = retrieve_and_rerank(
query_text=message,
vectorstore=vectorstore,
k=50, # number of initial documents to retrieve
rerank_model="cross-encoder/ms-marco-MiniLM-L-6-v2",
top_m=20, # number of documents to return after reranking
min_score=0.5, # minimum score for reranked documents
only_docs=False # return both documents and scores
)
if not reranked_results:
return "I'm sorry, I couldn't find any relevant information in the policy documents to answer your question. Could you try rephrasing your question or asking about a different topic?"
top_docs = [doc for doc, score in reranked_results]
# Perform sentiment and coherence analysis if enabled
sentiment_rollup = get_sentiment(top_docs) if ENABLE_SENTIMENT else {}
coherence_report_ = coherence_report(reranked_results=top_docs, input_text=message) if ENABLE_COHERENCE else ""
# Build messages for the LLM, including conversation history
messages = build_messages_with_history(
query=message,
history=history,
top_docs=top_docs,
task_mode="verbatim_sentiment",
sentiment_rollup=sentiment_rollup,
coherence_report=coherence_report_,
)
# Stream response from the API
response = ""
for chunk in stream_llm_response(messages):
response += chunk
yield response
except Exception as e:
error_msg = f"I encountered an error while processing your request: {str(e)}"
yield error_msg
def build_messages_with_history(query, history, top_docs, task_mode, sentiment_rollup, coherence_report):
"""Build messages including conversation history for better context."""
# System message
system_msg = (
"You are a compliance-grade policy analyst assistant specializing in Kenya policy documents. "
"Your job is to return precise, fact-grounded responses based on the provided policy documents. "
"Avoid hallucinations. Base everything strictly on the content provided. "
"Maintain conversation context from previous exchanges when relevant. "
"If sentiment or coherence analysis is not available, do not mention it in the response."
)
messages = [{"role": "system", "content": system_msg}]
# Add conversation history (keep last 4 exchanges to maintain context without exceeding limits)
recent_history = history[-4:] if len(history) > 4 else history
for user_msg, bot_msg in recent_history:
messages.append({"role": "user", "content": user_msg})
messages.append({"role": "assistant", "content": bot_msg})
# Build context from retrieved documents
context_block = "\n\n".join([
f"**Source: {getattr(doc, 'metadata', {}).get('source', 'Unknown')} "
f"(Page {getattr(doc, 'metadata', {}).get('page', 'Unknown')})**\n"
f"{doc.page_content}\n"
for doc in top_docs[:10] # Limit to top 10 docs to avoid token limits
])
# Current user query with context
current_query = f"""
Query: {query}
Based on the following policy documents, please provide:
1) **Quoted Policy Excerpts**: Quote key policy content directly. Cite the source using filename and page.
2) **Analysis**: Explain the policy implications in clear terms.
"""
if sentiment_rollup:
current_query += f"\n3) **Sentiment Summary**: {sentiment_rollup}"
if coherence_report:
current_query += f"\n4) **Coherence Assessment**: {coherence_report}"
current_query += f"\n\nContext Sources:\n{context_block}"
messages.append({"role": "user", "content": current_query})
return messages
def stream_llm_response(messages):
"""Stream response from the LLM API."""
headers = {
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json"
}
data = {
"model": MODEL,
"messages": messages,
"temperature": 0.2,
"stream": True,
"max_tokens": 2000
}
try:
with requests.post("https://inference.do-ai.run/v1/chat/completions",
headers=headers, json=data, stream=True, timeout=30) as r:
if r.status_code != 200:
yield f"[ERROR] API returned status {r.status_code}: {r.text}"
return
for line in r.iter_lines(decode_unicode=True):
if not line or line.strip() == "data: [DONE]":
continue
if line.startswith("data: "):
line = line[len("data: "):]
try:
chunk = json.loads(line)
delta = chunk.get("choices", [{}])[0].get("delta", {}).get("content", "")
if delta:
yield delta
time.sleep(0.01) # Small delay for smooth streaming
except json.JSONDecodeError:
continue
except Exception as e:
print(f"Streaming error: {e}")
continue
except requests.exceptions.RequestException as e:
yield f"[ERROR] Network error: {str(e)}"
except Exception as e:
yield f"[ERROR] Unexpected error: {str(e)}"
def update_sentiment_setting(enable):
"""Update global sentiment analysis setting."""
global ENABLE_SENTIMENT
ENABLE_SENTIMENT = enable
return f"β
Sentiment analysis {'enabled' if enable else 'disabled'}"
def update_coherence_setting(enable):
"""Update global coherence analysis setting."""
global ENABLE_COHERENCE
ENABLE_COHERENCE = enable
return f"β
Coherence analysis {'enabled' if enable else 'disabled'}"
# Create the chat interface
with gr.Blocks(title="Kenya Policy Assistant - Chat", theme=gr.themes.Soft()) as demo:
gr.Markdown("""
# ποΈ Kenya Policy Assistant - Interactive Chat
Ask questions about Kenya's policies and have a conversation! I can help you understand policy documents with sentiment and coherence analysis.
""")
with gr.Row():
with gr.Column(scale=3):
# Settings row at the top
with gr.Row():
sentiment_toggle = gr.Checkbox(
label="π Sentiment Analysis",
value=True,
info="Analyze tone and sentiment of policy documents"
)
coherence_toggle = gr.Checkbox(
label="π Coherence Analysis",
value=True,
info="Check coherence and consistency of retrieved documents"
)
# Main chat interface
chatbot = gr.Chatbot(
height=500,
bubble_full_width=False,
show_copy_button=True,
show_share_button=True,
avatar_images=("π€", "π€")
)
msg = gr.Textbox(
placeholder="Ask me about Kenya's policies... (e.g., 'What are the renewable energy regulations?')",
label="Your Question",
lines=2
)
with gr.Row():
submit_btn = gr.Button("π€ Send", variant="primary")
clear_btn = gr.Button("ποΈ Clear Chat")
with gr.Column(scale=1):
gr.Markdown("""
### π‘ Chat Tips
- Ask specific questions about Kenya policies
- Ask follow-up questions based on responses
- Reference previous answers: *"What does this mean?"*
- Request elaboration: *"Can you explain more?"*
### π Example Questions
- *"What are Kenya's renewable energy policies?"*
- *"Tell me about water management regulations"*
- *"What penalties exist for environmental violations?"*
- *"How does this relate to what you mentioned earlier?"*
### βοΈ Analysis Features
**Sentiment Analysis**: Understands the tone and intent of policy text
**Coherence Analysis**: Checks if retrieved documents are relevant and consistent
""")
with gr.Accordion("π Analysis Status", open=False):
sentiment_status = gr.Textbox(
value="β
Sentiment analysis enabled",
label="Sentiment Status",
interactive=False
)
coherence_status = gr.Textbox(
value="β
Coherence analysis enabled",
label="Coherence Status",
interactive=False
)
# Chat functionality
def respond(message, history):
if message.strip():
bot_message = chat_response(message, history)
history.append([message, ""])
for partial_response in bot_message:
history[-1][1] = partial_response
yield history, ""
else:
yield history, ""
submit_btn.click(respond, [msg, chatbot], [chatbot, msg])
msg.submit(respond, [msg, chatbot], [chatbot, msg])
clear_btn.click(lambda: ([], ""), outputs=[chatbot, msg])
# Update settings when toggles change
sentiment_toggle.change(
fn=update_sentiment_setting,
inputs=[sentiment_toggle],
outputs=[sentiment_status]
)
coherence_toggle.change(
fn=update_coherence_setting,
inputs=[coherence_toggle],
outputs=[coherence_status]
)
if __name__ == "__main__":
print("π Starting Kenya Policy Assistant Chat...")
demo.queue(max_size=20).launch(
share=True,
debug=True,
server_name="0.0.0.0",
server_port=7860
)
|