基于flask+pandas+csv的报表实现

news2025/5/11 17:36:40

基于大模型根据提示词去写SQL执行SQL返回结果输出报表技术上可行的,但为啥还要基于pandas去实现呢?

原因有以下几点:

1、大模型无法满足实时性输出报表的需求;

2、使用大模型比较适合数据量比较大的场景,大模型主要辅助写SQL;

3、使用pandas方便快捷,定制好各种模版后,功能也能通用。

代码如下:

from flask import Flask, request, jsonify, render_template_string
import pandas as pd
from io import StringIO
import random

app = Flask(__name__)

# 全局变量,用于保存上传的CSV文件内容和解析后的DataFrame
uploaded_csv_data = None
csv_dataframe = None
@app.route('/')
def index():
    html_content = '''
    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="UTF-8">
        <title>CSV 上传与图表分析</title>
        <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
        <style>
            body {
                font-family: Arial, sans-serif;
                margin: 20px;
            }
            .container {
                max-width: 800px;
                margin: 0 auto;
            }
            .row {
                display: flex;
                flex-wrap: wrap;
                justify-content: space-between;
                margin-bottom: 15px;
            }
            .row label {
                margin-right: 10px;
                white-space: nowrap;
            }
            .row select {
                flex: 1;
                margin-right: 10px;
            }
            .row button {
                margin-top: 10px;
            }
            canvas {
                margin-top: 20px;
            }
        </style>
    </head>
    <body>
        <div class="container">
            <h2>上传 CSV 文件</h2>
            <div class="row">
                <input type="file" id="csvFile" accept=".csv">
                <button onclick="uploadCSV()">上传文件</button>
            </div>
            <p id="uploadStatus"></p>
            
            <h2>选择列</h2>
            <div class="row">
                <label for="xAxisColumn">X轴列:</label>
                <select id="xAxisColumn"></select>
                <label for="yAxisColumn">Y轴列:</label>
                <select id="yAxisColumn"></select>
                <label for="groupColumn">分组列:</label>
                <select id="groupColumn"></select>
            </div>
            
            <h2>选择图表类型</h2>
            <div class="row">
                <label for="chartType">图表类型:</label>
                <select id="chartType">
                    <option value="bar">柱状图</option>
                    <option value="line">折线图</option>
                </select>
            </div>
            
            <div class="row">
                <button onclick="analyzeData()">生成图表</button>
                <button onclick="analyzeData('above')">显示均值线上</button>
                <button onclick="analyzeData('below')">显示均值线下</button>
            </div>
            
            <canvas id="myChart" width="600" height="400"></canvas>
        </div>
        
        <script>
            var csvUploaded = false;
            var columns = [];
            
            function uploadCSV() {
                var fileInput = document.getElementById("csvFile");
                if (fileInput.files.length === 0) {
                    alert("请选择一个 CSV 文件!");
                    return;
                }
                var file = fileInput.files[0];
                var reader = new FileReader();
                reader.onload = function(e) {
                    var csvContent = e.target.result;
                    fetch('/upload', {
                        method: 'POST',
                        headers: {
                            'Content-Type': 'text/plain'
                        },
                        body: csvContent
                    })
                    .then(response => response.json())
                    .then(data => {
                        if (data.success) {
                            document.getElementById("uploadStatus").innerText = "CSV 文件上传成功!";
                            csvUploaded = true;
                            columns = data.columns;
                            populateColumns();
                        } else {
                            alert("上传失败:" + data.error);
                        }
                    });
                };
                reader.readAsText(file);
            }
            
            function populateColumns() {
                var xAxisSelect = document.getElementById("xAxisColumn");
                var yAxisSelect = document.getElementById("yAxisColumn");
                var groupSelect = document.getElementById("groupColumn");
                columns.forEach(column => {
                    var option = document.createElement("option");
                    option.value = column;
                    option.text = column;
                    xAxisSelect.appendChild(option.cloneNode(true));
                    yAxisSelect.appendChild(option.cloneNode(true));
                    groupSelect.appendChild(option.cloneNode(true));
                });
            }
            
            function analyzeData(filter = '') {
                var xAxisColumn = document.getElementById("xAxisColumn").value;
                var yAxisColumn = document.getElementById("yAxisColumn").value;
                var groupColumn = document.getElementById("groupColumn").value;
                var chartType = document.getElementById("chartType").value;
                
                if (!csvUploaded) {
                    alert("请先上传 CSV 文件!");
                    return;
                }
                if (!xAxisColumn || !yAxisColumn || !groupColumn) {
                    alert("请选择X轴列、Y轴列和分组列!");
                    return;
                }
                
                fetch(`/analyze?xAxis=${encodeURIComponent(xAxisColumn)}&yAxis=${encodeURIComponent(yAxisColumn)}&group=${encodeURIComponent(groupColumn)}&chartType=${encodeURIComponent(chartType)}&filter=${filter}`)
                .then(response => response.json())
                .then(data => {
                    renderChart(data, chartType);
                });
            }
            
            function renderChart(chartData, chartType) {
                var ctx = document.getElementById('myChart').getContext('2d');
                if (window.myChartInstance) {
                    window.myChartInstance.destroy();
                }
                window.myChartInstance = new Chart(ctx, {
                    type: chartType,
                    data: {
                        labels: chartData.labels,
                        datasets: chartData.datasets
                    },
                    options: {
                        responsive: true,
                        scales: {
                            y: {
                                beginAtZero: true
                            }
                        }
                    }
                });
            }
        </script>
    </body>
    </html>


    '''
    return render_template_string(html_content)

@app.route('/upload', methods=['POST'])
def upload():
    global uploaded_csv_data, csv_dataframe
    content = request.data.decode('utf-8')
    try:
        # 将上传的 CSV 文件内容解析为 DataFrame
        df = pd.read_csv(StringIO(content))
        uploaded_csv_data = content  # 存储原始数据(可选)
        csv_dataframe = df  # 保存解析后的DataFrame供后续分析使用
        columns = df.columns.tolist()  # 获取列名
        return jsonify({'success': True, 'columns': columns})
    except Exception as e:
        return jsonify({'success': False, 'error': str(e)})
    
@app.route('/get_unique_values')
def get_unique_values():
    global csv_dataframe
    column = request.args.get('column', '')
    if csv_dataframe is None or column not in csv_dataframe.columns:
        return jsonify({'uniqueValues': []})
    unique_values = csv_dataframe[column].dropna().unique().tolist()
    return jsonify({'uniqueValues': unique_values})

@app.route('/analyze')
def analyze():
    global csv_dataframe
    xAxis = request.args.get('xAxis', '')
    yAxis = request.args.get('yAxis', '')
    group = request.args.get('group', '')
    chartType = request.args.get('chartType', 'bar')  # 获取图表类型
    filter_type = request.args.get('filter', '')  # 获取过滤类型

    # 若未上传文件,则返回空数据
    if csv_dataframe is None:
        return jsonify({'labels': [], 'datasets': []})

    df = csv_dataframe.copy()

    # 如果 X 轴是日期类型,确保其为日期格式
    if pd.api.types.is_string_dtype(df[xAxis]):
        df[xAxis] = pd.to_datetime(df[xAxis])

    # 按 X 轴列和分组列分组,并对 Y 轴列进行求和
    grouped = df.groupby([xAxis, group])[yAxis].sum().reset_index()

    # 按 X 轴列排序
    grouped = grouped.sort_values(by=xAxis)

    # 获取所有唯一的 X 轴值(日期)
    labels = grouped[xAxis].dt.strftime('%Y-%m-%d').unique().tolist()  # 转换为字符串格式

    datasets = []

    # 计算每个 X 轴值对应的 Y 轴均值
    mean_values = grouped.groupby(xAxis)[yAxis].mean().reset_index()
    mean_values_dict = mean_values.set_index(xAxis)[yAxis].to_dict()

    # 添加均值线
    mean_data = [mean_values_dict.get(pd.to_datetime(label), 0) for label in labels]
    datasets.append({
        'label': '均值',
        'data': mean_data,
        'borderColor': 'rgba(255, 0, 0, 1)',
        'borderWidth': 2,
        'borderDash': [5, 5],  # 虚线
        'fill': False,
        'type': 'line'
    })

    # 根据均值线过滤数据
    if filter_type == 'above':
        filtered_df = df[df.apply(lambda row: row[yAxis] > mean_values_dict.get(row[xAxis], 0), axis=1)]
    elif filter_type == 'below':
        filtered_df = df[df.apply(lambda row: row[yAxis] < mean_values_dict.get(row[xAxis], 0), axis=1)]
    else:
        filtered_df = df

    # 重新分组并计算
    filtered_grouped = filtered_df.groupby([xAxis, group])[yAxis].sum().reset_index()

    # 确保每个日期都有数据
    all_dates = pd.date_range(start=grouped[xAxis].min(), end=grouped[xAxis].max(), freq='D')
    all_dates_str = all_dates.strftime('%Y-%m-%d').tolist()

    for obj in filtered_grouped[group].unique():
        data = []
        for date in all_dates:
            value = filtered_grouped[(filtered_grouped[xAxis] == date) & (filtered_grouped[group] == obj)][yAxis].sum()
            if value > 0:  # 只包括值大于0的点
                data.append(value)
            else:
                data.append(None)  # 使用 None 来表示没有数据的点
        color = f"rgba({random.randint(0, 255)}, {random.randint(0, 255)}, {random.randint(0, 255)}, 0.6)"
        datasets.append({
            'label': obj,
            'data': data,
            'backgroundColor': color,
            'borderColor': color.replace("0.6", "1"),
            'borderWidth': 1,
            'type': chartType  # 使用用户选择的图表类型
        })

    return jsonify({'labels': all_dates_str, 'datasets': datasets})



if __name__ == '__main__':
    app.run(debug=True)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2373295.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

PySide6 GUI 学习笔记——常用类及控件使用方法(常用类字体QFont)

文章目录 一、QFont常用方法二、常用方法总结1. 基础属性设置2. 高级样式控制3. 序列化与反序列化4. 字体信息获取 三、应用实例 字体类QFont用于设置界面控件上显示的字体&#xff0c;它包含字体名称、字体尺寸、粗体字、斜体字、删除线、上划线、下划线、字体间距等属性。 如…

宝塔服务安装使用的保姆级教程

宝塔介绍&#xff1a; 宝塔面板&#xff08;BT Panel&#xff09; 是一款 国产的服务器运维管理面板&#xff0c;主要用于简化 Linux/Windows 服务器的网站、数据库、FTP、防火墙等管理操作。它通过图形化界面&#xff08;Web端&#xff09;和命令行工具&#xff08;bt 命令&a…

Linux平台下SSH 协议克隆Github远程仓库并配置密钥

目录 注意&#xff1a;先提前配置好SSH密钥&#xff0c;然后再git clone 1. 检查现有 SSH 密钥 2. 生成新的 SSH 密钥 3. 将 SSH 密钥添加到 ssh-agent 4. 将公钥添加到 GitHub 5. 测试 SSH 连接 6. 配置 Git 使用 SSH 注意&#xff1a;先提前配置好SSH密钥&#xff0c;然…

Java【网络原理】(5)深入浅出HTTPS:状态码与SSL/TLS加密全解析

目录 1.前言 2.正文 2.1状态码 2.2HTTP与HTTPS的关系 2.3SSL协议 2.3.1对称加密 2.3.2非对称加密 2.3.3中间人攻击 2.3.4校验机制 2.3.4.1证书 2.3.4.2数字签名 1. 数字签名的生成过程 2. 数字签名的验证过程 2.4TLS协议&#xff08;握手过程&#xff09; 3.小结…

【基础IO下】磁盘/软硬链接/动静态库

前言&#xff1a; 文件分为内存文件和磁盘文件。磁盘文件是一个特殊的存在&#xff0c;因为磁盘文件不属于冯诺依曼体系&#xff0c;而是位于专门的存储设备中。因此&#xff0c;磁盘文件存在的意义是将文件更好的存储起来&#xff0c;一边后续对文件进行访问。在高效存储磁盘…

SpringBoot项目容器化进行部署,meven的docker插件远程构建docker镜像

需求&#xff1a;将Spring Boot项目使用容器化进行部署 前提 默认其他环境,如mysql,redis等已经通过docker部署完毕, 这里只讨论,如何制作springboot项目的镜像 要将Spring Boot项目使用docker容器进行部署&#xff0c;就需要将Spring Boot项目构建成一个docker镜像 一、手动…

【小记】excel vlookup一对多匹配

一个学生报四门课&#xff0c;输出每个学生课程 应用概述操作预处理数据计数指令 COUNTIFS进行一对多匹配 vlookup 应用概述 应用场景&#xff1a;学生报名考试&#xff0c;需要整理成指定格式&#xff0c;发给考试院。 一个学生最多报考四门 格式实例&#xff1a;准考证号 …

LeetCode热题100 两数之和

目录 两数之和题目解析方法一暴力求解代码 方法二哈希代码 感谢各位大佬对我的支持,如果我的文章对你有用,欢迎点击以下链接 &#x1f412;&#x1f412;&#x1f412; 个人主页 &#x1f978;&#x1f978;&#x1f978; C语言 &#x1f43f;️&#x1f43f;️&#x1f43f;…

[春秋云镜] Brute4Road 仿真场景

文章目录 靶标介绍&#xff1a;知识点约束性委派攻击 外网redis主从复制base64提权 内网搭建代理wpcargo插件漏洞mssql弱口令SweetPotato提权远程桌面连接mimikatz抓取hash约束性委派攻击 参考文章 靶标介绍&#xff1a; Brute4Road是一套难度为中等的靶场环境&#xff0c;完成…

鸿蒙系统使用ArkTS开发语言支持身份证阅读器、社保卡读卡器等调用二次开发SDK

har库导入&#xff1a; { "license": "", "devDependencies": {}, "author": "", "name": "entry", "description": "Please describe the basic information.", &qu…

《Python星球日记》 第54天:卷积神经网络进阶

名人说&#xff1a;路漫漫其修远兮&#xff0c;吾将上下而求索。—— 屈原《离骚》 创作者&#xff1a;Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#x1f60a;&#xff09; 目录 一、深度CNN架构解析1. LeNet-5&#xff08;1998&#xff09;2. AlexNet&#x…

《AI大模型应知应会100篇》第53篇:Hugging Face生态系统入门

第53篇&#xff1a;Hugging Face生态系统入门 ——从模型获取到部署的全流程实战指南 &#x1f4cc; 摘要 在人工智能快速发展的今天&#xff0c;Hugging Face已成为自然语言处理&#xff08;NLP&#xff09;领域最具影响力的开源平台之一。它不仅提供丰富的预训练模型、强大…

【基于 LangChain 的异步天气查询2】GeoNames实现地区实时气温查询

目录 功能简介 一、创建GeoNames账号 1、进入官网 2、创建账号 二、运行代码 weather_runnable.py main.py 运行结果 功能简介 本文主要通过Langchain&#xff0c;结合GeoNames实现了地区温度的实时查询&#xff0c;并通过GPT-4o对温度进行一段简短的描述。 一、创建Ge…

服务器数据恢复—硬盘坏道导致EqualLogic存储不可用的数据恢复

服务器存储数据恢复环境&故障&#xff1a; 一台EqualLogic某型号存储中有一组由16块SAS硬盘组建的RAID5阵列。上层采用VMFS文件系统&#xff0c;存放虚拟机文件&#xff0c;上层一共分了4个卷。 磁盘故障导致存储不可用&#xff0c;且设备已经过保。 服务器存储数据恢复过程…

JAVA实战开源项目:智能学习平台系统 (Vue+SpringBoot) 附源码

本文项目编号 T 181 &#xff0c;文末自助获取源码 \color{red}{T181&#xff0c;文末自助获取源码} T181&#xff0c;文末自助获取源码 目录 一、系统介绍二、数据库设计三、配套教程3.1 启动教程3.2 讲解视频3.3 二次开发教程 四、功能截图五、文案资料5.1 选题背景5.2 国内…

傅利叶十周年,升级核心战略:“有温度”的具身智能蓝图

5月9日&#xff0c;傅利叶十周年庆典暨首届具身智能生态峰会在上海正式召开。本次大会以“十年共创&#xff0c;具身成翼”为主题&#xff0c;汇聚了来自通用机器人与医疗康复领域的顶尖专家学者、合作伙伴与投资机构&#xff0c;共同探索具身智能在未来十年的技术应用与生态发…

AI安全之对抗样本攻击---FGSM实战脚本解析

一、对抗样本与FGSM的背景 在深度学习安全领域&#xff0c;对抗样本&#xff08;Adversarial Examples&#xff09;因其特殊的生成机制备受关注。2015年ICLR会议收录的里程碑式论文《Explaining and Harnessing Adversarial Examples》中&#xff0c;Goodfellow等学者首次系统…

《Python星球日记》 第50天:深度学习概述与环境搭建

名人说&#xff1a;路漫漫其修远兮&#xff0c;吾将上下而求索。—— 屈原《离骚》 创作者&#xff1a;Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#x1f60a;&#xff09; 目录 一、什么是深度学习&#xff1f;它与传统机器学习的区别1. 深度学习的定义2. 深…

linux搭建hadoop学习

linux搭建hadoop学习 下载安装包: 海外资源可能需要翻墙或者找国内资源 cd /opt wget https://dlcdn.apache.org/hadoop/common/hadoop-2.10.2/hadoop-2.10.2.tar.gz tar -zxvf hadoop-2.10.2.tar.gz mv hadoop-2.10.2 hadoop配置环境变量 # 在/etc/profile文件中添加下面内…

PyTorch API 8 - 工具集、onnx、option、复数、DDP、量化、分布式 RPC、NeMo

文章目录 torch.nn.inittorch.nn.attention工具集子模块 torch.onnx概述基于 TorchDynamo 的 ONNX 导出器基于TorchScript的ONNX导出器贡献与开发 torch.optim如何使用优化器构建优化器每个参数的选项执行优化步骤optimizer.step()optimizer.step(closure) 基类算法如何调整学习…