DrMostafa commited on
Commit
76f11d4
Β·
verified Β·
1 Parent(s): 0835fd1

Upload 2 files

Browse files
Files changed (2) hide show
  1. app.py +302 -0
  2. requirements.txt +2 -0
app.py ADDED
@@ -0,0 +1,302 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Data Analyst Agent - Streamlit Version
3
+ Beautiful UI with Voice Input
4
+ """
5
+
6
+ import streamlit as st
7
+ import asyncio
8
+ import os
9
+ import base64
10
+ import tempfile
11
+ from fastapi_poe.client import get_bot_response
12
+ from fastapi_poe.types import ProtocolMessage, Attachment
13
+
14
+ # Page config
15
+ st.set_page_config(
16
+ page_title="πŸ“Š Data Analyst Agent",
17
+ page_icon="πŸ“Š",
18
+ layout="wide",
19
+ initial_sidebar_state="expanded"
20
+ )
21
+
22
+ # Custom CSS for beautiful UI
23
+ st.markdown("""
24
+ <style>
25
+ .main-header {
26
+ text-align: center;
27
+ padding: 1.5rem;
28
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
29
+ border-radius: 16px;
30
+ margin-bottom: 2rem;
31
+ color: white;
32
+ }
33
+ .main-header h1 {
34
+ margin: 0;
35
+ font-size: 2.5rem;
36
+ }
37
+ .main-header p {
38
+ margin: 0.5rem 0 0 0;
39
+ opacity: 0.9;
40
+ }
41
+ .sidebar-card {
42
+ background: linear-gradient(135deg, #f5f7fa 0%, #e4e8ec 100%);
43
+ border-radius: 12px;
44
+ padding: 1rem;
45
+ margin-bottom: 1rem;
46
+ }
47
+ .voice-card {
48
+ background: linear-gradient(135deg, #a8edea 0%, #fed6e3 100%);
49
+ border-radius: 12px;
50
+ padding: 1rem;
51
+ margin-bottom: 1rem;
52
+ }
53
+ .stButton > button {
54
+ border-radius: 12px;
55
+ font-weight: 600;
56
+ }
57
+ .chat-message {
58
+ padding: 1rem;
59
+ border-radius: 12px;
60
+ margin-bottom: 1rem;
61
+ }
62
+ .user-message {
63
+ background: #e3f2fd;
64
+ border-left: 4px solid #2196f3;
65
+ }
66
+ .assistant-message {
67
+ background: #f5f5f5;
68
+ border-left: 4px solid #667eea;
69
+ }
70
+ </style>
71
+ """, unsafe_allow_html=True)
72
+
73
+ # Get API key
74
+ POE_API_KEY = os.environ.get("POE_API_KEY", "")
75
+
76
+ SYSTEM_PROMPT = """You are a powerful data analysis agent. You can:
77
+
78
+ 1. **Analyze Data**: Read CSV, Excel (.xlsx, .xls) files and perform comprehensive analysis
79
+ 2. **Generate Visualizations**: Create charts using matplotlib, seaborn, plotly
80
+ 3. **Execute Python Code**: Run any Python code for data manipulation and analysis
81
+ 4. **Install Libraries**: Use `pip install` if a library is not available
82
+ 5. **Create Reports**: Generate Word (.docx) or PowerPoint (.pptx) documents with charts and summaries
83
+
84
+ ## Guidelines
85
+ - When user uploads a file, first explore the data (shape, columns, dtypes, sample rows, missing values)
86
+ - Create meaningful visualizations based on the data types and relationships
87
+ - Always display charts inline so the user can see them
88
+ - For reports, save charts as images first, then embed them in Word/PowerPoint
89
+ - Be proactive: suggest insights and additional analyses the user might find valuable
90
+ - When creating downloadable files, provide the download link"""
91
+
92
+
93
+ async def transcribe_audio(audio_bytes: bytes) -> str:
94
+ """Transcribe audio using Whisper via Poe API."""
95
+ if not audio_bytes:
96
+ return ""
97
+ try:
98
+ b64_data = base64.b64encode(audio_bytes).decode("utf-8")
99
+ data_url = f"data:audio/wav;base64,{b64_data}"
100
+ attachment = Attachment(url=data_url, name="voice.wav", content_type="audio/wav")
101
+ messages = [ProtocolMessage(role="user", content="Transcribe this audio accurately.", attachments=[attachment])]
102
+ text = ""
103
+ async for partial in get_bot_response(messages=messages, bot_name="Whisper-V3-Large-T", api_key=POE_API_KEY):
104
+ text += partial.text
105
+ return text.strip()
106
+ except Exception as e:
107
+ return f"Transcription error: {str(e)}"
108
+
109
+
110
+ async def call_analyst(message: str, file_bytes: bytes = None, filename: str = None, history: list = None):
111
+ """Call Claude-Code for analysis."""
112
+ if not POE_API_KEY:
113
+ return "❌ **Error**: POE_API_KEY not set! Go to Settings β†’ Secrets and add your Poe API key."
114
+
115
+ messages = [ProtocolMessage(role="system", content=SYSTEM_PROMPT)]
116
+
117
+ # Add history
118
+ if history:
119
+ for item in history:
120
+ if item["role"] == "user":
121
+ messages.append(ProtocolMessage(role="user", content=item["content"]))
122
+ elif item["role"] == "assistant":
123
+ messages.append(ProtocolMessage(role="assistant", content=item["content"]))
124
+
125
+ # Handle file
126
+ attachments = []
127
+ if file_bytes and filename:
128
+ if filename.endswith(".csv"):
129
+ ctype = "text/csv"
130
+ elif filename.endswith(".xlsx"):
131
+ ctype = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
132
+ else:
133
+ ctype = "application/octet-stream"
134
+
135
+ b64 = base64.b64encode(file_bytes).decode("utf-8")
136
+ attachments.append(Attachment(url=f"data:{ctype};base64,{b64}", name=filename, content_type=ctype))
137
+
138
+ messages.append(ProtocolMessage(role="user", content=message, attachments=attachments))
139
+
140
+ response = ""
141
+ try:
142
+ async for partial in get_bot_response(messages=messages, bot_name="Claude-Code", api_key=POE_API_KEY):
143
+ response += partial.text
144
+ except Exception as e:
145
+ response = f"❌ **API Error**: {str(e)}"
146
+
147
+ return response
148
+
149
+
150
+ def run_async(coro):
151
+ """Run async function."""
152
+ loop = asyncio.new_event_loop()
153
+ asyncio.set_event_loop(loop)
154
+ try:
155
+ return loop.run_until_complete(coro)
156
+ finally:
157
+ loop.close()
158
+
159
+
160
+ # Initialize session state
161
+ if "messages" not in st.session_state:
162
+ st.session_state.messages = []
163
+ if "file_bytes" not in st.session_state:
164
+ st.session_state.file_bytes = None
165
+ if "filename" not in st.session_state:
166
+ st.session_state.filename = None
167
+
168
+ # Header
169
+ st.markdown("""
170
+ <div class="main-header">
171
+ <h1>πŸ“Š Data Analyst Agent</h1>
172
+ <p>Upload your data β€’ Ask questions β€’ Get insights, charts & reports</p>
173
+ </div>
174
+ """, unsafe_allow_html=True)
175
+
176
+ # Sidebar
177
+ with st.sidebar:
178
+ st.markdown("### πŸ“ Upload Your Data")
179
+ uploaded_file = st.file_uploader(
180
+ "Drop CSV or Excel file here",
181
+ type=["csv", "xlsx", "xls"],
182
+ help="Upload a CSV or Excel file to analyze"
183
+ )
184
+
185
+ if uploaded_file:
186
+ st.session_state.file_bytes = uploaded_file.read()
187
+ st.session_state.filename = uploaded_file.name
188
+ st.success(f"βœ… Loaded: {uploaded_file.name}")
189
+ uploaded_file.seek(0) # Reset for potential re-read
190
+
191
+ st.markdown("---")
192
+
193
+ st.markdown("### πŸ’‘ Example Prompts")
194
+ st.markdown("""
195
+ - Analyze this data and show key insights
196
+ - Create a bar chart of sales by category
197
+ - Show me a correlation heatmap
198
+ - Find the top 10 records by value
199
+ - Generate a PowerPoint summary
200
+ - Create a Word report with charts
201
+ """)
202
+
203
+ st.markdown("---")
204
+
205
+ st.markdown("### 🎀 Voice Input")
206
+ audio_file = st.file_uploader(
207
+ "Upload audio recording",
208
+ type=["wav", "mp3", "m4a", "ogg"],
209
+ help="Record audio on your device, then upload it here"
210
+ )
211
+
212
+ if audio_file:
213
+ audio_bytes = audio_file.read()
214
+ st.audio(audio_bytes, format=f"audio/{audio_file.type.split('/')[-1]}")
215
+
216
+ if st.button("🎯 Transcribe Audio", use_container_width=True):
217
+ with st.spinner("Transcribing..."):
218
+ transcription = run_async(transcribe_audio(audio_bytes))
219
+ if transcription:
220
+ st.session_state.voice_text = transcription
221
+ st.success("βœ… Transcribed!")
222
+ st.info(f"πŸ“ {transcription}")
223
+
224
+ st.markdown("---")
225
+
226
+ if st.button("πŸ—‘οΈ Clear Chat History", use_container_width=True):
227
+ st.session_state.messages = []
228
+ st.rerun()
229
+
230
+ # Main chat area
231
+ st.markdown("### πŸ’¬ Analysis Chat")
232
+
233
+ # Display chat history
234
+ for msg in st.session_state.messages:
235
+ if msg["role"] == "user":
236
+ st.markdown(f"""
237
+ <div class="chat-message user-message">
238
+ <strong>πŸ‘€ You:</strong><br>{msg["content"]}
239
+ </div>
240
+ """, unsafe_allow_html=True)
241
+ else:
242
+ st.markdown(f"""
243
+ <div class="chat-message assistant-message">
244
+ <strong>πŸ€– Agent:</strong><br>{msg["content"]}
245
+ </div>
246
+ """, unsafe_allow_html=True)
247
+
248
+ # Input area
249
+ col1, col2 = st.columns([5, 1])
250
+
251
+ with col1:
252
+ # Check if we have voice text to use
253
+ default_text = st.session_state.get("voice_text", "")
254
+ user_input = st.text_area(
255
+ "Your message",
256
+ value=default_text,
257
+ placeholder="Ask about your data, request charts, or generate reports...",
258
+ height=100,
259
+ label_visibility="collapsed"
260
+ )
261
+ # Clear voice text after using
262
+ if default_text and user_input == default_text:
263
+ st.session_state.voice_text = ""
264
+
265
+ with col2:
266
+ st.write("") # Spacer
267
+ st.write("") # Spacer
268
+ analyze_clicked = st.button("πŸ” Analyze", use_container_width=True, type="primary")
269
+
270
+ # Process input
271
+ if analyze_clicked and user_input.strip():
272
+ # Add user message
273
+ display_msg = user_input
274
+ if st.session_state.filename:
275
+ display_msg = f"πŸ“Ž **{st.session_state.filename}**\n\n{user_input}"
276
+
277
+ st.session_state.messages.append({"role": "user", "content": display_msg})
278
+
279
+ # Get response
280
+ with st.spinner("πŸ” Analyzing..."):
281
+ response = run_async(call_analyst(
282
+ user_input,
283
+ st.session_state.file_bytes,
284
+ st.session_state.filename,
285
+ st.session_state.messages[:-1] # Exclude the message we just added
286
+ ))
287
+
288
+ # Add assistant response
289
+ st.session_state.messages.append({"role": "assistant", "content": response})
290
+
291
+ # Clear the file after first use (optional - comment out if you want to keep it)
292
+ # st.session_state.file_bytes = None
293
+ # st.session_state.filename = None
294
+
295
+ st.rerun()
296
+
297
+ # Footer
298
+ st.markdown("---")
299
+ st.markdown(
300
+ "<p style='text-align: center; color: #666;'>Powered by <a href='https://poe.com'>Poe API</a> β€’ Claude-Code for intelligent analysis</p>",
301
+ unsafe_allow_html=True
302
+ )
requirements.txt ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ streamlit>=1.28.0
2
+ fastapi_poe>=0.0.36