|
|
from asyncio.log import logger |
|
|
import yaml |
|
|
from pathlib import Path |
|
|
import gradio as gr |
|
|
import asyncio |
|
|
from langchain_mcp_client import lc_mcp_exec |
|
|
from dotenv import load_dotenv |
|
|
import os |
|
|
import base64 |
|
|
from memory_store import MemoryStore |
|
|
import logging |
|
|
|
|
|
|
|
|
|
|
|
load_dotenv() |
|
|
VERSION = "0.0.1" |
|
|
|
|
|
|
|
|
def load_db_configs(): |
|
|
"""Load database configurations from configs.yaml""" |
|
|
configs_path = Path("configs.yaml") |
|
|
|
|
|
if not configs_path.exists(): |
|
|
raise FileNotFoundError("configs.yaml not found") |
|
|
|
|
|
with open(configs_path) as f: |
|
|
configs = yaml.safe_load(f) |
|
|
|
|
|
return configs["db_configs"] |
|
|
|
|
|
|
|
|
def image_to_base64_html(image_path, alt_text="Customer Status", width=600): |
|
|
with open(image_path, "rb") as f: |
|
|
encoded = base64.b64encode(f.read()).decode("utf-8") |
|
|
return f'<img src="data:image/png;base64,{encoded}" alt="{alt_text}" style="width:{width}px; max-width:100%; display:block; margin:0 auto 24px auto; border-radius:12px; box-shadow:0 2px 12px rgba(0,0,0,0.08);" />' |
|
|
|
|
|
|
|
|
|
|
|
async def run_agent(request, history=None): |
|
|
try: |
|
|
|
|
|
response, messages = await lc_mcp_exec(request) |
|
|
|
|
|
|
|
|
image_path = "" |
|
|
load_dotenv() |
|
|
PANDAS_EXPORTS_PATH = os.environ["PANDAS_EXPORTS_PATH"] |
|
|
|
|
|
|
|
|
os.makedirs(PANDAS_EXPORTS_PATH, exist_ok=True) |
|
|
|
|
|
|
|
|
generated_files = [f for f in os.listdir(PANDAS_EXPORTS_PATH) |
|
|
if f.startswith("temp_chart_") and f.endswith(".png")] |
|
|
|
|
|
if generated_files: |
|
|
image_path = os.path.join(PANDAS_EXPORTS_PATH, generated_files[0]) |
|
|
try: |
|
|
image_markdown = image_to_base64_html(image_path) |
|
|
output = f"{image_markdown}\n\n{response}" |
|
|
os.remove(image_path) |
|
|
except Exception as e: |
|
|
logger.error(f"Error processing image: {e}") |
|
|
output = response |
|
|
else: |
|
|
output = response |
|
|
|
|
|
return output |
|
|
|
|
|
except Exception as e: |
|
|
logger.error(f"Error in run_agent: {str(e)}", exc_info=True) |
|
|
return f"Error: {str(e)}" |
|
|
|
|
|
|
|
|
|
|
|
LOGO_PATH = "resources/pialogo.png" |
|
|
|
|
|
|
|
|
custom_css = """ |
|
|
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;600&display=swap'); |
|
|
body, .markdown-content, .container, .chat-container, .message-container { |
|
|
font-family: 'Inter', Arial, sans-serif !important; |
|
|
} |
|
|
.container { |
|
|
max-width: 2200px !important; |
|
|
margin: auto; |
|
|
padding: 20px; |
|
|
} |
|
|
.chat-container { |
|
|
height: 1000px !important; |
|
|
min-height: 1000px !important; |
|
|
overflow-y: auto; |
|
|
} |
|
|
.message-container { |
|
|
padding: 15px; |
|
|
border-radius: 10px; |
|
|
margin: 10px 0; |
|
|
} |
|
|
.markdown-content { |
|
|
font-size: 18px; |
|
|
line-height: 1.7; |
|
|
} |
|
|
|
|
|
button.svelte-lixn6qd { |
|
|
display: none !important; |
|
|
} |
|
|
#component-16 { |
|
|
display: none !important; |
|
|
} |
|
|
""" |
|
|
|
|
|
xtheme = gr.themes.Soft() |
|
|
|
|
|
with gr.Blocks(css=custom_css, theme=xtheme) as demo: |
|
|
with gr.Row(elem_classes="container"): |
|
|
|
|
|
|
|
|
with gr.Column(scale=5): |
|
|
gr.Markdown( |
|
|
""" |
|
|
<h1 style='text-align: center; margin-bottom: 1rem'>Talk to Your Data</h1> |
|
|
<p style='text-align: center'>Ask questions about your database, analyze and visualize data.</p> |
|
|
<p style='text-align: center; color: #666; font-size: 0.9em; margin-top: -0.5rem'>Version: {}</p> |
|
|
""".format(VERSION) |
|
|
) |
|
|
with gr.Row(elem_classes="container"): |
|
|
with gr.Column(scale=3): |
|
|
chat = gr.ChatInterface( |
|
|
fn=run_agent, |
|
|
chatbot=gr.Chatbot( |
|
|
height=1000, |
|
|
show_label=False, |
|
|
elem_classes="chat-container", |
|
|
render_markdown=True, |
|
|
type="messages" |
|
|
), |
|
|
textbox=gr.Textbox( |
|
|
placeholder="Type your questions here...", |
|
|
container=False, |
|
|
scale=4 |
|
|
), |
|
|
examples=[ |
|
|
"Describe the database", |
|
|
"List all tables in the database", |
|
|
"Show me the top 10 customers by ticket count and visualize it bar chart with different colors", |
|
|
"Show distribution of tickets by status, use pie chart", |
|
|
"List all tables with columns and data types", |
|
|
"How many comments are there per ticket channel (email, chat, portal)? Also Visualize it as a pie chart", |
|
|
"Delete ticket with id BR-90001", |
|
|
"Show top 5 products with highest number of tickets in a bar chart, add legand, print product names vertically", |
|
|
"How many customers are in each industry?", |
|
|
"List the 5 most active agents by ticket count in 2025.", |
|
|
"How many tickets were reopened at least once?", |
|
|
"In which of the records, have the customer provided positive feedback as a result of the service they got?", |
|
|
"Show the number of comments per ticket, grouped by channel (email, chat, portal), for tickets with comments. Visualize using box plot.", |
|
|
"Display the number of tickets and average reopen count per customer, colored by industry, for customers with resolved tickets. Visualize using Scatter Plot." |
|
|
], |
|
|
save_history=True, |
|
|
type="messages" |
|
|
) |
|
|
with gr.Column(scale=1): |
|
|
with gr.Accordion("Example Questions", open=True): |
|
|
gr.Markdown(""" |
|
|
- π Describe the database |
|
|
- π List all tables in database |
|
|
- π₯ Total number of customers |
|
|
- π Top 10 customers by ticket count |
|
|
- π Ticket count by status and visualize |
|
|
- π Average ticket reopened |
|
|
- π§Ή Clear memory : `/clear-cache` |
|
|
""") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__": |
|
|
demo.launch( |
|
|
server_name="0.0.0.0", |
|
|
|
|
|
|
|
|
debug=True |
|
|
) |
|
|
|