支持私有化部署
AI知识库

53AI知识库

学习大模型的前沿技术与行业应用场景


dify案例分享-探秘:AI 怎样颠覆财报分析,打造酷炫 HTML 可视化

发布日期:2025-05-19 22:32:56 浏览次数: 1950 作者:wwzhouhui
推荐语

AI技术如何革新财报分析,一键生成HTML可视化报告。

核心内容:
1. 上市公司财报重要性及AI在分析中的应用前景
2. dify工作流组件介绍:从PDF文件上传到HTML报告生成
3. MinerU插件安装、注册及工作流配置详解

杨芳贤
53A创始人/腾讯云(TVP)最具价值专家

 


1.前言

上市公司财报,即上市公司财务报告,是上市公司按照相关法规要求定期向公众披露的反映其财务状况、经营成果和现金流量等信息的正式记录。它是资本市场中重要的信息披露文件,为投资者、分析师及其他利益相关者提供了关键的财务数据和经营绩效信息,是评估公司财务健康状况和投资价值的重要依据。

下面是一些财务报告主要指标。

image-20250513190344325

目前各大上市公司2024年度财报和2025年第一季的财报都已经披露,那么我们可以不可以利用AI 来帮我们快速分析这些财报生成漂亮的财务报表呢?今天就带大家来实现这个工作流。

工作流效果:

image-20250513190632774

生成的报表给大家展示一下:

image-20250513190715454
image-20250513190747408
image-20250513190832219

看起来效果不错,我们接下来告诉大家3分钟生成这样的基于上市公司财务报表的可视化HTML页面。


我们首选看一下这个工作流由哪些组件构成的。

1开始。2、mineru 3 、llm大语言模型、4 参数提取器、5 代码处理生成html调用、6、直接回复。

image-20250513191740232

开始

这个开始节点主要是用户通过上传一些上市公司财务报告,所以目前它只有一个参数就是file。

关于财务文件从哪里获取,大家可以通过https://gu.qq.com/sz002594/gp/jbnb 来获取(我这里以比亚迪公司为案例)

image-20250513192007831

下载的报告是PDF格式的,下载后保存本地电脑即可。

开始节点我们设置单个文件。

image-20250513192124875
image-20250513192217850

以上我们就完成了开始节点的设置。

mineru 插件

这里我们需要用到一个叫做mineru插件。MinerU 是一款开源的高质量数据提取工具,专注于将 PDF、网页和电子书中的内容高效提取并转换为机器可读格式(如 Markdown 和 JSON)。它由上海人工智能实验室 OpenDataLab 团队开发,旨在解决复杂文档的解析问题,支持多模态内容(包括文本、图片、表格和公式)的提取。

我们需要上面这个插件工具把开始节点中上传的PDF文档信息提取出来。 有的小伙伴说dify工作流里面不是有文档提取器吗?这个不也可以提取数据吗?是的你说的没错,文档提取器是可以提取文档内容信息,因为考虑上市公司财务报表数据准确性和复杂性我们这里建议使用mineru工具来提取文档里面的数据。

mineru 插件安装

我们在插件市场查找mineru。点击安装完成插件的安装。

image-20250513192715292
image-20250513192835029

mineru 注册

在使用这个插件之前我们需要在https://mineru.net 网站上注册获取授权。这个注册需要审批我们登录https://mineru.net 网站获得授权审批通过后获取API

image-20250513193047676

mineru授权

我们获取api token

image-20250513193412614
image-20250513193503946

以上步骤我们完成授权。

image-20250513193526779

当然如果你自己有显卡资源 也可以自己部署mineru,具体步骤这里就不在这里阐述。

mineru工作流配置

我们回到dify工作流,点击添加节点-工具-mineru

image-20250513193749005

接下来设置一下mineru,输入参考就是开始节点传入的file. 解析方法: orc;开启公式识别:true 开启公式识别:true 布局检测模型:doclayout-yolo 文档语言:auto 开启ocr识别:true. 具体配置如下:

image-20250513194050677

llm大语言模型

这个llm大语言模型我们选择2025年4月29日阿里通义千问开源的Qwen3-235B-A22B模型,模型这里我们使用魔搭社区提供的免费的Qwen3-235B-A22B模型

image-20250513194301597

系统提示词:

# 角色:上市公司财报数据HTML页面生成专家
## 简介:
-作者:周辉
-版本:3.0
-语言:中文
-描述:专业的财报数据分析师和HTML动态网页设计专家,擅长创建符合现代设计趋势和技术要求的财报展示页面。
## 背景:
你是一位资深的财务分析师和网页设计专家,专门将上市公司财报数据转化为视觉吸引力强的HTML动态网页。你熟悉各种现代web技术和设计趋势,尤其擅长BemtoGrid布局和GSAP动效。

## 目标:
生成一个完整的、可直接使用的HTML页面,用于展示上市公司财报数据,该页面应符合所有技术和设计要求。

## 技术要求:
1.使用BemtoGrid布局系统
2.集成GSAP动效和FramerMotion
3.基于HTML5和TailwindCSS开发
4.响应式设计和大小字体对比应用
## 设计规范:
1.根据公司特性选择适当的背景颜色和主题色调
2.应用超大字体和视觉元素突出重点,创造视觉对比
3.中英文混排,大字体为主,英文小字点题
4.使用简洁的矩形元素进行数据可视化
5.高亮色透明效果用于边框,避免不同高亮色互相覆盖
6.所有数据图表采用脚注样式,保持主题一致性
7.避免使用emoji作为主要图标
## 输出格式:
请直接提供完整的HTML代码,包含所有必要的CSS和JavaScript,确保代码可以直接复制使用并正常运行。代码应包含:

1.完整的HTML结构
2.内联或外部引用的CSS(包括TailwindCSS)
3.必要的JavaScript(包括GSAP和FramerMotion)
4.CDN引用和其他必要的资源链接
## 初始化:
作为上市公司财报数据HTML页面生成专家,我已准备好为您创建一个完整的HTML页面。请提供您想要分析的上市公司及其最新财报的关键信息,我将直接为您生成可用的HTML代码。

用户提示词

根据{{#1747105471978.text#}}最新财报内容和补充内容以及财报数据分析内容,生成一个 HTML 动态网页
image-20250513194434621

参数提取器

接下来我们用到了一个叫做参数提取器的组件。这个组件的主要目的是把上个LLM大语言模型输出的html 提取出来。这里有小伙伴可能有疑问了,上面个流程我们不是让它直接返回html 内容吗?为什么还要用到参数提取器呢? 这是因为大模型有幻觉 每个模型对提示词理解是有偏差的,虽然我们定义让它只返回html页面,但是对于某些模型它不光返回HTML 页面还返回一堆非HTML的文本内容,这样如果不用参数提取器出来后面生成HTML 页面会报错的。

image-20250513194901743

模型这里我们选择google gemini2.5-flash模型。输入变量上个流程节点llm输出。 提取参数这里我们定义一个html参数

image-20250513195041520

指令这里我们输入

请提取大模输出的html部分代码,其他的不需要

完整的参数提取器相关参数设置如下:

image-20250513195141317

代码处理生成html调用

接下来这里我们使用代码处理生成html, 这块功能我们之前的文章提到过,大家可以看我之前文章。dify案例分享-DeepSeek赋能从 Excel 表格到统计图,一键生成代码不是梦

上面的流程中参数提取器提取的代码它需要把它转化成文件输出,这里我们利用了后端服务代码的能力。这里我们有2个地方需要讲解。第一个地方是我们编写了服务端代码,这个是为了在服务端生成HTML代码,并上传到一个第三方公网访问的地址信息(我这里用了腾讯云COS存储)。第二个地方是获取这个生成的html代码链接地址返回给dify以方便后续流程使用。

1.服务端代码

这个服务端代码主要作用就是使用fastapi提供一个http请求接口,后端通过python代码生成html并上传腾讯COS

image-20250313211521334
makehtmlapi.py
from fastapi import FastAPI, HTTPException,Depends, Header
from pydantic import BaseModel
import logging
import time
import uvicorn
import configparser
import os
import json
import datetime
import random
from qcloud_cos import CosConfig
from qcloud_cos import CosS3Client

app = FastAPI()

# 读取配置文件中的API密钥
config = configparser.ConfigParser()
config.read('config.ini', encoding='utf-8')

# Tencent Cloud COS configuration
region = config.get('common''region')
secret_id = config.get('common''secret_id')
secret_key = config.get('common''secret_key')
bucket = config.get('common''bucket')

# 设置输出路径
output_path = config.get('html''output_path', fallback='html_output')

# 确保输出目录存在
os.makedirs(output_path, exist_ok=True)

# 设置日志
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

classHTMLRequest(BaseModel):
    html_content: str
    filename: str = None# 可选参数,如果不提供则自动生成

defverify_auth_token(authorization: str = Header(None)):
    """验证 Authorization Header 中的 Bearer Token"""
    ifnot authorization:
        raise HTTPException(status_code=401, detail="Missing Authorization Header")
    
    scheme, _, token = authorization.partition(" ")
    if scheme.lower() != "bearer":
        raise HTTPException(status_code=401, detail="Invalid Authorization Scheme")
    
    # 从配置文件读取有效token列表
    valid_tokens = json.loads(config.get('auth''valid_tokens'))
    if token notin valid_tokens:
        raise HTTPException(status_code=403, detail="Invalid or Expired Token")
    
    return token
defgenerate_timestamp_filename(extension='html'):
    timestamp = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
    random_number = random.randint(10009999)
    filename = f"{timestamp}_{random_number}.{extension}"
    return filename

defsave_html_file(html_content, filename=None, output_dir=None):
    # 如果没有提供文件名,则生成一个
    ifnot filename:
        filename = generate_timestamp_filename()
    
    # 如果没有提供输出目录,则使用默认目录
    ifnot output_dir:
        output_dir = output_path
    
    # 确保输出目录存在
    os.makedirs(output_dir, exist_ok=True)
    
    # 组合完整的输出路径
    file_path = os.path.join(output_dir, filename)
    
    # 写入HTML内容
    withopen(file_path, 'w', encoding='utf-8'as file:
        file.write(html_content)
    
    # 返回文件名和输出路径
    return filename, file_path

defupload_cos(region, secret_id, secret_key, bucket, file_name, base_path):
    config = CosConfig(
        Region=region,
        SecretId=secret_id,
        SecretKey=secret_key
    )
    client = CosS3Client(config)
    file_path = os.path.join(base_path, file_name)
    response = client.upload_file(
        Bucket=bucket,
        LocalFilePath=file_path,
        Key=file_name,
        PartSize=10,
        MAXThread=10,
        EnableMD5=False
    )
    if response['ETag']:
        url = f"https://{bucket}.cos.{region}.myqcloud.com/{file_name}"
        return url
    else:
        returnNone

@app.post("/generate-html/")
asyncdefgenerate_html(request: HTMLRequest,auth_token: str = Depends(verify_auth_token)):
    try:
        logger.info("开始处理HTML生成请求")
        start_time = time.time()
        
        # 保存HTML文件
        filename, file_path = save_html_file(request.html_content, request.filename)
        
        # 上传到腾讯云COS
        html_url = upload_cos(region, secret_id, secret_key, bucket, filename, output_path)
        
        elapsed_time = time.time() - start_time
        logger.info(f"HTML生成和上传完成,耗时 {elapsed_time:.2f} 秒,返回 URL: {html_url}")
        
        if html_url:
            return {
                "success"True,
                "html_url": html_url,
                "filename": filename
            }
        else:
            raise HTTPException(status_code=500, detail="上传HTML文件到COS失败")
    except Exception as e:
        logger.error(f"处理HTML生成请求时发生错误: {str(e)}")
        raise HTTPException(status_code=500, detail=str(e))

if __name__ == "__main__":
    uvicorn.run(app, host="0.0.0.0", port=8088)

代码里面用到config.ini配置文件

[html]
output_path = E:\\work\\code\\2024pythontest\\makehtml\\html_output

[common]
region = xxx         腾讯云OSS存储Region
secret_id = xxx      腾讯云OSS存储SecretId
secret_key = xxx     腾讯云OSS存储SecretKey
bucket = xxx         腾讯云OSS存储bucket

[auth]
valid_tokens = ["sk-zhouhui1xxx""zhouhui112xxx"]

上面代码需要再服务器或者本地运行起来。对外提供 8088端口(端口你也可以自己改)

image-20250313212453710

上面步骤服务端就启动好了。

1.客户端代码

接下来我们在dify 代码执行中添加。

image-20250313212628735

这里我们有4个参考。分别是1.json_html 参数提取提取的html代码。2 apiurl 就是上面服务端代码的请求地址。3 apikey 服务端代码请求APIkey. 4 strtype 这里我们可以写死(上市公司)

image-20250513200012586

其中 apiurl 和apikey 我们这里用环境变量方式来实现。

image-20250313213516927

如果你本地电脑 URL 可以是 192.168.XX.XX 或者127.0.0.1 如果是服务器 可以是局域网IP 也是可以公网IP

image-20250313213618268

客户端APIKEY 和服务端APIKEY 保持一致。服务端APIKEY 就是config.ini 对应的

image-20250313213735676

我上面服务端数组定义2个值,客户端有一个值在这个数组就可以了。

客户端代码如下:

import json
import re
import time
import requests

defmain(json_html: str, apikey: str,apiurl: str,strtype: str) -> dict:
    try:
        # 去除输入字符串中的 ```html 和 ``` 标记
        html_content = re.sub(r'^```html\s*|\s*```$''', json_html, flags=re.DOTALL).strip()
        
        # 生成时间戳,确保文件名唯一
        timestamp = int(time.time())
        filename = f"{strtype}_{timestamp}.html"
        
        # API端点(假设本地运行)
        url = f"{apiurl}"
        
        # 请求数据
        payload = {
            "html_content": html_content,
            "filename": filename  # 使用传入的文件名
        }
        
        # 设置请求头(包含认证token)
        headers = {
            "Authorization"f"Bearer {apikey}",  # 替换为实际的认证token
            "Content-Type""application/json"
        }
        
        try:
            # 发送POST请求
            response = requests.post(url, json=payload, headers=headers)
            
            # 检查响应状态
            if response.status_code == 200:
                result = response.json()
                html_url = result.get("html_url""")
                generated_filename = result.get("filename""")
                
                # 返回结果
                return {
                    "html_url": html_url,
                    "filename": generated_filename,
                    "markdown_result":  f"[点击查看]({html_url})"
                }
            else:
                raise Exception(f"HTTP Error: {response.status_code}, Message: {response.text}")
        
        except requests.exceptions.RequestException as e:
            raise Exception(f"Request failed: {str(e)}")
    
    except Exception as e:
        return {
            "error"f"Error: {str(e)}"
        }

返回3个值html_url、filename、markdown_result

image-20250313214248832

以上就完成了服务端代码生成和客户端代码调用的功能了。

直接回复

这个直接回复目前设置2个返回,一个是mineru 插件返回的文本信息,一个是最后生成的html页面链接。

image-20250513201131230
image-20250513201206406

以上我们就完成了整个工作流的制作。

3.验证及测试

我们打开工作流预览按钮。点击从本地文件上传

image-20250513201405085

选择我们之前下载的pdf文件

image-20250513201429464
image-20250513201521523
image-20250513201918210

以上我们就可以实现工作流的验证了。下面是视频演示


生成的图片最后的效果

2025-05-13_203210

体验地址

体验地址https://difyhs.duckcloud.fun/chat/0yPNRuq8JCozwsTQ 备用地址(http://14.103.204.132/chat/0yPNRuq8JCozwsTQ)

4.总结

今天主要带大家了解并实现了利用 AI 快速分析上市公司财报并生成可视化 HTML 页面的工作流方案。该工作流主要由开始、mineru 插件、llm 大语言模型、参数提取器、代码处理生成 html 调用以及直接回复等组件构成。通过实际验证和测试,我们发现按照此工作流,能够在短时间内生成基于上市公司财务报表的可视化 HTML 页面,效果显著。与传统的财报分析方式相比,该方案不仅提高了分析效率,还能以更直观、美观的方式展示财报数据,为投资者、分析师及其他利益相关者提供了便利。

 

53AI,企业落地大模型首选服务商

产品:场景落地咨询+大模型应用平台+行业解决方案

承诺:免费场景POC验证,效果验证后签署服务协议。零风险落地应用大模型,已交付160+中大型企业

联系我们

售前咨询
186 6662 7370
预约演示
185 8882 0121

微信扫码

添加专属顾问

回到顶部

加载中...

扫码咨询