import streamlit as st
import pandas as pd
import anthropic
import base64
import plotly.express as px
from datetime import datetime
import json
from pathlib import Path
from utils import EmbeddingManager
def send_to_llm(user_query, data, df):
"""Send data chunks to the LLM and get a response."""
columns = df.columns.tolist()
dtypes = df.dtypes.to_dict()
summary_stats = df.describe().to_json()
client = anthropic.AnthropicBedrock()
prompt = """You are a data analysis expert. Your task is to generate a complete, standalone HTML report.
You MUST return ONLY valid HTML code that starts with and includes all necessary elements.
Data Details:
- Columns: {columns}
- Data Types: {dtypes}
- Summary Stats: {summary_stats}
Required HTML Structure:
Requirements:
1. Create visualizations using Plotly.js
2. Include executive summary, insights, and analysis
3. Add proper styling and make it visually appealing
4. Ensure all Plotly charts have proper div containers
5. Include the current date
DO NOT include any explanatory text outside the HTML code. Return ONLY the complete HTML document."""
message = client.messages.create(
model="anthropic.claude-3-5-sonnet-20240620-v1:0",
max_tokens=4096, # Increased token limit for full HTML response
system=prompt,
messages=[{
"role": "user",
"content": f"Generate a complete HTML report analyzing this data: {str(data)} \nUser query: {user_query}"
}]
)
# Extract only the HTML content
response_text = message.content[0].text
if "" not in response_text:
# Fallback if response isn't proper HTML
return f"""
Analysis Report
{response_text}
"""
return response_text
def create_chunks_and_send(data_dict: dict, filename):
"""Process each sheet separately and combine their chunks"""
all_chunks = []
for sheet_name, df in data_dict.items():
# Reset index for each DataFrame
df = df.reset_index(drop=True)
output_dir = Path('./output')
embeddings_dir = output_dir / 'embeddings' / filename / sheet_name
if embeddings_dir.exists():
chunks_file = embeddings_dir / "chunks.json"
if chunks_file.is_file():
with open(chunks_file, "r", encoding="utf-8") as f:
sheet_chunks = json.load(f)
all_chunks.extend(sheet_chunks)
else:
embeddings_dir.mkdir(parents=True, exist_ok=True)
embedding_manager = EmbeddingManager(output_dir=Path('./output'))
# Convert DataFrame to JSON with orient='records'
text = df.to_json(orient='records')
sheet_chunks, _ = embedding_manager.process_script(data=str(text), filename=f"{filename}_{sheet_name}")
all_chunks.extend(sheet_chunks)
return all_chunks
def main():
st.title("Excel Chatbot")
query = st.text_input("Enter the query")
# File upload
uploaded_file = st.file_uploader("Upload Excel File", type=['xlsx', 'xls'])
if uploaded_file and query:
try:
# Read Excel without concatenating sheets
df_dict = pd.read_excel(uploaded_file, sheet_name=None)
st.success("File uploaded successfully!")
# Show preview of each sheet
for sheet_name, df in df_dict.items():
st.subheader(f"Data Preview - {sheet_name}")
st.dataframe(df)
with st.spinner("Generating response with Claude..."):
# Process all sheets and get combined chunks
data = create_chunks_and_send(df_dict, uploaded_file.name)
# Get complete HTML report from Claude
response = send_to_llm(user_query=query, data=data, df=pd.concat(df_dict.values()))
# Get the HTML content (ensure it's a string)
html_report = ''.join(str(message.text) for message in response.content)
st.components.v1.html(html_report, height=800, scrolling=True)
st.success("Report generated successfully! Click the link above to download.")
except Exception as e:
st.error(f"An error occurred: {str(e)}")
#st.error("Please check your API key and file format, then try again.")
if __name__ == "__main__":
main()