更新测试页面和更新接口swagger文档

This commit is contained in:
python 2025-12-05 09:33:09 +08:00
parent d0ad41fddd
commit 42c254fe51
6 changed files with 867 additions and 98 deletions

Binary file not shown.

23
app.py
View File

@ -52,6 +52,10 @@ swagger_template = {
"name": "AI解析",
"description": "AI字段提取相关接口"
},
{
"name": "文档生成",
"description": "文档生成相关接口"
},
{
"name": "字段配置",
"description": "字段配置查询接口"
@ -465,6 +469,25 @@ def generate_document():
fpolicFieldParamFileList:
type: array
description: 文件列表包含filePath
items:
type: object
properties:
fileId:
type: integer
description: 文件ID
example: 1
fileName:
type: string
description: 文件名称
example: 请示报告卡.doc
templateCode:
type: string
description: 模板编码
example: PRELIMINARY_VERIFICATION_APPROVAL
filePath:
type: string
description: MinIO相对路径
example: /202511261123/请示报告卡.doc
msg:
type: string
example: ok

View File

@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>智慧监督AI文书写作 - 解析接口测试</title>
<title>智慧监督AI文书写作 - API接口测试</title>
<style>
* {
margin: 0;
@ -19,7 +19,7 @@
}
.container {
max-width: 1200px;
max-width: 1400px;
margin: 0 auto;
background: white;
border-radius: 12px;
@ -44,10 +44,43 @@
font-size: 14px;
}
.content {
.tabs {
display: flex;
background: #f5f5f5;
border-bottom: 2px solid #667eea;
}
.tab {
flex: 1;
padding: 15px 20px;
text-align: center;
cursor: pointer;
background: transparent;
border: none;
font-size: 16px;
font-weight: 500;
color: #666;
transition: all 0.3s;
}
.tab:hover {
background: #e0e0e0;
}
.tab.active {
background: #667eea;
color: white;
}
.tab-content {
display: none;
padding: 30px;
}
.tab-content.active {
display: block;
}
.section {
margin-bottom: 30px;
}
@ -96,15 +129,12 @@
font-family: inherit;
}
.input-fields {
.field-row {
display: grid;
grid-template-columns: 1fr 2fr;
gap: 15px;
margin-bottom: 15px;
}
.input-fields input {
margin-bottom: 0;
align-items: start;
}
.btn {
@ -134,13 +164,23 @@
transform: none;
}
.btn-secondary {
background: #4caf50;
}
.btn-danger {
background: #f44336;
padding: 8px 15px;
font-size: 14px;
}
.result-box {
background: #f8f9fa;
border: 2px solid #e0e0e0;
border-radius: 6px;
padding: 20px;
margin-top: 20px;
max-height: 500px;
max-height: 600px;
overflow-y: auto;
}
@ -203,18 +243,22 @@
border-left-color: #4caf50;
}
.add-field-btn {
background: #4caf50;
padding: 8px 15px;
font-size: 14px;
margin-top: 10px;
.info-link {
text-align: center;
margin-top: 20px;
padding: 15px;
background: #e3f2fd;
border-radius: 6px;
}
.remove-field-btn {
background: #f44336;
padding: 6px 12px;
font-size: 12px;
margin-left: 10px;
.info-link a {
color: #667eea;
text-decoration: none;
font-weight: 500;
}
.info-link a:hover {
text-decoration: underline;
}
</style>
</head>
@ -222,135 +266,208 @@
<div class="container">
<div class="header">
<h1>智慧监督AI文书写作</h1>
<p>解析接口测试工具 - 初步核实审批表</p>
<p>API接口测试工具 - 解析接口 & 文档生成接口</p>
</div>
<div class="content">
<!-- 输入区域 -->
<!-- 标签页 -->
<div class="tabs">
<button class="tab active" onclick="switchTab('extract')">AI解析接口</button>
<button class="tab" onclick="switchTab('generate')">文档生成接口</button>
</div>
<!-- 解析接口标签页 -->
<div id="extract-tab" class="tab-content active">
<div class="section">
<div class="section-title">输入数据</div>
<div class="form-group">
<label>业务类型</label>
<select id="businessType">
<option value="INVESTIGATION">INVESTIGATION (调查核实)</option>
<option value="COMPLAINT">COMPLAINT (投诉举报)</option>
</select>
</div>
<div class="form-group">
<label>输入字段数据</label>
<div id="inputFieldsContainer">
<!-- 动态生成的输入字段 -->
</div>
<button class="btn add-field-btn" onclick="addInputField()">+ 添加输入字段</button>
<button class="btn btn-secondary" onclick="addInputField()">+ 添加输入字段</button>
</div>
<div class="form-group">
<label>输出字段列表(需要提取的字段)</label>
<div id="outputFieldsContainer">
<!-- 动态生成的输出字段 -->
</div>
<button class="btn btn-secondary" onclick="addOutputField()">+ 添加输出字段</button>
</div>
</div>
<!-- 操作按钮 -->
<div class="section">
<button class="btn" onclick="extractData()" id="extractBtn">开始解析</button>
</div>
<!-- 加载提示 -->
<div class="loading" id="loading">
<div class="loading" id="extractLoading">
<div class="spinner"></div>
<p>AI正在解析中请稍候...</p>
</div>
<!-- 结果展示 -->
<div class="section" id="resultSection" style="display: none;">
<div class="section" id="extractResultSection" style="display: none;">
<div class="section-title">解析结果</div>
<div class="result-box" id="resultBox"></div>
<div class="result-box" id="extractResultBox"></div>
</div>
</div>
<!-- 文档生成接口标签页 -->
<div id="generate-tab" class="tab-content">
<div class="section">
<div class="section-title">输入数据</div>
<div class="form-group">
<label>字段数据(用于填充模板)</label>
<div id="generateFieldsContainer">
<!-- 动态生成的字段 -->
</div>
<button class="btn btn-secondary" onclick="addGenerateField()">+ 添加字段</button>
</div>
<div class="form-group">
<label>文件列表</label>
<div id="fileListContainer">
<!-- 动态生成的文件列表 -->
</div>
<button class="btn btn-secondary" onclick="addFileItem()">+ 添加文件</button>
</div>
</div>
<div class="section">
<button class="btn" onclick="generateDocument()" id="generateBtn">生成文档</button>
</div>
<div class="loading" id="generateLoading">
<div class="spinner"></div>
<p>正在生成文档,请稍候...</p>
</div>
<div class="section" id="generateResultSection" style="display: none;">
<div class="section-title">生成结果</div>
<div class="result-box" id="generateResultBox"></div>
</div>
</div>
<div class="info-link">
<a href="/api-docs" target="_blank">📖 查看完整的API文档 (Swagger)</a>
</div>
</div>
<script>
let inputFields = [];
let outputFields = [];
// 页面加载时初始化
window.onload = function() {
loadFields();
initDefaultInputFields();
initExtractTab();
initGenerateTab();
};
// 加载字段配置
async function loadFields() {
try {
const response = await fetch('/api/fields?businessType=INVESTIGATION');
const result = await response.json();
// 切换标签页
function switchTab(tabName) {
// 隐藏所有标签页内容
document.querySelectorAll('.tab-content').forEach(content => {
content.classList.remove('active');
});
if (result.isSuccess && result.data) {
outputFields = result.data.output_fields || [];
// 可以在这里使用outputFields来显示字段信息
}
} catch (error) {
console.error('加载字段配置失败:', error);
}
// 移除所有标签页的active类
document.querySelectorAll('.tab').forEach(tab => {
tab.classList.remove('active');
});
// 显示选中的标签页
document.getElementById(tabName + '-tab').classList.add('active');
event.target.classList.add('active');
}
// 初始化默认输入字段
function initDefaultInputFields() {
addInputField('clue_info', '线索信息', '被举报用户名称是张三年龄30岁某公司总经理');
addInputField('target_basic_info_clue', '被核查人员工作基本情况线索', '张三汉族1980年5月出生山西太原人本科学历2000年参加工作2005年加入中国共产党。');
// ==================== 解析接口相关 ====================
function initExtractTab() {
// 初始化默认输入字段
addInputField('clue_info', '被举报用户名称是张三年龄30岁某公司总经理男性1980年5月出生中共党员正处级');
// 初始化默认输出字段
addOutputField('target_name');
addOutputField('target_gender');
addOutputField('target_organization_and_position');
}
// 添加输入字段
function addInputField(fieldCode = '', fieldName = '', fieldValue = '') {
function addInputField(fieldCode = 'clue_info', fieldValue = '') {
const container = document.getElementById('inputFieldsContainer');
const fieldDiv = document.createElement('div');
fieldDiv.className = 'input-fields';
fieldDiv.className = 'field-row';
fieldDiv.innerHTML = `
<input type="text" placeholder="字段编码 (如: clue_info)" value="${fieldCode}" class="field-code">
<div style="display: flex; gap: 10px;">
<input type="text" placeholder="字段值" value="${fieldValue}" class="field-value" style="flex: 1;">
<button class="btn remove-field-btn" onclick="removeInputField(this)">删除</button>
<textarea placeholder="字段值(原始文本)" class="field-value" style="flex: 1; min-height: 60px;">${fieldValue}</textarea>
<button class="btn btn-danger" onclick="removeField(this)">删除</button>
</div>
`;
container.appendChild(fieldDiv);
}
// 删除输入字段
function removeInputField(btn) {
btn.closest('.input-fields').remove();
function addOutputField(fieldCode = '') {
const container = document.getElementById('outputFieldsContainer');
const fieldDiv = document.createElement('div');
fieldDiv.className = 'field-row';
fieldDiv.innerHTML = `
<input type="text" placeholder="字段编码 (如: target_name)" value="${fieldCode}" class="output-field-code">
<div style="display: flex; gap: 10px;">
<div style="flex: 1;"></div>
<button class="btn btn-danger" onclick="removeField(this)">删除</button>
</div>
`;
container.appendChild(fieldDiv);
}
// 提取数据
async function extractData() {
const extractBtn = document.getElementById('extractBtn');
const loading = document.getElementById('loading');
const resultSection = document.getElementById('resultSection');
const resultBox = document.getElementById('resultBox');
const loading = document.getElementById('extractLoading');
const resultSection = document.getElementById('extractResultSection');
const resultBox = document.getElementById('extractResultBox');
// 收集输入数据
const inputFields = [];
const fieldContainers = document.querySelectorAll('#inputFieldsContainer .input-fields');
const inputData = [];
const fieldContainers = document.querySelectorAll('#inputFieldsContainer .field-row');
fieldContainers.forEach(container => {
const fieldCode = container.querySelector('.field-code').value.trim();
const fieldValue = container.querySelector('.field-value').value.trim();
if (fieldCode && fieldValue) {
inputFields.push({
inputData.push({
fieldCode: fieldCode,
fieldValue: fieldValue
});
}
});
if (inputFields.length === 0) {
// 收集输出字段
const outputData = [];
const outputContainers = document.querySelectorAll('#outputFieldsContainer .field-row');
outputContainers.forEach(container => {
const fieldCode = container.querySelector('.output-field-code').value.trim();
if (fieldCode) {
outputData.push({
fieldCode: fieldCode
});
}
});
if (inputData.length === 0) {
alert('请至少添加一个输入字段');
return;
}
const businessType = document.getElementById('businessType').value;
if (outputData.length === 0) {
alert('请至少添加一个输出字段');
return;
}
// 构建请求数据
// 构建请求数据(新接口格式)
const requestData = {
businessType: businessType,
inputData: inputFields
inputData: inputData,
outputData: outputData
};
// 显示加载状态
@ -359,7 +476,7 @@
resultSection.style.display = 'none';
try {
const response = await fetch('/api/ai/extract', {
const response = await fetch('/ai/extract', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
@ -368,22 +485,19 @@
});
const result = await response.json();
// 显示结果
displayResult(result, requestData);
displayExtractResult(result, requestData);
} catch (error) {
displayError(error.message);
displayError('extract', error.message);
} finally {
extractBtn.disabled = false;
loading.classList.remove('active');
}
}
// 显示结果
function displayResult(result, requestData) {
const resultSection = document.getElementById('resultSection');
const resultBox = document.getElementById('resultBox');
function displayExtractResult(result, requestData) {
const resultSection = document.getElementById('extractResultSection');
const resultBox = document.getElementById('extractResultBox');
resultSection.style.display = 'block';
@ -395,19 +509,20 @@
// 显示响应结果
if (result.isSuccess) {
html += '<div class="result-item success"><strong>解析成功!</strong></div>';
html += '<div class="result-item success"><strong>解析成功!</strong></div>';
if (result.data && result.data.outData) {
html += '<div class="result-item"><strong>提取的字段:</strong></div>';
result.data.outData.forEach(item => {
const value = item.fieldValue || '(空)';
html += `<div class="result-item">
<strong>${item.fieldCode}:</strong> ${item.fieldValue || '(空)'}
<strong>${item.fieldCode}:</strong> ${value}
</div>`;
});
}
} else {
html += `<div class="result-item error">
<strong>解析失败!</strong><br>
<strong>解析失败!</strong><br>
错误码: ${result.code}<br>
错误信息: ${result.errorMsg}
</div>`;
@ -418,15 +533,195 @@
html += '<div class="result-item"><pre>' + JSON.stringify(result, null, 2) + '</pre></div>';
resultBox.innerHTML = html;
// 滚动到结果区域
resultSection.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
}
// 显示错误
function displayError(errorMsg) {
const resultSection = document.getElementById('resultSection');
const resultBox = document.getElementById('resultBox');
// ==================== 文档生成接口相关 ====================
function initGenerateTab() {
// 初始化默认字段
addGenerateField('target_name', '张三');
addGenerateField('target_gender', '男');
addGenerateField('target_organization_and_position', '某公司总经理');
// 初始化默认文件
addFileItem(1, '初步核实审批表.doc', 'PRELIMINARY_VERIFICATION_APPROVAL');
}
function addGenerateField(fieldCode = '', fieldValue = '') {
const container = document.getElementById('generateFieldsContainer');
const fieldDiv = document.createElement('div');
fieldDiv.className = 'field-row';
fieldDiv.innerHTML = `
<input type="text" placeholder="字段编码 (如: target_name)" value="${fieldCode}" class="generate-field-code">
<div style="display: flex; gap: 10px;">
<input type="text" placeholder="字段值" value="${fieldValue}" class="generate-field-value" style="flex: 1;">
<button class="btn btn-danger" onclick="removeField(this)">删除</button>
</div>
`;
container.appendChild(fieldDiv);
}
function addFileItem(fileId = '', fileName = '', templateCode = '') {
const container = document.getElementById('fileListContainer');
const fileDiv = document.createElement('div');
fileDiv.className = 'field-row';
fileDiv.innerHTML = `
<input type="number" placeholder="文件ID" value="${fileId}" class="file-id" style="width: 150px;">
<div style="display: flex; gap: 10px; flex: 1;">
<input type="text" placeholder="文件名称 (如: 初步核实审批表.doc)" value="${fileName}" class="file-name" style="flex: 1;">
<input type="text" placeholder="模板编码 (如: PRELIMINARY_VERIFICATION_APPROVAL)" value="${templateCode}" class="template-code" style="flex: 1;">
<button class="btn btn-danger" onclick="removeField(this)">删除</button>
</div>
`;
container.appendChild(fileDiv);
}
async function generateDocument() {
const generateBtn = document.getElementById('generateBtn');
const loading = document.getElementById('generateLoading');
const resultSection = document.getElementById('generateResultSection');
const resultBox = document.getElementById('generateResultBox');
// 收集字段数据
const inputData = [];
const fieldContainers = document.querySelectorAll('#generateFieldsContainer .field-row');
fieldContainers.forEach(container => {
const fieldCode = container.querySelector('.generate-field-code').value.trim();
const fieldValue = container.querySelector('.generate-field-value').value.trim();
if (fieldCode) {
inputData.push({
fieldCode: fieldCode,
fieldValue: fieldValue || ''
});
}
});
// 收集文件列表
const fileList = [];
const fileContainers = document.querySelectorAll('#fileListContainer .field-row');
fileContainers.forEach(container => {
const fileId = container.querySelector('.file-id').value.trim();
const fileName = container.querySelector('.file-name').value.trim();
const templateCode = container.querySelector('.template-code').value.trim();
if (fileId && fileName && templateCode) {
fileList.push({
fileId: parseInt(fileId),
fileName: fileName,
templateCode: templateCode
});
}
});
if (inputData.length === 0) {
alert('请至少添加一个字段');
return;
}
if (fileList.length === 0) {
alert('请至少添加一个文件');
return;
}
// 构建请求数据
const requestData = {
inputData: inputData,
fpolicFieldParamFileList: fileList
};
// 显示加载状态
generateBtn.disabled = true;
loading.classList.add('active');
resultSection.style.display = 'none';
try {
const response = await fetch('/ai/generate-document', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(requestData)
});
const result = await response.json();
displayGenerateResult(result, requestData);
} catch (error) {
displayError('generate', error.message);
} finally {
generateBtn.disabled = false;
loading.classList.remove('active');
}
}
function displayGenerateResult(result, requestData) {
const resultSection = document.getElementById('generateResultSection');
const resultBox = document.getElementById('generateResultBox');
resultSection.style.display = 'block';
let html = '';
// 显示请求数据
html += '<div class="result-item"><strong>请求数据:</strong></div>';
html += '<div class="result-item"><pre>' + JSON.stringify(requestData, null, 2) + '</pre></div>';
// 显示响应结果
if (result.isSuccess) {
html += '<div class="result-item success"><strong>✓ 文档生成成功!</strong></div>';
if (result.data) {
if (result.data.documentId) {
html += `<div class="result-item">
<strong>文档ID:</strong> ${result.data.documentId}
</div>`;
}
if (result.data.documentName) {
html += `<div class="result-item">
<strong>文档名称:</strong> ${result.data.documentName}
</div>`;
}
if (result.data.fpolicFieldParamFileList && result.data.fpolicFieldParamFileList.length > 0) {
html += '<div class="result-item"><strong>生成的文件:</strong></div>';
result.data.fpolicFieldParamFileList.forEach(file => {
html += `<div class="result-item">
<strong>${file.fileName}:</strong><br>
文件路径: ${file.filePath || '(无路径)'}
</div>`;
});
}
}
} else {
html += `<div class="result-item error">
<strong>✗ 文档生成失败!</strong><br>
错误码: ${result.code}<br>
错误信息: ${result.errorMsg}
</div>`;
}
// 显示完整响应
html += '<div class="result-item"><strong>完整响应:</strong></div>';
html += '<div class="result-item"><pre>' + JSON.stringify(result, null, 2) + '</pre></div>';
resultBox.innerHTML = html;
resultSection.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
}
// ==================== 通用函数 ====================
function removeField(btn) {
btn.closest('.field-row').remove();
}
function displayError(tabType, errorMsg) {
const resultSection = document.getElementById(tabType + 'ResultSection');
const resultBox = document.getElementById(tabType + 'ResultBox');
resultSection.style.display = 'block';
resultBox.innerHTML = `<div class="result-item error">
@ -437,4 +732,3 @@
</script>
</body>
</html>

203
测试页面使用指南.md Normal file
View File

@ -0,0 +1,203 @@
# 测试页面使用指南
## 🎯 概述
测试页面提供了两个API接口的可视化测试功能
1. **AI解析接口** - 从非结构化文本中提取结构化字段
2. **文档生成接口** - 根据字段数据填充Word模板并生成文档
---
## 📋 功能说明
### 1. AI解析接口测试
#### 功能描述
使用AI大模型从输入文本中提取结构化字段数据。
#### 使用步骤
1. **切换到"AI解析接口"标签页**
- 点击页面顶部的"AI解析接口"标签
2. **添加输入字段**
- 输入字段编码(如:`clue_info`
- 输入字段值(原始文本)
- 可以添加多个输入字段
- 点击"+ 添加输入字段"添加更多
3. **添加输出字段**
- 输入需要提取的字段编码(如:`target_name`
- 可以添加多个输出字段
- 点击"+ 添加输出字段"添加更多
4. **开始解析**
- 点击"开始解析"按钮
- 等待AI处理可能需要一些时间
- 查看解析结果
#### 示例数据
**输入字段:**
```
字段编码: clue_info
字段值: 被举报用户名称是张三年龄30岁某公司总经理男性1980年5月出生中共党员正处级
```
**输出字段:**
```
target_name
target_gender
target_organization_and_position
```
#### 预期结果
```json
{
"code": 0,
"data": {
"outData": [
{
"fieldCode": "target_name",
"fieldValue": "张三"
},
{
"fieldCode": "target_gender",
"fieldValue": "男"
},
{
"fieldCode": "target_organization_and_position",
"fieldValue": "某公司总经理"
}
]
},
"isSuccess": true
}
```
---
### 2. 文档生成接口测试
#### 功能描述
根据字段数据填充Word模板生成填充后的文档并上传到MinIO。
#### 使用步骤
1. **切换到"文档生成接口"标签页**
- 点击页面顶部的"文档生成接口"标签
2. **添加字段数据**
- 输入字段编码(如:`target_name`
- 输入字段值(如:`张三`
- 可以添加多个字段
- 点击"+ 添加字段"添加更多
3. **添加文件配置**
- 输入文件ID`1`
- 输入文件名称(如:`初步核实审批表.doc`
- 输入模板编码(如:`PRELIMINARY_VERIFICATION_APPROVAL`
- 可以添加多个文件
- 点击"+ 添加文件"添加更多
4. **生成文档**
- 点击"生成文档"按钮
- 等待文档生成和上传(可能需要一些时间)
- 查看生成结果
#### 示例数据
**字段数据:**
```
target_name: 张三
target_gender: 男
target_organization_and_position: 某公司总经理
```
**文件配置:**
```
文件ID: 1
文件名称: 初步核实审批表.doc
模板编码: PRELIMINARY_VERIFICATION_APPROVAL
```
#### 预期结果
```json
{
"code": 0,
"data": {
"documentId": "DOC202411260001",
"documentName": "初步核实审批表_张三.docx",
"fpolicFieldParamFileList": [
{
"fileId": 1,
"fileName": "初步核实审批表.doc",
"filePath": "/202511261123/初步核实审批表.doc"
}
]
},
"isSuccess": true
}
```
---
## ⚠️ 注意事项
### AI解析接口
1. **字段编码必须正确**
- 字段编码需要与数据库中的配置一致
- 可以使用数据库中已有的字段编码
2. **输出字段必须存在**
- 输出字段必须在数据库中已配置
- 如果字段不存在,可能无法提取
3. **AI服务配置**
- 需要配置 `SILICONFLOW_API_KEY``.env` 文件中
- 如果未配置,解析将失败
### 文档生成接口
1. **模板编码必须正确**
- 模板编码需要与数据库中的文件配置一致
- 必须使用 `template_code` 字段的值
2. **MinIO配置**
- 需要配置MinIO连接信息
- 模板文件必须存在于MinIO中
3. **字段值匹配**
- Word模板中的占位符需要与字段编码匹配
- 未匹配的占位符将保持为空
---
## 🔗 相关链接
- **Swagger API文档**: http://localhost:7500/api-docs
- **测试页面**: http://localhost:7500/
---
## 📝 常见问题
### Q: 解析接口一直加载怎么办?
A: 检查AI服务配置是否正确查看浏览器控制台是否有错误信息。
### Q: 文档生成失败?
A:
1. 检查模板编码是否正确
2. 检查MinIO配置和连接
3. 检查模板文件是否存在于MinIO
### Q: 如何查看详细的接口文档?
A: 点击页面底部的"查看完整的API文档 (Swagger)"链接。
---
**祝测试顺利!** 🎉

View File

@ -0,0 +1,143 @@
# 测试页面和Swagger更新总结
## ✅ 更新完成
### 1. 测试页面更新 (`static/index.html`)
#### 主要改动
- ✅ **双标签页设计**
- 新增标签页切换功能
- AI解析接口标签页
- 文档生成接口标签页
- 清晰的界面导航
- ✅ **AI解析接口更新**
- 移除了 `businessType` 选择框(新接口不再需要)
- 新增 `outputData` 输入区域
- 支持动态添加/删除输入字段
- 支持动态添加/删除输出字段
- 使用新的接口格式(`inputData` + `outputData`
- ✅ **文档生成接口支持**
- 新增字段数据输入区域
- 新增文件列表配置区域
- 支持多个文件同时生成
- 显示完整的生成结果文档ID、文档名称、文件路径
- ✅ **界面优化**
- 现代化的UI设计
- 清晰的结果展示区域
- 友好的错误提示
- 链接到Swagger API文档
#### 接口路径
- 解析接口: `/ai/extract``/api/ai/extract`
- 文档生成接口: `/ai/generate-document``/api/ai/generate-document`
---
### 2. Swagger配置更新 (`app.py`)
#### 主要改动
- ✅ **新增标签定义**
- 添加"文档生成"标签到Swagger配置
- 标签列表包含AI解析、文档生成、字段配置
- ✅ **接口文档完整性**
- ✅ AI解析接口 (`/ai/extract`)
- 完整的请求参数说明
- 完整的响应结构说明
- 错误码定义2001, 2002等
- ✅ 文档生成接口 (`/ai/generate-document`)
- 完整的请求参数说明
- 完整的响应结构说明
- 错误码定义1001, 3001, 3002等
- 包含 `filePath` 字段说明
#### Swagger访问
- URL: http://localhost:7500/api-docs
- 可以查看和测试所有接口
---
## 📋 功能对比
### 之前 vs 现在
| 功能 | 之前 | 现在 |
|------|------|------|
| 解析接口测试 | ✅ 支持 | ✅ 支持(新格式) |
| 文档生成测试 | ❌ 不支持 | ✅ 支持 |
| businessType参数 | ✅ 需要 | ❌ 已移除 |
| outputData参数 | ❌ 不支持 | ✅ 支持 |
| 标签页切换 | ❌ 不支持 | ✅ 支持 |
| Swagger文档 | ✅ 部分接口 | ✅ 完整接口 |
---
## 🎯 测试指南
### 快速测试步骤
1. **启动服务**
```bash
python app.py
```
2. **访问测试页面**
- 打开浏览器访问: http://localhost:7500/
3. **测试解析接口**
- 切换到"AI解析接口"标签页
- 添加输入字段和输出字段
- 点击"开始解析"
4. **测试文档生成接口**
- 切换到"文档生成接口"标签页
- 添加字段数据和文件配置
- 点击"生成文档"
5. **查看API文档**
- 访问: http://localhost:7500/api-docs
- 或点击测试页面底部的链接
---
## 📝 相关文档
- `测试页面使用指南.md` - 详细的使用说明
- `测试页面更新说明.md` - 更新内容说明
- `技术文档/智慧监督AI文书写作接口定义-20251204-1.md` - 接口定义文档
---
## ✨ 亮点功能
1. **双标签页设计** - 方便在两个接口之间切换
2. **动态字段管理** - 可以随时添加/删除字段
3. **完整的结果展示** - 显示请求数据、响应结果和完整响应
4. **友好的错误提示** - 清晰的错误信息展示
5. **Swagger集成** - 完整的API文档和测试功能
---
## 🔍 验证清单
- [x] 测试页面已更新为双标签页
- [x] AI解析接口使用新格式无businessType
- [x] 支持outputData参数
- [x] 文档生成接口测试功能完整
- [x] Swagger配置已更新
- [x] 两个接口都在Swagger中
- [x] 接口文档完整准确
- [x] 错误码定义完整
---
**所有更新已完成!可以开始测试了!** 🎉

106
测试页面更新说明.md Normal file
View File

@ -0,0 +1,106 @@
# 测试页面更新说明
## ✅ 更新内容
### 1. 测试页面更新 (`static/index.html`)
#### 新增功能
1. **双标签页设计**
- AI解析接口标签页
- 文档生成接口标签页
- 可以在两个接口之间切换测试
2. **AI解析接口更新**
- ✅ 取消 `businessType` 参数选择
- ✅ 新增 `outputData` 输入区域
- ✅ 支持动态添加/删除输入字段和输出字段
- ✅ 使用新的接口格式
3. **文档生成接口支持**
- ✅ 字段数据输入区域
- ✅ 文件列表配置区域
- ✅ 支持多个文件同时生成
- ✅ 显示文档ID、文档名称和文件路径
4. **界面优化**
- ✅ 现代化的标签页设计
- ✅ 清晰的结果展示
- ✅ 友好的错误提示
- ✅ 链接到Swagger API文档
### 2. Swagger配置更新
- ✅ 添加"文档生成"标签
- ✅ 两个接口都已包含在Swagger文档中
- ✅ 完整的接口文档说明
---
## 📋 使用说明
### 测试AI解析接口
1. 切换到"AI解析接口"标签页
2. 添加输入字段(字段编码 + 字段值)
3. 添加输出字段(只需字段编码)
4. 点击"开始解析"按钮
5. 查看解析结果
### 测试文档生成接口
1. 切换到"文档生成接口"标签页
2. 添加字段数据(字段编码 + 字段值)
3. 添加文件配置文件ID + 文件名称 + 模板编码)
4. 点击"生成文档"按钮
5. 查看生成结果(包括文件路径)
---
## 🎯 接口路径
- **解析接口**: `/ai/extract``/api/ai/extract`
- **文档生成接口**: `/ai/generate-document``/api/ai/generate-document`
- **API文档**: `/api-docs`
---
## 📝 示例数据
### AI解析接口示例
**输入字段:**
- 字段编码: `clue_info`
- 字段值: `被举报用户名称是张三年龄30岁某公司总经理男性1980年5月出生中共党员正处级`
**输出字段:**
- `target_name`
- `target_gender`
- `target_organization_and_position`
### 文档生成接口示例
**字段数据:**
- `target_name`: `张三`
- `target_gender`: `男`
- `target_organization_and_position`: `某公司总经理`
**文件配置:**
- 文件ID: `1`
- 文件名称: `初步核实审批表.doc`
- 模板编码: `PRELIMINARY_VERIFICATION_APPROVAL`
---
## 🔍 验证清单
- [x] 测试页面已更新
- [x] 支持解析接口测试
- [x] 支持文档生成接口测试
- [x] Swagger配置已更新
- [x] 两个接口都在Swagger中
---
**更新完成!** 🎉