rra_chatbot_v2 / app.py
Irakoze's picture
Upload 2 files
ae60efb verified
import gradio as gr
import requests
import json
import logging
import os
from dotenv import load_dotenv
from typing import Dict, List, Tuple
# Load environment variables
load_dotenv()
# Configure logging
logging.basicConfig(
filename='gradio_frontend.log',
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
# API Configuration
API_BASE_URL=os.getenv("API_BASE_URL")
async def process_query(message: str, language: str, mode: str, chat_history: List[Dict]) -> Tuple[str, str]:
"""Make API request to get chatbot response"""
try:
payload = {
"message": message,
"language": language,
"mode": mode
}
response = requests.post(
f"{API_BASE_URL}/api/query",
json=payload
)
response.raise_for_status()
result = response.json()
return result["answer"], result.get("id")
except requests.RequestException as e:
logging.error(f"API request failed: {str(e)}")
return f"Sorry, there was an error processing your request: {str(e)}", None
async def submit_feedback(feedback_type: str, full_chat_history: List[Dict], language_choice: str, mode: str) -> str:
"""Submit feedback via API"""
try:
if mode == "Private":
return "Feedback is disabled in private mode."
if not full_chat_history or len(full_chat_history) < 2:
return "No recent interaction to provide feedback for."
# Get the last assistant message with an ID
assistant_messages = [msg for msg in full_chat_history
if msg.get("role") == "assistant" and "id" in msg]
if not assistant_messages:
logging.error("No assistant messages with ID found in chat history")
return "No response found to provide feedback for."
last_message = assistant_messages[-1]
question_id = last_message.get("id")
if not question_id:
logging.error(f"No ID found in last message: {last_message}")
return "Question ID not found. Please try asking another question."
logging.info(f"Submitting feedback for question ID: {question_id}")
# Submit feedback
payload = {
"question_id": question_id,
"feedback_type": feedback_type,
"language": language_choice,
"mode": mode
}
response = requests.post(
f"{API_BASE_URL}/api/feedback",
json=payload
)
response.raise_for_status()
return "Thanks for your feedback! Your response has been recorded."
except requests.RequestException as e:
logging.error(f"Failed to submit feedback: {str(e)}")
return f"Sorry, there was an error submitting your feedback: {str(e)}"
except Exception as e:
logging.error(f"Unexpected error in submit_feedback: {str(e)}")
return "An unexpected error occurred. Please try again."
# Create Gradio interface
with gr.Blocks(title="RRA FAQ Chatbot") as demo:
full_chat_history = gr.State([]) # Add this line
gr.Markdown(
"""
# RRA FAQ Chatbot
Ask tax-related questions in English or Kinyarwanda
"""
)
# Add mode selector
with gr.Row():
interaction_mode = gr.Radio(
choices=["Normal", "Private"],
value="Normal",
label="Interaction Mode",
info="Normal: Stores interactions to improve service | Private: No data storage"
)
with gr.Row():
gr.Markdown(
"""
> πŸ“ **Data Storage Notice:**
> - Normal Mode: Questions and interactions are stored to improve our service
> - Private Mode: No data is stored, feedback feature is disabled
"""
)
# Add language selector
language = gr.Radio(
choices=["English", "Kinyarwanda"],
value="English",
label="Select Language / Hitamo Ururimi"
)
chatbot = gr.Chatbot(
value=[],
show_label=False,
height=400
)
with gr.Row():
msg = gr.Textbox(
label="Ask your question",
placeholder="Type your tax-related question here...",
show_label=False
)
submit = gr.Button("Send")
# Add feedback section
feedback_container = gr.Row(visible=True)
with feedback_container:
with gr.Column(scale=2):
feedback_label = gr.Markdown("Was this response helpful?")
with gr.Column(scale=1):
feedback_positive = gr.Button("πŸ‘ Helpful")
with gr.Column(scale=1):
feedback_negative = gr.Button("πŸ‘Ž Not Helpful")
# Add feedback status message
feedback_status = gr.Markdown("")
async def respond(message, lang, mode, chat_history, full_chat_history):
"""Process a user message and update chat history"""
try:
if chat_history is None:
chat_history = []
if full_chat_history is None:
full_chat_history = []
# Get response from API
bot_message, question_id = await process_query(message, lang, mode, chat_history)
if not bot_message:
return "", chat_history, full_chat_history
# Build new messages
user_message = {
"content": message,
"role": "user"
}
assistant_message = {
"content": bot_message,
"role": "assistant",
"id": question_id # Store ID in the message
}
# Append to full chat history
new_full_history = full_chat_history + [user_message, assistant_message]
# Prepare messages for chatbot display
new_chat_history = chat_history + [[message, bot_message]]
return "", new_chat_history, new_full_history
except Exception as e:
logging.error(f"Error in respond function: {e}")
return "", chat_history, full_chat_history
def update_mode(mode: str):
"""Update UI when mode changes"""
is_private = (mode == "Private")
return {
feedback_container: gr.update(visible=not is_private),
feedback_status: gr.update(value="" if not is_private else "Feedback is disabled in private mode")
}
# Connect feedback buttons
async def submit_positive_feedback(full_chat_history, language_choice, mode):
return await submit_feedback("positive", full_chat_history, language_choice, mode)
async def submit_negative_feedback(full_chat_history, language_choice, mode):
return await submit_feedback("negative", full_chat_history, language_choice, mode)
feedback_positive.click(
fn=submit_positive_feedback,
inputs=[full_chat_history, language, interaction_mode],
outputs=feedback_status
)
feedback_negative.click(
fn=submit_negative_feedback,
inputs=[full_chat_history, language, interaction_mode],
outputs=feedback_status
)
# Update UI when mode changes
interaction_mode.change(
fn=update_mode,
inputs=[interaction_mode],
outputs=[feedback_container, feedback_status]
)
# Example questions
with gr.Row() as english_examples_row:
gr.Examples(
examples=[
"What is VAT in Rwanda?",
"How do I register for taxes?",
"What are the tax payment deadlines?",
"How can I get a TIN number?",
"How do I get purchase code?"
],
inputs=msg,
label="English Examples"
)
with gr.Row(visible=False) as kinyarwanda_examples_row:
gr.Examples(
examples=[
"Ese VAT ni iki mu Rwanda?",
"Nabona TIN number nte?",
"Ni ryari tugomba kwishyura imisoro?",
"Ese nandikwa nte ku musoro?",
"Ni gute nabone kode yo kugura?"
],
inputs=msg,
label="Kinyarwanda Examples"
)
def toggle_language_interface(language_choice):
if language_choice == "English":
placeholder_text = "Type your tax-related question here..."
return {
msg: gr.update(placeholder=placeholder_text),
english_examples_row: gr.update(visible=True),
kinyarwanda_examples_row: gr.update(visible=False)
}
else:
placeholder_text = "Andika ibibazo bijyanye n'umusoro hano"
return {
msg: gr.update(placeholder=placeholder_text),
english_examples_row: gr.update(visible=False),
kinyarwanda_examples_row: gr.update(visible=True)
}
# Connect user inputs
msg.submit(
respond,
[msg, language, interaction_mode, chatbot, full_chat_history],
[msg, chatbot, full_chat_history]
)
submit.click(
respond,
[msg, language, interaction_mode, chatbot, full_chat_history],
[msg, chatbot, full_chat_history]
)
# Update interface on language change
language.change(
fn=toggle_language_interface,
inputs=language,
outputs=[msg, english_examples_row, kinyarwanda_examples_row]
)
gr.Markdown(
"""
### About
- Created by: [Cedric](mailto:[email protected])
- Data source: [RRA Website FAQ](https://www.rra.gov.rw/en/domestic-tax-services/faqs)
**Disclaimer:** This chatbot provides general tax information. For official guidance,
consult RRA or call 3004.
"""
)
if __name__ == "__main__":
try:
demo.launch(share=False)
logging.info("Gradio app launched successfully.")
except Exception as launch_error:
logging.critical(f"Failed to launch Gradio app: {launch_error}")
raise