更新测试页面和更新接口swagger文档
This commit is contained in:
parent
d0ad41fddd
commit
42c254fe51
Binary file not shown.
23
app.py
23
app.py
@ -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
|
||||
|
||||
@ -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 initExtractTab() {
|
||||
// 初始化默认输入字段
|
||||
function initDefaultInputFields() {
|
||||
addInputField('clue_info', '线索信息', '被举报用户名称是张三,年龄30岁,某公司总经理');
|
||||
addInputField('target_basic_info_clue', '被核查人员工作基本情况线索', '张三,男,汉族,1980年5月出生,山西太原人,本科学历,2000年参加工作,2005年加入中国共产党。');
|
||||
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
203
测试页面使用指南.md
Normal 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)"链接。
|
||||
|
||||
---
|
||||
|
||||
**祝测试顺利!** 🎉
|
||||
|
||||
143
测试页面和Swagger更新总结.md
Normal file
143
测试页面和Swagger更新总结.md
Normal 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
106
测试页面更新说明.md
Normal 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中
|
||||
|
||||
---
|
||||
|
||||
**更新完成!** 🎉
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user