Spaces:
Sleeping
Sleeping
| from flask import Flask, request, jsonify | |
| from flask_cors import CORS | |
| import pandas as pd | |
| from openai import OpenAI | |
| import re | |
| import plotly.io as pio | |
| import json | |
| import plotly.express as px | |
| import os | |
| from dotenv import load_dotenv | |
| import logging | |
| # Load environment variables from .env file | |
| load_dotenv() | |
| # Get the API key from the environment variable | |
| api_key = os.getenv('OPENAI_API_KEY') | |
| pio.renderers.default = 'json' | |
| app = Flask(__name__) | |
| CORS(app, resources={r"/analyze": {"origins": "https://viz.zhanglearning.com"}}) | |
| logging.basicConfig(level=logging.INFO) | |
| def analyze(): | |
| app.logger.info("Analyze function called") | |
| if 'file' not in request.files: | |
| app.logger.error("No file uploaded") | |
| return jsonify({'error': '没有文件上传'}), 400 | |
| file = request.files['file'] | |
| prompt = request.form.get('prompt', '') | |
| if file.filename == '': | |
| app.logger.error("No file selected") | |
| return jsonify({'error': '没有选择文件'}), 400 | |
| if file and file.filename.endswith('.csv'): | |
| try: | |
| df = pd.read_csv(file) | |
| app.logger.info(f"CSV file read successfully. Shape: {df.shape}") | |
| data_info = df.dtypes.to_dict() | |
| app.logger.info("Initializing OpenAI client") | |
| client = OpenAI(api_key=api_key, base_url="https://api.deepseek.com") | |
| messages = [ | |
| {"role": "system", "content": """ | |
| 你是数据分析、可视化和 Jupyter Notebook 开发方面的专家,专注于 Python 库,如 pandas、matplotlib、seaborn 和 numpy。 | |
| **关键原则:** | |
| - 用准确的 Python 示例写出简洁的技术回复。 | |
| - 在数据分析工作流中优先考虑可读性和可重复性。 | |
| - 在适当的时候使用函数式编程;避免不必要的类。 | |
| - 优先使用向量化操作而不是显式循环以获得更好的性能。 | |
| - 使用描述性的变量名以反映它们所包含的数据。 | |
| - 遵循 Python 代码的 PEP 8 风格指南。 | |
| **数据分析和操作:** | |
| - 使用 pandas 进行数据操作和分析。 | |
| - 在可能的情况下,优先使用方法链进行数据转换。 | |
| - 使用 loc 和 iloc 进行明确的数据选择。 | |
| - 利用 groupby 操作进行高效的数据聚合。 | |
| **可视化:** | |
| - 使用 matplotlib 进行低级绘图控制和自定义。 | |
| - 使用 seaborn 进行统计可视化和美观的默认设置。 | |
| - 创建带有适当标签、标题和图例的信息丰富且视觉上吸引人的图。 | |
| - 使用适当的配色方案并考虑色盲可访问性。 | |
| **Jupyter Notebook 最佳实践:** | |
| - 使用 Markdown 单元格以清晰的部分结构笔记本。 | |
| - 使用有意义的单元格执行顺序以确保可重复性。 | |
| - 在 Markdown 单元格中包含解释性文本以记录分析步骤。 | |
| - 保持代码单元格专注且模块化,以便于理解和调试。 | |
| - 使用诸如 %matplotlib inline 之类的魔术命令进行内联绘图。 | |
| **错误处理和数据验证:** | |
| - 在分析开始时实施数据质量检查。 | |
| - 适当地处理缺失数据(插补、删除或标记)。 | |
| - 对于容易出错的操作使用 try-except 块,尤其是在读取外部数据时。 | |
| - 验证数据类型和范围以确保数据完整性。 | |
| **依赖项:** | |
| - pandas | |
| - numpy | |
| - matplotlib | |
| - seaborn | |
| - jupyter | |
| - scikit-learn(用于机器学习任务) | |
| **关键约定:** | |
| 1. 以数据探索和汇总统计开始分析。 | |
| 2. 创建可重用的绘图函数以实现一致的可视化。 | |
| 3. heatmap已经从plotly.express迁移到plotly.graph_objects中 | |
| 参考 pandas、matplotlib 和 Jupyter 的官方文档以获取最佳实践和最新的 API。 | |
| """}, | |
| {"role": "user", "content": f"根据接收的数据字段和类型:{data_info},{prompt},注意:我已经安装好了所有依赖;请确保在代码中使用 'df' 变量来引用数据框;直接给我最终代码即可,不要写注释;请确保在代码中使用 'df' 变量来引用数据框。使用 plotly.express 进行可视化,并使用 'px' 作为别名。不要使用 df_filtered 变量,所有的过滤操作都应该直接在 df 上进行。"} | |
| ] | |
| app.logger.info("Sending request to OpenAI") | |
| response = client.chat.completions.create( | |
| model="deepseek-coder", | |
| messages=messages, | |
| stream=False | |
| ) | |
| app.logger.info("Received response from OpenAI") | |
| response_code = response.choices[0].message.content | |
| code_blocks = re.findall(r'```(.*?)```', response_code, re.DOTALL) | |
| cleaned_code_blocks = [code.replace("python\n", "") for code in code_blocks] | |
| results = [] | |
| for code in cleaned_code_blocks: | |
| try: | |
| app.logger.info(f"Executing code block: {code[:100]}...") # Log first 100 chars of code | |
| local_vars = {'df': df, 'px': px} | |
| exec(code, globals(), local_vars) | |
| for var_name, var_value in local_vars.items(): | |
| if var_name.startswith('fig'): | |
| results.append(pio.to_json(var_value)) | |
| app.logger.info(f"Code block executed successfully. Results: {len(results)}") | |
| except Exception as e: | |
| app.logger.error(f"Error executing code: {str(e)}") | |
| app.logger.info(f"Returning {len(results)} plots") | |
| return jsonify({'plots': results}) | |
| except Exception as e: | |
| app.logger.error(f"Error in analyze function: {str(e)}") | |
| return jsonify({'error': str(e)}), 500 | |
| app.logger.error("Unsupported file type") | |
| return jsonify({'error': '不支持的文件类型'}), 400 | |
| if __name__ == '__main__': | |
| app.run(debug=True) |