Update app.py
Browse files
app.py
CHANGED
|
@@ -10,7 +10,9 @@ import io
|
|
| 10 |
import base64
|
| 11 |
import requests
|
| 12 |
import google.generativeai as genai
|
| 13 |
-
from fpdf import FPDF
|
|
|
|
|
|
|
| 14 |
|
| 15 |
# API Endpoint and payload
|
| 16 |
API_URL = "https://irisplus.elixir.co.zw/public/api/profile/reporting/stock-card/genericReports"
|
|
@@ -39,25 +41,102 @@ def fetch_data():
|
|
| 39 |
st.error(f"Error fetching data: {response.status_code} - {response.text}")
|
| 40 |
return None
|
| 41 |
|
| 42 |
-
#
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 47 |
|
| 48 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 49 |
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 55 |
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
)
|
|
|
|
|
|
|
| 60 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 61 |
class StreamLitResponse(ResponseParser):
|
| 62 |
def __init__(self, context):
|
| 63 |
super().__init__(context)
|
|
@@ -173,21 +252,6 @@ def handle_userinput(question, df):
|
|
| 173 |
except Exception as e:
|
| 174 |
st.error(f"Error processing input: {e}")
|
| 175 |
|
| 176 |
-
def generate_pdf(report_text):
|
| 177 |
-
"""
|
| 178 |
-
Generate a PDF in memory from the report text.
|
| 179 |
-
This function uses FPDF to create a PDF and returns its bytes.
|
| 180 |
-
"""
|
| 181 |
-
pdf = FPDF()
|
| 182 |
-
pdf.add_page()
|
| 183 |
-
pdf.set_font("Arial", size=12)
|
| 184 |
-
# Split report text into lines for writing
|
| 185 |
-
for line in report_text.split('\n'):
|
| 186 |
-
pdf.multi_cell(0, 10, line)
|
| 187 |
-
# Output PDF to a byte string
|
| 188 |
-
pdf_bytes = pdf.output(dest="S").encode("latin1")
|
| 189 |
-
return pdf_bytes
|
| 190 |
-
|
| 191 |
def main():
|
| 192 |
st.set_page_config(page_title="AI Chat with Your Data", page_icon="📊")
|
| 193 |
|
|
@@ -240,6 +304,8 @@ def main():
|
|
| 240 |
prompt = f"""
|
| 241 |
"You are an expert business analyst. Analyze the following data and generate a comprehensive and insightful business report
|
| 242 |
including key performance indicators and recommendations.\n\nData:\n" + {str(filtered_df.to_json(orient='records'))}
|
|
|
|
|
|
|
| 243 |
"""
|
| 244 |
response = model.generate_content(prompt)
|
| 245 |
# Display the report text; adjust according to your response format.
|
|
|
|
| 10 |
import base64
|
| 11 |
import requests
|
| 12 |
import google.generativeai as genai
|
| 13 |
+
from fpdf import FPDF
|
| 14 |
+
import markdown2
|
| 15 |
+
import re
|
| 16 |
|
| 17 |
# API Endpoint and payload
|
| 18 |
API_URL = "https://irisplus.elixir.co.zw/public/api/profile/reporting/stock-card/genericReports"
|
|
|
|
| 41 |
st.error(f"Error fetching data: {response.status_code} - {response.text}")
|
| 42 |
return None
|
| 43 |
|
| 44 |
+
# Function to render a table in the PDF
|
| 45 |
+
def render_table(pdf, df):
|
| 46 |
+
pdf.set_font("Arial", "B", 12)
|
| 47 |
+
# Column Widths
|
| 48 |
+
col_widths = [40] * len(df.columns)
|
| 49 |
+
|
| 50 |
+
# Header Row
|
| 51 |
+
for i, col in enumerate(df.columns):
|
| 52 |
+
pdf.cell(col_widths[i], 10, col, border=1, align="C")
|
| 53 |
+
pdf.ln()
|
| 54 |
+
|
| 55 |
+
# Data Rows
|
| 56 |
+
pdf.set_font("Arial", "", 12)
|
| 57 |
+
for _, row in df.iterrows():
|
| 58 |
+
for i, col in enumerate(row):
|
| 59 |
+
pdf.cell(col_widths[i], 10, col, border=1, align="C")
|
| 60 |
+
pdf.ln()
|
| 61 |
|
| 62 |
+
# Function to handle Markdown conversion to PDF
|
| 63 |
+
def md_to_pdf(md_text, pdf):
|
| 64 |
+
lines = md_text.split("\n")
|
| 65 |
+
for line in lines:
|
| 66 |
+
line = line.strip()
|
| 67 |
|
| 68 |
+
# Convert Headings
|
| 69 |
+
if line.startswith("### "): # H3
|
| 70 |
+
pdf.set_font("Arial", "B", 14)
|
| 71 |
+
pdf.cell(0, 10, line[4:], ln=True)
|
| 72 |
+
elif line.startswith("## "): # H2
|
| 73 |
+
pdf.set_font("Arial", "B", 16)
|
| 74 |
+
pdf.cell(0, 10, line[3:], ln=True)
|
| 75 |
+
elif line.startswith("# "): # H1
|
| 76 |
+
pdf.set_font("Arial", "B", 18)
|
| 77 |
+
pdf.cell(0, 10, line[2:], ln=True)
|
| 78 |
+
|
| 79 |
+
# Convert Bold Text (**bold** → bold)
|
| 80 |
+
elif "**" in line:
|
| 81 |
+
bold_text = re.sub(r"\*\*(.*?)\*\*", r"\1", line)
|
| 82 |
+
pdf.set_font("Arial", "B", 12)
|
| 83 |
+
pdf.multi_cell(0, 10, bold_text)
|
| 84 |
+
|
| 85 |
+
# Convert Bullet Points
|
| 86 |
+
elif line.startswith("- "):
|
| 87 |
+
pdf.set_font("Arial", "", 12)
|
| 88 |
+
pdf.cell(10) # Indent bullet points
|
| 89 |
+
pdf.multi_cell(0, 10, f"• {line[2:]}")
|
| 90 |
+
|
| 91 |
+
# Detect and Convert Tables (Markdown tables)
|
| 92 |
+
elif "|" in line and "-" not in line: # Skip separator lines
|
| 93 |
+
table_data.append(line.split("|")[1:-1]) # Remove empty edges
|
| 94 |
|
| 95 |
+
# Normal Text
|
| 96 |
+
else:
|
| 97 |
+
pdf.set_font("Arial", "", 12)
|
| 98 |
+
pdf.multi_cell(0, 10, line)
|
| 99 |
+
|
| 100 |
+
pdf.ln(5) # Add spacing
|
| 101 |
|
| 102 |
+
# Modified generate_pdf function to handle markdown
|
| 103 |
+
def generate_pdf(report_text):
|
| 104 |
+
"""
|
| 105 |
+
Generate a PDF from Markdown content and return the bytes.
|
| 106 |
+
"""
|
| 107 |
+
pdf = FPDF()
|
| 108 |
+
pdf.add_page()
|
| 109 |
+
|
| 110 |
+
# Convert Markdown text to PDF
|
| 111 |
+
md_to_pdf(report_text, pdf)
|
| 112 |
+
|
| 113 |
+
# Output PDF to a byte string
|
| 114 |
+
pdf_bytes = pdf.output(dest="S").encode("latin1")
|
| 115 |
+
return pdf_bytes
|
| 116 |
+
|
| 117 |
+
# Extract Tables from Markdown
|
| 118 |
+
def extract_tables(md_text):
|
| 119 |
+
tables = []
|
| 120 |
+
lines = md_text.split("\n")
|
| 121 |
+
table_lines = []
|
| 122 |
+
|
| 123 |
+
for line in lines:
|
| 124 |
+
if "|" in line: # Identify table lines
|
| 125 |
+
table_lines.append(line)
|
| 126 |
+
elif table_lines: # Table ended
|
| 127 |
+
tables.append(table_lines)
|
| 128 |
+
table_lines = []
|
| 129 |
+
|
| 130 |
+
return tables
|
| 131 |
+
|
| 132 |
+
# Convert Extracted Markdown Table to DataFrame
|
| 133 |
+
def table_to_dataframe(table_lines):
|
| 134 |
+
headers = table_lines[0].split("|")[1:-1] # Extract column headers
|
| 135 |
+
data = [row.split("|")[1:-1] for row in table_lines[2:]] # Extract row data
|
| 136 |
+
df = pd.DataFrame(data, columns=headers)
|
| 137 |
+
return df
|
| 138 |
+
|
| 139 |
+
# --- Chat Tab Functions ---
|
| 140 |
class StreamLitResponse(ResponseParser):
|
| 141 |
def __init__(self, context):
|
| 142 |
super().__init__(context)
|
|
|
|
| 252 |
except Exception as e:
|
| 253 |
st.error(f"Error processing input: {e}")
|
| 254 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 255 |
def main():
|
| 256 |
st.set_page_config(page_title="AI Chat with Your Data", page_icon="📊")
|
| 257 |
|
|
|
|
| 304 |
prompt = f"""
|
| 305 |
"You are an expert business analyst. Analyze the following data and generate a comprehensive and insightful business report
|
| 306 |
including key performance indicators and recommendations.\n\nData:\n" + {str(filtered_df.to_json(orient='records'))}
|
| 307 |
+
|
| 308 |
+
Instructions: Answer directly, without any introductory remarks, salutations, or extra commentary. Just provide the solution.
|
| 309 |
"""
|
| 310 |
response = model.generate_content(prompt)
|
| 311 |
# Display the report text; adjust according to your response format.
|