Dify创建 echarts图表 (二)dify+python后端flask实现
通过python flask创建了一个接口,用来生成echarts能够适应更多场景应用
本次遇到的主要就是docker环境下,要访问本地接口需要转换一下接口ip,当然通过docker访问外部接口同样也有类似问题,也需要中间代理转换一下。当然最麻烦的就是dify传值这一步,简单做个记录
场景1:测试流程是否可用
这里传的是一个空值
from urllib import request
import urllib.request
import jsondef main(str) -> dict:data = {"str": str}url = 'http://host.docker.internal:5000/fixed_string'json_data = json.dumps(data)byte_data = json_data.encode('utf-8')req = urllib.request.Request(url, data=byte_data, headers={'Content-Type': 'application/json'})response = urllib.request.urlopen(req)response_data = response.read().decode('utf-8')return {"result": response_data,}
后端接到请求直接返回字符串就好了,不得不感叹AI真的太强大了,后端代码几乎全是AI写的十来分钟搞定
@app.route('/dynamic-string', methods=['POST'])
def dynamic_string():print("dynamic-string接口")print(request)if not request.json:return jsonify({"error": "请求必须包含JSON数据"}), 400return get_dynamic_string(json.dumps(request.json))def get_fixed_string():option = {"xAxis": {"type": "category","data": ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]},"yAxis": {"type": "value"},"series": [{"data": [120, 200, 150, 80, 70, 110, 130],"type": "line"}]}# 将字典转换为格式化的 JSON 字符串option_json = json.dumps(option, indent=2)# 构建正确的 Markdown 代码块output = "```echarts\n" + option_json + "\n```"return output
场景2:Dify传值到后端,再通过后端拼接好图表字符串后返给Dify端
目前做图的思路比较简单,Dify这边根据需求提问自动生成SQL并查询返回结果,然后在后端完成做图,再返给dify端,这个场景遇到稍微麻烦的地方就在于如何拿到制作图表需要的关键参数,如名称、类型、基础的X轴、Y轴数据,虽然可以通过大模型提取,试吧,一试一个不吱声,各种报错
最后实现方式是用的参数提取器做,模型选的阿里千问的
大致流程如下:
简单记录一下,数据库查结果还是用的插件,中间有个过滤代码,需要处理一下异常问题,巨烦
import re
def main(arg1: str) -> dict:result = re.sub(r'"', '', arg1)result = re.sub(r'\n', ' ', result)result = result.replace("date('now')","CURRENT_DATE")result = result.replace("DATE('now')","CURRENT_DATE")return {"result": result,}
结果查出来了需要对数据再做一下处理
import json
def main(arg1: str) -> dict:return {"result": json.dumps(arg1,ensure_ascii=False)}
最关键的就是下面的这个参数提取器,目前只是跑通了的版本,还有优化的空间
接下来就是往本地接口传值了,获取到参数提取器输出的四个数组,然后开始往接口丢
from urllib import request
import urllib.request
import jsondef main(title, chart_category, xdata, ydata) -> dict:url = 'http://host.docker.internal:5000/custom-chart'# 将4个数组封装成字典(可自定义字段名)payload = {"title": title,"chart_category": chart_category,"xdata": xdata,"ydata": ydata}# 构造请求json_data = json.dumps(payload) # 序列化为JSON字符串byte_data = json_data.encode('utf-8')req = urllib.request.Request(url, data=byte_data, headers={'Content-Type': 'application/json'})# 发送请求并解析响应response = urllib.request.urlopen(req)response_data = response.read().decode('utf-8')return {"result": response_data} # 返回接口响应
后端代码如下,稍微改良了一下,由固定字符串变成了自动传参,但由于不同图表的特性不同,这里不能通用,接下来改造的方向,通过Dify传回来的图表类型,输出适配不同图表的参数
@app.route('/custom-chart', methods=['POST'])
def custom_chart():"""接收前端参数生成自定义图表"""print("custom-chart接口")print(request)if not request.json:return jsonify({"error": "请求必须包含JSON数据"}), 400data = request.jsontitle = data.get('title', '自定义图表')chart_category = data.get('chart_category', 'line')ydata = data.get('ydata', [])xdata = data.get('xdata', [])return generate_chart_from_params(title, chart_category, ydata, xdata)def generate_chart_from_params(title, chart_category, ydata, xdata):"""根据参数生成ECharts配置"""# 处理xdata格式if isinstance(xdata, str):# 去除首尾引号,按分号分割,去除每个元素的首尾引号xdata = [item.strip().strip("'") for item in xdata.strip("'").split(';')]# 处理ydata格式if isinstance(ydata, str):# 去除首尾引号,按逗号分割,去除每个元素的首尾引号和空格,转换为数字ydata = [int(item.strip().strip("'")) for item in ydata.strip("'").split(',')]option = {"title": {"text": title},"tooltip": {},"xAxis": {"type": "category","data": xdata},"yAxis": {"type": "value"},"series": [{"data": ydata,"type": chart_category}]}# 将字典转换为格式化的JSON字符串option_json = json.dumps(option, indent=2, ensure_ascii=False)# 构建正确的Markdown代码块output = "```echarts\n" + option_json + "\n```"print(output) return output
好了,基本上流程就是这样了