Compare commits
58 Commits
difyPlugin
...
pigx迁移
| Author | SHA1 | Date | |
|---|---|---|---|
| 843146cdd7 | |||
| b30af4aff8 | |||
| 1bf08ff52f | |||
| f4265995bc | |||
| 12d9294f3d | |||
| b7bf32e785 | |||
| 8ab6107f25 | |||
| 87f2772964 | |||
| 0bf7361672 | |||
| 1b02067d50 | |||
| 6921ac7e66 | |||
| 0972d504ab | |||
| f4b7337210 | |||
| bfd06dd8f6 | |||
| 0ae5343b11 | |||
| 8073a95f74 | |||
| f948362d1b | |||
| 54599f28d1 | |||
| 16e714730d | |||
| b0ddabd819 | |||
| b1e7aeca43 | |||
| 419b6ffec5 | |||
| 12d43e912c | |||
| 8e86f244c6 | |||
| 5190a0cc9c | |||
| 4784971d97 | |||
| 2e159ec318 | |||
| 23f08dec09 | |||
| 5bad18dd33 | |||
| 86bd6613b4 | |||
| c7c18d4dc3 | |||
| 2e84282424 | |||
| 72cea2935d | |||
| ec61f134a8 | |||
| 75877db4f9 | |||
| 576c7e9ed2 | |||
| b7378867c0 | |||
| 2d19ee784b | |||
| 5d54ac1cd4 | |||
| 97724c8c8d | |||
| 73badc175d | |||
| 89bc8bf1d4 | |||
| 19026c1b30 | |||
| e15305df85 | |||
| 4b6d7d04ec | |||
| 05c76fa3ec | |||
| b53faca120 | |||
| eb15706ccc | |||
| 4e373e6d2c | |||
| a07daa715a | |||
| 87baa347b7 | |||
| 48da0a4c81 | |||
| c0cbb059fe | |||
| 8cb8692b84 | |||
| 1bb1dba4d6 | |||
| 4f0eeede37 | |||
| 1ef1b32f5f | |||
| 154ac7f61c |
209
.gitignore
vendored
209
.gitignore
vendored
@@ -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
5
.idea/.gitignore
generated
vendored
@@ -1,5 +0,0 @@
|
||||
# 默认忽略的文件
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# 基于编辑器的 HTTP 客户端请求
|
||||
/httpRequests/
|
||||
6
.idea/misc.xml
generated
6
.idea/misc.xml
generated
@@ -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
8
.idea/modules.xml
generated
@@ -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>
|
||||
9
.idea/urbanLifeline.iml
generated
9
.idea/urbanLifeline.iml
generated
@@ -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
6
.idea/vcs.xml
generated
@@ -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
27
.vscode/launch.json
vendored
Normal 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"
|
||||
}
|
||||
]
|
||||
}
|
||||
6
.vscode/settings.json
vendored
6
.vscode/settings.json
vendored
@@ -1,4 +1,10 @@
|
||||
{
|
||||
"maven.view": "hierarchical",
|
||||
"editor.tabSize": 4,
|
||||
"[*.ts]": {
|
||||
"editor.tabSize": 2
|
||||
},
|
||||
"[*.vue]": {
|
||||
"editor.tabSize": 2
|
||||
}
|
||||
}
|
||||
116
Makefile
116
Makefile
@@ -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
227
README.md
@@ -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
1
ai-management-platform
Submodule
1
ai-management-platform
Submodule
Submodule ai-management-platform added at 199d8180a6
@@ -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
27
difyPlugin/.gitignore
vendored
@@ -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/
|
||||
17
difyPlugin/.vscode/launch.json
vendored
17
difyPlugin/.vscode/launch.json
vendored
@@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
0
difyPlugin/.vscode/settings.json
vendored
0
difyPlugin/.vscode/settings.json
vendored
146
difyPlugin/DifyCLI.md
Normal file
146
difyPlugin/DifyCLI.md
Normal 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)
|
||||
@@ -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
|
||||
```
|
||||
@@ -1 +0,0 @@
|
||||
# DifyPlugin FastAPI Application
|
||||
@@ -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"]
|
||||
@@ -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": {}})
|
||||
@@ -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"]
|
||||
@@ -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")
|
||||
@@ -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"]
|
||||
@@ -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", "内容无效"))
|
||||
@@ -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"]
|
||||
@@ -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()
|
||||
@@ -1 +0,0 @@
|
||||
# Core模块
|
||||
@@ -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()
|
||||
)
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -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():
|
||||
"""服务健康检查"""
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
from app.schemas.base import ResultDomain
|
||||
from app.schemas.plugin import PluginRequest, PluginResponse
|
||||
|
||||
__all__ = ["ResultDomain", "PluginRequest", "PluginResponse"]
|
||||
@@ -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": "操作成功"}]
|
||||
}
|
||||
}
|
||||
@@ -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="执行状态")
|
||||
@@ -1,2 +0,0 @@
|
||||
|
||||
__all__ = []
|
||||
@@ -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())
|
||||
@@ -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
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
"""二维码服务模块"""
|
||||
from .QrCodeService import QrCodeService
|
||||
|
||||
__all__ = ["QrCodeService"]
|
||||
@@ -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())
|
||||
@@ -1 +0,0 @@
|
||||
# Utils模块
|
||||
@@ -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}
|
||||
@@ -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": "返回数据"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 DLL、Linux .so 问题
|
||||
2. **企业级稳定** - OpenCV 由 Intel 支持,久经考验
|
||||
3. **预处理补偿** - 8种预处理策略让识别率不输 pyzbar
|
||||
4. **运维友好** - CI/CD、Docker 部署零配置
|
||||
5. **团队协作** - 新成员 5 分钟即可搭建环境
|
||||
|
||||
❌ **不推荐 pyzbar**,除非:
|
||||
1. 你只在 Linux 服务器部署
|
||||
2. 需要识别多种条码格式(EAN、Code128 等)
|
||||
3. 有专人负责处理依赖问题
|
||||
|
||||
---
|
||||
|
||||
## 常见问题
|
||||
|
||||
### Q1: 识别率怎么样?
|
||||
|
||||
**答:** 配合预处理策略,识别率可达 95%+
|
||||
- 清晰二维码:99%+
|
||||
- 轻度模糊:95%+
|
||||
- 中度模糊:85%+
|
||||
- 重度损坏:60%+
|
||||
|
||||
### Q2: 比 pyzbar 差多少?
|
||||
|
||||
**答:** 清晰图片无差异,模糊图片差距 < 5%
|
||||
- 对于大部分应用场景,差异可忽略
|
||||
- 配合 `all` 策略可进一步缩小差距
|
||||
|
||||
### Q3: 解析速度如何?
|
||||
|
||||
**答:**
|
||||
- basic: 50-100ms
|
||||
- auto: 200-500ms
|
||||
- all: 500-1000ms
|
||||
|
||||
根据场景选择合适策略即可。
|
||||
|
||||
### Q4: 支持哪些图片格式?
|
||||
|
||||
**答:** 支持所有 OpenCV 支持的格式
|
||||
- PNG、JPG、JPEG、BMP、WebP、TIFF 等
|
||||
|
||||
### 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
184
difyPlugin/pdf/.difyignore
Normal 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
|
||||
|
||||
3
difyPlugin/pdf/.env.example
Normal file
3
difyPlugin/pdf/.env.example
Normal file
@@ -0,0 +1,3 @@
|
||||
INSTALL_METHOD=remote
|
||||
REMOTE_INSTALL_URL=debug.dify.ai:5003
|
||||
REMOTE_INSTALL_KEY=********-****-****-****-************
|
||||
109
difyPlugin/pdf/.github/workflows/plugin-publish.yml
vendored
Normal file
109
difyPlugin/pdf/.github/workflows/plugin-publish.yml
vendored
Normal 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
176
difyPlugin/pdf/.gitignore
vendored
Normal 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
137
difyPlugin/pdf/GUIDE.md
Normal 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).
|
||||
3
difyPlugin/pdf/PRIVACY.md
Normal file
3
difyPlugin/pdf/PRIVACY.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## Privacy
|
||||
|
||||
!!! Please fill in the privacy policy of the plugin.
|
||||
10
difyPlugin/pdf/README.md
Normal file
10
difyPlugin/pdf/README.md
Normal file
@@ -0,0 +1,10 @@
|
||||
## pdf
|
||||
|
||||
**Author:** yslg
|
||||
**Version:** 0.0.1
|
||||
**Type:** tool
|
||||
|
||||
### Description
|
||||
|
||||
|
||||
|
||||
55
difyPlugin/pdf/_assets/icon-dark.svg
Normal file
55
difyPlugin/pdf/_assets/icon-dark.svg
Normal 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 |
55
difyPlugin/pdf/_assets/icon.svg
Normal file
55
difyPlugin/pdf/_assets/icon.svg
Normal 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
6
difyPlugin/pdf/main.py
Normal file
@@ -0,0 +1,6 @@
|
||||
from dify_plugin import Plugin, DifyPluginEnv
|
||||
|
||||
plugin = Plugin(DifyPluginEnv(MAX_REQUEST_TIMEOUT=120))
|
||||
|
||||
if __name__ == '__main__':
|
||||
plugin.run()
|
||||
37
difyPlugin/pdf/manifest.yaml
Normal file
37
difyPlugin/pdf/manifest.yaml
Normal 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
|
||||
64
difyPlugin/pdf/plugin.json
Normal file
64
difyPlugin/pdf/plugin.json
Normal 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"]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
53
difyPlugin/pdf/provider/pdf.py
Normal file
53
difyPlugin/pdf/provider/pdf.py
Normal 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)
|
||||
63
difyPlugin/pdf/provider/pdf.yaml
Normal file
63
difyPlugin/pdf/provider/pdf.yaml
Normal 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
|
||||
2
difyPlugin/pdf/requirements.txt
Normal file
2
difyPlugin/pdf/requirements.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
dify_plugin>=0.4.0,<0.7.0
|
||||
PyPDF2>=3.0.1
|
||||
61
difyPlugin/pdf/tools/pdf.py
Normal file
61
difyPlugin/pdf/tools/pdf.py
Normal 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
|
||||
})
|
||||
36
difyPlugin/pdf/tools/pdf.yaml
Normal file
36
difyPlugin/pdf/tools/pdf.yaml
Normal 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
|
||||
36
difyPlugin/pdf/tools/pdf_single_page.py
Normal file
36
difyPlugin/pdf/tools/pdf_single_page.py
Normal 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]
|
||||
})
|
||||
52
difyPlugin/pdf/tools/pdf_single_page.yaml
Normal file
52
difyPlugin/pdf/tools/pdf_single_page.yaml
Normal 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
|
||||
@@ -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
|
||||
@@ -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
|
||||
)
|
||||
@@ -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
122
difyPlugin/需求文档.md
Normal 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 文档
|
||||
- **测试报告**:测试结果和覆盖率报告
|
||||
- **插件开发指南**:插件开发和注册指南
|
||||
@@ -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;
|
||||
|
||||
# CORS(ES 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;
|
||||
#
|
||||
# # 其他配置同上...
|
||||
# }
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
BIN
docs/AI训练资料/2.pdf
Normal file
Binary file not shown.
BIN
docs/AI训练资料/MTU机组操作说明.pdf
Normal file
BIN
docs/AI训练资料/MTU机组操作说明.pdf
Normal file
Binary file not shown.
BIN
docs/AI训练资料/MTU机组维护计划.pdf
Normal file
BIN
docs/AI训练资料/MTU机组维护计划.pdf
Normal file
Binary file not shown.
BIN
docs/AI训练资料/THL系列柴油发电机组 使用维护说明书-中文-终稿.pdf
Normal file
BIN
docs/AI训练资料/THL系列柴油发电机组 使用维护说明书-中文-终稿.pdf
Normal file
Binary file not shown.
Binary file not shown.
BIN
docs/AI训练资料/丹控控制器/agc-150-modbus-tables-4189341212-中文.xlsx
Normal file
BIN
docs/AI训练资料/丹控控制器/agc-150-modbus-tables-4189341212-中文.xlsx
Normal file
Binary file not shown.
BIN
docs/AI训练资料/丹控控制器/agc-4-modbus-tables-4189341215-中文.xlsx
Normal file
BIN
docs/AI训练资料/丹控控制器/agc-4-modbus-tables-4189341215-中文.xlsx
Normal file
Binary file not shown.
BIN
docs/AI训练资料/丹控控制器/agc-4-操作手册-4189340690-中文.pdf
Normal file
BIN
docs/AI训练资料/丹控控制器/agc-4-操作手册-4189340690-中文.pdf
Normal file
Binary file not shown.
BIN
docs/AI训练资料/丹控控制器/sgc_420_421_用户手册_4189341227_-中文.pdf
Normal file
BIN
docs/AI训练资料/丹控控制器/sgc_420_421_用户手册_4189341227_-中文.pdf
Normal file
Binary file not shown.
BIN
docs/AI训练资料/丹控控制器/sgc_420通讯协议.pdf
Normal file
BIN
docs/AI训练资料/丹控控制器/sgc_420通讯协议.pdf
Normal file
Binary file not shown.
BIN
docs/AI训练资料/众智控制器/HGM6100N_HGM6100CAN_Protocol_cn.pdf
Normal file
BIN
docs/AI训练资料/众智控制器/HGM6100N_HGM6100CAN_Protocol_cn.pdf
Normal file
Binary file not shown.
BIN
docs/AI训练资料/众智控制器/HGM6110CAN_6120CAN_cn.pdf
Normal file
BIN
docs/AI训练资料/众智控制器/HGM6110CAN_6120CAN_cn.pdf
Normal file
Binary file not shown.
BIN
docs/AI训练资料/众智控制器/HGM6110N_6120N_6110NC_6120NC_cn.pdf
Normal file
BIN
docs/AI训练资料/众智控制器/HGM6110N_6120N_6110NC_6120NC_cn.pdf
Normal file
Binary file not shown.
BIN
docs/AI训练资料/众智控制器/HGM9300MPU(CAN)_Protocol_cn.pdf
Normal file
BIN
docs/AI训练资料/众智控制器/HGM9300MPU(CAN)_Protocol_cn.pdf
Normal file
Binary file not shown.
BIN
docs/AI训练资料/众智控制器/HGM9310MPU_9320MPU_9310CAN_9320CAN_cn.pdf
Normal file
BIN
docs/AI训练资料/众智控制器/HGM9310MPU_9320MPU_9310CAN_9320CAN_cn.pdf
Normal file
Binary file not shown.
BIN
docs/AI训练资料/众智控制器/HGM9510N_HGM9520N_HGM9530N_Protocol_cn.pdf
Normal file
BIN
docs/AI训练资料/众智控制器/HGM9510N_HGM9520N_HGM9530N_Protocol_cn.pdf
Normal file
Binary file not shown.
BIN
docs/AI训练资料/众智控制器/HGM9510N_HGM9530N_cn.pdf
Normal file
BIN
docs/AI训练资料/众智控制器/HGM9510N_HGM9530N_cn.pdf
Normal file
Binary file not shown.
BIN
docs/AI训练资料/众智控制器/HGM9510_HGM9520_HGM9530_Protocol_cn.pdf
Normal file
BIN
docs/AI训练资料/众智控制器/HGM9510_HGM9520_HGM9530_Protocol_cn.pdf
Normal file
Binary file not shown.
BIN
docs/AI训练资料/众智控制器/HGM9510_cn.pdf
Normal file
BIN
docs/AI训练资料/众智控制器/HGM9510_cn.pdf
Normal file
Binary file not shown.
BIN
docs/AI训练资料/利莱森玛电机说明书.pdf
Normal file
BIN
docs/AI训练资料/利莱森玛电机说明书.pdf
Normal file
Binary file not shown.
BIN
docs/AI训练资料/深海控制器/DSE7320 MKII Modbus 通讯地址点表~20250326等文件.tar
Normal file
BIN
docs/AI训练资料/深海控制器/DSE7320 MKII Modbus 通讯地址点表~20250326等文件.tar
Normal file
Binary file not shown.
BIN
docs/AI训练资料/深海控制器/DSE7320 MKII.tar
Normal file
BIN
docs/AI训练资料/深海控制器/DSE7320 MKII.tar
Normal file
Binary file not shown.
BIN
docs/AI训练资料/深海控制器/DSE8610.tar
Normal file
BIN
docs/AI训练资料/深海控制器/DSE8610.tar
Normal file
Binary file not shown.
BIN
docs/AI训练资料/深海控制器/常见故障处理.tar
Normal file
BIN
docs/AI训练资料/深海控制器/常见故障处理.tar
Normal file
Binary file not shown.
BIN
docs/AI训练资料/深海控制器/浮充电器故障指示信息.xlsx
Normal file
BIN
docs/AI训练资料/深海控制器/浮充电器故障指示信息.xlsx
Normal file
Binary file not shown.
2147
docs/AI训练资料/科迈控制/IG200通讯点表.txt
Normal file
2147
docs/AI训练资料/科迈控制/IG200通讯点表.txt
Normal file
File diff suppressed because it is too large
Load Diff
1394
docs/AI训练资料/科迈控制/IG4-200通讯点表.txt
Normal file
1394
docs/AI训练资料/科迈控制/IG4-200通讯点表.txt
Normal file
File diff suppressed because it is too large
Load Diff
1491
docs/AI训练资料/科迈控制/IG500-G2通讯点表.txt
Normal file
1491
docs/AI训练资料/科迈控制/IG500-G2通讯点表.txt
Normal file
File diff suppressed because it is too large
Load Diff
960
docs/AI训练资料/科迈控制/IL4MRS16.txt
Normal file
960
docs/AI训练资料/科迈控制/IL4MRS16.txt
Normal 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 围栏1报警BOC 固定保护状态
|
||||
00283 Value 20747 固定保护阶段 4 26 围栏1报警 固定保护状态
|
||||
00284 Value 20747 固定保护阶段 4 27 围栏2报警警告 固定保护状态
|
||||
00285 Value 20747 固定保护阶段 4 28 围栏2报警停机 固定保护状态
|
||||
00286 Value 20747 固定保护阶段 4 29 围栏2报警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
Reference in New Issue
Block a user