vdmbrsv commited on
Commit
6468ed6
Β·
verified Β·
1 Parent(s): 9473b99

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +271 -0
app.py ADDED
@@ -0,0 +1,271 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+ import gradio as gr
3
+ import pandas as pd
4
+ import os
5
+ from typing import Optional, Iterable
6
+ import sys
7
+ from pathlib import Path
8
+ from gradio.themes.base import Base
9
+ from gradio.themes.utils import colors, fonts, sizes
10
+ from augini import Augini
11
+
12
+ # Create custom dark theme
13
+ class AuginiDarkTheme(Base):
14
+ def __init__(
15
+ self,
16
+ *,
17
+ primary_hue: colors.Color | str = colors.indigo,
18
+ secondary_hue: colors.Color | str = colors.indigo,
19
+ neutral_hue: colors.Color | str = colors.gray,
20
+ spacing_size: sizes.Size | str = sizes.spacing_md,
21
+ radius_size: sizes.Size | str = sizes.radius_lg,
22
+ text_size: sizes.Size | str = sizes.text_md,
23
+ font: fonts.Font | str | Iterable[fonts.Font | str] = (
24
+ fonts.GoogleFont("Inter"),
25
+ "ui-sans-serif",
26
+ "sans-serif",
27
+ ),
28
+ ):
29
+ super().__init__(
30
+ primary_hue=primary_hue,
31
+ secondary_hue=secondary_hue,
32
+ neutral_hue=neutral_hue,
33
+ spacing_size=spacing_size,
34
+ radius_size=radius_size,
35
+ text_size=text_size,
36
+ font=font,
37
+ )
38
+ self.name = "augini_dark"
39
+ self.set(
40
+ # Dark theme colors
41
+ body_background_fill="*neutral_950",
42
+ body_text_color="*neutral_200",
43
+ background_fill_primary="*neutral_900",
44
+ background_fill_secondary="*neutral_800",
45
+ border_color_primary="*neutral_700",
46
+
47
+ # Components
48
+ block_background_fill="*neutral_900",
49
+ block_border_color="*neutral_700",
50
+ block_border_width="1px",
51
+ block_label_background_fill="*neutral_900",
52
+ block_label_text_color="*neutral_200",
53
+ block_title_text_color="*neutral_200",
54
+
55
+ # Buttons
56
+ button_primary_background_fill="*primary_600",
57
+ button_primary_background_fill_hover="*primary_500",
58
+ button_primary_text_color="white",
59
+ button_secondary_background_fill="*neutral_700",
60
+ button_secondary_background_fill_hover="*neutral_600",
61
+ button_secondary_text_color="*neutral_200",
62
+
63
+ # Inputs
64
+ input_background_fill="*neutral_800",
65
+ input_background_fill_focus="*neutral_800",
66
+ input_border_color="*neutral_700",
67
+ input_border_color_focus="*primary_500",
68
+ input_placeholder_color="*neutral_500",
69
+
70
+ # Shadows and effects
71
+ shadow_spread="1px",
72
+ block_shadow="0 1px 2px 0 rgb(0 0 0 / 0.05)",
73
+ button_shadow="0 1px 2px 0 rgb(0 0 0 / 0.05)",
74
+ )
75
+
76
+ class AuginiChat:
77
+ def __init__(self):
78
+ self.df: Optional[pd.DataFrame] = None
79
+ # Initialize Augini with the API key directly
80
+ self.augini = Augini(
81
+ api_key=os.environ.get('OPENROUTER_TOKEN'),
82
+ use_openrouter=True,
83
+ model='gpt-4o-mini',
84
+ temperature=0.7
85
+ )
86
+
87
+ def upload_file(self, file) -> str:
88
+ """Handle file upload and return preview"""
89
+ try:
90
+ if file is None:
91
+ return "Please upload a file"
92
+
93
+ file_path = file.name
94
+ file_extension = os.path.splitext(file_path)[1].lower()
95
+
96
+ # Read the file based on its extension
97
+ if file_extension == '.csv':
98
+ self.df = pd.read_csv(file_path)
99
+ elif file_extension in ['.xlsx', '.xls']:
100
+ self.df = pd.read_excel(file_path)
101
+ else:
102
+ return "❌ Unsupported file format. Please upload a CSV or Excel file."
103
+
104
+ return "βœ… File uploaded successfully!"
105
+
106
+ except Exception as e:
107
+ return f"❌ Error uploading file: {str(e)}"
108
+
109
+ def chat_with_data(self, message: str, history: list) -> tuple[str, list]:
110
+ """Process chat messages and return responses"""
111
+ try:
112
+ if not message or message.strip() == "":
113
+ return "", history
114
+
115
+ if self.df is None:
116
+ return "", history + [(message, "⚠️ Please upload a CSV file first.")]
117
+
118
+ # Get response from Augini
119
+ response = self.augini.chat(message, self.df)
120
+
121
+ # Update history and clear the message
122
+ new_history = history + [(message, response)]
123
+ return "", new_history
124
+
125
+ except Exception as e:
126
+ error_msg = f"❌ Error processing message: {str(e)}"
127
+ return "", history + [(message, error_msg)]
128
+
129
+ def create_app():
130
+ # Initialize the chat handler
131
+ chat_handler = AuginiChat()
132
+
133
+ # JavaScript to force dark theme - added to head
134
+ dark_mode_script = """
135
+ <script>
136
+ function setDarkTheme() {
137
+ const url = new URL(window.location);
138
+ if (url.searchParams.get('__theme') !== 'dark') {
139
+ url.searchParams.set('__theme', 'dark');
140
+ window.location.href = url.href;
141
+ }
142
+ }
143
+ document.addEventListener('DOMContentLoaded', setDarkTheme);
144
+ window.addEventListener('load', setDarkTheme);
145
+ // Also try to set it immediately
146
+ setDarkTheme();
147
+ </script>
148
+ """
149
+
150
+ # Create the Gradio interface with dark theme script in head
151
+ with gr.Blocks(head=dark_mode_script) as app:
152
+ gr.Markdown("""
153
+ # πŸ€– **augini** - your ai data analysis assistant
154
+
155
+ **augini** is an agentic AI system designed to help you analyze and understand your data through natural conversation.
156
+ Upload your data file and start chatting to uncover insights!
157
+
158
+ > πŸ’‘ **Tip**: Ask questions about patterns, relationships, or any aspect of your data. **augini** will provide detailed, evidence-based answers.
159
+ """, elem_classes=["center-content"])
160
+
161
+ with gr.Row(elem_classes=["container"]):
162
+ # Left sidebar for file upload
163
+ with gr.Column(scale=1, elem_classes=["sidebar"]):
164
+ gr.Markdown("### πŸ“ upload your data")
165
+ file_upload = gr.File(
166
+ label="Upload Data File",
167
+ file_types=[".csv", ".xlsx", ".xls"],
168
+ elem_classes=["file-upload"]
169
+ )
170
+ file_status = gr.Textbox(
171
+ label="Upload Status",
172
+ interactive=False,
173
+ elem_classes=["status-box"]
174
+ )
175
+
176
+ # Main chat area
177
+ with gr.Column(scale=3, elem_classes=["main-content"]):
178
+ chatbot = gr.Chatbot(
179
+ label="Chat History",
180
+ height=500,
181
+ elem_classes=["chat-window"]
182
+ )
183
+ with gr.Row():
184
+ msg = gr.Textbox(
185
+ label="your question",
186
+ placeholder="ask me anything about your data...",
187
+ lines=2,
188
+ scale=4,
189
+ elem_classes=["question-input"]
190
+ )
191
+ submit_btn = gr.Button("send πŸ“€", scale=1, elem_classes=["submit-btn"])
192
+ clear = gr.Button("clear chat πŸ—‘οΈ", elem_classes=["clear-btn"])
193
+
194
+ # Examples and Documentation in a collapsible section
195
+ with gr.Accordion("πŸ“š examples & features", open=False, elem_classes=["docs-section"]):
196
+ with gr.Row():
197
+ with gr.Column(scale=1):
198
+ gr.Markdown("""
199
+ ### 🎯 example questions
200
+
201
+ **data overview**
202
+ - "what are the key patterns in this dataset?"
203
+ - "give me a summary of the main statistics"
204
+
205
+ **data quality**
206
+ - "are there any missing values?"
207
+ - "how clean is this dataset?"
208
+
209
+ **relationships**
210
+ - "show me the correlations between columns"
211
+ - "what variables are most related?"
212
+
213
+ **deep analysis**
214
+ - "what insights can you find about [column]?"
215
+ - "is this a synthetic dataset?"
216
+ """)
217
+
218
+ with gr.Column(scale=1):
219
+ gr.Markdown("""
220
+ ### ✨ features
221
+
222
+ **smart analysis**
223
+ - advanced statistical analysis
224
+ - pattern recognition
225
+ - anomaly detection
226
+
227
+ **data support**
228
+ - csv files
229
+ - excel files (.xlsx, .xls)
230
+ - automatic type detection
231
+
232
+ **ai capabilities**
233
+ - natural language understanding
234
+ - context-aware responses
235
+ - evidence-based insights
236
+ """)
237
+
238
+ # Add powered by link
239
+ gr.Markdown("""
240
+ <div class="powered-by">
241
+ powered by <a href="https://tabularis.ai" target="_blank">tabularis.ai</a>
242
+ </div>
243
+ """, elem_classes=["footer"])
244
+
245
+ # Set up event handlers
246
+ file_upload.upload(
247
+ chat_handler.upload_file,
248
+ inputs=[file_upload],
249
+ outputs=[file_status]
250
+ )
251
+
252
+ # Add both message submission methods
253
+ msg.submit(
254
+ chat_handler.chat_with_data,
255
+ inputs=[msg, chatbot],
256
+ outputs=[msg, chatbot]
257
+ )
258
+
259
+ submit_btn.click(
260
+ chat_handler.chat_with_data,
261
+ inputs=[msg, chatbot],
262
+ outputs=[msg, chatbot]
263
+ )
264
+
265
+ clear.click(lambda: ([], None), None, [chatbot, msg], queue=False)
266
+
267
+ return app
268
+
269
+ if __name__ == "__main__":
270
+ app = create_app()
271
+ app.launch(share=True)