news 2026/4/16 7:25:36

DIFY合同生成全流程开发实践(三、后端接口以及优化方向)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
DIFY合同生成全流程开发实践(三、后端接口以及优化方向)

一、目标

前面两篇文章,实现了从合同模板到新的合同文字内容的生成,这篇文章提供后端接口实现以及docker一键部署,实现dify http节点传入合同文本,并返回word合同文本下载链接。

二、架构

  • nginx

nginx实现生成的word文本对外提供下载访问链接

  • python

fastApi对外发布文字转word文档接口

  • docker

部署nginx以及python服务。

  • docker-compose.yml

通过编排,实现通过命令行一键自动下载镜像以及部署服务。

docker-compose up -d

三、具体实现

创建好如下目录:

全部目录以及文件如下:

nginx配置文件:

server{ #以下配置只在http部分的server部分中生效 listen 80; server_name localhost; location /app/wordSave{ #以下配置只在http/server部分的location部分中生效 root /usr/share/nginx/html; index index.html index.htm; } }

python文件:

mdToword_tool_http_pypandoc.py:

#!/usr/bin/env python3 """ FastAPI服务器工具:将Markdown格式数据生成Word文档(使用pypandoc版本) """ from fastapi import FastAPI, HTTPException from fastapi.responses import JSONResponse import os import base64 import tempfile import pypandoc from typing import Dict, Any from datetime import datetime from pydantic import BaseModel # 创建FastAPI应用实例 # 修改应用创建部分,移除请求体大小限制 app = FastAPI( title="Markdown转Word服务", version="2.1.0", description="使用pypandoc的Markdown转Word文档服务", # 移除请求体大小限制 body_size_limit=None ) # 定义请求体模型 class ConvertRequest(BaseModel): markdown_content: str # base64加密后的Markdown内容 output_filename: str = None # 定义响应模型 class ConvertResponse(BaseModel): success: bool message: str output_path: str local_path: str output_filename: str content_length: int error: str = None # 定义信息响应模型 class InfoResponse(BaseModel): service_name: str version: str description: str supported_formats: list output_format: str features: list def process_markdown_to_word(markdown_content: str, output_filename: str = None) -> Dict[str, Any]: """ 使用pypandoc将Markdown内容转换为Word文档 Args: markdown_content: base64加密后的Markdown格式的文本内容 output_filename: 输出文件名(可选) Returns: 包含转换结果的字典 """ try: # 生成当前时间戳(格式:年-月-日_时-分-秒) timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") # 如果没有指定输出文件名,生成默认文件名 if not output_filename: output_filename = f"output_document_{timestamp}.docx" else: # 处理用户提供的文件名,添加时间戳 name, ext = os.path.splitext(output_filename) if not ext: ext = '.docx' output_filename = f"{name}_{timestamp}{ext}" # 获取当前文件所在目录 current_dir = os.path.dirname(os.path.abspath(__file__)) # 设置wordSave文件夹路径 word_save_dir = os.path.join(current_dir, 'wordSave') # 确保wordSave目录存在 if not os.path.exists(word_save_dir): os.makedirs(word_save_dir) # 构建完整的输出路径 output_path = os.path.join(word_save_dir, output_filename) # 构建nginx可用的相对路径 nginx_path = f"app/wordSave/{output_filename}" # 解码base64内容 try: decoded_content = base64.b64decode(markdown_content).decode('utf-8') except Exception as e: raise ValueError(f"Base64解码失败: {str(e)}") try: # 使用pypandoc转换Markdown到Word pypandoc.convert_text( decoded_content, 'docx', format='markdown', outputfile=output_path, # 添加额外的转换选项以获得更好的结果 extra_args=[ '--standalone', '--wrap=preserve', # 修改为更适合办公文档的字体设置,确保WPS完全兼容 '-V', 'CJKmainfont=SimSun', # 主字体:宋体(WPS最兼容的基础字体) '-V', 'CJKsansfont=SimHei', # 无衬线字体:黑体 '-V', 'CJKseriffont=KaiTi', # 衬线字体:楷体 '-V', 'CJKmonofont=FangSong', # 等宽字体:仿宋 '-V', 'mainfont=Times New Roman', # 西文字体:Times New Roman # 字体大小设置 '-V', 'fontsize=12pt', # 正文字体大小 # 目录设置 '--toc', # 添加目录生成 '--toc-depth=6', # 确保捕获所有6级标题 # 标题页设置 '-V', 'title-page=true', # 启用标题页 '-V', 'title=文档标题', # 文档标题 '-V', 'subtitle=副标题', # 副标题 '-V', 'author=作者名称', # 作者 '-V', 'date=\\today', # 当前日期 # 页面设置 '-V', 'header-includes=\\pagenumbering{gobble}', # Markdown格式设置 '--markdown-headings=atx', # 明确指定使用atx格式的标题(#开头) # 保留更多的格式信息 '-f', 'markdown+smart+auto_identifiers+header_attributes+raw_html' ] ) # 检查文件是否成功创建 if not os.path.exists(output_path): raise Exception("转换失败:未生成Word文件") return { "success": True, "message": "Markdown转Word成功(使用pypandoc)", "output_path": "http://127.0.0.1:9999/" + nginx_path, # 返回nginx可用的路径 "local_path": output_path, # 保留本地完整路径用于调试 "output_filename": output_filename, "content_length": len(markdown_content) } except Exception as e: return { "message": "转换过程中出现错误", "error": str(e), } except Exception as e: return { "success": False, "error": str(e), "message": "转换过程中出现错误", "output_path": "", "local_path": "", "output_filename": "", "content_length": 0 } @app.post("/convert", response_model=ConvertResponse) async def convert_markdown_to_word_endpoint(request: ConvertRequest): """ 将Markdown格式数据转换为Word文档的POST接口 Args: request: 包含markdown_content(必需)和output_filename(可选)的请求体 Returns: 转换结果,包含成功状态、文件路径等信息 """ print("接收到转换请求") if not request.markdown_content: raise HTTPException(status_code=400, detail="缺少markdown_content参数") result = process_markdown_to_word(request.markdown_content, request.output_filename) print(f"转换结果: {result}") if not result["success"]: raise HTTPException(status_code=500, detail=result.get("error", "转换失败")) return result @app.get("/info", response_model=InfoResponse) async def get_conversion_info_endpoint(): """ 获取转换服务信息的GET接口 Returns: 服务信息,包括版本、功能等 """ return { "service_name": "Markdown转Word服务", "version": "2.1.0", "description": "使用pypandoc和FastAPI框架的Markdown转Word文档服务", "supported_formats": ["markdown", "md"], "output_format": "docx", "features": [ "使用pypandoc实现高质量转换", "支持复杂Markdown语法", "保留原始格式和样式", "支持表格、代码块、数学公式", "文件名自动添加时间戳", "支持base64编码内容输入", "可选的目录生成功能" ] } @app.get("/") async def root(): """ 根路径,返回服务基本信息 """ return { "message": "欢迎使用Markdown转Word服务(pypandoc版)", "version": "2.1.0", "endpoints": { "convert": "POST /convert - 将Markdown转换为Word", "info": "GET /info - 获取服务信息" } } if __name__ == "__main__": import uvicorn # 运行FastAPI服务器 uvicorn.run( "mdToword_tool_http_pypandoc:app", host="127.0.0.1", port=7777, reload=True # 开发环境开启热重载 )

Dockerfile:以官方python镜像为基础,创建包含python接口镜像的

# 使用官方Python镜像作为基础镜像 FROM python:3.13.5 # 维护者信息 MAINTAINER 944658413@qq.com # 设置工作目录 WORKDIR /app # 复制requirements.txt到工作目录 COPY requirements.txt . # 安装Python依赖 RUN pip install --no-cache-dir -r requirements.txt # 复制Python代码到工作目录 #COPY mdToword_tool_http.py . COPY mdToword_tool_http_pypandoc.py . # 创建wordSave目录用于保存生成的Word文件 RUN mkdir -p /app/wordSave # 安装pandoc(pypandoc的系统依赖) RUN apt-get update && \ apt-get install -y pandoc && \ rm -rf /var/lib/apt/lists/* # 设置卷挂载,将容器中的wordSave目录挂载到外部 VOLUME ["./nginx/wordSave"] # 暴露Python应用端口(与代码中设置的7777端口一致) EXPOSE 7777 # 设置环境变量 ENV PYTHONDONTWRITEBYTECODE=1 \ PYTHONUNBUFFERED=1 # 启动Python应用 CMD ["uvicorn", "mdToword_tool_http_pypandoc:app", "--host", "0.0.0.0", "--port", "7777"]

requirements.txt:依赖

# Markdown转Word服务依赖列表 # Web框架 fastapi>=0.95.0 uvicorn[standard]>=0.22.0 # 文档处理 python-docx>=0.8.11 markdown>=3.4.0 pypandoc>=1.11 # HTML解析 beautifulsoup4>=4.11.0 # 数据验证 pydantic>=1.10.0 # 可选依赖:提高性能 httpx>=0.23.0 # 异步HTTP客户端 python-multipart>=0.0.6 # 表单数据支持

docker-compose:

PS:

两个虚拟机同时挂载同一个wordSave文件夹,可实现生成的word文件在nginx对外发布。

version: '3.8' services: wb-dify-nginx: image: nginx:latest environment: - TZ=Asia/Shanghai container_name: wb-dify-nginx ports: - "9999:80" volumes: - ./nginx/wordSave:/usr/share/nginx/html/app/wordSave - ./nginx/logs:/var/log/nginx - ./nginx/conf.d:/etc/nginx/conf.d restart: unless-stopped wb-dify-python: build: context: ./python dockerfile: Dockerfile environment: - TZ=Asia/Shanghai image: wb-dify-python container_name: wb-dify-python ports: - "7777:7777" volumes: - ./nginx/wordSave:/app/wordSave restart: unless-stopped # extra_hosts: # - "somehost:162.242.195.82" # 以上会在此服务的内部容器中 /etc/hosts 创建一个具有 ip 地址和主机名的映射关系:162.242.195.82 somehost

四、结果演示

dify节点,http得到返回以后,后面跟一个内容优化节点达到显示美观的效果

实际演示:

五、其他

docker安装与部署,参考我的这篇文章,很详细了:

轻松搞定Docker安装与虚拟化设置

dify的部署:

暂时没写,基本上都是梯子去github 克隆以后,去docker文件夹,运行类似的docker-compose.yml一键部署。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/16 7:22:46

你还在手动处理环境数据?3步用R语言实现自动化数据同化

第一章:环境监测中数据同化的意义与挑战在现代环境监测系统中,数据同化作为连接观测数据与数值模型的核心技术,发挥着至关重要的作用。它通过融合来自卫星、地面传感器和模型预测的多源异构数据,提升环境状态估计的精度与时效性&a…

作者头像 李华
网站建设 2026/4/9 21:31:43

深圳/东莞/广州/惠州商业美食街区美陈包装设计公司

当夜幕为大湾区的街巷镀上暖光,深圳东门的烟火气、广州西关的岭南韵、东莞商圈的潮流感与惠州老街的慢时光,正通过一场场精心的美陈包装,绽放出独特的商业魅力。肆墨设计顾问有限公司肆墨设计顾问有限公司是国内较早涉足商业美陈设计的创意机…

作者头像 李华
网站建设 2026/4/15 16:10:02

2026亚洲艺术电影节官宣:主竞赛单元评审团阵容揭晓!

在影像与思想交汇的边界,七位电影人以专业、敏锐与人文关怀,共筑亚洲电影的审美坐标。✨段奕宏 中国国家话剧院演员、一级演员、中国电影家协会理事会理事。凭借《烈日灼心》获得第18届上海国际电影节最佳男演员奖、凭借《暴雪将至》获得第30届东京国际电…

作者头像 李华