58 Commits

Author SHA1 Message Date
843146cdd7 插件 2026-03-02 17:12:17 +08:00
b30af4aff8 迁移结束 2026-02-11 14:14:15 +08:00
1bf08ff52f 路由修正 2026-01-28 11:42:55 +08:00
f4265995bc Merge branch 'master' into pigx迁移 2026-01-22 11:37:00 +08:00
12d9294f3d 小程序优化 2026-01-22 11:36:26 +08:00
b7bf32e785 Merge branch 'master' into pigx迁移 2026-01-20 16:18:14 +08:00
8ab6107f25 1轮修复 2026-01-20 16:17:39 +08:00
87f2772964 t 2026-01-14 15:42:26 +08:00
0bf7361672 退出登录修改 2026-01-12 11:09:14 +08:00
1b02067d50 Merge branch 'docker' 2026-01-12 10:48:46 +08:00
6921ac7e66 小程序聊天修正 2026-01-12 10:47:44 +08:00
0972d504ab 小程序 2026-01-09 17:27:16 +08:00
f4b7337210 聊天室url修正 2026-01-09 16:40:28 +08:00
bfd06dd8f6 serv微信登录修正 2026-01-09 12:46:32 +08:00
0ae5343b11 移除 2026-01-09 12:18:42 +08:00
8073a95f74 微信小程序登录修改 2026-01-09 12:17:21 +08:00
f948362d1b 日志修复 2026-01-08 17:59:07 +08:00
54599f28d1 路由 2026-01-08 16:40:02 +08:00
16e714730d 路由 2026-01-08 16:33:52 +08:00
b0ddabd819 修改 2026-01-08 16:16:06 +08:00
b1e7aeca43 修改 2026-01-08 15:38:33 +08:00
419b6ffec5 即可修正 2026-01-08 14:21:41 +08:00
12d43e912c 修正样式 2026-01-08 14:08:56 +08:00
8e86f244c6 修改 2026-01-08 14:01:27 +08:00
5190a0cc9c web打包修改 2026-01-08 13:20:40 +08:00
4784971d97 更新 2026-01-07 17:44:15 +08:00
2e159ec318 nginx修改 2026-01-07 16:58:56 +08:00
23f08dec09 修正 2026-01-07 16:45:01 +08:00
5bad18dd33 证书 2026-01-07 16:35:22 +08:00
86bd6613b4 修正 2026-01-07 16:25:43 +08:00
c7c18d4dc3 配置修改 2026-01-07 15:41:04 +08:00
2e84282424 docker web配置 2026-01-07 15:35:35 +08:00
72cea2935d web打包问题 2026-01-07 15:30:29 +08:00
ec61f134a8 web修改 2026-01-02 18:22:09 +08:00
75877db4f9 修正pom 2026-01-02 17:02:26 +08:00
576c7e9ed2 serv打包 2026-01-02 16:57:51 +08:00
b7378867c0 pg修正 2026-01-02 16:18:32 +08:00
2d19ee784b pg修正 2026-01-02 16:02:51 +08:00
5d54ac1cd4 编译修正 2026-01-02 15:50:20 +08:00
97724c8c8d web编译修正 2026-01-02 15:32:04 +08:00
73badc175d 修改makefile 2026-01-02 15:18:07 +08:00
89bc8bf1d4 服务打包初步结构 2026-01-02 14:56:14 +08:00
19026c1b30 服务配置修改 2026-01-02 14:55:57 +08:00
e15305df85 Merge branch 'master' into docker 2026-01-02 10:46:52 +08:00
4b6d7d04ec 在线热更新配置 2026-01-01 17:36:00 +08:00
05c76fa3ec 系统日志 2026-01-01 17:01:56 +08:00
b53faca120 overview统计 2026-01-01 16:19:55 +08:00
eb15706ccc 会话总结工作流接入、前后端处理 2026-01-01 15:12:29 +08:00
4e373e6d2c ai聊天input修改 2026-01-01 13:12:42 +08:00
a07daa715a 新增智能体 2026-01-01 12:16:24 +08:00
87baa347b7 修改 2026-01-01 11:04:24 +08:00
48da0a4c81 Merge branch 'master' into docker 2025-12-31 17:37:45 +08:00
c0cbb059fe dify工作流 2025-12-31 17:36:15 +08:00
8cb8692b84 知识库文件日志 2025-12-31 16:30:42 +08:00
1bb1dba4d6 文件上传大小限制相关 2025-12-31 15:43:02 +08:00
4f0eeede37 工单流程VO渲染效果 2025-12-31 12:45:26 +08:00
1ef1b32f5f 小程序工单设备代码传入 2025-12-31 12:06:21 +08:00
154ac7f61c docker初步构想 2025-12-28 18:30:17 +08:00
938 changed files with 7442 additions and 168841 deletions

209
.gitignore vendored
View File

@@ -1,206 +1,7 @@
# ---> Java
# Compiled class file
*.class
# Log file
*.log
# BlueJ files
*.ctxt
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.jar
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar
.claude
.idea
.kiro
.tmp
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
replay_pid*
.trae
# ---> Python
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# UV
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
#uv.lock
# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock
# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
#pdm.lock
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
# in version control.
# https://pdm.fming.dev/latest/usage/project/#working-with-version-control
.pdm.toml
.pdm-python
.pdm-build/
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
# Ruff stuff:
.ruff_cache/
# PyPI configuration file
.pypirc
江西城市生命线-可交互原型/frontend/node_modules/*
THAI-Platform/*
urbanLifelineWeb/packages/wechat_demo/*
urbanLifelineWeb/packages/workcase_wechat/unpackage/*
docs/AI训练资料
**/*.difypkg

5
.idea/.gitignore generated vendored
View File

@@ -1,5 +0,0 @@
# 默认忽略的文件
/shelf/
/workspace.xml
# 基于编辑器的 HTTP 客户端请求
/httpRequests/

6
.idea/misc.xml generated
View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

8
.idea/modules.xml generated
View File

@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/urbanLifeline.iml" filepath="$PROJECT_DIR$/.idea/urbanLifeline.iml" />
</modules>
</component>
</project>

View File

@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

6
.idea/vcs.xml generated
View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

27
.vscode/launch.json vendored Normal file
View File

@@ -0,0 +1,27 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Python: FastAPI Server",
"type": "python",
"request": "launch",
"program": "${workspaceFolder}/difyPlugin/main.py",
"console": "integratedTerminal",
"justMyCode": true,
"env": {
"PYTHONUNBUFFERED": "1"
},
"cwd": "${workspaceFolder}/difyPlugin",
"args": []
},
{
"name": "Python: Debug Plugin",
"type": "python",
"request": "launch",
"program": "${workspaceFolder}/difyPlugin/app/plugins/pdf/__init__.py",
"console": "integratedTerminal",
"justMyCode": true,
"cwd": "${workspaceFolder}/difyPlugin"
}
]
}

View File

@@ -1,4 +1,10 @@
{
"maven.view": "hierarchical",
"editor.tabSize": 4,
"[*.ts]": {
"editor.tabSize": 2
},
"[*.vue]": {
"editor.tabSize": 2
}
}

116
Makefile
View File

@@ -1,116 +0,0 @@
# Urban Lifeline 开发环境快捷命令
.PHONY: help up down logs restart clean build ps
# 默认目标
.DEFAULT_GOAL := help
# 帮助信息
help:
@echo "========================================="
@echo " 泰豪电源 Urban Lifeline 开发环境"
@echo "========================================="
@echo ""
@echo "可用命令:"
@echo " make up - 启动所有服务"
@echo " make down - 停止所有服务"
@echo " make restart - 重启所有服务"
@echo " make logs - 查看所有服务日志"
@echo " make ps - 查看服务状态"
@echo " make build - 重新构建镜像"
@echo " make clean - 清理所有数据(慎用)"
@echo ""
@echo "单独服务操作:"
@echo " make logs-portal - 查看主应用日志"
@echo " make logs-gateway - 查看网关日志"
@echo " make restart-portal - 重启主应用"
@echo " make shell-portal - 进入主应用容器"
@echo ""
# 启动所有服务
up:
@echo "启动开发环境..."
docker-compose -f docker-compose.dev.yml up -d
@echo "服务启动中,请稍候..."
@sleep 5
@echo ""
@echo "访问地址:"
@echo " 主应用: http://localhost"
@echo " 招投标: http://localhost/bidding"
@echo " 智能客服: http://localhost/customer-service"
@echo " Gateway: http://localhost/api"
@echo " Nacos: http://localhost/nacos"
@echo ""
# 停止所有服务
down:
@echo "停止所有服务..."
docker-compose -f docker-compose.dev.yml down
# 查看日志
logs:
docker-compose -f docker-compose.dev.yml logs -f
# 重启所有服务
restart:
@echo "重启所有服务..."
docker-compose -f docker-compose.dev.yml restart
# 查看服务状态
ps:
docker-compose -f docker-compose.dev.yml ps
# 重新构建镜像
build:
@echo "重新构建所有镜像..."
docker-compose -f docker-compose.dev.yml build --no-cache
# 清理所有数据(危险操作)
clean:
@echo "警告:此操作将删除所有容器、数据卷和镜像!"
@read -p "确认继续吗?(y/N): " confirm && [ "$$confirm" = "y" ] || exit 1
docker-compose -f docker-compose.dev.yml down -v
docker system prune -af
# ==================== 单独服务操作 ====================
# Portal 日志
logs-portal:
docker-compose -f docker-compose.dev.yml logs -f portal
# Gateway 日志
logs-gateway:
docker-compose -f docker-compose.dev.yml logs -f gateway
# Nginx 日志
logs-nginx:
docker-compose -f docker-compose.dev.yml logs -f nginx
# 共享包日志
logs-shared:
docker-compose -f docker-compose.dev.yml logs -f shared
# 重启 Portal
restart-portal:
docker-compose -f docker-compose.dev.yml restart portal
# 重启 Gateway
restart-gateway:
docker-compose -f docker-compose.dev.yml restart gateway
# 进入 Portal 容器
shell-portal:
docker-compose -f docker-compose.dev.yml exec portal sh
# 进入 Gateway 容器
shell-gateway:
docker-compose -f docker-compose.dev.yml exec gateway sh
# 进入数据库
db:
docker-compose -f docker-compose.dev.yml exec postgres psql -U postgres -d urban_lifeline
# 初始化数据库
db-init:
@echo "初始化数据库..."
docker-compose -f docker-compose.dev.yml exec postgres psql -U postgres -d urban_lifeline -f /docker-entrypoint-initdb.d/initAll.sql

227
README.md
View File

@@ -1,227 +0,0 @@
# 泰豪电源 AI 数智化平台
城市生命线智能管理系统 - Urban Lifeline
## 项目简介
基于 **"一个底座、多种智能体"** 架构的企业级 AI 数智化平台,包含四大核心业务模块:
1. **资料管理智能化** - 智能文档管理与检索
2. **招投标自动化** - 招投标全流程智能化
3. **售后客服智能化** - AI 驱动的智能客服系统
4. **企业内部知识协同** - 知识库管理与协作
## 技术架构
### 后端技术栈
- **Java 21** + **Spring Boot 3.5**
- **Spring Cloud Gateway** - API 网关
- **Nacos** - 服务注册与配置中心
- **PostgreSQL 16** - 主数据库
- **Redis 7** - 缓存
- **Dubbo 3.3** - RPC 框架
### 前端技术栈
- **Vue 3.5** (`<script setup>`)
- **TypeScript 5.7**
- **Vite 6.0** - 构建工具
- **Pinia 2.2** - 状态管理
- **Element Plus 2.9** - UI 组件库
- **pnpm 9.0 + Turborepo 2.0** - Monorepo 管理
### 核心特性:共享组件 HTTP 导入
采用 **Import Maps + ES Module** 方案,实现真正的运行时组件共享:
```vue
<script setup lang="ts">
// 直接从 HTTP URL 导入共享组件
import { UlTable } from '@shared/components' // → http://localhost/shared/components.js
import { http } from '@shared/utils' // → http://localhost/shared/utils.js
import { authApi } from '@shared/api' // → http://localhost/shared/api.js
</script>
```
**工作原理**
1. 共享包构建为 ES Module (`components.js`)
2. 部署到独立 HTTP 服务 (`http://localhost:5000`)
3. 通过 Nginx 统一代理 (`http://localhost/shared/`)
4. 浏览器通过 Import Maps 直接加载
## 快速开始
### 方式一Docker Compose推荐
```bash
# 1. 启动所有服务(自动构建)
make up
# 2. 等待服务启动约1-2分钟
make ps
# 3. 访问应用
open http://localhost
```
### 方式二:本地开发
```bash
# 1. 安装依赖
pnpm install
# 2. 启动后端服务(需要 Java 21
cd urbanLifelineServ
mvn spring-boot:run
# 3. 启动前端服务
cd urbanLifelineWeb
pnpm dev
# 4. 访问
open http://localhost:3000
```
## 项目结构
```
urbanLifeline/
├── urbanLifelineServ/ # 后端服务Spring Boot
│ ├── gateway/ # API 网关
│ ├── auth/ # 认证服务
│ ├── system/ # 系统服务
│ ├── file/ # 文件服务
│ └── common/ # 公共模块
├── urbanLifelineWeb/ # 前端应用Vue 3 Monorepo
│ ├── packages/
│ │ ├── shared/ # 共享组件库
│ │ │ ├── components/ # 公共组件
│ │ │ ├── utils/ # 工具函数
│ │ │ ├── api/ # API 封装
│ │ │ └── composables/ # 组合式函数
│ │ ├── portal/ # 主应用
│ │ ├── app-bidding/ # 招投标应用
│ │ └── app-knowledge/ # 知识协同应用
│ ├── pnpm-workspace.yaml
│ └── turbo.json
├── docker-compose.dev.yml # Docker 开发环境
├── Makefile # 快捷命令
└── docs/ # 文档
├── 前端完整指南.md # ⭐ 前端全流程文档
└── 数据库设计文档.md # ⭐ 数据库全流程文档
```
## 访问地址
| 应用 | 地址 | 说明 |
|------|------|------|
| **主应用** | http://localhost/ | Portal 统一入口 |
| **招投标** | http://localhost/bidding | 招投标智能体 |
| **智能客服** | http://localhost/customer-service | 客服系统 |
| **共享组件** | http://localhost/shared/components.js | ES Module |
| **API 网关** | http://localhost/api | Gateway |
| **Nacos** | http://localhost/nacos | 注册中心 |
## 常用命令
```bash
# Docker 环境
make up # 启动所有服务
make down # 停止所有服务
make logs # 查看日志
make ps # 查看服务状态
make restart # 重启服务
make clean # 清理所有数据
# 单独服务
make logs-portal # 查看主应用日志
make logs-gateway # 查看网关日志
make restart-portal # 重启主应用
make shell-portal # 进入容器
make db # 连接数据库
# 前端开发
pnpm dev # 启动所有应用
pnpm build # 构建所有应用
pnpm --filter portal dev # 启动单个应用
pnpm --filter portal build # 构建单个应用
```
## 文档索引
- **[前端完整指南](./docs/前端完整指南.md)** - ⭐ 架构、开发、部署全流程
- **[数据库完整指南](./docs/数据库完整指南.md)** - ⭐ Schema、表结构、优化方案
## 核心亮点
### 1. 共享组件运行时加载
```html
<!-- index.html -->
<script type="importmap">
{
"imports": {
"@shared/components": "http://localhost/shared/components.js",
"@shared/utils": "http://localhost/shared/utils.js"
}
}
</script>
```
```vue
<script setup lang="ts">
// 浏览器自动从 URL 加载,无需打包!
import { UlTable } from '@shared/components'
</script>
```
### 2. Monorepo + Turborepo
- 统一依赖管理
- 增量构建加速
- 任务并行执行
- 远程缓存
### 3. Docker 一键启动
- 所有服务容器化
- Nginx 统一网关
- 支持热更新HMR
- 数据持久化
### 4. TypeScript 全栈
- 类型安全
- 智能提示
- 重构友好
## 环境要求
### Docker 环境(推荐)
- Docker 20.10+
- Docker Compose 2.0+
### 本地开发
- Node.js 20+
- pnpm 9+
- Java 21+
- Maven 3.9+
- PostgreSQL 16+
## 开发规范
- **前端**ESLint + Prettier + Husky
- **提交规范**Conventional Commits
- **分支策略**Git Flow
- **代码审查**:必须 Code Review
## License
MIT
---
**Built with ❤️ by Taihao Team**

Submodule ai-management-dify updated: aa57f8551a...9fffb6e421

Submodule ai-management-platform added at 199d8180a6

View File

@@ -1,16 +0,0 @@
# 应用配置
APP_NAME=DifyPlugin
APP_VERSION=1.0.0
DEBUG=false
# API配置
API_V1_PREFIX=/api/v1
# 跨域配置
CORS_ORIGINS=["*"]
# Redis配置
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_PASSWORD=
REDIS_DB=0

27
difyPlugin/.gitignore vendored
View File

@@ -1,27 +0,0 @@
# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
venv/
.venv/
ENV/
# IDE
.idea/
.vscode/
*.swp
*.swo
# 环境配置
.env
# 日志
*.log
logs/
# 测试
.pytest_cache/
.coverage
htmlcov/

View File

@@ -1,17 +0,0 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "DifyPlugin: FastAPI",
"type": "debugpy",
"request": "launch",
"program": "run.py",
"cwd": "${workspaceFolder}",
"python": "F:\\Environment\\conda\\envs\\difyPlugin\\python.exe",
"env": {
"PYTHONPATH": "${workspaceFolder}/difyPlugin"
},
"jinja": true
}
]
}

View File

146
difyPlugin/DifyCLI.md Normal file
View File

@@ -0,0 +1,146 @@
> ## Documentation Index
> Fetch the complete documentation index at: https://docs.dify.ai/llms.txt
> Use this file to discover all available pages before exploring further.
# CLI
> Dify 插件开发命令行界面
<Note> ⚠️ 本文档由 AI 自动翻译。如有任何不准确之处,请参考[英文原版](/en/develop-plugin/getting-started/cli)。</Note>
使用命令行界面CLI设置和打包你的 Dify 插件。CLI 提供了一种简化的方式来管理你的插件开发工作流,从初始化到打包。
本指南将指导你如何使用 CLI 进行 Dify 插件开发。
## 前提条件
在开始之前,请确保已安装以下内容:
* Python 版本 ≥ 3.12
* Dify CLI
* Homebrew适用于 Mac 用户)
## 创建 Dify 插件项目
<Tabs>
<Tab title="Mac">
```bash theme={null}
brew tap langgenius/dify
brew install dify
```
</Tab>
<Tab title="Linux">
从 [Dify GitHub 发布页面](https://github.com/langgenius/dify-plugin-daemon/releases) 获取最新的 Dify CLI
```bash theme={null}
# Download dify-plugin-darwin-arm64
chmod +x dify-plugin-darwin-arm64
mv dify-plugin-darwin-arm64 dify
sudo mv dify /usr/local/bin/
```
</Tab>
</Tabs>
现在你已成功安装 Dify CLI。你可以通过运行以下命令来验证安装
```bash theme={null}
dify version
```
你可以使用以下命令创建一个新的 Dify 插件项目:
```bash theme={null}
dify plugin init
```
根据提示填写必填字段:
```bash theme={null}
Edit profile of the plugin
Plugin name (press Enter to next step): hello-world
Author (press Enter to next step): langgenius
Description (press Enter to next step): hello world example
Repository URL (Optional) (press Enter to next step): Repository URL (Optional)
Enable multilingual README: [✔] English is required by default
Languages to generate:
English: [✔] (required)
→ 简体中文 (Simplified Chinese): [✔]
日本語 (Japanese): [✘]
Português (Portuguese - Brazil): [✘]
Controls:
↑/↓ Navigate • Space/Tab Toggle selection • Enter Next step
```
选择 `python` 并按 Enter 继续使用 Python 插件模板。
```bash theme={null}
Select the type of plugin you want to create, and press `Enter` to continue
Before starting, here's some basic knowledge about Plugin types in Dify:
- Tool: Tool Providers like Google Search, Stable Diffusion, etc. Used to perform specific tasks.
- Model: Model Providers like OpenAI, Anthropic, etc. Use their models to enhance AI capabilities.
- Endpoint: Similar to Service API in Dify and Ingress in Kubernetes. Extend HTTP services as endpoints with custom logi
- Agent Strategy: Implement your own agent strategies like Function Calling, ReAct, ToT, CoT, etc.
Based on the ability you want to extend, Plugins are divided into four types: Tool, Model, Extension, and Agent Strategy
- Tool: A tool provider that can also implement endpoints. For example, building a Discord Bot requires both Sending and
- Model: Strictly for model providers, no other extensions allowed.
- Extension: For simple HTTP services that extend functionality.
- Agent Strategy: Implement custom agent logic with a focused approach.
We've provided templates to help you get started. Choose one of the options below:
-> tool
agent-strategy
llm
text-embedding
rerank
tts
speech2text
moderation
extension
```
输入默认的 dify 版本,留空则使用最新版本:
```bash theme={null}
Edit minimal Dify version requirement, leave it blank by default
Minimal Dify version (press Enter to next step):
```
现在你已准备就绪CLI 将创建一个以你提供的插件名称命名的新目录,并为你的插件设置基本结构。
```bash theme={null}
cd hello-world
```
## 运行插件
确保你在 hello-world 目录中
```bash theme={null}
cp .env.example .env
```
编辑 `.env` 文件以设置插件的环境变量,例如 API 密钥或其他配置。你可以在 Dify 仪表板中找到这些变量。登录到你的 Dify 环境,点击右上角的"插件"图标,然后点击调试图标(或类似虫子的图标)。在弹出窗口中,复制"API Key"和"Host Address"。(请参考你本地对应的截图,其中显示了获取密钥和主机地址的界面)
```bash theme={null}
INSTALL_METHOD=remote
REMOTE_INSTALL_HOST=debug-plugin.dify.dev
REMOTE_INSTALL_PORT=5003
REMOTE_INSTALL_KEY=********-****-****-****-************
```
现在你可以使用以下命令在本地运行你的插件:
```bash theme={null}
pip install -r requirements.txt
python -m main
```
***
[编辑此页面](https://github.com/langgenius/dify-docs/edit/main/en/develop-plugin/getting-started/cli.mdx) | [报告问题](https://github.com/langgenius/dify-docs/issues/new?template=docs.yml)

View File

@@ -1,38 +0,0 @@
# DifyPlugin
Dify插件服务 - 基于FastAPI构建
## 快速开始
### 安装依赖
```bash
pip install -r requirements.txt
```
### 运行服务
```bash
uvicorn app.main:app --reload --host 0.0.0.0 --port 8000
```
### API文档
- Swagger UI: http://localhost:8000/docs
- ReDoc: http://localhost:8000/redoc
## 项目结构
```
difyPlugin/
├── app/
│ ├── main.py # 应用入口
│ ├── config.py # 配置管理
│ ├── api/v1/ # API路由
│ ├── schemas/ # Pydantic数据模型
│ ├── services/ # 业务逻辑
│ ├── core/ # 核心功能
│ └── utils/ # 工具函数
├── requirements.txt
└── README.md
```

View File

@@ -1 +0,0 @@
# DifyPlugin FastAPI Application

View File

@@ -1,16 +0,0 @@
# API模块
from fastapi import APIRouter
from app.api.workcase import router as workcase_router
from app.api.bidding import router as bidding_router
from app.api.test import router as test_router
# 创建主路由器
router = APIRouter()
# 注册所有子路由
router.include_router(workcase_router, prefix="/workcase", tags=["工单相关服务"])
router.include_router(bidding_router, prefix="/bidding", tags=["招标相关服务"])
router.include_router(test_router, prefix="/test", tags=["招标相关服务"])
__all__ = ["router"]

View File

@@ -1,38 +0,0 @@
"""文件读取相关接口"""
from fastapi import APIRouter
from app.schemas import ResultDomain
router = APIRouter()
@router.post(
"/read",
response_model=ResultDomain[dict],
summary="读取文件",
description="读取指定路径的文件内容"
)
async def read_file(file_path: str) -> ResultDomain[dict]:
"""
读取文件内容
- **file_path**: 文件路径
"""
# TODO: 实现文件读取逻辑
return ResultDomain.success(message="读取成功", data={"content": ""})
@router.post(
"/parse",
response_model=ResultDomain[dict],
summary="解析文件",
description="解析招标文件内容"
)
async def parse_file(file_path: str) -> ResultDomain[dict]:
"""
解析招标文件
- **file_path**: 文件路径
"""
# TODO: 实现文件解析逻辑
return ResultDomain.success(message="解析成功", data={"result": {}})

View File

@@ -1,13 +0,0 @@
# API模块
from fastapi import APIRouter
from .ReadFileAPI import router as readfile_router
# 创建主路由器
router = APIRouter()
# 注册所有子路由
router.include_router(readfile_router, prefix="/readfile", tags=["文件读取相关服务"])
__all__ = ["router"]

View File

@@ -1,28 +0,0 @@
"""测试相关接口"""
from fastapi import APIRouter
from app.schemas.base import ResultDomain
router = APIRouter()
@router.get(
"/world",
response_model=ResultDomain[str],
summary="Hello World",
description="测试接口连通性"
)
async def hello_word() -> ResultDomain[str]:
"""Hello World 测试接口"""
return ResultDomain.ok(message="Hello World", data="Hello World")
@router.get(
"/ping",
response_model=ResultDomain[str],
summary="Ping测试",
description="测试服务是否正常运行"
)
async def ping() -> ResultDomain[str]:
"""Ping 测试接口"""
return ResultDomain.ok(message="pong", data="pong")

View File

@@ -1,13 +0,0 @@
# API模块
from fastapi import APIRouter
from .HelloWordAPI import router as hello_router
# 创建主路由器
router = APIRouter()
# 注册所有子路由
router.include_router(hello_router, prefix="/hello", tags=["测试服务"])
__all__ = ["router"]

View File

@@ -1,150 +0,0 @@
"""二维码相关接口 - API层"""
from fastapi import APIRouter, File, UploadFile
from app.schemas import ResultDomain
from app.services.workcase.qrcode import QrCodeService
router = APIRouter()
# 初始化服务
qrcode_service = QrCodeService()
@router.post(
"/generate",
response_model=ResultDomain[dict],
summary="生成二维码",
description="根据内容生成二维码"
)
async def generate_qrcode(
content: str,
size: int = 300,
error_correction: str = "H"
) -> ResultDomain[dict]:
"""
生成二维码
- **content**: 二维码内容
- **size**: 图片大小像素100-2000
- **error_correction**: 纠错级别
- L: 7% 容错
- M: 15% 容错
- Q: 25% 容错
- H: 30% 容错 (推荐)
"""
result = await qrcode_service.generate_qrcode(
content=content,
size=size,
error_correction=error_correction
)
if result["success"]:
return ResultDomain.success(message="生成成功", data=result)
else:
return ResultDomain.fail(message=result.get("error", "生成失败"))
@router.post(
"/parse",
response_model=ResultDomain[dict],
summary="解析二维码",
description="解析二维码图片内容支持URL、base64"
)
async def parse_qrcode(
image_source: str,
strategy: str = "auto"
) -> ResultDomain[dict]:
"""
解析二维码
- **image_source**: 图片来源
- URL: http://... 或 https://...
- base64: data:image/...;base64,...
- 本地路径: /path/to/image.png
- **strategy**: 预处理策略
- basic: 基础模式,仅尝试原图和灰度图
- auto: 自动模式,尝试多种预处理方法 (推荐)
- enhanced: 增强模式,使用更多预处理技术
- all: 全部模式,尝试所有可能的预处理方法(包括多尺度)
"""
result = await qrcode_service.parse_qrcode(
image_source=image_source,
strategy=strategy
)
if result["success"]:
return ResultDomain.success(message="解析成功", data=result)
else:
return ResultDomain.fail(
message=result.get("error", "解析失败"),
data={"total_attempts": result.get("total_attempts", 0)}
)
@router.post(
"/parse-file",
response_model=ResultDomain[dict],
summary="解析二维码文件",
description="通过文件上传解析二维码"
)
async def parse_qrcode_file(
file: UploadFile = File(...),
strategy: str = "auto"
) -> ResultDomain[dict]:
"""
解析二维码文件上传
- **file**: 二维码图片文件(支持 png/jpg/jpeg/bmp 等格式)
- **strategy**: 预处理策略 (basic/auto/enhanced/all)
"""
# 读取文件内容
content = await file.read()
# 提取文件类型
if file.content_type:
file_type = file.content_type.split("/")[-1]
else:
# 从文件名提取扩展名
file_type = file.filename.split(".")[-1] if file.filename else "png"
# 调用服务
result = await qrcode_service.parse_qrcode_from_file(
file_content=content,
file_type=file_type,
strategy=strategy
)
if result["success"]:
return ResultDomain.success(message="解析成功", data=result)
else:
return ResultDomain.fail(
message=result.get("error", "解析失败"),
data={"total_attempts": result.get("total_attempts", 0)}
)
@router.post(
"/validate",
response_model=ResultDomain[dict],
summary="验证二维码内容",
description="验证内容是否适合生成二维码"
)
async def validate_qrcode_content(
content: str,
max_length: int = 2953
) -> ResultDomain[dict]:
"""
验证二维码内容
- **content**: 要验证的内容
- **max_length**: 最大长度(字节)
"""
result = qrcode_service.validate_qrcode_content(content, max_length)
if result["valid"]:
return ResultDomain.success(
message="内容有效",
data={"length": result["length"]}
)
else:
return ResultDomain.fail(message=result.get("error", "内容无效"))

View File

@@ -1,13 +0,0 @@
# API模块
from fastapi import APIRouter
from .QrCodeAPI import router as qrcode_router
# 创建主路由器
router = APIRouter()
# 注册所有子路由
router.include_router(qrcode_router, prefix="/qrcode", tags=["二维码相关服务"])
__all__ = ["router"]

View File

@@ -1,38 +0,0 @@
"""应用配置管理"""
from pydantic_settings import BaseSettings
from functools import lru_cache
class Settings(BaseSettings):
"""应用配置"""
# 应用基础配置
APP_NAME: str = "DifyPlugin"
APP_VERSION: str = "1.0.0"
DEBUG: bool = False
# API配置
API_V1_PREFIX: str = "/api/v1"
HOST: str = "0.0.0.0"
API_HOST: str = "localhost" # OpenAPI servers 显示的地址
PORT: int = 8380
# 跨域配置
CORS_ORIGINS: list[str] = ["*"]
# Redis配置
REDIS_HOST: str = "localhost"
REDIS_PORT: int = 6379
REDIS_PASSWORD: str = "123456"
REDIS_DB: int = 0
class Config:
env_file = ".env"
case_sensitive = True
@lru_cache()
def get_settings() -> Settings:
return Settings()
settings = get_settings()

View File

@@ -1 +0,0 @@
# Core模块

View File

@@ -1,42 +0,0 @@
"""自定义异常和异常处理器"""
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
from app.schemas.base import ResultDomain
class BusinessException(Exception):
"""业务异常"""
def __init__(self, code: int = 500, message: str = "业务异常"):
self.code = code
self.message = message
class NotFoundException(BusinessException):
"""资源不存在异常"""
def __init__(self, message: str = "资源不存在"):
super().__init__(code=404, message=message)
class ValidationException(BusinessException):
"""参数校验异常"""
def __init__(self, message: str = "参数校验失败"):
super().__init__(code=400, message=message)
def register_exception_handlers(app: FastAPI):
"""注册全局异常处理器"""
@app.exception_handler(BusinessException)
async def business_exception_handler(request: Request, exc: BusinessException):
return JSONResponse(
status_code=200,
content=ResultDomain.fail(message=exc.message, code=exc.code).model_dump()
)
@app.exception_handler(Exception)
async def global_exception_handler(request: Request, exc: Exception):
return JSONResponse(
status_code=500,
content=ResultDomain.fail(message=str(exc), code=500).model_dump()
)

View File

@@ -1,26 +0,0 @@
"""中间件定义"""
import time
import logging
from fastapi import Request
from starlette.middleware.base import BaseHTTPMiddleware
logger = logging.getLogger(__name__)
class RequestLoggingMiddleware(BaseHTTPMiddleware):
"""请求日志中间件"""
async def dispatch(self, request: Request, call_next):
start_time = time.time()
response = await call_next(request)
process_time = time.time() - start_time
logger.info(
f"{request.method} {request.url.path} "
f"- Status: {response.status_code} "
f"- Time: {process_time:.3f}s"
)
response.headers["X-Process-Time"] = str(process_time)
return response

View File

@@ -1,128 +0,0 @@
"""Redis 服务"""
import json
from typing import Any, Optional, Union
import redis.asyncio as redis
from redis.asyncio import Redis
from app.config import settings
class RedisService:
"""Redis 服务类"""
_client: Optional[Redis] = None
@classmethod
async def init(cls) -> None:
"""初始化 Redis 连接"""
cls._client = redis.Redis(
host=settings.REDIS_HOST,
port=settings.REDIS_PORT,
password=settings.REDIS_PASSWORD or None,
db=settings.REDIS_DB,
decode_responses=True
)
@classmethod
async def close(cls) -> None:
"""关闭 Redis 连接"""
if cls._client:
await cls._client.close()
cls._client = None
@classmethod
def get_client(cls) -> Redis:
"""获取 Redis 客户端"""
if not cls._client:
raise RuntimeError("Redis 未初始化,请先调用 init()")
return cls._client
# ==================== String 操作 ====================
@classmethod
async def get(cls, key: str) -> Optional[str]:
"""获取值"""
return await cls.get_client().get(key)
@classmethod
async def set(cls, key: str, value: Union[str, int, float], expire: Optional[int] = None) -> bool:
"""设置值"""
return await cls.get_client().set(key, value, ex=expire)
@classmethod
async def delete(cls, *keys: str) -> int:
"""删除键"""
return await cls.get_client().delete(*keys)
@classmethod
async def exists(cls, key: str) -> bool:
"""判断键是否存在"""
return await cls.get_client().exists(key) > 0
@classmethod
async def expire(cls, key: str, seconds: int) -> bool:
"""设置过期时间"""
return await cls.get_client().expire(key, seconds)
@classmethod
async def ttl(cls, key: str) -> int:
"""获取剩余过期时间"""
return await cls.get_client().ttl(key)
# ==================== JSON 操作 ====================
@classmethod
async def get_json(cls, key: str) -> Optional[Any]:
"""获取 JSON 值"""
value = await cls.get(key)
return json.loads(value) if value else None
@classmethod
async def set_json(cls, key: str, value: Any, expire: Optional[int] = None) -> bool:
"""设置 JSON 值"""
return await cls.set(key, json.dumps(value, ensure_ascii=False), expire)
# ==================== Hash 操作 ====================
@classmethod
async def hget(cls, name: str, key: str) -> Optional[str]:
"""获取 Hash 字段值"""
return await cls.get_client().hget(name, key)
@classmethod
async def hset(cls, name: str, key: str, value: str) -> int:
"""设置 Hash 字段值"""
return await cls.get_client().hset(name, key, value)
@classmethod
async def hgetall(cls, name: str) -> dict:
"""获取 Hash 所有字段"""
return await cls.get_client().hgetall(name)
@classmethod
async def hdel(cls, name: str, *keys: str) -> int:
"""删除 Hash 字段"""
return await cls.get_client().hdel(name, *keys)
# ==================== List 操作 ====================
@classmethod
async def lpush(cls, key: str, *values: str) -> int:
"""左侧插入列表"""
return await cls.get_client().lpush(key, *values)
@classmethod
async def rpush(cls, key: str, *values: str) -> int:
"""右侧插入列表"""
return await cls.get_client().rpush(key, *values)
@classmethod
async def lrange(cls, key: str, start: int = 0, end: int = -1) -> list:
"""获取列表范围"""
return await cls.get_client().lrange(key, start, end)
@classmethod
async def llen(cls, key: str) -> int:
"""获取列表长度"""
return await cls.get_client().llen(key)

View File

@@ -1,79 +0,0 @@
"""FastAPI 应用入口"""
from contextlib import asynccontextmanager
import os
import sys
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from app.config import settings
from app.api import router as api_router
from app.core.exceptions import register_exception_handlers
from app.core.redis import RedisService
@asynccontextmanager
async def lifespan(app: FastAPI):
"""应用生命周期管理"""
# 启动时初始化
await RedisService.init()
yield
# 关闭时清理
await RedisService.close()
def create_app() -> FastAPI:
"""创建FastAPI应用实例"""
app = FastAPI(
title=settings.APP_NAME,
version=settings.APP_VERSION,
description="Dify插件服务API",
openapi_url=f"{settings.API_V1_PREFIX}/openapi.json",
docs_url="/docs",
redoc_url="/redoc",
lifespan=lifespan,
servers=[
{"url": f"http://{settings.API_HOST}:{settings.PORT}", "description": "API服务器"},
],
)
# 注册CORS中间件
app.add_middleware(
CORSMiddleware,
allow_origins=settings.CORS_ORIGINS,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# 注册异常处理器
register_exception_handlers(app)
# 注册路由
app.include_router(api_router, prefix=settings.API_V1_PREFIX)
return app
app = create_app()
def print_routes(app: FastAPI):
"""打印所有注册的路由"""
print("\n" + "=" * 60)
print("Registered Routes:")
print("=" * 60)
for route in app.routes:
if hasattr(route, "methods"):
methods = ", ".join(route.methods - {"HEAD", "OPTIONS"})
print(f" {methods:8} {route.path}")
print("=" * 60 + "\n")
# 启动时打印路由
print_routes(app)
@app.get("/health", tags=["健康检查"], summary="健康检查接口")
async def health_check():
"""服务健康检查"""

View File

@@ -1,4 +0,0 @@
from app.schemas.base import ResultDomain
from app.schemas.plugin import PluginRequest, PluginResponse
__all__ = ["ResultDomain", "PluginRequest", "PluginResponse"]

View File

@@ -1,52 +0,0 @@
"""统一返回类型定义"""
from typing import TypeVar, Generic, Optional, List, Any
from pydantic import BaseModel, Field
T = TypeVar('T')
class PageDomain(BaseModel, Generic[T]):
"""分页数据模型"""
page: int = Field(default=1, description="当前页码")
pageSize: int = Field(default=10, description="每页大小")
total: int = Field(default=0, description="总记录数")
dataList: Optional[List[T]] = Field(default=None, description="数据列表")
class ResultDomain(BaseModel, Generic[T]):
"""统一返回类型"""
code: Optional[int] = Field(default=None, description="状态码")
success: Optional[bool] = Field(default=None, description="是否成功")
message: Optional[str] = Field(default=None, description="返回消息")
data: Optional[T] = Field(default=None, description="单条数据")
dataList: Optional[List[T]] = Field(default=None, description="数据列表")
pageDomain: Optional[PageDomain[T]] = Field(default=None, description="分页数据")
@staticmethod
def ok(message: str = "success", data: Any = None) -> "ResultDomain":
"""成功返回 - 单条数据"""
return ResultDomain(code=200, success=True, message=message, data=data)
@staticmethod
def ok_list(message: str = "success", data_list: List[Any] = None) -> "ResultDomain":
"""成功返回 - 数据列表"""
return ResultDomain(code=200, success=True, message=message, dataList=data_list)
@staticmethod
def ok_page(message: str = "success", page_domain: "PageDomain" = None) -> "ResultDomain":
"""成功返回 - 分页数据"""
result = ResultDomain(code=200, success=True, message=message, pageDomain=page_domain)
if page_domain:
result.dataList = page_domain.dataList
return result
@staticmethod
def fail(message: str = "failure", code: int = 500) -> "ResultDomain":
"""失败返回"""
return ResultDomain(code=code, success=False, message=message)
model_config = {
"json_schema_extra": {
"examples": [{"code": 200, "success": True, "message": "操作成功"}]
}
}

View File

@@ -1,43 +0,0 @@
"""插件相关数据模型"""
from typing import Optional, Dict, Any
from pydantic import BaseModel, Field
class PluginRequest(BaseModel):
"""
插件请求模型
Attributes:
plugin_id: 插件ID
action: 执行动作
params: 请求参数
"""
plugin_id: str = Field(..., description="插件ID", examples=["plugin_001"])
action: str = Field(..., description="执行动作", examples=["execute"])
params: Optional[Dict[str, Any]] = Field(default=None, description="请求参数")
model_config = {
"json_schema_extra": {
"examples": [
{
"plugin_id": "plugin_001",
"action": "execute",
"params": {"key": "value"}
}
]
}
}
class PluginResponse(BaseModel):
"""
插件响应模型
Attributes:
plugin_id: 插件ID
result: 执行结果
status: 执行状态
"""
plugin_id: str = Field(..., description="插件ID")
result: Optional[Dict[str, Any]] = Field(default=None, description="执行结果")
status: str = Field(default="success", description="执行状态")

View File

@@ -1,2 +0,0 @@
__all__ = []

View File

@@ -1,298 +0,0 @@
# -*- coding: utf-8 -*-
"""二维码处理核心类 - 基于 OpenCV QRCodeDetector
本模块使用 OpenCV 的 QRCodeDetector 进行二维码识别,
配合多种图像预处理策略,确保高识别率和跨平台兼容性。
"""
import base64
import io
from typing import Optional, Callable, Tuple
import cv2
import httpx
import numpy as np
import qrcode
from PIL import Image
class QRCodeProcessor:
"""二维码处理器 - 负责二维码的生成、解析和图像预处理"""
# 预处理策略映射
PREPROCESSING_STRATEGIES = {
"original": ("原图", lambda img, gray: img),
"grayscale": ("灰度图", lambda img, gray: cv2.cvtColor(gray, cv2.COLOR_GRAY2BGR)),
"clahe": ("CLAHE增强", lambda img, gray: cv2.cvtColor(
cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8)).apply(gray),
cv2.COLOR_GRAY2BGR
)),
"adaptive_threshold": ("自适应二值化", lambda img, gray: cv2.cvtColor(
cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2),
cv2.COLOR_GRAY2BGR
)),
"otsu": ("Otsu二值化", lambda img, gray: cv2.cvtColor(
cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1],
cv2.COLOR_GRAY2BGR
)),
"denoise": ("去噪+二值化", lambda img, gray: cv2.cvtColor(
cv2.threshold(
cv2.fastNlMeansDenoising(gray, None, 10, 7, 21),
0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU
)[1],
cv2.COLOR_GRAY2BGR
)),
"sharpen": ("锐化", lambda img, gray: cv2.cvtColor(
cv2.filter2D(gray, -1, np.array([[-1, -1, -1], [-1, 9, -1], [-1, -1, -1]])),
cv2.COLOR_GRAY2BGR
)),
"morphology": ("形态学处理", lambda img, gray: cv2.cvtColor(
cv2.morphologyEx(
cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2),
cv2.MORPH_CLOSE,
cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
),
cv2.COLOR_GRAY2BGR
)),
"scale_0.5": ("0.5x缩放", lambda img, gray: cv2.resize(
img, None, fx=0.5, fy=0.5, interpolation=cv2.INTER_AREA
)),
"scale_1.5": ("1.5x缩放", lambda img, gray: cv2.resize(
img, None, fx=1.5, fy=1.5, interpolation=cv2.INTER_CUBIC
)),
"scale_2.0": ("2.0x缩放", lambda img, gray: cv2.resize(
img, None, fx=2.0, fy=2.0, interpolation=cv2.INTER_CUBIC
)),
}
# 策略组合映射
STRATEGY_MAP = {
"basic": ["original", "grayscale"],
"enhanced": ["original", "grayscale", "clahe", "adaptive_threshold", "otsu", "denoise", "sharpen", "morphology"],
"all": ["original", "grayscale", "clahe", "adaptive_threshold", "otsu", "denoise", "sharpen", "morphology", "scale_0.5", "scale_1.5", "scale_2.0"],
}
@staticmethod
def generate(
content: str,
size: int = 300,
error_correction: str = "H",
box_size: int = 10,
border: int = 4
) -> str:
"""
生成二维码
Args:
content: 二维码内容
size: 图片大小(像素)
error_correction: 纠错级别 (L/M/Q/H)
box_size: 每个格子的像素大小
border: 边框大小(格子数)
Returns:
base64编码的图片数据 (data:image/png;base64,...)
Raises:
ValueError: 参数错误时抛出异常
"""
# 验证纠错级别
error_levels = {
"L": qrcode.constants.ERROR_CORRECT_L, # 7% 容错
"M": qrcode.constants.ERROR_CORRECT_M, # 15% 容错
"Q": qrcode.constants.ERROR_CORRECT_Q, # 25% 容错
"H": qrcode.constants.ERROR_CORRECT_H, # 30% 容错
}
if error_correction not in error_levels:
raise ValueError(f"无效的纠错级别: {error_correction},支持: L/M/Q/H")
# 创建二维码对象
qr = qrcode.QRCode(
version=None, # 自动确定版本
error_correction=error_levels[error_correction],
box_size=box_size,
border=border,
)
# 添加数据并生成
qr.add_data(content)
qr.make(fit=True)
# 生成图片
img = qr.make_image(fill_color="black", back_color="white")
# 调整到指定大小
img = img.resize((size, size), Image.Resampling.LANCZOS)
# 转换为base64
buffer = io.BytesIO()
img.save(buffer, format="PNG")
img_base64 = base64.b64encode(buffer.getvalue()).decode()
return f"data:image/png;base64,{img_base64}"
@staticmethod
async def load_image(image_source: str) -> np.ndarray:
"""
加载图片支持URL、base64、本地路径
Args:
image_source: 图片来源
- URL: http://... 或 https://...
- base64: data:image/...;base64,...
- 本地路径: /path/to/image.png
Returns:
OpenCV图片对象 (BGR格式)
Raises:
ValueError: 图片加载失败时抛出异常
"""
try:
# 检查是否为base64
if image_source.startswith("data:image"):
# 提取base64数据
base64_data = image_source.split(",")[1]
img_data = base64.b64decode(base64_data)
img_array = np.frombuffer(img_data, np.uint8)
img = cv2.imdecode(img_array, cv2.IMREAD_COLOR)
elif image_source.startswith("http://") or image_source.startswith("https://"):
# 下载图片
async with httpx.AsyncClient(timeout=30.0) as client:
response = await client.get(image_source)
response.raise_for_status()
img_array = np.frombuffer(response.content, np.uint8)
img = cv2.imdecode(img_array, cv2.IMREAD_COLOR)
else:
# 本地文件
img = cv2.imread(image_source)
if img is None:
raise ValueError("无法解析图片数据")
return img
except Exception as e:
raise ValueError(f"图片加载失败: {str(e)}")
@staticmethod
async def search_qrcode(img: np.ndarray)-> list[np.ndarray]:
"""
搜索二维码,只搜索不解析
Args:
img: OpenCV图像对象
Returns:
二维码列表
"""
detector = cv2.QRCodeDetector()
imgs = detector.detect(img)
@staticmethod
def decode(img: np.ndarray) -> Optional[str]:
"""
使用 OpenCV QRCodeDetector 解码二维码
Args:
img: OpenCV图像对象
Returns:
二维码内容如果没有检测到返回None
"""
detector = cv2.QRCodeDetector()
data, bbox, _ = detector.detectAndDecode(img)
if data:
return data
return None
@staticmethod
async def parse(
image_source: str,
strategy: str = "auto"
) -> dict:
"""
解析二维码(使用 OpenCV + 按需预处理策略)
解码策略:
1. 根据 strategy 参数选择预处理步骤列表
2. 按需应用每种预处理算法并立即尝试解码
3. 一旦成功立即返回,避免不必要的计算
Args:
image_source: 图片来源URL/base64/本地路径)
strategy: 预处理策略
- basic: 原图 + 灰度图2种
- enhanced: basic + 6种增强算法8种
- all: auto + 多尺度11种
Returns:
解析结果字典:
{
"success": bool,
"content": str or None,
"strategy_used": str, # 使用的预处理策略名称
"preprocessing_index": int, # 预处理索引
"total_attempts": int,
"message": str # 仅失败时有
}
"""
# 验证策略参数
if strategy not in QRCodeProcessor.STRATEGY_MAP:
raise ValueError(f"无效的策略: {strategy},支持: {list(QRCodeProcessor.STRATEGY_MAP.keys())}")
# 加载原始图片
img = await QRCodeProcessor.load_image(image_source)
# 预先生成灰度图(很多预处理都需要)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 获取该策略对应的预处理步骤列表
preprocessing_steps = QRCodeProcessor.STRATEGY_MAP[strategy]
# 依次应用每种预处理并尝试解码
for idx, step_key in enumerate(preprocessing_steps):
strategy_name, preprocess_func = QRCodeProcessor.PREPROCESSING_STRATEGIES[step_key]
try:
# 按需处理图像
processed_img = preprocess_func(img, gray)
# 立即尝试解码
result = QRCodeProcessor.decode(processed_img)
if result:
# 解码成功,立即返回
return {
"success": True,
"content": result,
"strategy_used": f"opencv_{strategy_name}",
"preprocessing_index": idx,
"total_attempts": idx + 1
}
except Exception as e:
# 某个预处理步骤失败,继续尝试下一个
continue
# 所有预处理方法都失败
return {
"success": False,
"content": None,
"message": f"未检测到二维码或二维码损坏(已尝试 {len(preprocessing_steps)} 种预处理)",
"total_attempts": len(preprocessing_steps)
}
if __name__ == "__main__":
import asyncio
async def main():
# 示例用法
result = await QRCodeProcessor.parse("F:/Project/urbanLifeline/docs/qrcode.png", "enhanced")
print(result)
asyncio.run(main())

View File

@@ -1,201 +0,0 @@
"""二维码服务层 - 提供统一的业务逻辑接口"""
import base64
from typing import Optional
from .QrCode import QRCodeProcessor
class QrCodeService:
"""二维码服务 - 业务逻辑层"""
def __init__(self):
"""初始化服务"""
self.processor = QRCodeProcessor()
async def generate_qrcode(
self,
content: str,
size: int = 300,
error_correction: str = "H"
) -> dict:
"""
生成二维码
Args:
content: 二维码内容
size: 图片大小(像素)
error_correction: 纠错级别 (L/M/Q/H)
Returns:
{
"success": bool,
"image": str, # base64编码的图片
"content": str,
"size": int,
"error_correction": str,
"error": str # 仅失败时有
}
"""
try:
# 验证参数
if not content:
return {
"success": False,
"error": "内容不能为空"
}
if size < 100 or size > 2000:
return {
"success": False,
"error": "尺寸必须在100-2000之间"
}
if error_correction not in ["L", "M", "Q", "H"]:
return {
"success": False,
"error": "纠错级别必须是 L/M/Q/H 之一"
}
# 生成二维码
img_base64 = self.processor.generate(
content=content,
size=size,
error_correction=error_correction
)
return {
"success": True,
"image": img_base64,
"content": content,
"size": size,
"error_correction": error_correction
}
except Exception as e:
return {
"success": False,
"error": f"生成失败: {str(e)}"
}
async def parse_qrcode(
self,
image_source: str,
strategy: str = "auto"
) -> dict:
"""
解析二维码
Args:
image_source: 图片来源URL/base64/本地路径)
strategy: 预处理策略 (basic/auto/enhanced/all)
Returns:
{
"success": bool,
"content": str or None,
"strategy_used": str,
"total_attempts": int,
"error": str # 仅失败时有
}
"""
try:
# 验证参数
if not image_source:
return {
"success": False,
"error": "图片来源不能为空"
}
if strategy not in ["basic", "auto", "enhanced", "all"]:
return {
"success": False,
"error": "策略必须是 basic/auto/enhanced/all 之一"
}
# 解析二维码
result = await self.processor.parse(image_source, strategy)
if result["success"]:
return result
else:
return {
"success": False,
"content": None,
"error": result.get("message", "解析失败"),
"total_attempts": result.get("total_attempts", 0)
}
except Exception as e:
return {
"success": False,
"content": None,
"error": f"解析失败: {str(e)}"
}
async def parse_qrcode_from_file(
self,
file_content: bytes,
file_type: str = "png",
strategy: str = "auto"
) -> dict:
"""
从文件内容解析二维码
Args:
file_content: 文件二进制内容
file_type: 文件类型 (png/jpg/jpeg等)
strategy: 预处理策略
Returns:
解析结果格式同parse_qrcode
"""
try:
# 转换为base64
img_base64 = base64.b64encode(file_content).decode()
image_source = f"data:image/{file_type};base64,{img_base64}"
# 调用解析方法
return await self.parse_qrcode(image_source, strategy)
except Exception as e:
return {
"success": False,
"content": None,
"error": f"文件解析失败: {str(e)}"
}
def validate_qrcode_content(self, content: str, max_length: int = 2953) -> dict:
"""
验证二维码内容是否合法
Args:
content: 要验证的内容
max_length: 最大长度默认2953字节version 40 with L级别
Returns:
{
"valid": bool,
"length": int,
"error": str # 仅无效时有
}
"""
if not content:
return {
"valid": False,
"error": "内容不能为空"
}
content_bytes = content.encode("utf-8")
length = len(content_bytes)
if length > max_length:
return {
"valid": False,
"length": length,
"error": f"内容过长,当前{length}字节,最大支持{max_length}字节"
}
return {
"valid": True,
"length": length
}

View File

@@ -1,4 +0,0 @@
"""二维码服务模块"""
from .QrCodeService import QrCodeService
__all__ = ["QrCodeService"]

View File

@@ -1,324 +0,0 @@
"""二维码服务测试脚本
使用方法:
python test_qrcode.py
测试内容:
1. 生成二维码
2. 解析生成的二维码
3. 测试不同的预处理策略
4. 测试错误处理
"""
import asyncio
import os
import sys
from pathlib import Path
# 添加项目根目录到Python路径
project_root = Path(__file__).parent.parent.parent.parent
sys.path.insert(0, str(project_root))
from app.services.workcase.qrcode import QrCodeService
class QRCodeTester:
"""二维码服务测试类"""
def __init__(self):
self.service = QrCodeService()
self.test_results = []
def print_header(self, title: str):
"""打印测试标题"""
print("\n" + "=" * 60)
print(f" {title}")
print("=" * 60)
def print_result(self, test_name: str, success: bool, details: str = ""):
"""打印测试结果"""
status = "✓ 通过" if success else "✗ 失败"
print(f"\n{status} - {test_name}")
if details:
print(f" 详情: {details}")
self.test_results.append((test_name, success))
async def test_generate_qrcode(self):
"""测试生成二维码"""
self.print_header("测试1: 生成二维码")
# 测试1.1: 基本生成
result = await self.service.generate_qrcode(
content="https://github.com",
size=300,
error_correction="H"
)
if result["success"] and "image" in result:
self.print_result(
"1.1 基本生成",
True,
f"内容长度: {len(result['image'])} 字符"
)
# 保存生成的图片用于后续测试
self.generated_image = result["image"]
else:
self.print_result("1.1 基本生成", False, result.get("error", "未知错误"))
self.generated_image = None
# 测试1.2: 不同纠错级别
for level in ["L", "M", "Q", "H"]:
result = await self.service.generate_qrcode(
content="测试内容",
size=200,
error_correction=level
)
self.print_result(
f"1.2 纠错级别 {level}",
result["success"],
f"图片大小: {result.get('size', 'N/A')}"
)
# 测试1.3: 参数验证
result = await self.service.generate_qrcode(
content="",
size=300,
error_correction="H"
)
self.print_result(
"1.3 空内容验证",
not result["success"],
result.get("error", "")
)
# 测试1.4: 无效尺寸
result = await self.service.generate_qrcode(
content="test",
size=50, # 太小
error_correction="H"
)
self.print_result(
"1.4 无效尺寸验证",
not result["success"],
result.get("error", "")
)
async def test_parse_qrcode(self):
"""测试解析二维码"""
self.print_header("测试2: 解析二维码")
if not self.generated_image:
print("⚠ 跳过解析测试(没有生成的图片)")
return
# 测试2.1: 解析自己生成的二维码
result = await self.service.parse_qrcode(
image_source=self.generated_image,
strategy="auto"
)
if result["success"]:
self.print_result(
"2.1 解析生成的二维码",
True,
f"内容: {result['content']}, 尝试次数: {result.get('total_attempts', 0)}"
)
else:
self.print_result(
"2.1 解析生成的二维码",
False,
result.get("error", "未知错误")
)
# 测试2.2: 测试不同策略
for strategy in ["basic", "auto", "enhanced"]:
result = await self.service.parse_qrcode(
image_source=self.generated_image,
strategy=strategy
)
self.print_result(
f"2.2 策略 {strategy}",
result["success"],
f"尝试次数: {result.get('total_attempts', 0)}"
)
# 测试2.3: 无效输入
result = await self.service.parse_qrcode(
image_source="",
strategy="auto"
)
self.print_result(
"2.3 空图片源验证",
not result["success"],
result.get("error", "")
)
async def test_validate_content(self):
"""测试内容验证"""
self.print_header("测试3: 内容验证")
# 测试3.1: 正常内容
result = self.service.validate_qrcode_content("https://example.com")
self.print_result(
"3.1 正常内容",
result["valid"],
f"长度: {result.get('length', 0)} 字节"
)
# 测试3.2: 空内容
result = self.service.validate_qrcode_content("")
self.print_result(
"3.2 空内容",
not result["valid"],
result.get("error", "")
)
# 测试3.3: 超长内容
long_content = "a" * 3000
result = self.service.validate_qrcode_content(long_content)
self.print_result(
"3.3 超长内容",
not result["valid"],
result.get("error", "")
)
# 测试3.4: 中文内容
result = self.service.validate_qrcode_content("这是一段中文测试内容")
self.print_result(
"3.4 中文内容",
result["valid"],
f"长度: {result.get('length', 0)} 字节"
)
async def test_integration(self):
"""集成测试:生成 -> 解析 -> 验证"""
self.print_header("测试4: 集成测试")
test_contents = [
"https://github.com",
"简单文本",
"{'key': 'value', 'number': 123}", # JSON
"mailto:test@example.com",
"tel:+86-123-4567-8900"
]
for idx, content in enumerate(test_contents, 1):
# 生成
gen_result = await self.service.generate_qrcode(
content=content,
size=300,
error_correction="H"
)
if not gen_result["success"]:
self.print_result(
f"4.{idx} 集成测试: {content[:20]}...",
False,
"生成失败"
)
continue
# 解析
parse_result = await self.service.parse_qrcode(
image_source=gen_result["image"],
strategy="auto"
)
# 验证内容是否一致
success = (
parse_result["success"] and
parse_result.get("content") == content
)
self.print_result(
f"4.{idx} {content[:30]}",
success,
f"原始: {content[:20]}... | 解析: {parse_result.get('content', '')[:20]}..."
)
async def test_error_handling(self):
"""测试错误处理"""
self.print_header("测试5: 错误处理")
# 测试5.1: 无效的图片URL
result = await self.service.parse_qrcode(
image_source="https://invalid-url-that-does-not-exist.com/image.png",
strategy="auto"
)
self.print_result(
"5.1 无效URL处理",
not result["success"],
result.get("error", "")[:50]
)
# 测试5.2: 无效的base64
result = await self.service.parse_qrcode(
image_source="data:image/png;base64,invalid_base64",
strategy="auto"
)
self.print_result(
"5.2 无效base64处理",
not result["success"],
result.get("error", "")[:50]
)
# 测试5.3: 无效的纠错级别
result = await self.service.generate_qrcode(
content="test",
size=300,
error_correction="X" # 无效
)
self.print_result(
"5.3 无效纠错级别",
not result["success"],
result.get("error", "")
)
def print_summary(self):
"""打印测试总结"""
self.print_header("测试总结")
total = len(self.test_results)
passed = sum(1 for _, success in self.test_results if success)
failed = total - passed
print(f"\n总测试数: {total}")
print(f"通过: {passed} (✓)")
print(f"失败: {failed} (✗)")
print(f"成功率: {passed/total*100:.1f}%\n")
if failed > 0:
print("失败的测试:")
for name, success in self.test_results:
if not success:
print(f" - {name}")
async def run_all_tests(self):
"""运行所有测试"""
print("\n" + "=" * 60)
print(" 二维码服务测试套件")
print("=" * 60)
try:
await self.test_generate_qrcode()
await self.test_parse_qrcode()
await self.test_validate_content()
await self.test_integration()
await self.test_error_handling()
self.print_summary()
except Exception as e:
print(f"\n❌ 测试过程中出现错误: {str(e)}")
import traceback
traceback.print_exc()
async def main():
"""主函数"""
tester = QRCodeTester()
await tester.run_all_tests()
if __name__ == "__main__":
# 运行测试
asyncio.run(main())

View File

@@ -1 +0,0 @@
# Utils模块

View File

@@ -1,22 +0,0 @@
"""工具函数"""
from typing import Any, Dict
import json
from datetime import datetime
def format_datetime(dt: datetime, fmt: str = "%Y-%m-%d %H:%M:%S") -> str:
"""格式化日期时间"""
return dt.strftime(fmt)
def safe_json_loads(json_str: str, default: Any = None) -> Any:
"""安全的JSON解析"""
try:
return json.loads(json_str)
except (json.JSONDecodeError, TypeError):
return default
def dict_filter_none(data: Dict[str, Any]) -> Dict[str, Any]:
"""过滤字典中的None值"""
return {k: v for k, v in data.items() if v is not None}

View File

@@ -1,78 +0,0 @@
{
"openapi": "3.1.0",
"info": {
"title": "DifyPlugin",
"description": "Dify插件服务API",
"version": "1.0.0"
},
"servers": [
{
"url": "http://192.168.0.253:8380/api/v1",
"description": "开发服务器"
}
],
"paths": {
"/test/hello/world": {
"get": {
"operationId": "HelloWord",
"summary": "Hello World",
"description": "测试接口连通性",
"responses": {
"200": {
"description": "成功响应",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ResultDomain"
}
}
}
}
}
}
},
"/test/hello/ping": {
"get": {
"operationId": "Ping",
"summary": "Ping测试",
"description": "测试服务是否正常运行",
"responses": {
"200": {
"description": "成功响应",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ResultDomain"
}
}
}
}
}
}
}
},
"components": {
"schemas": {
"ResultDomain": {
"type": "object",
"properties": {
"code": {
"type": "integer",
"description": "状态码"
},
"success": {
"type": "boolean",
"description": "是否成功"
},
"message": {
"type": "string",
"description": "返回消息"
},
"data": {
"description": "返回数据"
}
}
}
}
}
}

View File

@@ -1,372 +0,0 @@
# 二维码服务 README
## 功能概述
基于 **OpenCV QRCodeDetector** 的高性能二维码生成和解析服务,配合多种图像预处理策略,确保高识别率。
### 核心特性
**纯 OpenCV 引擎** - 无需额外依赖,跨平台稳定
**8种预处理策略** - CLAHE、二值化、去噪、锐化等
**多种输入方式** - URL、base64、文件上传
**智能容错** - 自动尝试多种预处理策略直到成功
**企业级稳定性** - Windows/Linux 完美支持,无 DLL 问题
---
## 快速开始
### 1. 安装依赖
```bash
pip install -r requirements.txt
```
所有依赖都是标准库,无需额外配置!
### 2. 测试服务
```bash
# 运行测试脚本
python app/services/workcase/qrcode/test_qrcode.py
```
### 3. 启动服务
```bash
uvicorn app.main:app --reload
```
---
## API 使用
### 生成二维码
**请求:**
```http
POST /api/workcase/qrcode/generate
Content-Type: application/json
{
"content": "https://github.com",
"size": 300,
"error_correction": "H"
}
```
**响应:**
```json
{
"code": 200,
"message": "生成成功",
"data": {
"success": true,
"image": "data:image/png;base64,iVBORw0KG...",
"content": "https://github.com",
"size": 300,
"error_correction": "H"
}
}
```
**参数说明:**
- `content`: 二维码内容(必填)
- `size`: 图片大小100-2000像素默认 300
- `error_correction`: 纠错级别
- `L`: 7% 容错
- `M`: 15% 容错
- `Q`: 25% 容错
- `H`: 30% 容错(默认,推荐)
---
### 解析二维码URL/base64
**请求:**
```http
POST /api/workcase/qrcode/parse
Content-Type: application/json
{
"image_source": "https://example.com/qrcode.png",
"strategy": "auto"
}
```
**响应:**
```json
{
"code": 200,
"message": "解析成功",
"data": {
"success": true,
"content": "https://github.com",
"strategy_used": "opencv_灰度图",
"preprocessing_index": 1,
"total_attempts": 2
}
}
```
**参数说明:**
- `image_source`: 图片来源(必填)
- URL: `https://...`
- base64: `data:image/png;base64,...`
- 本地路径: `/path/to/image.png`
- `strategy`: 预处理策略
- `basic`: 基础模式2种- 快速
- `auto`: 自动模式8种- **推荐**
- `enhanced`: 增强模式8种
- `all`: 全部模式11种- 包括多尺度
---
### 解析二维码(文件上传)
**请求:**
```http
POST /api/workcase/qrcode/parse-file
Content-Type: multipart/form-data
file: [二维码图片文件]
strategy: auto
```
---
### 验证二维码内容
**请求:**
```http
POST /api/workcase/qrcode/validate
Content-Type: application/json
{
"content": "要验证的内容",
"max_length": 2953
}
```
---
## 预处理策略详解
### basic 模式2种
1. **原图**
2. **灰度图**
**适用场景:** 清晰二维码,追求速度
**性能:** 最快,< 100ms
### auto 模式8种⭐ 推荐
1. **原图**
2. **灰度图**
3. **CLAHE 对比度增强** - 光照不均
4. **自适应二值化** - 复杂背景
5. **Otsu 二值化** - 自动阈值
6. **去噪 + 二值化** - 模糊图片
7. **锐化处理** - 增强边缘
8. **形态学处理** - 修复断裂
**适用场景:**
- 光照不均
- 模糊/噪声
- 低对比度
- 轻微损坏
**性能:** 平衡200-500ms
### all 模式11种
auto 基础上增加多尺度
9. **0.5x 缩放**
10. **1.5x 缩放**
11. **2.0x 缩放**
**适用场景:**
- 分辨率问题
- 尺寸过小/过大
**性能:** 较慢500-1000ms
---
## 服务层使用Python
```python
from app.services.workcase.qrcode import QrCodeService
# 初始化服务
service = QrCodeService()
# 生成二维码
result = await service.generate_qrcode(
content="https://github.com",
size=300,
error_correction="H"
)
print(result["image"]) # base64 图片
# 解析二维码
result = await service.parse_qrcode(
image_source="https://example.com/qr.png",
strategy="auto"
)
print(result["content"]) # 解析结果
# 验证内容
result = service.validate_qrcode_content("测试内容")
print(result["valid"]) # True/False
```
---
## 性能优化建议
### 提高识别速度
1. 使用 `basic` 策略清晰图片场景
2. 调整图片大小到 300-500px
3. 预先转换为灰度图
### 提高识别率
1. 使用 `auto` `all` 策略
2. 确保图片分辨率足够二维码 100x100px
3. 提高二维码纠错级别使用 H
### 批量处理
```python
import asyncio
async def batch_parse(image_sources):
service = QrCodeService()
tasks = [
service.parse_qrcode(src, strategy="basic")
for src in image_sources
]
return await asyncio.gather(*tasks)
# 使用
results = await batch_parse([
"https://example.com/qr1.png",
"https://example.com/qr2.png",
"https://example.com/qr3.png"
])
```
---
## 为什么选择纯 OpenCV 方案?
### 技术优势
| 特性 | OpenCV | pyzbar | 说明 |
|------|--------|---------|------|
| **跨平台** | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | OpenCV 无需额外配置 |
| **Windows 友好** | ⭐⭐⭐⭐⭐ | ⭐⭐ | pyzbar 需要手动安装 DLL |
| **安装难度** | ⭐⭐⭐⭐⭐ | ⭐⭐ | pip install 即可 vs 需要 libzbar |
| **识别率(清晰)** | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | 相当 |
| **识别率(模糊)** | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | 配合预处理差距不大 |
| **稳定性** | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | OpenCV 更成熟 |
| **维护性** | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | 依赖少问题少 |
### 工程实践建议
**推荐使用 OpenCV**因为
1. **无依赖地狱** - 不用担心 Windows DLLLinux .so 问题
2. **企业级稳定** - OpenCV Intel 支持久经考验
3. **预处理补偿** - 8种预处理策略让识别率不输 pyzbar
4. **运维友好** - CI/CDDocker 部署零配置
5. **团队协作** - 新成员 5 分钟即可搭建环境
**不推荐 pyzbar**除非
1. 你只在 Linux 服务器部署
2. 需要识别多种条码格式EANCode128
3. 有专人负责处理依赖问题
---
## 常见问题
### Q1: 识别率怎么样?
**答:** 配合预处理策略识别率可达 95%+
- 清晰二维码99%+
- 轻度模糊95%+
- 中度模糊85%+
- 重度损坏60%+
### Q2: 比 pyzbar 差多少?
**答:** 清晰图片无差异模糊图片差距 < 5%
- 对于大部分应用场景差异可忽略
- 配合 `all` 策略可进一步缩小差距
### Q3: 解析速度如何?
**答:**
- basic: 50-100ms
- auto: 200-500ms
- all: 500-1000ms
根据场景选择合适策略即可
### Q4: 支持哪些图片格式?
**答:** 支持所有 OpenCV 支持的格式
- PNGJPGJPEGBMPWebPTIFF
### Q5: 如何提高识别成功率?
**答:**
1. 生成时使用 H 级纠错30% 容错
2. 解析时使用 `auto` `all` 策略
3. 确保二维码尺寸 100x100px
4. 避免过度压缩图片
---
## 项目结构
```
app/services/workcase/qrcode/
├── __init__.py # 模块导出
├── QrCode.py # 核心处理器OpenCV QRCodeDetector
├── QrCodeService.py # 业务逻辑层
└── test_qrcode.py # 测试脚本
docs/
└── qrcode_service_readme.md # 本文档
```
---
## 技术栈
- **qrcode** - 二维码生成
- **Pillow (PIL)** - 图像处理
- **OpenCV** - 图像预处理和解码
- **httpx** - 异步HTTP客户端
- **numpy** - 数组处理
---
## 许可证
MIT License
---
## 更新日志
### v1.1.0 (2025-12-30)
- 🔥 **完全移除 pyzbar 依赖**
- 采用纯 OpenCV QRCodeDetector 方案
- 优化预处理策略命名
- 📝 简化文档和安装流程
- 🎯 企业级稳定性提升
### v1.0.0 (2025-12-30)
- 初始版本发布
- 双引擎解码支持已废弃
- 8种预处理策略

184
difyPlugin/pdf/.difyignore Normal file
View File

@@ -0,0 +1,184 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
.python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
Pipfile.lock
# UV
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
uv.lock
# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
poetry.lock
# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
#pdm.lock
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
# in version control.
# https://pdm.fming.dev/latest/usage/project/#working-with-version-control
.pdm.toml
.pdm-python
.pdm-build/
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
.idea/
# Vscode
.vscode/
# Git
.git/
.gitignore
.github/
# Mac
.DS_Store
# Windows
Thumbs.db
# Dify plugin packages
# To prevent packaging repetitively
*.difypkg

View File

@@ -0,0 +1,3 @@
INSTALL_METHOD=remote
REMOTE_INSTALL_URL=debug.dify.ai:5003
REMOTE_INSTALL_KEY=********-****-****-****-************

View File

@@ -0,0 +1,109 @@
name: Plugin Publish Workflow
on:
release:
types: [published]
jobs:
publish:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Download CLI tool
run: |
mkdir -p $RUNNER_TEMP/bin
cd $RUNNER_TEMP/bin
wget https://github.com/langgenius/dify-plugin-daemon/releases/download/0.0.6/dify-plugin-linux-amd64
chmod +x dify-plugin-linux-amd64
echo "CLI tool location:"
pwd
ls -la dify-plugin-linux-amd64
- name: Get basic info from manifest
id: get_basic_info
run: |
PLUGIN_NAME=$(grep "^name:" manifest.yaml | cut -d' ' -f2)
echo "Plugin name: $PLUGIN_NAME"
echo "plugin_name=$PLUGIN_NAME" >> $GITHUB_OUTPUT
VERSION=$(grep "^version:" manifest.yaml | cut -d' ' -f2)
echo "Plugin version: $VERSION"
echo "version=$VERSION" >> $GITHUB_OUTPUT
# If the author's name is not your github username, you can change the author here
AUTHOR=$(grep "^author:" manifest.yaml | cut -d' ' -f2)
echo "Plugin author: $AUTHOR"
echo "author=$AUTHOR" >> $GITHUB_OUTPUT
- name: Package Plugin
id: package
run: |
cd $GITHUB_WORKSPACE
PACKAGE_NAME="${{ steps.get_basic_info.outputs.plugin_name }}-${{ steps.get_basic_info.outputs.version }}.difypkg"
$RUNNER_TEMP/bin/dify-plugin-linux-amd64 plugin package . -o "$PACKAGE_NAME"
echo "Package result:"
ls -la "$PACKAGE_NAME"
echo "package_name=$PACKAGE_NAME" >> $GITHUB_OUTPUT
echo "\nFull file path:"
pwd
echo "\nDirectory structure:"
tree || ls -R
- name: Checkout target repo
uses: actions/checkout@v3
with:
repository: ${{steps.get_basic_info.outputs.author}}/dify-plugins
path: dify-plugins
token: ${{ secrets.PLUGIN_ACTION }}
fetch-depth: 1
persist-credentials: true
- name: Prepare and create PR
run: |
PACKAGE_NAME="${{ steps.get_basic_info.outputs.plugin_name }}-${{ steps.get_basic_info.outputs.version }}.difypkg"
mkdir -p dify-plugins/${{ steps.get_basic_info.outputs.author }}/${{ steps.get_basic_info.outputs.plugin_name }}
mv "$PACKAGE_NAME" dify-plugins/${{ steps.get_basic_info.outputs.author }}/${{ steps.get_basic_info.outputs.plugin_name }}/
cd dify-plugins
git config user.name "GitHub Actions"
git config user.email "actions@github.com"
git fetch origin main
git checkout main
git pull origin main
BRANCH_NAME="bump-${{ steps.get_basic_info.outputs.plugin_name }}-plugin-${{ steps.get_basic_info.outputs.version }}"
git checkout -b "$BRANCH_NAME"
git add .
git commit -m "bump ${{ steps.get_basic_info.outputs.plugin_name }} plugin to version ${{ steps.get_basic_info.outputs.version }}"
git push -u origin "$BRANCH_NAME" --force
git branch -a
echo "Waiting for branch to sync..."
sleep 10 # Wait 10 seconds for branch sync
- name: Create PR via GitHub API
env:
# How to config the token:
# 1. Profile -> Settings -> Developer settings -> Personal access tokens -> Generate new token (with repo scope) -> Copy the token
# 2. Go to the target repository -> Settings -> Secrets and variables -> Actions -> New repository secret -> Add the token as PLUGIN_ACTION
GH_TOKEN: ${{ secrets.PLUGIN_ACTION }}
run: |
gh pr create \
--repo langgenius/dify-plugins \
--head "${{ steps.get_basic_info.outputs.author }}:${{ steps.get_basic_info.outputs.plugin_name }}-${{ steps.get_basic_info.outputs.version }}" \
--base main \
--title "bump ${{ steps.get_basic_info.outputs.plugin_name }} plugin to version ${{ steps.get_basic_info.outputs.version }}" \
--body "bump ${{ steps.get_basic_info.outputs.plugin_name }} plugin package to version ${{ steps.get_basic_info.outputs.version }}
Changes:
- Updated plugin package file" || echo "PR already exists or creation skipped." # Handle cases where PR already exists

176
difyPlugin/pdf/.gitignore vendored Normal file
View File

@@ -0,0 +1,176 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# UV
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
#uv.lock
# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock
# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
#pdm.lock
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
# in version control.
# https://pdm.fming.dev/latest/usage/project/#working-with-version-control
.pdm.toml
.pdm-python
.pdm-build/
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
.idea/
# Vscode
.vscode/
# macOS
.DS_Store
.AppleDouble
.LSOverride

137
difyPlugin/pdf/GUIDE.md Normal file
View File

@@ -0,0 +1,137 @@
# Dify Plugin Development Guide
Welcome to Dify plugin development! This guide will help you get started quickly.
## Plugin Types
Dify plugins extend three main capabilities:
| Type | Description | Example |
|------|-------------|---------|
| **Tool** | Perform specific tasks | Google Search, Stable Diffusion |
| **Model** | AI model integrations | OpenAI, Anthropic |
| **Endpoint** | HTTP services | Custom APIs, integrations |
You can create:
- **Tool**: Tool provider with optional endpoints (e.g., Discord bot)
- **Model**: Model provider only
- **Extension**: Simple HTTP service
## Setup
### Requirements
- Python 3.11+
- Dependencies: `pip install -r requirements.txt`
## Development Process
<details>
<summary><b>1. Manifest Structure</b></summary>
Edit `manifest.yaml` to describe your plugin:
```yaml
version: 0.1.0 # Required: Plugin version
type: plugin # Required: plugin or bundle
author: YourOrganization # Required: Organization name
label: # Required: Multi-language names
en_US: Plugin Name
zh_Hans: 插件名称
created_at: 2023-01-01T00:00:00Z # Required: Creation time (RFC3339)
icon: assets/icon.png # Required: Icon path
# Resources and permissions
resource:
memory: 268435456 # Max memory (bytes)
permission:
tool:
enabled: true # Tool permission
model:
enabled: true # Model permission
llm: true
text_embedding: false
# Other model types...
# Other permissions...
# Extensions definition
plugins:
tools:
- tools/my_tool.yaml # Tool definition files
models:
- models/my_model.yaml # Model definition files
endpoints:
- endpoints/my_api.yaml # Endpoint definition files
# Runtime metadata
meta:
version: 0.0.1 # Manifest format version
arch:
- amd64
- arm64
runner:
language: python
version: "3.12"
entrypoint: main
```
**Restrictions:**
- Cannot extend both tools and models
- Must have at least one extension
- Cannot extend both models and endpoints
- Limited to one supplier per extension type
</details>
<details>
<summary><b>2. Implementation Examples</b></summary>
Study these examples to understand plugin implementation:
- [OpenAI](https://github.com/langgenius/dify-plugin-sdks/tree/main/python/examples/openai) - Model provider
- [Google Search](https://github.com/langgenius/dify-plugin-sdks/tree/main/python/examples/google) - Tool provider
- [Neko](https://github.com/langgenius/dify-plugin-sdks/tree/main/python/examples/neko) - Endpoint group
</details>
<details>
<summary><b>3. Testing & Debugging</b></summary>
1. Copy `.env.example` to `.env` and configure:
```
INSTALL_METHOD=remote
REMOTE_INSTALL_URL=debug.dify.ai:5003
REMOTE_INSTALL_KEY=your-debug-key
```
2. Run your plugin:
```bash
python -m main
```
3. Refresh your Dify instance to see the plugin (marked as "debugging")
</details>
<details>
<summary><b>4. Publishing</b></summary>
#### Manual Packaging
```bash
dify-plugin plugin package ./YOUR_PLUGIN_DIR
```
#### Automated GitHub Workflow
Configure GitHub Actions to automate PR creation:
1. Create a Personal Access Token for your forked repository
2. Add it as `PLUGIN_ACTION` secret in your source repo
3. Create `.github/workflows/plugin-publish.yml`
When you create a release, the action will:
- Package your plugin
- Create a PR to your fork
[Detailed workflow documentation](https://docs.dify.ai/plugins/publish-plugins/plugin-auto-publish-pr)
</details>
## Privacy Policy
If publishing to the Marketplace, provide a privacy policy in [PRIVACY.md](PRIVACY.md).

View File

@@ -0,0 +1,3 @@
## Privacy
!!! Please fill in the privacy policy of the plugin.

10
difyPlugin/pdf/README.md Normal file
View File

@@ -0,0 +1,10 @@
## pdf
**Author:** yslg
**Version:** 0.0.1
**Type:** tool
### Description

View File

@@ -0,0 +1,55 @@
<!--
~ Dify Marketplace Template Icon
~ Dify 市场模板图标
~ Dify マーケットプレイステンプレートアイコン
~
~ WARNING / 警告 / 警告:
~
~ English: This is a TEMPLATE icon from Dify Marketplace only. You MUST NOT use this default icon in any way.
~ Please replace it with your own custom icon before submit this plugin.
~
~ 中文: 这只是来自 Dify 市场的模板图标。您绝对不能以任何方式使用此默认图标。
~ 请在提交此插件之前将其替换为您自己的自定义图标。
~
~ 日本語: これは Dify マーケットプレイスのテンプレートアイコンです。このデフォルトアイコンをいかなる方法でも使用してはいけません。
~ このプラグインを提出する前に、独自のカスタムアイコンに置き換えてください。
~
~ DIFY_MARKETPLACE_TEMPLATE_ICON_DO_NOT_USE
-->
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_15253_95095)">
<rect width="40" height="40" fill="#0033FF"/>
<g filter="url(#filter0_n_15253_95095)">
<rect width="40" height="40" fill="url(#paint0_linear_15253_95095)"/>
</g>
<path d="M28 10C28.5523 10 29 10.4477 29 11V16C29 16.5523 28.5523 17 28 17H23V30C23 30.5523 22.5523 31 22 31H18C17.4477 31 17 30.5523 17 30V17H11.5C10.9477 17 10.5 16.5523 10.5 16V13.618C10.5 13.2393 10.714 12.893 11.0528 12.7236L16.5 10H28ZM23 12H16.9721L12.5 14.2361V15H19V29H21V15H23V12ZM27 12H25V15H27V12Z" fill="white"/>
</g>
<defs>
<filter id="filter0_n_15253_95095" x="0" y="0" width="40" height="40" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feTurbulence type="fractalNoise" baseFrequency="2 2" stitchTiles="stitch" numOctaves="3" result="noise" seed="8033" />
<feComponentTransfer in="noise" result="coloredNoise1">
<feFuncR type="linear" slope="2" intercept="-0.5" />
<feFuncG type="linear" slope="2" intercept="-0.5" />
<feFuncB type="linear" slope="2" intercept="-0.5" />
<feFuncA type="discrete" tableValues="1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 "/>
</feComponentTransfer>
<feComposite operator="in" in2="shape" in="coloredNoise1" result="noise1Clipped" />
<feComponentTransfer in="noise1Clipped" result="color1">
<feFuncA type="table" tableValues="0 0.06" />
</feComponentTransfer>
<feMerge result="effect1_noise_15253_95095">
<feMergeNode in="shape" />
<feMergeNode in="color1" />
</feMerge>
</filter>
<linearGradient id="paint0_linear_15253_95095" x1="0" y1="0" x2="40" y2="40" gradientUnits="userSpaceOnUse">
<stop stop-color="#1443FF"/>
<stop offset="1" stop-color="#0031F5"/>
</linearGradient>
<clipPath id="clip0_15253_95095">
<rect width="40" height="40" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

@@ -0,0 +1,55 @@
<!--
~ Dify Marketplace Template Icon
~ Dify 市场模板图标
~ Dify マーケットプレイステンプレートアイコン
~
~ WARNING / 警告 / 警告:
~
~ English: This is a TEMPLATE icon from Dify Marketplace only. You MUST NOT use this default icon in any way.
~ Please replace it with your own custom icon before submit this plugin.
~
~ 中文: 这只是来自 Dify 市场的模板图标。您绝对不能以任何方式使用此默认图标。
~ 请在提交此插件之前将其替换为您自己的自定义图标。
~
~ 日本語: これは Dify マーケットプレイスのテンプレートアイコンです。このデフォルトアイコンをいかなる方法でも使用してはいけません。
~ このプラグインを提出する前に、独自のカスタムアイコンに置き換えてください。
~
~ DIFY_MARKETPLACE_TEMPLATE_ICON_DO_NOT_USE
-->
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_15255_46435)">
<rect width="40" height="40" fill="#0033FF"/>
<g filter="url(#filter0_n_15255_46435)">
<rect width="40" height="40" fill="url(#paint0_linear_15255_46435)"/>
</g>
<path d="M28 10C28.5523 10 29 10.4477 29 11V16C29 16.5523 28.5523 17 28 17H23V30C23 30.5523 22.5523 31 22 31H18C17.4477 31 17 30.5523 17 30V17H11.5C10.9477 17 10.5 16.5523 10.5 16V13.618C10.5 13.2393 10.714 12.893 11.0528 12.7236L16.5 10H28ZM23 12H16.9721L12.5 14.2361V15H19V29H21V15H23V12ZM27 12H25V15H27V12Z" fill="white"/>
</g>
<defs>
<filter id="filter0_n_15255_46435" x="0" y="0" width="40" height="40" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feTurbulence type="fractalNoise" baseFrequency="2 2" stitchTiles="stitch" numOctaves="3" result="noise" seed="8033" />
<feComponentTransfer in="noise" result="coloredNoise1">
<feFuncR type="linear" slope="2" intercept="-0.5" />
<feFuncG type="linear" slope="2" intercept="-0.5" />
<feFuncB type="linear" slope="2" intercept="-0.5" />
<feFuncA type="discrete" tableValues="1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 "/>
</feComponentTransfer>
<feComposite operator="in" in2="shape" in="coloredNoise1" result="noise1Clipped" />
<feComponentTransfer in="noise1Clipped" result="color1">
<feFuncA type="table" tableValues="0 0.06" />
</feComponentTransfer>
<feMerge result="effect1_noise_15255_46435">
<feMergeNode in="shape" />
<feMergeNode in="color1" />
</feMerge>
</filter>
<linearGradient id="paint0_linear_15255_46435" x1="0" y1="0" x2="40" y2="40" gradientUnits="userSpaceOnUse">
<stop stop-color="#1F4CFF"/>
<stop offset="1" stop-color="#0033FF"/>
</linearGradient>
<clipPath id="clip0_15255_46435">
<rect width="40" height="40" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 3.0 KiB

6
difyPlugin/pdf/main.py Normal file
View File

@@ -0,0 +1,6 @@
from dify_plugin import Plugin, DifyPluginEnv
plugin = Plugin(DifyPluginEnv(MAX_REQUEST_TIMEOUT=120))
if __name__ == '__main__':
plugin.run()

View File

@@ -0,0 +1,37 @@
version: 0.0.1
type: plugin
author: yslg
name: pdf
label:
en_US: pdf
ja_JP: pdf
zh_Hans: pdf
pt_BR: pdf
description:
en_US: pdfTools
ja_JP: pdfTools
zh_Hans: pdfTools
pt_BR: pdfTools
icon: icon.svg
icon_dark: icon-dark.svg
resource:
memory: 268435456
permission:
tool:
enabled: true
plugins:
tools:
- provider/pdf.yaml
meta:
version: 0.0.1
arch:
- amd64
- arm64
runner:
language: python
version: "3.12"
entrypoint: main
minimum_dify_version: null
created_at: 2026-03-02T13:21:03.2806864+08:00
privacy: PRIVACY.md
verified: false

View File

@@ -0,0 +1,64 @@
{
"name": "pdf-plugin",
"version": "1.0.0",
"description": "PDF plugin for analyzing table of contents and extracting text",
"author": "System",
"type": "tool",
"main": "main.py",
"requirements": "requirements.txt",
"icon": "https://neeko-copilot.bytedance.net/api/text2image?prompt=PDF%20document%20icon&size=square",
"settings": [
{
"key": "debug",
"type": "boolean",
"default": false,
"description": "Enable debug mode"
}
],
"functions": [
{
"name": "analyze_toc",
"description": "Analyze PDF and find table of contents",
"parameters": {
"type": "object",
"properties": {
"file": {
"type": "file",
"description": "PDF file to analyze",
"fileTypes": ["pdf"]
}
},
"required": ["file"]
}
},
{
"name": "extract_text",
"description": "Extract text from specified page range",
"parameters": {
"type": "object",
"properties": {
"file": {
"type": "file",
"description": "PDF file to extract text from",
"fileTypes": ["pdf"]
},
"page_range": {
"type": "object",
"properties": {
"start": {
"type": "integer",
"default": 0,
"description": "Start page index"
},
"end": {
"type": "integer",
"description": "End page index"
}
}
}
},
"required": ["file"]
}
}
]
}

View File

@@ -0,0 +1,53 @@
from typing import Any
from dify_plugin import ToolProvider
from dify_plugin.errors.tool import ToolProviderCredentialValidationError
class PdfProvider(ToolProvider):
def _validate_credentials(self, credentials: dict[str, Any]) -> None:
try:
"""
IMPLEMENT YOUR VALIDATION HERE
"""
except Exception as e:
raise ToolProviderCredentialValidationError(str(e))
#########################################################################################
# If OAuth is supported, uncomment the following functions.
# Warning: please make sure that the sdk version is 0.4.2 or higher.
#########################################################################################
# def _oauth_get_authorization_url(self, redirect_uri: str, system_credentials: Mapping[str, Any]) -> str:
# """
# Generate the authorization URL for pdf OAuth.
# """
# try:
# """
# IMPLEMENT YOUR AUTHORIZATION URL GENERATION HERE
# """
# except Exception as e:
# raise ToolProviderOAuthError(str(e))
# return ""
# def _oauth_get_credentials(
# self, redirect_uri: str, system_credentials: Mapping[str, Any], request: Request
# ) -> Mapping[str, Any]:
# """
# Exchange code for access_token.
# """
# try:
# """
# IMPLEMENT YOUR CREDENTIALS EXCHANGE HERE
# """
# except Exception as e:
# raise ToolProviderOAuthError(str(e))
# return dict()
# def _oauth_refresh_credentials(
# self, redirect_uri: str, system_credentials: Mapping[str, Any], credentials: Mapping[str, Any]
# ) -> OAuthCredentials:
# """
# Refresh the credentials
# """
# return OAuthCredentials(credentials=credentials, expires_at=-1)

View File

@@ -0,0 +1,63 @@
identity:
author: "yslg"
name: "pdf"
label:
en_US: "pdf"
zh_Hans: "pdf"
pt_BR: "pdf"
ja_JP: "pdf"
description:
en_US: "pdfTools"
zh_Hans: "pdfTools"
pt_BR: "pdfTools"
ja_JP: "pdfTools"
icon: "icon.svg"
#########################################################################################
# If you want to support OAuth, you can uncomment the following code.
#########################################################################################
# oauth_schema:
# client_schema:
# - name: "client_id"
# type: "secret-input"
# required: true
# url: https://example.com/oauth/authorize
# placeholder:
# en_US: "Please input your Client ID"
# zh_Hans: "请输入你的 Client ID"
# pt_BR: "Insira seu Client ID"
# help:
# en_US: "Client ID is used to authenticate requests to the example.com API."
# zh_Hans: "Client ID 用于认证请求到 example.com API。"
# pt_BR: "Client ID é usado para autenticar solicitações à API do example.com."
# label:
# zh_Hans: "Client ID"
# en_US: "Client ID"
# - name: "client_secret"
# type: "secret-input"
# required: true
# url: https://example.com/oauth/authorize
# placeholder:
# en_US: "Please input your Client Secret"
# zh_Hans: "请输入你的 Client Secret"
# pt_BR: "Insira seu Client Secret"
# help:
# en_US: "Client Secret is used to authenticate requests to the example.com API."
# zh_Hans: "Client Secret 用于认证请求到 example.com API。"
# pt_BR: "Client Secret é usado para autenticar solicitações à API do example.com."
# label:
# zh_Hans: "Client Secret"
# en_US: "Client Secret"
# credentials_schema:
# - name: "access_token"
# type: "secret-input"
# label:
# zh_Hans: "Access Token"
# en_US: "Access Token"
tools:
- tools/pdf.yaml
- tools/pdf_single_page.yaml
extra:
python:
source: provider/pdf.py

View File

@@ -0,0 +1,2 @@
dify_plugin>=0.4.0,<0.7.0
PyPDF2>=3.0.1

View File

@@ -0,0 +1,61 @@
import re
from collections.abc import Generator
from io import BytesIO
from typing import Any
import PyPDF2
from dify_plugin import Tool
from dify_plugin.entities.tool import ToolInvokeMessage
class PdfTool(Tool):
def _invoke(self, tool_parameters: dict[str, Any]) -> Generator[ToolInvokeMessage]:
file = tool_parameters.get("file")
if not file:
yield self.create_text_message("Error: file is required")
return
# file.blob returns bytes
pdf_bytes = file.blob
reader = PyPDF2.PdfReader(BytesIO(pdf_bytes))
num_pages = len(reader.pages)
toc_start = None
toc_end = None
toc_patterns = [
r'目录',
r'Table of Contents',
r'Contents',
r'目次'
]
for page_num in range(num_pages):
page = reader.pages[page_num]
text = page.extract_text() or ""
if any(re.search(pattern, text, re.IGNORECASE) for pattern in toc_patterns):
if toc_start is None:
toc_start = page_num
toc_end = page_num
elif toc_start is not None and toc_end is not None:
break
if toc_start is None:
yield self.create_json_message({
"start": None,
"end": None,
"pages": []
})
return
toc_pages = []
for page_num in range(toc_start, toc_end + 1):
page = reader.pages[page_num]
toc_pages.append(page.extract_text() or "")
yield self.create_json_message({
"start": toc_start,
"end": toc_end,
"pages": toc_pages
})

View File

@@ -0,0 +1,36 @@
identity:
name: "pdf"
author: "yslg"
label:
en_US: "Extract TOC Pages and Content"
zh_Hans: "提取目录页和内容"
pt_BR: "Extrair páginas de sumário e conteúdo"
ja_JP: "目次ページと内容を抽出"
description:
human:
en_US: "Extract table-of-contents page range and all page text in that range"
zh_Hans: "提取目录页范围以及该范围内所有页文本"
pt_BR: "Extrair intervalo de páginas de sumário e todo o texto nesse intervalo"
ja_JP: "目次ページ範囲とその範囲内の全ページテキストを抽出"
llm: "Extract table-of-contents page range and all page text in that range"
parameters:
- name: file
type: file
required: true
label:
en_US: PDF File
zh_Hans: PDF 文件
pt_BR: Arquivo PDF
ja_JP: PDFファイル
human_description:
en_US: "PDF file to process"
zh_Hans: "要处理的 PDF 文件"
pt_BR: "Arquivo PDF para processar"
ja_JP: "処理するPDFファイル"
llm_description: "PDF file to process, output contains start/end/pages"
form: llm
fileTypes:
- "pdf"
extra:
python:
source: tools/pdf.py

View File

@@ -0,0 +1,36 @@
from collections.abc import Generator
from io import BytesIO
from typing import Any
import PyPDF2
from dify_plugin import Tool
from dify_plugin.entities.tool import ToolInvokeMessage
class PdfSinglePageTool(Tool):
def _invoke(self, tool_parameters: dict[str, Any]) -> Generator[ToolInvokeMessage]:
file = tool_parameters.get("file")
page = tool_parameters.get("page", 0)
if not file:
yield self.create_text_message("Error: file is required")
return
pdf_bytes = file.blob
reader = PyPDF2.PdfReader(BytesIO(pdf_bytes))
num_pages = len(reader.pages)
page_index = int(page)
if page_index < 0:
page_index = 0
if page_index >= num_pages:
page_index = num_pages - 1
selected_page = reader.pages[page_index]
text = selected_page.extract_text() or ""
yield self.create_json_message({
"start": page_index,
"end": page_index,
"pages": [text]
})

View File

@@ -0,0 +1,52 @@
identity:
name: "pdf_single_page"
author: "yslg"
label:
en_US: "Extract Single-Page Text"
zh_Hans: "提取单页文字"
pt_BR: "Extrair texto de página única"
ja_JP: "単一ページのテキストを抽出"
description:
human:
en_US: "Extract text from one specified page"
zh_Hans: "提取指定单页文字"
pt_BR: "Extrair texto de uma página especificada"
ja_JP: "指定した1ページのテキストを抽出"
llm: "Extract text from one specified page"
parameters:
- name: file
type: file
required: true
label:
en_US: PDF File
zh_Hans: PDF 文件
pt_BR: Arquivo PDF
ja_JP: PDFファイル
human_description:
en_US: "PDF file to process"
zh_Hans: "要处理的 PDF 文件"
pt_BR: "Arquivo PDF para processar"
ja_JP: "処理するPDFファイル"
llm_description: "PDF file to process"
form: llm
fileTypes:
- "pdf"
- name: page
type: number
required: true
label:
en_US: Page Index
zh_Hans: 页码
pt_BR: Índice da Página
ja_JP: ページ番号
human_description:
en_US: "Single page index to extract"
zh_Hans: "要提取的单页页码"
pt_BR: "Índice da página única para extrair"
ja_JP: "抽出対象のページ番号"
llm_description: "Single page index to extract"
form: llm
default: 0
extra:
python:
source: tools/pdf_single_page.py

View File

@@ -1,14 +0,0 @@
fastapi
pydantic
pydantic-settings
python-dotenv
redis
anyio>=4.5
uvicorn[standard]>=0.31.1
# 二维码处理
qrcode>=7.4.2
pillow>=10.0.0
opencv-python-headless>=4.8.0
numpy>=1.24.0
httpx>=0.27.0

View File

@@ -1,12 +0,0 @@
import uvicorn
from app.main import app
from app.config import settings
if __name__ == "__main__":
uvicorn.run(
app,
host="0.0.0.0",
port=settings.PORT,
reload=False,
workers=1
)

View File

@@ -1,36 +0,0 @@
#!/usr/bin/env python3
"""验证二维码服务(纯 OpenCV 方案)"""
import sys
import asyncio
try:
from app.services.workcase.qrcode import QrCodeService
print("✓ 二维码服务导入成功")
async def test():
service = QrCodeService()
# 测试生成
result = await service.generate_qrcode("https://github.com", size=300)
if result["success"]:
print("✓ 二维码生成成功")
# 测试解析
parse_result = await service.parse_qrcode(result["image"], strategy="auto")
if parse_result["success"]:
print(f"✓ 二维码解析成功: {parse_result['content']}")
print(f" 使用策略: {parse_result['strategy_used']}")
print(f" 尝试次数: {parse_result['total_attempts']}")
else:
print(f"✗ 解析失败: {parse_result.get('error', '未知错误')}")
else:
print(f"✗ 生成失败: {result.get('error', '未知错误')}")
asyncio.run(test())
print("\n✅ 所有测试通过 - 纯 OpenCV 方案运行正常")
except Exception as e:
print(f"✗ 错误: {e}")
import traceback
traceback.print_exc()
sys.exit(1)

122
difyPlugin/需求文档.md Normal file
View File

@@ -0,0 +1,122 @@
# Dify 插件服务需求文档
## 1. 项目概述
开发一个基于 FastAPI 框架的 Dify 插件服务,实现与 Dify 平台的集成,支持多种插件的部署和管理,提供各种功能扩展。
## 2. 技术栈
- **框架**FastAPI
- **语言**Python 3.9+
- **依赖管理**Poetry 或 Pip
- **部署方式**Docker 容器化
## 3. 项目架构
### 3.1 架构设计
- **插件管理系统**:统一管理多个 Dify 插件
- **插件加载机制**:支持动态加载和热更新插件
- **插件隔离**:每个插件运行在独立的环境中
- **API 网关**:统一的 API 入口,路由到对应插件
### 3.2 目录结构
```
difyPlugin/
├── main.py # 应用入口
├── requirements.txt # 依赖管理
├── .env # 环境配置
├── app/
│ ├── api/ # API 路由
│ ├── core/ # 核心配置
│ ├── plugins/ # 插件目录
│ │ ├── plugin1/ # 插件1
│ │ ├── plugin2/ # 插件2
│ │ └── __init__.py # 插件加载器
│ └── services/ # 公共服务
└── tests/ # 测试目录
```
### 3.3 插件规范
- **插件结构**:每个插件包含独立的配置、逻辑和 API
- **插件接口**:统一的插件接口规范
- **插件注册**:自动发现和注册插件
- **插件生命周期**:支持插件的启动、停止和重启
## 4. 核心功能
### 4.1 基础功能
- **健康检查**:提供服务状态检查接口
- **版本管理**:支持插件版本控制
- **认证机制**:实现与 Dify 的安全认证
- **插件管理**:支持插件的注册、启动、停止和卸载
### 4.2 业务功能
- **数据处理**:支持各种数据格式的转换和处理
- **外部 API 集成**:对接第三方服务的 API
- **自定义逻辑**:支持用户自定义业务逻辑
- **事件处理**:响应 Dify 平台的事件触发
## 5. 接口设计
### 5.1 主要接口
- `GET /health`:健康检查
- `GET /api/v1/plugins`:获取插件列表
- `GET /api/v1/plugins/{plugin_id}`:获取插件详情
- `POST /api/v1/plugins/{plugin_id}/execute`:执行插件功能
- `GET /api/v1/plugins/{plugin_id}/metadata`:获取插件元数据
- `POST /api/v1/plugins/{plugin_id}/start`:启动插件
- `POST /api/v1/plugins/{plugin_id}/stop`:停止插件
### 5.2 请求/响应格式
- **请求格式**JSON
- **响应格式**JSON包含状态码和数据
## 6. 部署要求
- **环境变量**:支持通过环境变量配置服务参数
- **日志管理**:集成结构化日志
- **监控指标**:提供 Prometheus 指标接口
- **错误处理**:完善的错误处理和异常捕获
- **插件隔离**:支持插件的独立部署和隔离
## 7. 集成方式
- **Dify 插件注册**:按照 Dify 插件规范注册
- **Webhook 配置**:支持 Dify 平台的 Webhook 回调
- **事件订阅**:订阅 Dify 平台的事件
- **插件发现**:自动发现和注册新插件
## 8. 开发计划
### 8.1 阶段一:项目初始化
- 创建 FastAPI 项目结构
- 配置依赖管理
- 实现插件管理系统
### 8.2 阶段二:核心功能开发
- 实现插件加载机制
- 开发插件接口规范
- 实现数据处理功能
- 集成外部 API
### 8.3 阶段三:测试与部署
- 编写单元测试
- 集成测试
- 容器化部署
- 插件示例开发
## 9. 技术要求
- **代码质量**:遵循 PEP 8 编码规范
- **文档**:完善的 API 文档
- **性能**:优化响应速度和资源占用
- **安全**:实现安全的认证和授权机制
- **可扩展性**:支持插件的动态添加和移除
## 10. 交付物
- **源代码**:完整的项目代码
- **部署文档**:详细的部署步骤
- **API 文档**:自动生成的 API 文档
- **测试报告**:测试结果和覆盖率报告
- **插件开发指南**:插件开发和注册指南

View File

@@ -1,196 +0,0 @@
# 开发环境统一入口配置
# 上游服务定义
upstream gateway {
server gateway:8080;
keepalive 32;
}
upstream portal {
server portal:3000;
keepalive 16;
}
upstream app-bidding {
server app-bidding:3001;
keepalive 16;
}
upstream app-customer-service {
server app-customer-service:3002;
keepalive 16;
}
upstream shared {
server shared:5000;
keepalive 16;
}
# WebSocket 升级配置
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
# 主服务器配置
server {
listen 80;
server_name localhost;
# 安全头
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
# 开发环境允许所有跨域
add_header Access-Control-Allow-Origin "*" always;
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;
add_header Access-Control-Allow-Headers "DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization" always;
# 健康检查
location /health {
access_log off;
return 200 "healthy\n";
add_header Content-Type text/plain;
}
# ==================== 共享包服务ES Module + Module Federation ====================
location /shared/ {
proxy_pass http://shared:5000/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# CORSES Module / Module Federation 必需)
add_header Access-Control-Allow-Origin "*" always;
add_header Access-Control-Allow-Methods "GET, OPTIONS" always;
add_header Access-Control-Allow-Headers "Content-Type" always;
# ES Module MIME 类型
if ($request_filename ~* \.(js|mjs)$) {
add_header Content-Type "application/javascript; charset=utf-8";
}
# 开发环境不缓存
add_header Cache-Control "no-cache, no-store, must-revalidate";
# HMR 支持
proxy_read_timeout 86400;
proxy_send_timeout 86400;
}
# ==================== API 网关代理 ====================
location /api/ {
proxy_pass http://gateway/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# 超时设置
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
# WebSocket 代理
location /ws/ {
proxy_pass http://gateway/ws/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
# WebSocket 超时设置
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
}
# ==================== 主应用Portal ====================
location / {
proxy_pass http://portal/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
# Vite HMR 支持
proxy_read_timeout 86400;
}
# ==================== 招投标应用 ====================
location /bidding {
rewrite ^/bidding/(.*)$ /$1 break;
proxy_pass http://app-bidding/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
# Vite HMR 支持
proxy_read_timeout 86400;
}
# 招投标应用静态资源
location /bidding/ {
proxy_pass http://app-bidding/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $host;
proxy_read_timeout 86400;
}
# ==================== 智能客服应用 ====================
location /customer-service {
rewrite ^/customer-service/(.*)$ /$1 break;
proxy_pass http://app-customer-service/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $host;
proxy_read_timeout 86400;
}
location /customer-service/ {
proxy_pass http://app-customer-service/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $host;
proxy_read_timeout 86400;
}
# ==================== Nacos 管理界面(开发用) ====================
location /nacos/ {
proxy_pass http://nacos:8848/nacos/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
# 可选HTTPS 配置(开发环境使用自签名证书)
# server {
# listen 443 ssl http2;
# server_name localhost;
#
# ssl_certificate /etc/nginx/ssl/cert.pem;
# ssl_certificate_key /etc/nginx/ssl/key.pem;
# ssl_protocols TLSv1.2 TLSv1.3;
# ssl_ciphers HIGH:!aNULL:!MD5;
#
# # 其他配置同上...
# }

View File

@@ -1,51 +0,0 @@
# Dify 服务代理配置
# Dify Web 前端
location /dify/ {
proxy_pass http://dify-web:3000/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# 支持 WebSocket
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# 超时配置
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
# Dify API
location /dify/api/ {
proxy_pass http://dify-api:5001/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# 支持 WebSocket (SSE)
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# 超时配置AI 响应可能较慢)
proxy_connect_timeout 300s;
proxy_send_timeout 300s;
proxy_read_timeout 300s;
# 禁用缓冲(支持流式响应)
proxy_buffering off;
}
# Dify App (公开应用)
location /dify/app/ {
proxy_pass http://dify-web:3000/app/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}

View File

@@ -1,42 +0,0 @@
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
use epoll;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
# 日志格式
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
# 性能优化
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
# Gzip 压缩
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_comp_level 6;
gzip_types text/plain text/css text/xml text/javascript
application/javascript application/json application/xml+rss;
# 上传大小限制
client_max_body_size 100M;
# 包含具体配置
include /etc/nginx/conf.d/*.conf;
}

BIN
docs/AI训练资料/2.pdf Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,960 @@
HEADER
========================================================================================================================================================================================
Format: 2.3
LongNamesLength: 64 - Name, Name of State, Name of Value, Bit Name, Group
ShortNamesLength: 10 - Dimension, Type
========================================================================================================================================================================================
========================================================================================================================================================================================
Table: Binaries
========================================================================================================================================================================================
Allowed MODBUS functions: 01, 02
Addresses Source
Modbus Addr. = Value C.O.# Name of Value Bit # Bit Name Group / Subgroup
Prot. Addr. = State State # Name of State Activated by protection(s):
========================================================================================================================================================================================
00000 Value 8235 开关量输入 1 遥控启动/停机 控制器I/O口
00001 Value 8235 开关量输入 2 GC反饋 控制器I/O口
00002 Not Used
00003 Value 8235 开关量输入 4 存取锁 控制器I/O口
00004 Value 8235 开关量输入 5 远程关 控制器I/O口
00005 Not Used
00006 Value 8235 开关量输入 7 禁止停机 控制器I/O口
00007 Not Used
00008 Value 8239 开关量输出 1 起动马达1 控制器I/O口
00009 Value 8239 开关量输出 2 燃油阀 控制器I/O口
00010 Value 8239 开关量输出 3 GCB合/分 控制器I/O口
00011 Value 8239 开关量输出 4 预起动 控制器I/O口
00012 Value 8239 开关量输出 5 可以加载 控制器I/O口
00013 Value 8239 开关量输出 6 警告 控制器I/O口
00014 Not Used
00015 Not Used
00016 Not Used
00017 Value 9143 Log开关量输出1 2 起动马达1 开关量逻辑输出
00018 Value 9143 Log开关量输出1 3 燃油阀 开关量逻辑输出
00019 Value 9143 Log开关量输出1 4 停机阀 开关量逻辑输出
00020 Value 9143 Log开关量输出1 5 停机脉冲 开关量逻辑输出
00021 Value 9143 Log开关量输出1 6 点火 开关量逻辑输出
00022 Value 9143 Log开关量输出1 7 预起动 开关量逻辑输出
00023 Value 9143 Log开关量输出1 8 冷却泵 开关量逻辑输出
00024 Value 9143 Log开关量输出1 9 怠速/额定 开关量逻辑输出
00025 Value 9143 Log开关量输出1 10 空气阀 开关量逻辑输出
00026 Value 9143 Log开关量输出1 11 警告 开关量逻辑输出
00027 Value 9143 Log开关量输出1 12 蜂鸣 开关量逻辑输出
00028 Value 9143 Log开关量输出1 13 GCB合/分 开关量逻辑输出
00029 Value 9143 Log开关量输出1 14 GCB闭合线圈 开关量逻辑输出
00030 Value 9143 Log开关量输出1 15 GCB断开线圈 开关量逻辑输出
00031 Value 9143 Log开关量输出1 16 GCB失压线圈 开关量逻辑输出
00032 Value 9144 Log开关量输出2 1 保留 开关量逻辑输出
00033 Value 9144 Log开关量输出2 2 保留 开关量逻辑输出
00034 Value 9144 Log开关量输出2 3 保留 开关量逻辑输出
00035 Value 9144 Log开关量输出2 4 保留 开关量逻辑输出
00036 Value 9144 Log开关量输出2 5 候命中 开关量逻辑输出
00037 Value 9144 Log开关量输出2 6 保留 开关量逻辑输出
00038 Value 9144 Log开关量输出2 7 可以加载 开关量逻辑输出
00039 Value 9144 Log开关量输出2 8 不在自动 开关量逻辑输出
00040 Value 9144 Log开关量输出2 9 运行中 开关量逻辑输出
00041 Value 9144 Log开关量输出2 10 冷却中 开关量逻辑输出
00042 Value 9144 Log开关量输出2 11 加载 开关量逻辑输出
00043 Value 9144 Log开关量输出2 12 发电正常 开关量逻辑输出
00044 Value 9144 Log开关量输出2 13 保留 开关量逻辑输出
00045 Value 9144 Log开关量输出2 14 动作计时器1 开关量逻辑输出
00046 Value 9144 Log开关量输出2 15 动作计时器2 开关量逻辑输出
00047 Value 9144 Log开关量输出2 16 预热塞 开关量逻辑输出
00048 Value 9145 Log开关量输出3 1 停止按鈕 开关量逻辑输出
00049 Value 9145 Log开关量输出3 2 温度开关 开关量逻辑输出
00050 Value 9145 Log开关量输出3 3 保留 开关量逻辑输出
00051 Value 9145 Log开关量输出3 4 点火启动 开关量逻辑输出
00052 Value 9145 Log开关量输出3 5 手动候命 开关量逻辑输出
00053 Value 9145 Log开关量输出3 6 心跳 开关量逻辑输出
00054 Value 9145 Log开关量输出3 7 关模式 开关量逻辑输出
00055 Value 9145 Log开关量输出3 8 手动模式 开关量逻辑输出
00056 Value 9145 Log开关量输出3 9 自动模式 开关量逻辑输出
00057 Value 9145 Log开关量输出3 10 保留 开关量逻辑输出
00058 Value 9145 Log开关量输出3 11 发电电压报警报警 开关量逻辑输出
00059 Value 9145 Log开关量输出3 12 发电电压警告 开关量逻辑输出
00060 Value 9145 Log开关量输出3 13 公共报警值1 开关量逻辑输出
00061 Value 9145 Log开关量输出3 14 公共报警值2 开关量逻辑输出
00062 Value 9145 Log开关量输出3 15 公共报警有效值1 开关量逻辑输出
00063 Value 9145 Log开关量输出3 16 公共报警有效值2 开关量逻辑输出
00064 Value 9146 Log开关量输出4 1 发电频率警告 开关量逻辑输出
00065 Value 9146 Log开关量输出4 2 发电频率报警 开关量逻辑输出
00066 Value 9146 Log开关量输出4 3 保留 开关量逻辑输出
00067 Value 9146 Log开关量输出4 4 保留 开关量逻辑输出
00068 Value 9146 Log开关量输出4 5 保留 开关量逻辑输出
00069 Value 9146 Log开关量输出4 6 公共警告 开关量逻辑输出
00070 Value 9146 Log开关量输出4 7 公共报警停机 开关量逻辑输出
00071 Value 9146 Log开关量输出4 8 公共报警BOC 开关量逻辑输出
00072 Value 9146 Log开关量输出4 9 传感器故障公共报警 开关量逻辑输出
00073 Value 9146 Log开关量输出4 10 ECU供电 开关量逻辑输出
00074 Value 9146 Log开关量输出4 11 ECU停止运行 开关量逻辑输出
00075 Value 9146 Log开关量输出4 12 保留 开关量逻辑输出
00076 Value 9146 Log开关量输出4 13 保留 开关量逻辑输出
00077 Value 9146 Log开关量输出4 14 双备正常 开关量逻辑输出
00078 Value 9146 Log开关量输出4 15 过流 开关量逻辑输出
00079 Value 9146 Log开关量输出4 16 保留 开关量逻辑输出
00080 Value 9147 Log开关量输出5 1 禁止停机 开关量逻辑输出
00081 Value 9147 Log开关量输出5 2 静态逻辑0 开关量逻辑输出
00082 Value 9147 Log开关量输出5 3 静态逻辑1 开关量逻辑输出
00083 Value 9147 Log开关量输出5 4 需要再生regen 开关量逻辑输出
00084 Value 9147 Log开关量输出5 5 后处理HEST 灯 开关量逻辑输出
00085 Value 9147 Log开关量输出5 6 保留 开关量逻辑输出
00086 Value 9147 Log开关量输出5 7 保留 开关量逻辑输出
00087 Value 9147 Log开关量输出5 8 保留 开关量逻辑输出
00088 Value 9147 Log开关量输出5 9 消音按钮 开关量逻辑输出
00089 Value 9147 Log开关量输出5 10 起动按钮 开关量逻辑输出
00090 Value 9147 Log开关量输出5 11 停止按钮 开关量逻辑输出
00091 Value 9147 Log开关量输出5 12 保留 开关量逻辑输出
00092 Value 9147 Log开关量输出5 13 GCB按钮 开关量逻辑输出
00093 Value 9147 Log开关量输出5 14 故障复位按钮 开关量逻辑输出
00094 Value 9147 Log开关量输出5 15 电力报警 开关量逻辑输出
00095 Not Used
00096 Value 9148 Log开关量输出6 1 ECU等待起动中 开关量逻辑输出
00097 Value 9148 Log开关量输出6 2 AIN1开关 开关量逻辑输出
00098 Value 9148 Log开关量输出6 3 AIN2开关 开关量逻辑输出
00099 Value 9148 Log开关量输出6 4 AIN3开关 开关量逻辑输出
00100 Value 9148 Log开关量输出6 5 AIN4开关 开关量逻辑输出
00101 Value 9148 Log开关量输出6 6 保留 开关量逻辑输出
00102 Value 9148 Log开关量输出6 7 保留 开关量逻辑输出
00103 Value 9148 Log开关量输出6 8 保留 开关量逻辑输出
00104 Value 9148 Log开关量输出6 9 保留 开关量逻辑输出
00105 Value 9148 Log开关量输出6 10 保留 开关量逻辑输出
00106 Value 9148 Log开关量输出6 11 保留 开关量逻辑输出
00107 Value 9148 Log开关量输出6 12 保留 开关量逻辑输出
00108 Value 9148 Log开关量输出6 13 保留 开关量逻辑输出
00109 Value 9148 Log开关量输出6 14 保留 开关量逻辑输出
00110 Value 9148 Log开关量输出6 15 保留 开关量逻辑输出
00111 Value 9148 Log开关量输出6 16 保留 开关量逻辑输出
00112 Value 9149 Log开关量输出7 1 保留 开关量逻辑输出
00113 Value 9149 Log开关量输出7 2 保留 开关量逻辑输出
00114 Value 9149 Log开关量输出7 3 保留 开关量逻辑输出
00115 Value 9149 Log开关量输出7 4 保留 开关量逻辑输出
00116 Value 9149 Log开关量输出7 5 保留 开关量逻辑输出
00117 Value 9149 Log开关量输出7 6 ECU通讯故障 开关量逻辑输出
00118 Value 9149 Log开关量输出7 7 ECU红灯 开关量逻辑输出
00119 Value 9149 Log开关量输出7 8 ECU 黄灯 开关量逻辑输出
00120 Value 9149 Log开关量输出7 9 后处理DEF值灯 开关量逻辑输出
00121 Value 9149 Log开关量输出7 10 后处理阻止灯 开关量逻辑输出
00122 Value 9149 Log开关量输出7 11 运用计时3 开关量逻辑输出
00123 Value 9149 Log开关量输出7 12 运用计时4 开关量逻辑输出
00124 Value 9149 Log开关量输出7 13 Exercise Timer 5 开关量逻辑输出
00125 Value 9149 Log开关量输出7 14 Exercise Timer 6 开关量逻辑输出
00126 Value 9149 Log开关量输出7 15 Exercise Timer 7 开关量逻辑输出
00127 Value 9149 Log开关量输出7 16 Exercise Timer 8 开关量逻辑输出
00128 Value 9150 Log开关量输出8 1 负载撤载阶段1 开关量逻辑输出
00129 Value 9150 Log开关量输出8 2 负载撤载阶段2 开关量逻辑输出
00130 Value 9150 Log开关量输出8 3 负载撤载阶段3 开关量逻辑输出
00131 Value 9150 Log开关量输出8 4 卸载阶段4 开关量逻辑输出
00132 Value 9150 Log开关量输出8 5 卸载阶段5 开关量逻辑输出
00133 Value 9150 Log开关量输出8 6 频率选择 开关量逻辑输出
00134 Value 9150 Log开关量输出8 7 保留 开关量逻辑输出
00135 Value 9150 Log开关量输出8 8 ATT DPF Lamp 开关量逻辑输出
00136 Value 9150 Log开关量输出8 9 后处理SCR故障灯 开关量逻辑输出
00137 Value 9150 Log开关量输出8 10 排空 开关量逻辑输出
00138 Value 9150 Log开关量输出8 11 排空通脉冲 开关量逻辑输出
00139 Value 9150 Log开关量输出8 12 排空断脉冲 开关量逻辑输出
00140 Value 9150 Log开关量输出8 13 阻风门 开关量逻辑输出
00141 Value 9150 Log开关量输出8 14 起动马达2 开关量逻辑输出
00142 Value 9150 Log开关量输出8 15 ATT连锁状态 开关量逻辑输出
00143 Value 9150 Log开关量输出8 16 ECU 通信正常 开关量逻辑输出
00144 Value 11896 Log开关量输出 1 ATT Regen ACK Lamp 开关量逻辑输出
00145 Value 11896 Log开关量输出 2 ATT PCD 灯 开关量逻辑输出
00146 Value 11896 Log开关量输出 3 维护时间1报警 开关量逻辑输出
00147 Value 11896 Log开关量输出 4 维护时间2报警 开关量逻辑输出
00148 Value 11896 Log开关量输出 5 维护时间3报警 开关量逻辑输出
00149 Value 11896 Log开关量输出 6 MCB 状态 开关量逻辑输出
00150 Value 11896 Log开关量输出 7 GCB 状态 开关量逻辑输出
00151 Value 11896 Log开关量输出 8 Exercise Timer 9 开关量逻辑输出
00152 Value 11896 Log开关量输出 9 Exercise Timer 10 开关量逻辑输出
00153 Value 11896 Log开关量输出 10 Exercise Timer 11 开关量逻辑输出
00154 Value 11896 Log开关量输出 11 Exercise Timer 12 开关量逻辑输出
00155 Value 11896 Log开关量输出 12 Exercise Timer 13 开关量逻辑输出
00156 Value 11896 Log开关量输出 13 Exercise Timer 14 开关量逻辑输出
00157 Value 11896 Log开关量输出 14 Exercise Timer 15 开关量逻辑输出
00158 Value 11896 Log开关量输出 15 Exercise Timer 16 开关量逻辑输出
00159 Value 11896 Log开关量输出 16 Peripheral Module Comm Fail 开关量逻辑输出
00160 Value 11897 Log开关量输出10 1 Initialized 开关量逻辑输出
00161 Value 11897 Log开关量输出10 2 发电机有效 开关量逻辑输出
00162 Not Used
00163 Not Used
00164 Not Used
00165 Not Used
00166 Not Used
00167 Not Used
00168 Not Used
00169 Not Used
00170 Not Used
00171 Not Used
00172 Value 20744 固定保护阶段 1 11 ECU 1通信故障警告 固定保护状态
00173 Value 20744 固定保护阶段 1 12 ECU 1 通信故障停机 固定保护状态
00174 Value 20744 固定保护阶段 1 13 ECU 黄灯 固定保护状态
00175 Value 20744 固定保护阶段 1 14 ECU红灯 固定保护状态
00176 Value 20744 固定保护阶段 1 15 ECU等待起动中 固定保护状态
00177 Value 20744 固定保护阶段 1 16 ATT DPF Lamp 固定保护状态
00178 Value 20744 固定保护阶段 1 17 后处理HEST 灯 固定保护状态
00179 Value 20744 固定保护阶段 1 18 后处理SCR故障灯 固定保护状态
00180 Value 20744 固定保护阶段 1 19 后处理DEF值灯 固定保护状态
00181 Value 20744 固定保护阶段 1 20 后处理阻止灯 固定保护状态
00182 Value 20744 固定保护阶段 1 21 紧急停机 固定保护状态
00183 Value 20744 固定保护阶段 1 22 充电发电机故障警告 固定保护状态
00184 Value 20744 固定保护阶段 1 23 充电机故障停机 固定保护状态
00185 Value 20744 固定保护阶段 1 24 停机失败警告 固定保护状态
00186 Value 20744 固定保护阶段 1 25 超速停机 固定保护状态
00187 Value 20744 固定保护阶段 1 26 欠速停机 固定保护状态
00188 Value 20744 固定保护阶段 1 27 转速测量故障停机 固定保护状态
00189 Value 20744 固定保护阶段 1 28 电池耗尽停机 固定保护状态
00190 Value 20744 固定保护阶段 1 29 维修时间1运行时间警告 固定保护状态
00191 Value 20744 固定保护阶段 1 30 维修时间2运行时间警告 固定保护状态
00192 Value 20744 固定保护阶段 1 31 维修时间3运行时间警告 固定保护状态
00193 Value 20744 固定保护阶段 1 32 起动失败停机 固定保护状态
00194 Not Used
00195 Value 20745 固定保护阶段 2 2 GCB故障停机 固定保护状态
00196 Value 20745 固定保护阶段 2 3 发电L1电压高警告 固定保护状态
00197 Value 20745 固定保护阶段 2 4 发电L1 过电压停机 固定保护状态
00198 Value 20745 固定保护阶段 2 5 发电L2电压高警告 固定保护状态
00199 Value 20745 固定保护阶段 2 6 发电L2过电压 固定保护状态
00200 Value 20745 固定保护阶段 2 7 发电L3电压高警告 固定保护状态
00201 Value 20745 固定保护阶段 2 8 发电L3过电压 固定保护状态
00202 Value 20745 固定保护阶段 2 9 发电L1L2电压高警告 固定保护状态
00203 Value 20745 固定保护阶段 2 10 发电L1L2过电压停机 固定保护状态
00204 Value 20745 固定保护阶段 2 11 发电L2L3电压高警告 固定保护状态
00205 Value 20745 固定保护阶段 2 12 发电L2L3过电压 固定保护状态
00206 Value 20745 固定保护阶段 2 13 发电L3L1电压高警告 固定保护状态
00207 Value 20745 固定保护阶段 2 14 发电L3L1过电压 固定保护状态
00208 Value 20745 固定保护阶段 2 15 发电L1电压低警告 固定保护状态
00209 Value 20745 固定保护阶段 2 16 发电L1 低电压BOC 固定保护状态
00210 Value 20745 固定保护阶段 2 17 发电L2电压低警告 固定保护状态
00211 Value 20745 固定保护阶段 2 18 发电L2低电压BOC 固定保护状态
00212 Value 20745 固定保护阶段 2 19 发电L3电压低警告 固定保护状态
00213 Value 20745 固定保护阶段 2 20 发电L3低电压BOC 固定保护状态
00214 Value 20745 固定保护阶段 2 21 发电L1L2电压低警告 固定保护状态
00215 Value 20745 固定保护阶段 2 22 发电L1L2低电压BOC 固定保护状态
00216 Value 20745 固定保护阶段 2 23 发电L2L3电压低警告 固定保护状态
00217 Value 20745 固定保护阶段 2 24 发电L2L3低电压BOC 固定保护状态
00218 Value 20745 固定保护阶段 2 25 发电L3L1电压低警告 固定保护状态
00219 Value 20745 固定保护阶段 2 26 发电L3L1低电压BOC 固定保护状态
00220 Value 20745 固定保护阶段 2 27 线电压不平衡BOC 固定保护状态
00221 Value 20745 固定保护阶段 2 28 相电压不平衡BOC 固定保护状态
00222 Value 20745 固定保护阶段 2 29 发电频率高警告 固定保护状态
00223 Value 20745 固定保护阶段 2 30 发电频率高BOC 固定保护状态
00224 Value 20745 固定保护阶段 2 31 发电频率低警告 固定保护状态
00225 Value 20745 固定保护阶段 2 32 发电频率低BOC 固定保护状态
00226 Value 20746 固定保护阶段 3 1 逆功率分闸 固定保护状态
00227 Not Used
00228 Value 20746 固定保护阶段 3 3 电流不平衡BOC 固定保护状态
00229 Not Used
00230 Not Used
00231 Not Used
00232 Not Used
00233 Not Used
00234 Not Used
00235 Not Used
00236 Not Used
00237 Not Used
00238 Not Used
00239 Not Used
00240 Not Used
00241 Value 20746 固定保护阶段 3 16 封锁输入密码 固定保护状态
00242 Value 20746 固定保护阶段 3 17 ATT 互锁有效 固定保护状态
00243 Value 20746 固定保护阶段 3 18 ATT 强制再生有效 固定保护状态
00244 Value 20746 固定保护阶段 3 19 ATT 禁止再生有效 固定保护状态
00245 Value 20746 固定保护阶段 3 20 默认密码 固定保护状态
00246 Value 20746 固定保护阶段 3 21 双运行故障 固定保护状态
00247 Value 20746 固定保护阶段 3 22 双运行固件版本不同 固定保护状态
00248 Value 20746 固定保护阶段 3 23 AHI 双运行主机故障 固定保护状态
00249 Value 20746 固定保护阶段 3 24 双运行主故障警告 固定保护状态
00250 Value 20746 固定保护阶段 3 25 AHI 双运行从机故障 固定保护状态
00251 Value 20746 固定保护阶段 3 26 双运行从故障警告 固定保护状态
00252 Value 20746 固定保护阶段 3 27 双运行市电不同 固定保护状态
00253 Value 20746 固定保护阶段 3 28 ALI发电相序反 固定保护状态
00254 Not Used
00255 Not Used
00256 Not Used
00257 Not Used
00258 Value 20747 固定保护阶段 4 1 过载警告 固定保护状态
00259 Value 20747 固定保护阶段 4 2 过载BOC 固定保护状态
00260 Value 20747 固定保护阶段 4 3 电流短路BOC 固定保护状态
00261 Value 20747 固定保护阶段 4 4 IDMT 过流BOC 固定保护状态
00262 Not Used
00263 Value 20747 固定保护阶段 4 6 燃油传送 固定保护状态
00264 Value 20747 固定保护阶段 4 7 燃油传输失败 固定保护状态
00265 Value 20747 固定保护阶段 4 8 电池充电器故障警告 固定保护状态
00266 Value 20747 固定保护阶段 4 9 越控所有停机警告 固定保护状态
00267 Value 20747 固定保护阶段 4 10 租赁计时1警告 固定保护状态
00268 Value 20747 固定保护阶段 4 11 租赁计时2警告 固定保护状态
00269 Value 20747 固定保护阶段 4 12 租赁计时1时间到 固定保护状态
00270 Value 20747 固定保护阶段 4 13 租赁计时2时间到 固定保护状态
00271 Value 20747 固定保护阶段 4 14 租赁计时1超时停机 固定保护状态
00272 Value 20747 固定保护阶段 4 15 租赁计时2超时停机 固定保护状态
00273 Value 20747 固定保护阶段 4 16 租赁计时器封锁开始警告 固定保护状态
00274 Not Used
00275 Not Used
00276 Value 20747 固定保护阶段 4 19 偷油警告 固定保护状态
00277 Not Used
00278 Value 20747 固定保护阶段 4 21 接地电流保护停机 固定保护状态
00279 Not Used
00280 Value 20747 固定保护阶段 4 23 围栏1报警警告 固定保护状态
00281 Value 20747 固定保护阶段 4 24 围栏1报警停机 固定保护状态
00282 Value 20747 固定保护阶段 4 25 围栏报警BOC 固定保护状态
00283 Value 20747 固定保护阶段 4 26 围栏1报警 固定保护状态
00284 Value 20747 固定保护阶段 4 27 围栏2报警警告 固定保护状态
00285 Value 20747 固定保护阶段 4 28 围栏2报警停机 固定保护状态
00286 Value 20747 固定保护阶段 4 29 围栏报警BOC 固定保护状态
00287 Value 20747 固定保护阶段 4 30 围栏2报警 固定保护状态
00288 Value 20747 固定保护阶段 4 31 维修时间1间隔警告 固定保护状态
00289 Value 20747 固定保护阶段 4 32 维修时间2间隔警告 固定保护状态
00290 Value 20748 固定保护阶段 5 1 维修时间3间隔警告 固定保护状态
00291 Not Used
00292 Value 20748 固定保护阶段 5 3 电池充电器低压警告 固定保护状态
00293 Value 20748 固定保护阶段 5 4 电池充电器过压警告 固定保护状态
00294 Value 20748 固定保护阶段 5 5 紧急停 固定保护状态
00295 Value 20748 固定保护阶段 5 6 维修时间1运行时间BOC 固定保护状态
00296 Value 20748 固定保护阶段 5 7 维修时间2运行时间BOC 固定保护状态
00297 Value 20748 固定保护阶段 5 8 维修时间3运行时间BOC 固定保护状态
00298 Value 20748 固定保护阶段 5 9 维修时间1间隔BOC 固定保护状态
00299 Value 20748 固定保护阶段 5 10 维修时间2间隔BOC 固定保护状态
00300 Value 20748 固定保护阶段 5 11 维修时间3间隔BOC 固定保护状态
00301 Value 20748 固定保护阶段 5 12 Wrn MCB Fail To Open 固定保护状态
00302 Value 20748 固定保护阶段 5 13 Wrn MCB Fail To Close 固定保护状态
00303 Value 20748 固定保护阶段 5 14 Sd GCB Fail To Open 固定保护状态
00304 Value 20748 固定保护阶段 5 15 Sd GCB Fail To Close 固定保护状态
========================================================================================================================================================================================
Table: Values
========================================================================================================================================================================================
Allowed MODBUS functions: 03, 04
Register(s) Com.Obj. Name Dimension Type Len Dec Min Max Group / Subgroup
========================================================================================================================================================================================
01000 10123 转速 RPM Integer 2 0 0 3000 发动机
01001 8202 Load P kW Integer 2 0 -32767 32767 负载
01002 8524 Load P L1 kW Integer 2 0 -32767 32767 负载
01003 8525 Load P L2 kW Integer 2 0 -32767 32767 负载
01004 8526 Load P L3 kW Integer 2 0 -32767 32767 负载
01005 8203 Load Q kVAr Integer 2 0 -32767 32767 负载
01006 8527 Load Q L1 kVAr Integer 2 0 -32767 32767 负载
01007 8528 Load Q L2 kVAr Integer 2 0 -32767 32767 负载
01008 8529 Load Q L3 kVAr Integer 2 0 -32767 32767 负载
01009 8565 Load S kVA Integer 2 0 0 32767 负载
01010 8530 Load S L1 kVA Integer 2 0 0 32767 负载
01011 8531 Load S L2 kVA Integer 2 0 0 32767 负载
01012 8532 Load S L3 kVA Integer 2 0 0 32767 负载
01013 8204 功率因数 Integer 1 2 -100 100 负载
01014 8533 L1功率因数 Integer 1 2 -100 100 负载
01015 8534 L2功率因数 Integer 1 2 -100 100 负载
01016 8535 L3功率因数 Integer 1 2 -100 100 负载
01017 8210 发电频率 Hz Unsigned 2 1 0 4000 发电机
01018 8192 发电电压L1-N V Unsigned 2 0 0 65534 发电机
01019 8193 发电电压L2-N V Unsigned 2 0 0 65534 发电机
01020 8194 发电电压L3-N V Unsigned 2 0 0 65534 发电机
01021 9628 发电电压L1-L2 V Unsigned 2 0 0 65534 发电机
01022 9629 发电电压L2-L3 V Unsigned 2 0 0 65534 发电机
01023 9630 发电电压L3-L1 V Unsigned 2 0 0 65534 发电机
01024 8198 负载电流L1 A Unsigned 2 0 0 32767 负载
01025 8199 负载电流L2 A Unsigned 2 0 0 32767 负载
01026 8200 负载电流L3 A Unsigned 2 0 0 32767 负载
01027 Not Used
01028 Not Used
01029 Not Used
01030 Not Used
01031 Not Used
01032 Not Used
01033 Not Used
01034 Not Used
01035 Not Used
01036 8213 电池电压 V Integer 2 1 0 360 控制器I/O口
01037 10603 D+ V Integer 2 1 0 360 控制器I/O口
01038 9151 油压 Bar Integer 2 1 0 100 控制器I/O口
01039 9152 水温 °C Integer 2 0 -16 120 控制器I/O口
01040 9153 燃油位 % Integer 2 0 0 100 控制器I/O口
01041 Not Used
01042 8235 开关量输入 Binary#1 2 0 - - 控制器I/O口
01043 15780 紧急停机 Binary#2 1 0 - - 控制器I/O口
01044 8239 开关量输出 Binary#3 2 0 - - 控制器I/O口
01045 23924 以太网界面状态 List#1 1 0 0 4 CM-ETHERNET
01046-01053(8) 23931 IP地址 String 16 0 - - CM-ETHERNET
01054-01061(8) 23930 当前子网掩码 String 16 0 - - CM-ETHERNET
01062-01069(8) 23929 当前网关 String 16 0 - - CM-ETHERNET
01070-01077(8) 23928 主DNS String 16 0 - - CM-ETHERNET
01078-01085(8) 23927 次级DNS String 16 0 - - CM-ETHERNET
01086 23925 最后E-mail结果 Unsigned 1 0 0 254 CM-ETHERNET
01087-01102(16) 23932 MAC 地址 String 32 0 - - CM-ETHERNET
01103 23916 以太网接线模式 List#2 1 0 0 3 CM-ETHERNET
01104-01111(8) 23926 AirGate ID String 16 0 - - CM-ETHERNET
01112 23910 AirGate 状态 List#3 1 0 0 8 CM-ETHERNET
01113-01144(32) 23915 AirGate服务节点 String 64 0 - - CM-ETHERNET
01145-01152(8) 24309 AirGate ID String 16 0 - - CM-4G-GPS
01153 23967 AirGate 状态 List#3 1 0 0 8 CM-4G-GPS
01154-01185(32) 23991 AirGate服务节点 String 64 0 - - CM-4G-GPS; CM-4G-GPS
01186-01193(8) 23971 IP地址 String 16 0 - - CM-4G-GPS
01194-01201(8) 23984 主DNS String 16 0 - - CM-4G-GPS
01202-01209(8) 23983 次级DNS String 16 0 - - CM-4G-GPS
01210 24307 最后E-mail结果 Unsigned 1 0 0 254 CM-4G-GPS
01211 24302 讯号强度 % Unsigned 1 0 0 100 CM-4G-GPS
01212 24288 数据机状态 List#4 1 0 0 29 CM-4G-GPS
01213 23972 网络状态 List#5 1 0 0 2 CM-4G-GPS
01214 23973 GPS 状态 List#6 1 0 0 2 CM-4G-GPS
01215-01230(16) 24147 网络名称 String 32 0 - - CM-4G-GPS
01231-01238(8) 24146 网络模式 String 16 0 - - CM-4G-GPS
01239-01246(8) 24268 纬度 String 16 0 - - CM-4G-GPS
01247-01254(8) 24267 经度 String 16 0 - - CM-4G-GPS
01255 24265 有效卫星 Unsigned 1 0 0 15 CM-4G-GPS
01256 24264 速度 km/h Unsigned 2 0 0 65535 CM-4G-GPS
01257-01258(2) 8205 发电KWh kWh Integer 4 0 -32768000 32767000 统计值
01259-01260(2) 8539 发电KVArh kVArh Integer 4 0 -32768000 32767000 统计值
01261 Not Used
01262 Not Used
01263 Not Used
01264 Not Used
01265-01266(2) 8206 运行小时 h Integer 4 1 -32768000 32767000 统计值
01267 8207 起动次数 Unsigned 2 0 0 65534 统计值
01268 11616 维修时间1运行小时 h Integer 2 0 -10000 10000 统计值
01269 11617 维修时间2运行小时 h Integer 2 0 -10000 10000 统计值
01270 11618 维修时间3运行小时 h Integer 2 0 -10000 10000 统计值
01271-01272(2) 14328 租赁1 h Integer 4 0 0 9000 统计值
01273-01274(2) 14369 租赁2 天 Integer 4 0 0 32000 统计值
01275-01276(2) 11195 急停次数 Unsigned 4 0 0 65535000 统计值
01277-01278(2) 11196 停机 Unsigned 4 0 0 65535000 统计值
01279-01280(2) 9040 总燃油消耗 l Unsigned 4 0 0 65535000 统计值
01281 13772 时间到清空 天 Integer 2 0 0 32000 统计值
01282 13771 时间到清空 hrs Integer 2 0 0 23 统计值
01283 13770 时间到清空 min Integer 2 0 0 59 统计值
01284 9887 控制器模式 List#7 1 0 0 2 信息
01285 9591 负载撤载状态 List#8 1 0 0 5 信息
01286 9244 发动机状态 List#9 1 0 0 17 信息
01287 9245 断路器状态 List#10 1 0 0 12 信息
01288 10040 计时文本 List#11 1 0 0 37 信息
01289 12944 连接类型 List#12 1 0 0 7 信息
01290-01305(16) 24501 ID 字串 String 32 0 - - 信息
01306-01313(8) 24339 FW版本 String 16 0 - - 信息
01314 8480 应用 List#13 1 0 0 10 信息
01315 8707 FW分支 List#14 1 0 0 1 信息
01316 9143 Log开关量输出1 Binary#4 2 0 - - 开关量逻辑输出
01317 9144 Log开关量输出2 Binary#5 2 0 - - 开关量逻辑输出
01318 9145 Log开关量输出3 Binary#6 2 0 - - 开关量逻辑输出
01319 9146 Log开关量输出4 Binary#7 2 0 - - 开关量逻辑输出
01320 9147 Log开关量输出5 Binary#8 2 0 - - 开关量逻辑输出
01321 9148 Log开关量输出6 Binary#9 2 0 - - 开关量逻辑输出
01322 9149 Log开关量输出7 Binary#10 2 0 - - 开关量逻辑输出
01323 9150 Log开关量输出8 Binary#11 2 0 - - 开关量逻辑输出
01324 11896 Log开关量输出 Binary#12 2 0 - - 开关量逻辑输出
01325 11897 Log开关量输出10 Binary#13 2 0 - - 开关量逻辑输出
01326-01327(2) 16387 维修时间1间隔 天 Integer 4 0 -10000 10000 统计值
01328-01329(2) 16388 维修时间2间隔 天 Integer 4 0 -10000 10000 统计值
01330-01331(2) 16389 维修时间3间隔 天 Integer 4 0 -10000 10000 统计值
========================================================================================================================================================================================
Table: Setpoints
========================================================================================================================================================================================
Allowed MODBUS functions: 03, 04, 06, 16
Register(s) Com.Obj. Name Dimension Type Len Dec Min Max Group / Subgroup
========================================================================================================================================================================================
========================================================================================================================================================================================
List# Types Meaning
========================================================================================================================================================================================
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
List#1
Value Name
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
0 未知
1 已断开
2 连接中
3 已连接
4 失败
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
List#2
Value Name
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
0 10-HD
1 10-FD
2 100-HD
3 100-FD
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
List#3
Value Name
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
0 没有定义
1 等待连线
2 解析
3 连接中
4 产生第二通道
5 注册中
6 连线不互通
7 连线互通
8 Susp AGkeyEmpty
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
List#4
Value Name
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
0
1 OK
2 EO1
3 EO2
4 E SIM
5 EO4
6 E 注册
7 E 注册
8 E 注册
9 E 内容
10 E 连接
11 E08
12 E09
13 E10
14 E 注册
15 E12
16 E13
17 E14
18 E SMS 发送
19 起始1错误
20 起始2错误
21 起始3错误
22 E18
23 E18
24 E18
25 E 失去连线
26 E19
27 E18
28 重启-配置
29 重启-app
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
List#5
Value Name
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
0 无法使用
1 可以使用
2 附上
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
List#6
Value Name
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
0 未定义
1 寻找中
2 固定
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
List#7
Value Name
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
0 关
1 手动
2 自动
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
List#8
Value Name
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
0 未卸载
1 甩负载1
2 甩负载2
3 甩负载3
4 甩负载S4
5 甩负载S5
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
List#9
Value Name
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
0 初始化
1 候命中
2 未预备
3 预起动
4 盘车中
5 间歇
6 起动中
7 运行中
8 已加载
9 软卸载
10 冷却中
11 停机
12 故障停机
13 通风
14 应急手动
15 软加载
16 等待停机
17 故障停机通风
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
List#10
Value Name
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
0 初始化
1 断路器分
2 孤岛运行
3 市电运行
4 并联操作
5 反向同步
6 同步中
7 市电故障
8 有效错误
9 市电恢复
10 多台岛运
11 多台并运
12 应急手动
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
List#11
Value Name
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
0 无计时
1 预起动
2 盘车中
3 怠速运行
4 冷却中
5 停机阀
6 后冷却
7 间歇
8 燃气通风
9 最短稳定到
10 最大稳定至
11 MCB合
12 转换延时
13 恢复延时
14 启动延时
15 电压侦测
16 GCB延时
17 GCB分闸
18 同步超时
19 GCB闭合
20 MCB分闸
21 等待停机
22 系统起动
23 系统停机
24 下一台起动
25 下一台停机
26 甩负载改变
27 重接载变换(无效)
28 卸载停机
29 警告
30 RPM 窗口超时
31 励磁延时
32 发动机起动超时
33 允许同步
34 Fuel Sol Lead
35 Deexcitation
36 Dummy Load On
37 Dummy Load Off
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
List#12
Value Name
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
0 单相
1 SplPhL1L2
2 SplPhL1L3
3 三角接电压
4 3相3线
5 3相4线
6 3PH 黄低
7 3相黄高
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
List#13
Value Name
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
0 未用
1 未用
2 未用
3 未用
4 未用
5 未用
6 MRS16
7 AMF8
8 AMF9
9 AMF20
10 AMF25
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
List#14
Value Name
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
0 未用
1 标准
========================================================================================================================================================================================
Binary# Types Meaning
========================================================================================================================================================================================
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Binary#1
Bit Name
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
0 遥控启动/停机
1 GC反饋
2 未用
3 存取锁
4 远程关
5 未用
6 禁止停机
7 未用
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Binary#2
Bit Name
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
0 紧急停机
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Binary#3
Bit Name
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
0 起动马达1
1 燃油阀
2 GCB合/分
3 预起动
4 可以加载
5 警告
6 未用
7 未用
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Binary#4
Bit Name
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
0 未用
1 起动马达1
2 燃油阀
3 停机阀
4 停机脉冲
5 点火
6 预起动
7 冷却泵
8 怠速/额定
9 空气阀
10 警告
11 蜂鸣
12 GCB合/分
13 GCB闭合线圈
14 GCB断开线圈
15 GCB失压线圈
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Binary#5
Bit Name
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
0 保留
1 保留
2 保留
3 保留
4 候命中
5 保留
6 可以加载
7 不在自动
8 运行中
9 冷却中
10 加载
11 发电正常
12 保留
13 动作计时器1
14 动作计时器2
15 预热塞
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Binary#6
Bit Name
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
0 停止按鈕
1 温度开关
2 保留
3 点火启动
4 手动候命
5 心跳
6 关模式
7 手动模式
8 自动模式
9 保留
10 发电电压报警报警
11 发电电压警告
12 公共报警值1
13 公共报警值2
14 公共报警有效值1
15 公共报警有效值2
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Binary#7
Bit Name
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
0 发电频率警告
1 发电频率报警
2 保留
3 保留
4 保留
5 公共警告
6 公共报警停机
7 公共报警BOC
8 传感器故障公共报警
9 ECU供电
10 ECU停止运行
11 保留
12 保留
13 双备正常
14 过流
15 保留
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Binary#8
Bit Name
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
0 禁止停机
1 静态逻辑0
2 静态逻辑1
3 需要再生regen
4 后处理HEST 灯
5 保留
6 保留
7 保留
8 消音按钮
9 起动按钮
10 停止按钮
11 保留
12 GCB按钮
13 故障复位按钮
14 电力报警
15 未用
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Binary#9
Bit Name
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
0 ECU等待起动中
1 AIN1开关
2 AIN2开关
3 AIN3开关
4 AIN4开关
5 保留
6 保留
7 保留
8 保留
9 保留
10 保留
11 保留
12 保留
13 保留
14 保留
15 保留
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Binary#10
Bit Name
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
0 保留
1 保留
2 保留
3 保留
4 保留
5 ECU通讯故障
6 ECU红灯
7 ECU 黄灯
8 后处理DEF值灯
9 后处理阻止灯
10 运用计时3
11 运用计时4
12 Exercise Timer 5
13 Exercise Timer 6
14 Exercise Timer 7
15 Exercise Timer 8
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Binary#11
Bit Name
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
0 负载撤载阶段1
1 负载撤载阶段2
2 负载撤载阶段3
3 卸载阶段4
4 卸载阶段5
5 频率选择
6 保留
7 ATT DPF Lamp
8 后处理SCR故障灯
9 排空
10 排空通脉冲
11 排空断脉冲
12 阻风门
13 起动马达2
14 ATT连锁状态
15 ECU 通信正常
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Binary#12
Bit Name
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
0 ATT Regen ACK Lamp
1 ATT PCD 灯
2 维护时间1报警
3 维护时间2报警
4 维护时间3报警
5 MCB 状态
6 GCB 状态
7 Exercise Timer 9
8 Exercise Timer 10
9 Exercise Timer 11
10 Exercise Timer 12
11 Exercise Timer 13
12 Exercise Timer 14
13 Exercise Timer 15
14 Exercise Timer 16
15 Peripheral Module Comm Fail
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Binary#13
Bit Name
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
0 Initialized
1 发电机有效
2 ECU1 通信故障
3 ECU2 通信故障
4 Dummy Load Stage 1
5 Dummy Load Stage 2
6 Dummy Load Stage 3
7 Dummy Load Stage 4
8 Dummy Load Stage 5
9 Start Button State
10 Stop Button State
11 FltRes Button State
12 HornRes Button State
13 MCB Button State
14 GCB Button State

Some files were not shown because too many files have changed in this diff Show More