2025-12-04 14:41:20 +08:00

386 lines
12 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
智慧监督AI文书写作服务 - 主应用
"""
from flask import Flask, request, jsonify, send_from_directory
from flask_cors import CORS
from flasgger import Swagger
import os
from datetime import datetime
from dotenv import load_dotenv
from services.ai_service import AIService
from services.field_service import FieldService
from utils.response import success_response, error_response
# 加载环境变量
load_dotenv()
app = Flask(__name__)
CORS(app) # 允许跨域请求
# 配置Swagger
swagger_config = {
"headers": [],
"specs": [
{
"endpoint": "apispec",
"route": "/apispec.json",
"rule_filter": lambda rule: True,
"model_filter": lambda tag: True,
}
],
"static_url_path": "/flasgger_static",
"swagger_ui": True,
"specs_route": "/api-docs"
}
swagger_template = {
"swagger": "2.0",
"info": {
"title": "智慧监督AI文书写作服务 API",
"description": "基于大模型的智能文书生成服务,支持从非结构化文本中提取结构化字段数据",
"version": "1.0.0",
"contact": {
"name": "API支持"
}
},
"basePath": "/",
"schemes": ["http", "https"],
"tags": [
{
"name": "AI解析",
"description": "AI字段提取相关接口"
},
{
"name": "字段配置",
"description": "字段配置查询接口"
}
]
}
swagger = Swagger(app, config=swagger_config, template=swagger_template)
# 初始化服务
ai_service = AIService()
field_service = FieldService()
@app.route('/')
def index():
"""返回测试页面"""
return send_from_directory('static', 'index.html')
@app.route('/api/ai/extract', methods=['POST'])
def extract():
"""
AI字段提取接口
从输入的非结构化文本中提取结构化字段数据
---
tags:
- AI解析
summary: 从输入数据中提取结构化字段
description: 使用AI大模型从输入文本中提取结构化字段支持多种业务类型
consumes:
- application/json
produces:
- application/json
parameters:
- in: body
name: body
description: 请求参数
required: true
schema:
type: object
required:
- businessType
- inputData
properties:
businessType:
type: string
description: 业务类型
example: INVESTIGATION
inputData:
type: array
description: 输入数据列表
items:
type: object
properties:
fieldCode:
type: string
description: 字段编码
example: clue_info
fieldValue:
type: string
description: 字段值(原始文本)
example: 被举报用户名称是张三年龄30岁某公司总经理
responses:
200:
description: 解析成功
schema:
type: object
properties:
code:
type: integer
description: 响应码0表示成功
example: 0
data:
type: object
properties:
outData:
type: array
description: 提取的字段列表
items:
type: object
properties:
fieldCode:
type: string
description: 字段编码
example: target_name
fieldValue:
type: string
description: 提取的字段值
example: 张三
msg:
type: string
description: 响应消息
example: ok
isSuccess:
type: boolean
description: 是否成功
example: true
timestamp:
type: string
description: 时间戳
errorMsg:
type: string
description: 错误信息(成功时为空)
400:
description: 请求参数错误
schema:
type: object
properties:
code:
type: integer
example: 400
errorMsg:
type: string
example: 请求参数不能为空
isSuccess:
type: boolean
example: false
1001:
description: 业务类型不存在
schema:
type: object
properties:
code:
type: integer
example: 1001
errorMsg:
type: string
example: 未找到业务类型 INVESTIGATION 对应的字段配置
isSuccess:
type: boolean
example: false
2001:
description: AI解析超时或发生错误
schema:
type: object
properties:
code:
type: integer
example: 2001
errorMsg:
type: string
example: AI解析超时或发生错误
isSuccess:
type: boolean
example: false
2002:
description: AI解析失败
schema:
type: object
properties:
code:
type: integer
example: 2002
errorMsg:
type: string
example: AI解析失败请检查输入文本质量
isSuccess:
type: boolean
example: false
"""
try:
data = request.get_json()
# 验证请求参数
if not data:
return error_response(400, "请求参数不能为空")
business_type = data.get('businessType')
input_data = data.get('inputData', [])
if not business_type:
return error_response(400, "businessType参数不能为空")
if not input_data or not isinstance(input_data, list):
return error_response(400, "inputData参数必须是非空数组")
# 获取业务类型对应的输出字段
output_fields = field_service.get_output_fields_by_business_type(business_type)
if not output_fields:
return error_response(1001, f"未找到业务类型 {business_type} 对应的字段配置")
# 构建AI提示词
prompt = field_service.build_extract_prompt(input_data, output_fields, business_type)
# 调用AI服务进行解析
ai_result = ai_service.extract_fields(prompt, output_fields)
if not ai_result:
return error_response(2002, "AI解析失败请检查输入文本质量")
# 构建返回数据
out_data = []
for field in output_fields:
field_code = field['field_code']
field_value = ai_result.get(field_code, '')
out_data.append({
'fieldCode': field_code,
'fieldValue': field_value
})
return success_response({'outData': out_data})
except Exception as e:
return error_response(2001, f"AI解析超时或发生错误: {str(e)}")
@app.route('/api/fields', methods=['GET'])
def get_fields():
"""
获取字段配置接口
获取指定业务类型的输入和输出字段配置
---
tags:
- 字段配置
summary: 获取字段配置
description: 获取指定业务类型的输入字段和输出字段配置,用于测试页面展示
produces:
- application/json
parameters:
- in: query
name: businessType
type: string
required: false
default: INVESTIGATION
description: 业务类型
example: INVESTIGATION
responses:
200:
description: 获取成功
schema:
type: object
properties:
code:
type: integer
description: 响应码0表示成功
example: 0
data:
type: object
properties:
fields:
type: object
properties:
input_fields:
type: array
description: 输入字段列表
items:
type: object
properties:
id:
type: integer
description: 字段ID
name:
type: string
description: 字段名称
example: 线索信息
field_code:
type: string
description: 字段编码
example: clue_info
field_type:
type: integer
description: 字段类型1=输入字段2=输出字段)
example: 1
output_fields:
type: array
description: 输出字段列表
items:
type: object
properties:
id:
type: integer
description: 字段ID
name:
type: string
description: 字段名称
example: 被核查人姓名
field_code:
type: string
description: 字段编码
example: target_name
field_type:
type: integer
description: 字段类型1=输入字段2=输出字段)
example: 2
msg:
type: string
description: 响应消息
example: ok
isSuccess:
type: boolean
description: 是否成功
example: true
500:
description: 服务器错误
schema:
type: object
properties:
code:
type: integer
example: 500
errorMsg:
type: string
example: 获取字段配置失败
isSuccess:
type: boolean
example: false
"""
try:
business_type = request.args.get('businessType', 'INVESTIGATION')
fields = field_service.get_fields_by_business_type(business_type)
return success_response({'fields': fields})
except Exception as e:
return error_response(500, f"获取字段配置失败: {str(e)}")
if __name__ == '__main__':
# 确保static目录存在
os.makedirs('static', exist_ok=True)
port = int(os.getenv('PORT', 7500))
debug = os.getenv('DEBUG', 'False').lower() == 'true'
print(f"服务启动在 http://localhost:{port}")
print(f"测试页面: http://localhost:{port}/")
print(f"Swagger API文档: http://localhost:{port}/api-docs")
app.run(host='0.0.0.0', port=port, debug=debug)