rmishuk commited on
Commit
d59dddf
·
verified ·
1 Parent(s): 0133d2a

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +46 -61
app.py CHANGED
@@ -13,46 +13,47 @@ from google import genai
13
  api_key = os.environ.get('GEMINI_API_KEY')
14
  client = genai.Client(api_key=api_key)
15
 
16
- # 2. Define the core data, plotting, and machine learning logic
17
  def analyze_and_plot(uploaded_file, user_question):
18
  if uploaded_file is None:
19
- return "⚠️ Please upload a CSV file first.", None, gr.update(visible=False), gr.update(visible=False)
 
20
 
21
  try:
22
- # Clear previous session files
23
  plt.close('all')
24
- for f in ["analysis_report.txt", "output_chart.png", "cleaned_dataset.csv"]:
25
- if os.path.exists(f):
26
- os.remove(f)
 
27
 
28
  # Read the uploaded CSV file using Pandas
29
  df = pd.read_csv(uploaded_file.name)
30
 
31
- # Gather basic details about the dataset
32
  row_count = len(df)
33
  col_count = len(df.columns)
34
  column_names = ", ".join(df.columns.tolist())
35
  data_preview = df.head(3).to_string()
36
  data_types = df.dtypes.to_string()
37
- missing_values = df.isnull().sum().to_string()
38
 
39
- # Comprehensive system instructions enabling advanced Machine Learning tasks
40
  system_context = (
41
- f"You are an expert Python Data Scientist and Machine Learning Engineer. The user has uploaded a dataset.\n"
42
  f"Dataset Statistics:\n"
43
  f"- Total Rows: {row_count}\n"
44
  f"- Total Columns: {col_count}\n"
45
  f"- Column Names: {column_names}\n\n"
46
  f"Data Types:\n{data_types}\n\n"
47
- f"Missing Values per column:\n{missing_values}\n\n"
48
  f"Preview:\n{data_preview}\n\n"
49
  f"INSTRUCTIONS:\n"
50
  f"1. Answer the user's question clearly.\n"
51
- f"2. You are fully capable of implementing: Linear/Logistic Regression, Random Forests, Decision Trees, K-Means Clustering, and SVMs using 'sklearn'.\n"
52
- f"3. CRUCIAL FOR ML: If a model target or feature contains non-numeric text, write code using sklearn's 'LabelEncoder' or pandas 'get_dummies' to encode it to numeric values before fitting the model. Always drop or impute missing values inside the code block before training.\n"
53
- f"4. For classification/regression models, explicitly output evaluation metrics (Accuracy, F1-Score, Mean Squared Error, R-squared, etc.) via Python 'print()' or text response.\n"
54
- f"5. If a chart is requested (like a Decision Tree visual boundary, Feature Importance bar chart, K-Means scatter plot clusters, or Confusion Matrix), generate Python code using 'matplotlib.pyplot'. The LAST line must be: plt.savefig('output_chart.png')\n"
55
- f"6. Do not include plt.show(). Only save outputs to files."
 
56
  )
57
 
58
  # Send the metadata context and user query to Gemini
@@ -64,90 +65,74 @@ def analyze_and_plot(uploaded_file, user_question):
64
  text_response = response.text
65
  chart_path = None
66
 
67
- # Extract and execute the python code block generated by Gemini
68
  if "```python" in text_response:
69
  try:
70
- code_block = text_response.split("```python").split("```")
 
71
 
72
- # Setup string buffer to trap code outputs (e.g. classification reports)
73
  old_stdout = sys.stdout
74
  redirected_output = sys.stdout = io.StringIO()
75
 
76
- # Create execution environment
77
  local_vars = {'df': df, 'plt': plt}
78
  exec(code_block, {}, local_vars)
79
 
 
80
  sys.stdout = old_stdout
81
  printed_results = redirected_output.getvalue()
82
 
 
83
  if printed_results:
84
- text_response += f"\n\n### 🖥️ Machine Learning Execution Output:\n```text\n{printed_results}\n```"
85
 
86
- # Check for rendered chart image
87
  if os.path.exists("output_chart.png"):
88
  chart_path = "output_chart.png"
89
-
90
  except Exception as e:
91
- # Restore output settings if it crashes during script execution
92
- sys.stdout = old_stdout
93
- text_response += f"\n\n*(Note: ML execution script error: {str(e)})*"
94
 
95
- # Save the text report
96
  with open("analysis_report.txt", "w", encoding="utf-8") as f:
97
  f.write(text_response)
98
 
99
- # Check if a newly cleaned dataset CSV file was generated
100
- csv_update = gr.update(visible=False)
101
- if os.path.exists("cleaned_dataset.csv"):
102
- csv_update = gr.update(value="cleaned_dataset.csv", visible=True)
103
- text_response += "\n\n✅ **Success:** A processed dataset file has been generated. Use the download button below to grab it!"
104
-
105
- return text_response, chart_path, gr.update(value="analysis_report.txt", visible=True), csv_update
106
 
107
  except Exception as e:
108
- return f"❌ An error occurred processing the file: {str(e)}", None, gr.update(visible=False), gr.update(visible=False)
109
 
110
- # 3. Design the expanded Machine Learning layout using Gradio Blocks
111
  with gr.Blocks(theme=gr.themes.Soft()) as demo:
112
- gr.Markdown("# 🤖 Cloud Machine Learning & Data Workspace")
113
- gr.Markdown("Upload a CSV file to automatically clean your data, train advanced Machine Learning models, and visually analyze results.")
114
 
115
  with gr.Row():
116
  with gr.Column(scale=1):
117
  file_input = gr.File(label="Step 1: Upload CSV Dataset", file_types=[".csv"])
118
  question_input = gr.Textbox(
119
- label="Step 2: Define your Machine Learning or Data workflow",
120
- placeholder="e.g., 'Train a Random Forest classifier to predict...' or 'Cluster my data into 3 groups'..."
121
- )
122
- submit_btn = gr.Button("Execute ML Pipeline", variant="primary")
123
-
124
- # Clickable Example Prompts Section covering brand new models
125
- gr.Examples(
126
- examples=[
127
- ["Train a Random Forest model to predict [Target Column] using all other columns. Print out the model accuracy and display a feature importance bar chart."],
128
- ["Run a K-Means clustering algorithm on [Column X] and [Column Y] to group the data into 3 clusters. Plot the clusters in different colors with their centroids."],
129
- ["Build a Decision Tree classifier to predict [Target Column]. Print the classification report and plot a visual graph of the top nodes of the tree."],
130
- ["Train a Support Vector Machine (SVM) to classify [Target Column] using [Feature 1] and [Feature 2]. Show model metrics."]
131
- ],
132
- inputs=question_input,
133
- label="💡 Advanced Machine Learning Templates"
134
  )
 
135
 
136
  with gr.Column(scale=1):
137
- output_text = gr.Markdown(label="AI Analysis & Model Metrics")
138
 
139
- with gr.Row():
140
- download_report_btn = gr.DownloadButton("📥 Download Model Report", visible=False)
141
- download_csv_btn = gr.DownloadButton("💾 Download Processed CSV", visible=False, variant="secondary")
142
-
143
- output_image = gr.Image(label="Model Visualization Chart", type="filepath")
144
 
145
- # Connect inputs to execution function and distribute interface updates
146
  submit_btn.click(
147
  fn=analyze_and_plot,
148
  inputs=[file_input, question_input],
149
- outputs=[output_text, output_image, download_report_btn, download_csv_btn]
150
  )
151
 
 
152
  if __name__ == "__main__":
153
  demo.launch()
 
 
13
  api_key = os.environ.get('GEMINI_API_KEY')
14
  client = genai.Client(api_key=api_key)
15
 
16
+ # 2. Define the core data and plotting logic
17
  def analyze_and_plot(uploaded_file, user_question):
18
  if uploaded_file is None:
19
+ # Return error message, hide chart, disable download button
20
+ return "⚠️ Please upload a CSV file first.", None, gr.update(visible=False)
21
 
22
  try:
23
+ # Clear any previous figures and delete old reports to keep clean states
24
  plt.close('all')
25
+ if os.path.exists("analysis_report.txt"):
26
+ os.remove("analysis_report.txt")
27
+ if os.path.exists("output_chart.png"):
28
+ os.remove("output_chart.png")
29
 
30
  # Read the uploaded CSV file using Pandas
31
  df = pd.read_csv(uploaded_file.name)
32
 
33
+ # Gather basic details about the dataset to feed the AI context
34
  row_count = len(df)
35
  col_count = len(df.columns)
36
  column_names = ", ".join(df.columns.tolist())
37
  data_preview = df.head(3).to_string()
38
  data_types = df.dtypes.to_string()
 
39
 
40
+ # System instructions forcing Gemini to return structured code and metrics
41
  system_context = (
42
+ f"You are an expert Python Data Analyst. The user has uploaded a dataset.\n"
43
  f"Dataset Statistics:\n"
44
  f"- Total Rows: {row_count}\n"
45
  f"- Total Columns: {col_count}\n"
46
  f"- Column Names: {column_names}\n\n"
47
  f"Data Types:\n{data_types}\n\n"
 
48
  f"Preview:\n{data_preview}\n\n"
49
  f"INSTRUCTIONS:\n"
50
  f"1. Answer the user's question clearly.\n"
51
+ f"2. If performing a regression or statistical test, you MUST explicitly state the key numerical metrics "
52
+ f"(such as R-squared value, Slope/Coefficients, Intercept, or p-values) in your final written text response.\n"
53
+ f"3. If a chart is requested, include a clean Python code block using 'matplotlib.pyplot' and 'sklearn'. "
54
+ f"Assume the dataframe is loaded as 'df'.\n"
55
+ f"4. Crucial: The LAST line of your chart code block must save the image exactly as: plt.savefig('output_chart.png')\n"
56
+ f"5. Do not include plt.show(). Only save it to 'output_chart.png'."
57
  )
58
 
59
  # Send the metadata context and user query to Gemini
 
65
  text_response = response.text
66
  chart_path = None
67
 
68
+ # Extract and execute the python code if Gemini generated a graph script
69
  if "```python" in text_response:
70
  try:
71
+ # Isolate the code inside the markdown blocks
72
+ code_block = text_response.split("```python")[1].split("```")[0]
73
 
74
+ # Setup a string buffer to catch anything the executed script tries to print out
75
  old_stdout = sys.stdout
76
  redirected_output = sys.stdout = io.StringIO()
77
 
78
+ # Create a safe execution environment containing the user's data
79
  local_vars = {'df': df, 'plt': plt}
80
  exec(code_block, {}, local_vars)
81
 
82
+ # Restore normal system output
83
  sys.stdout = old_stdout
84
  printed_results = redirected_output.getvalue()
85
 
86
+ # If the script printed extra statistical text, add it to the final display
87
  if printed_results:
88
+ text_response += f"\n\n### 🖥️ Calculated Execution Output:\n```text\n{printed_results}\n```"
89
 
90
+ # Check if the chart image file was successfully written
91
  if os.path.exists("output_chart.png"):
92
  chart_path = "output_chart.png"
 
93
  except Exception as e:
94
+ text_response += f"\n\n*(Note: There was a background error rendering the chart: {str(e)})*"
 
 
95
 
96
+ # Save the finalized text analysis into a downloadable file on the server
97
  with open("analysis_report.txt", "w", encoding="utf-8") as f:
98
  f.write(text_response)
99
 
100
+ # Return text, chart path, and make the download button visible with the report file attached
101
+ return text_response, chart_path, gr.update(value="analysis_report.txt", visible=True)
 
 
 
 
 
102
 
103
  except Exception as e:
104
+ return f"❌ An error occurred processing the file: {str(e)}", None, gr.update(visible=False)
105
 
106
+ # 3. Design the custom layout using Gradio Blocks
107
  with gr.Blocks(theme=gr.themes.Soft()) as demo:
108
+ gr.Markdown("# 📊 Visual Cloud AI Data Analyst")
109
+ gr.Markdown("Upload a CSV file, ask a question, and download your final text reports easily.")
110
 
111
  with gr.Row():
112
  with gr.Column(scale=1):
113
  file_input = gr.File(label="Step 1: Upload CSV Dataset", file_types=[".csv"])
114
  question_input = gr.Textbox(
115
+ label="Step 2: Ask a question or request a model",
116
+ placeholder="e.g., 'Run a linear regression between ColumnA and ColumnB'..."
 
 
 
 
 
 
 
 
 
 
 
 
 
117
  )
118
+ submit_btn = gr.Button("Analyze & Generate Chart", variant="primary")
119
 
120
  with gr.Column(scale=1):
121
+ output_text = gr.Markdown(label="AI Written Insights")
122
 
123
+ # The download button is hidden until an analysis runs successfully
124
+ download_btn = gr.DownloadButton("📥 Download Text Report", visible=False)
125
+
126
+ output_image = gr.Image(label="Generated Data Visualization", type="filepath")
 
127
 
128
+ # Connect inputs to the execution function and distribute the 3 outputs
129
  submit_btn.click(
130
  fn=analyze_and_plot,
131
  inputs=[file_input, question_input],
132
+ outputs=[output_text, output_image, download_btn]
133
  )
134
 
135
+ # 4. Launch the public cloud server
136
  if __name__ == "__main__":
137
  demo.launch()
138
+