初始化

This commit is contained in:
2026-05-11 11:22:55 +08:00
parent 5f6c571434
commit 80dcd070f7
39 changed files with 1997 additions and 0 deletions

50
app/services/__init__.py Normal file
View File

@@ -0,0 +1,50 @@
# Import mock data service
from .mock_data import (
get_mock_documents,
get_mock_quick_questions,
get_mock_retrieval,
get_mock_rag_answer,
get_mock_compliance_result,
get_mock_compliance_chat_response,
MOCK_SYSTEM_STATS,
MOCK_SYSTEM_CONFIG,
)
# Try importing real services (may fail if dependencies not installed)
try:
from .llm import llm_service, LLMService
from .embedding import embedding_service, EmbeddingService
from .milvus import milvus_service, MilvusService
from .document import DocumentService, get_document_service
_real_services_available = True
except ImportError:
_real_services_available = False
llm_service = None
LLMService = None
embedding_service = None
EmbeddingService = None
milvus_service = None
MilvusService = None
DocumentService = None
get_document_service = None
__all__ = [
# Mock data services
"get_mock_documents",
"get_mock_quick_questions",
"get_mock_retrieval",
"get_mock_rag_answer",
"get_mock_compliance_result",
"get_mock_compliance_chat_response",
"MOCK_SYSTEM_STATS",
"MOCK_SYSTEM_CONFIG",
# Real services (may be None if not available)
"llm_service",
"LLMService",
"embedding_service",
"EmbeddingService",
"milvus_service",
"MilvusService",
"DocumentService",
"get_document_service",
]

64
app/services/document.py Normal file
View File

@@ -0,0 +1,64 @@
import os
from typing import List, Optional
from PyPDF2 import PdfReader
from docx import Document
import pdfplumber
class DocumentService:
def __init__(self, raw_dir: str, parsed_dir: str):
self.raw_dir = raw_dir
self.parsed_dir = parsed_dir
def parse_pdf(self, file_path: str) -> str:
"""解析PDF文件"""
text = ""
try:
with pdfplumber.open(file_path) as pdf:
for page in pdf.pages:
page_text = page.extract_text()
if page_text:
text += page_text + "\n"
except Exception:
reader = PdfReader(file_path)
for page in reader.pages:
text += page.extract_text() + "\n"
return text.strip()
def parse_docx(self, file_path: str) -> str:
"""解析Word文件"""
doc = Document(file_path)
text = ""
for paragraph in doc.paragraphs:
text += paragraph.text + "\n"
return text.strip()
def parse_txt(self, file_path: str) -> str:
"""解析TXT文件"""
with open(file_path, "r", encoding="utf-8") as f:
return f.read().strip()
def parse_document(self, file_path: str) -> str:
"""根据文件类型解析文档"""
ext = os.path.splitext(file_path)[1].lower()
if ext == ".pdf":
return self.parse_pdf(file_path)
elif ext in [".docx", ".doc"]:
return self.parse_docx(file_path)
elif ext == ".txt":
return self.parse_txt(file_path)
else:
raise ValueError(f"Unsupported file format: {ext}")
def save_parsed_text(self, doc_id: str, text: str) -> str:
"""保存解析后的文本"""
parsed_path = os.path.join(self.parsed_dir, f"{doc_id}.txt")
with open(parsed_path, "w", encoding="utf-8") as f:
f.write(text)
return parsed_path
def get_document_service(raw_dir: str, parsed_dir: str) -> DocumentService:
return DocumentService(raw_dir, parsed_dir)

33
app/services/embedding.py Normal file
View File

@@ -0,0 +1,33 @@
import dashscope
from dashscope import TextEmbedding
from typing import List
class EmbeddingService:
def __init__(self):
from app.core.config import settings
self.model = settings.embedding_model
self.dimension = settings.embedding_dim
dashscope.api_key = settings.dashscope_api_key
def embed_texts(self, texts: List[str]) -> List[List[float]]:
"""批量文本嵌入"""
response = TextEmbedding.call(
model=self.model,
input=texts,
)
if response.status_code == 200:
embeddings = []
for item in response.output.embeddings:
embeddings.append(item.embedding)
return embeddings
raise Exception(f"Embedding failed: {response.code}")
def embed_single(self, text: str) -> List[float]:
"""单个文本嵌入"""
embeddings = self.embed_texts([text])
return embeddings[0]
embedding_service = EmbeddingService()

58
app/services/llm.py Normal file
View File

@@ -0,0 +1,58 @@
import dashscope
from dashscope import Generation
from typing import AsyncGenerator, Optional, Generator
class LLMService:
def __init__(self):
from app.core.config import settings
self.model = settings.llm_model
dashscope.api_key = settings.dashscope_api_key
def generate_stream(
self,
prompt: str,
system_prompt: Optional[str] = None,
) -> Generator[str, None, None]:
"""流式生成文本"""
messages = []
if system_prompt:
messages.append({"role": "system", "content": system_prompt})
messages.append({"role": "user", "content": prompt})
responses = Generation.call(
model=self.model,
messages=messages,
result_format="message",
stream=True,
)
for response in responses:
if response.status_code == 200:
content = response.output.choices[0].message.content
if content:
yield content
async def generate(
self,
prompt: str,
system_prompt: Optional[str] = None,
) -> str:
"""一次性生成文本"""
messages = []
if system_prompt:
messages.append({"role": "system", "content": system_prompt})
messages.append({"role": "user", "content": prompt})
response = Generation.call(
model=self.model,
messages=messages,
result_format="message",
)
if response.status_code == 200:
return response.output.choices[0].message.content
raise Exception(f"LLM generation failed: {response.code}")
llm_service = LLMService()

158
app/services/milvus.py Normal file
View File

@@ -0,0 +1,158 @@
from pymilvus import (
connections,
Collection,
FieldSchema,
CollectionSchema,
DataType,
utility,
)
from typing import List, Optional
class MilvusService:
def __init__(self):
from app.core.config import settings
self.host = settings.milvus_host
self.port = settings.milvus_port
self.regulations_collection_name = settings.regulations_collection
self.compliance_collection_name = settings.compliance_collection
self._connected = False
def connect(self):
"""连接Milvus"""
if not self._connected:
connections.connect(
alias="default",
host=self.host,
port=self.port,
)
self._connected = True
def disconnect(self):
"""断开连接"""
if self._connected:
connections.disconnect("default")
self._connected = False
def create_regulations_collection(self):
"""创建法规文档集合"""
from app.core.config import settings
self.connect()
if utility.has_collection(self.regulations_collection_name):
return Collection(self.regulations_collection_name)
fields = [
FieldSchema(name="id", dtype=DataType.INT64, is_primary=True, auto_id=True),
FieldSchema(name="embedding", dtype=DataType.FLOAT_VECTOR, dim=settings.embedding_dim),
FieldSchema(name="doc_name", dtype=DataType.VARCHAR, max_length=256),
FieldSchema(name="clause_id", dtype=DataType.VARCHAR, max_length=64),
FieldSchema(name="chapter", dtype=DataType.VARCHAR, max_length=128),
FieldSchema(name="source_file", dtype=DataType.VARCHAR, max_length=256),
FieldSchema(name="chunk_index", dtype=DataType.INT64),
FieldSchema(name="content", dtype=DataType.VARCHAR, max_length=65535),
FieldSchema(name="token_count", dtype=DataType.INT64),
]
schema = CollectionSchema(
fields=fields,
description="法规文档向量集合",
)
collection = Collection(
name=self.regulations_collection_name,
schema=schema,
)
index_params = {
"metric_type": "COSINE",
"index_type": "IVF_FLAT",
"params": {"nlist": 128},
}
collection.create_index(field_name="embedding", index_params=index_params)
return collection
def insert_chunks(
self,
embeddings: List[List[float]],
metadata: List[dict],
) -> List[int]:
"""插入向量数据"""
collection = Collection(self.regulations_collection_name)
collection.load()
data = [
embeddings,
[m.get("doc_name", "") for m in metadata],
[m.get("clause_id", "") for m in metadata],
[m.get("chapter", "") for m in metadata],
[m.get("source_file", "") for m in metadata],
[m.get("chunk_index", 0) for m in metadata],
[m.get("content", "") for m in metadata],
[m.get("token_count", 0) for m in metadata],
]
result = collection.insert(data)
collection.flush()
return result.primary_keys
def search(
self,
query_embedding: List[float],
top_k: int = 10,
) -> List[dict]:
"""向量检索"""
collection = Collection(self.regulations_collection_name)
collection.load()
search_params = {"metric_type": "COSINE", "params": {"nprobe": 16}}
results = collection.search(
data=[query_embedding],
anns_field="embedding",
param=search_params,
limit=top_k,
output_fields=["doc_name", "clause_id", "chapter", "content", "chunk_index"],
)
hits = []
for hit in results[0]:
hits.append({
"id": hit.id,
"score": hit.score,
"doc_name": hit.entity.get("doc_name"),
"clause_id": hit.entity.get("clause_id"),
"chapter": hit.entity.get("chapter"),
"content": hit.entity.get("content"),
"chunk_index": hit.entity.get("chunk_index"),
})
return hits
def get_collection_stats(self) -> dict:
"""获取集合统计"""
self.connect()
if not utility.has_collection(self.regulations_collection_name):
return {"exists": False}
collection = Collection(self.regulations_collection_name)
collection.load()
return {
"exists": True,
"name": self.regulations_collection_name,
"count": collection.num_entities,
}
def health_check(self) -> bool:
"""健康检查"""
try:
self.connect()
return True
except Exception:
return False
milvus_service = MilvusService()

425
app/services/mock_data.py Normal file
View File

@@ -0,0 +1,425 @@
"""
Mock数据服务 - 提供预设假数据供前后端对接测试
"""
from datetime import datetime
from typing import Dict, List, Any
import uuid
# 预设法规文档列表
MOCK_DOCUMENTS: List[Dict[str, Any]] = [
{
"id": "doc-001",
"name": "道路交通安全法.pdf",
"chunks": 156,
"status": "indexed",
"created_at": datetime(2026, 5, 10, 10, 0, 0),
},
{
"id": "doc-002",
"name": "机动车登记规定.docx",
"chunks": 89,
"status": "indexed",
"created_at": datetime(2026, 5, 10, 11, 0, 0),
},
{
"id": "doc-003",
"name": "电动自行车规范.pdf",
"chunks": 42,
"status": "indexed",
"created_at": datetime(2026, 5, 10, 12, 0, 0),
},
{
"id": "doc-004",
"name": "GB 38031-2020 电动汽车安全要求.pdf",
"chunks": 128,
"status": "indexed",
"created_at": datetime(2026, 5, 10, 13, 0, 0),
},
{
"id": "doc-005",
"name": "C-NCAP管理规则(2021版).pdf",
"chunks": 95,
"status": "indexed",
"created_at": datetime(2026, 5, 10, 14, 0, 0),
},
]
# 预设快捷问题
MOCK_QUICK_QUESTIONS: List[Dict[str, str]] = [
{"id": "q1", "question": "电动自行车需要上牌照吗?", "category": "车辆登记"},
{"id": "q2", "question": "新能源汽车有哪些补贴政策?", "category": "新能源"},
{"id": "q3", "question": "车辆年检的规定是什么?", "category": "年检"},
{"id": "q4", "question": "驾驶证过期了怎么处理?", "category": "驾驶证"},
]
# 预设检索结果
MOCK_RETRIEVAL_RESULTS: List[Dict[str, Any]] = [
{
"id": "chunk-001",
"score": 0.95,
"preview": "根据《道路交通安全法》第十八条规定,电动自行车经公安机关交通管理部门登记后,方可上道路行驶...",
"doc_name": "道路交通安全法",
"clause": "第十八条",
"content": "根据《道路交通安全法》第十八条规定,电动自行车经公安机关交通管理部门登记后,方可上道路行驶。电动自行车应当符合国家标准,最高设计车速不超过二十五公里每小时,整车质量不超过五十五千克。",
},
{
"id": "chunk-002",
"score": 0.88,
"preview": "电动自行车需符合GB17761-2018国家标准包括最高车速、整车质量、脚踏骑行能力等要求...",
"doc_name": "电动自行车规范",
"clause": "第4条",
"content": "电动自行车需符合GB17761-2018国家标准。主要技术要求包括最高设计车速不超过25km/h整车质量不超过55kg具有脚踏骑行能力蓄电池标称电压不超过48V电动机额定连续输出功率不超过400W。",
},
{
"id": "chunk-003",
"score": 0.82,
"preview": "机动车登记规定:初次申领机动车号牌、行驶证的,机动车所有人应当向住所地的车辆管理所申请注册登记...",
"doc_name": "机动车登记规定",
"clause": "第5条",
"content": "机动车登记规定:初次申领机动车号牌、行驶证的,机动车所有人应当向住所地的车辆管理所申请注册登记。申请注册登记的,应当提交机动车所有人的身份证明、购车发票等机动车来历证明、机动车整车出厂合格证明或者进口机动车进口凭证。",
},
{
"id": "chunk-004",
"score": 0.75,
"preview": "驾驶电动自行车上道路行驶,应当佩戴安全头盔,遵守道路交通安全法律法规...",
"doc_name": "道路交通安全法",
"clause": "第76条",
"content": "驾驶电动自行车上道路行驶,应当佩戴安全头盔,遵守道路交通安全法律法规。电动自行车不得逆向行驶,不得在机动车道内行驶,最高车速不得超过规定的限速。",
},
{
"id": "chunk-005",
"score": 0.68,
"preview": "电动汽车动力电池安全要求电池系统发生热失控后应在5分钟内不起火不爆炸...",
"doc_name": "GB 38031-2020",
"clause": "第7条",
"content": "电动汽车动力电池安全要求GB 38031-2020电池系统发生热失控后应在5分钟内不起火不爆炸为乘员预留逃生时间。电池包需通过针刺、过充、短路等安全测试。",
},
]
# 预设RAG问答答案模板按关键词匹配
MOCK_RAG_ANSWERS: Dict[str, Dict[str, Any]] = {
"电动自行车": {
"text": "根据《道路交通安全法》及相关规范,电动自行车上路需满足以下条件:\n\n1. 符合国家标准 GB17761-2018\n2. 经公安机关交通管理部门登记\n3. 最高设计车速不超过 25km/h\n4. 整车质量不超过 55kg\n5. 具有脚踏骑行能力\n6. 蓄电池标称电压不超过 48V\n\n行驶时还需佩戴安全头盔,不得逆向行驶或在机动车道内行驶。",
"retrieval_ids": ["chunk-001", "chunk-002", "chunk-004"],
},
"驾驶证": {
"text": "驾驶证申请流程如下:\n\n1. 到驾校报名并参加培训\n2. 通过科目一(理论考试)\n3. 通过科目二(场地驾驶技能考试)\n4. 通过科目三(道路驾驶技能考试)\n5. 通过科目四(安全文明驾驶常识考试)\n6. 领取驾驶证\n\n初次申领需到住所地车辆管理所申请注册登记。",
"retrieval_ids": ["chunk-003"],
},
"超速": {
"text": "超速处罚标准(根据《道路交通安全法》):\n\n- 超速10%以下:警告\n- 超速10%-20%罚款50-200元\n- 超速20%-50%罚款200-500元记3-6分\n- 超速50%以上罚款500-2000元记12分可吊销驾驶证\n\n机动车驾驶人违反道路交通安全法律、法规将处警告或二十元以上二百元以下罚款。",
"retrieval_ids": ["chunk-001"],
},
"年检": {
"text": "车辆年检规定:\n\n- 小型私家车6年内免检每2年申领标志6-10年每2年检验10年以上每年检验\n- 车辆需携带行驶证、交强险保单\n- 检验项目:灯光、制动、排放等\n\n机动车所有人的住所迁出车辆管理所管辖区域的,需在登记证书上签注变更事项。",
"retrieval_ids": ["chunk-003"],
},
"电池": {
"text": "电动汽车电池安全标准GB 38031-2020\n\n1. 热失控要求电池系统发生热失控后应在5分钟内不起火不爆炸为乘员预留逃生时间\n2. 电池包需通过针刺、过充、短路等安全测试\n3. 充电系统应具备过充保护功能当电池SOC达到100%时应自动停止充电\n4. 充电接口应符合GB/T 18487.1标准要求\n\n以上要求确保电动汽车的整车安全性。",
"retrieval_ids": ["chunk-005"],
},
"碰撞": {
"text": "正面碰撞测试要求C-NCAP管理规则\n\n1. 正面100%重叠刚性壁障碰撞试验\n2. 碰撞速度50km/h\n3. 试验后要求:\n - 车门应能打开\n - 燃油系统无泄漏\n - 座椅及安全带功能正常\n\n此测试用于评估车辆在正面碰撞事故中对乘员的保护能力。",
"retrieval_ids": [],
},
"AEB": {
"text": "AEB自动紧急制动系统测试标准\n\n1. 系统应在检测到前方障碍物时主动减速或停车\n2. 测试场景分为三种:\n - 目标车静止\n - 目标车移动\n - 目标车制动\n3. AEB功能是C-NCAP评分的重要加分项\n\n该系统对提升车辆主动安全性能具有重要意义。",
"retrieval_ids": [],
},
"高速公路": {
"text": "高速公路安全距离规定:\n\n1. 车速超过100km/h时与同车道前车保持100米以上距离\n2. 车速低于100km/h时距离可适当缩短\n3. 执行紧急任务的警车、消防车、救护车、工程救险车不受行驶速度限制\n\n保持安全距离是预防追尾事故的关键措施。",
"retrieval_ids": [],
},
}
# 预设合规分析结果
MOCK_COMPLIANCE_RESULT: Dict[str, Any] = {
"task_id": "task-001",
"dashboard": {
"score": 78,
"high_risk_count": 2,
"medium_risk_count": 1,
"low_risk_count": 0,
"need_fix_segments": 3,
"status": "warning",
"status_label": "需优化",
},
"segments": [
{
"id": 1,
"index": 1,
"intent": "车身结构设计",
"start_pos": 45,
"end_pos": 230,
"content": "车身采用高强度钢铝混合结构A柱和B柱使用热成型钢板厚度2.5mm。车顶结构设计满足GB 26112-2010抗压强度要求正面碰撞能量吸收区域采用渐进式变形设计确保碰撞时能量有效分散。",
"risk_level": "high",
"regulations": [
{
"id": 1,
"name": "GB 26112-2010",
"clause": "第4.2条",
"score": 0.95,
"match_keyword": "车顶抗压强度",
"category": "high",
"full_content": "车顶结构应能承受相当于车辆整备质量1.5倍的载荷,载荷分布应均匀,试验后车顶变形量不超过规定值。",
},
{
"id": 2,
"name": "C-NCAP管理规则",
"clause": "第3.1条",
"score": 0.88,
"match_keyword": "正面碰撞",
"category": "high",
"full_content": "正面碰撞试验速度为50km/h碰撞后车门应能打开燃油系统无泄漏座椅及安全带功能正常。",
},
{
"id": 3,
"name": "GB 11551-2014",
"clause": "第5条",
"score": 0.72,
"match_keyword": "碰撞能量吸收",
"category": "medium",
"full_content": "车辆正面碰撞时应有效保护乘员,碰撞能量应通过车身结构合理分散。",
},
{
"id": 4,
"name": "机动车安全技术条件",
"clause": "第12条",
"score": 0.58,
"match_keyword": "A柱强度",
"category": "medium",
"full_content": "A柱应具备足够的抗变形能力材料强度应符合相关标准要求。",
},
],
},
{
"id": 2,
"index": 2,
"intent": "动力系统配置",
"start_pos": 298,
"end_pos": 425,
"content": "搭载永磁同步电机最大功率150kW峰值扭矩310Nm。电池组采用三元锂离子电池容量75kWh能量密度180Wh/kg。充电接口支持快充30分钟充至80%和慢充8小时充满符合GB/T 18487.1-2015标准。",
"risk_level": "medium",
"regulations": [
{
"id": 5,
"name": "GB/T 18487.1-2015",
"clause": "第6条",
"score": 0.94,
"match_keyword": "充电接口标准",
"category": "high",
"full_content": "电动汽车传导充电接口应符合GB/T 18487.1标准要求,充电系统应具备过充保护功能。",
},
{
"id": 6,
"name": "GB/T 31484-2015",
"clause": "第4条",
"score": 0.85,
"match_keyword": "电池能量密度",
"category": "high",
"full_content": "动力电池能量密度不低于120Wh/kg电池系统需通过热失控测试。",
},
{
"id": 7,
"name": "新能源汽车生产企业准入",
"clause": "第8条",
"score": 0.65,
"match_keyword": "电机功率",
"category": "medium",
"full_content": "驱动电机应符合相关技术标准,功率参数应在规定范围内。",
},
{
"id": 8,
"name": "电动汽车安全要求",
"clause": "第7条",
"score": 0.45,
"match_keyword": "充电时间",
"category": "low",
"full_content": "充电系统应具备过充保护功能当电池SOC达到100%时应自动停止充电。",
},
],
},
{
"id": 3,
"index": 3,
"intent": "安全配置设计",
"start_pos": 570,
"end_pos": 725,
"content": "配备6个安全气囊前排双气囊、侧气囊、侧气帘采用预紧式安全带。ABS系统采用博世第9代ESP具备碰撞预警功能FCW和自动紧急制动AEB。方向盘集成驾驶员疲劳监测摄像头。",
"risk_level": "low",
"regulations": [
{
"id": 9,
"name": "GB 27887-2011",
"clause": "第5条",
"score": 0.92,
"match_keyword": "安全气囊",
"category": "high",
"full_content": "乘用车应配备驾驶员和乘客安全气囊,气囊系统应符合相关技术标准。",
},
{
"id": 10,
"name": "GB/T 26991-2011",
"clause": "第3条",
"score": 0.78,
"match_keyword": "ABS系统",
"category": "medium",
"full_content": "车辆应配备防抱死制动系统,系统性能应符合相关标准要求。",
},
{
"id": 11,
"name": "C-NCAP管理规则",
"clause": "第4.2条",
"score": 0.71,
"match_keyword": "AEB自动制动",
"category": "medium",
"full_content": "主动安全配置评分包含AEB功能AEB系统应能有效检测障碍物并主动减速。",
},
{
"id": 12,
"name": "机动车运行安全技术条件",
"clause": "第15条",
"score": 0.38,
"match_keyword": "疲劳监测",
"category": "low",
"full_content": "建议配备驾驶员状态监测系统,及时发现驾驶员疲劳或分心状态。",
},
],
},
],
"priority_actions": [
{
"regulation": "GB 26112-2010 第4.2条",
"issue": "缺少车顶抗压强度测试数据",
"suggestion": "补充车顶抗压强度具体测试数据确保满足1.5倍整备质量载荷要求",
"severity": "high",
},
{
"regulation": "GB/T 31484-2015 第4条",
"issue": "缺少电池热失控测试报告",
"suggestion": "补充电池热失控测试报告验证5分钟内不起火不爆炸",
"severity": "high",
},
{
"regulation": "C-NCAP管理规则 第3.1条",
"issue": "缺少碰撞后车门开启性能数据",
"suggestion": "提供碰撞后车门开启性能测试数据",
"severity": "medium",
},
],
}
# 预设合规对话响应模板
MOCK_COMPLIANCE_CHAT_RESPONSES: Dict[str, Dict[str, str]] = {
"车身结构设计": {
"compliance": "根据当前分析,车身结构设计部分存在以下合规问题:\n\n1. GB 26112-2010要求车顶承受1.5倍整备质量载荷,目前设计声明满足要求但缺少测试数据\n2. C-NCAP正面碰撞后车门应能打开需提供碰撞测试报告\n\n建议补充相关测试数据以提升合规评分。",
"interpretation": "GB 26112-2010 第4.2条具体要求解读:\n\n车顶抗压强度测试是车辆被动安全的重要指标。该标准要求车顶结构能够承受相当于车辆整备质量1.5倍的均匀分布载荷,试验后车顶变形量不得超过规定限值。\n\n热成型钢板22MnB5材料抗拉强度约1500-1650 MPa理论上能满足要求但需通过实际测试验证。",
"suggestion": "针对车身结构设计的修改建议:\n\n1. 补充车顶抗压强度测试报告\n2. 提供A柱材料认证证书\n3. 完善正面碰撞能量吸收设计说明\n4. 添加碰撞后车门开启性能数据\n\n这些补充材料可有效提升合规评分。",
},
"动力系统配置": {
"compliance": "动力系统配置整体合规性良好,主要检查点:\n\n1. 电池能量密度180Wh/kg超过最低要求120Wh/kg ✓\n2. 充电接口符合GB/T 18487.1标准 ✓\n3. 快充30分钟充至80%符合行业标准 ✓\n\n需补充电池热失控测试报告。",
"interpretation": "GB/T 31484-2015对动力电池的要求解读\n\n1. 能量密度不低于120Wh/kg您的设计180Wh/kg满足要求\n2. 循环寿命不少于1000次循环后容量保持率≥80%\n3. 安全测试:需通过针刺、过充、短路等测试\n\n建议补充循环寿命测试数据。",
"suggestion": "动力系统配置改进建议:\n\n1. 补充电池热失控测试报告\n2. 提供循环寿命测试数据\n3. 添加充电系统过充保护功能说明\n4. 完善电池管理系统BMS技术文档",
},
"安全配置设计": {
"compliance": "安全配置设计合规性评估:\n\n1. 安全气囊配置满足GB 27887-2011要求 ✓\n2. ABS/ESP系统符合标准 ✓\n3. AEB功能是C-NCAP加分项 ✓\n\n驾驶员疲劳监测是建议配置,不强制要求。",
"interpretation": "C-NCAP主动安全评分规则解读\n\nAEB自动紧急制动系统是C-NCAP评分的重要加分项最高可获得额外加分。测试场景包括\n- 目标车静止场景\n- 目标车移动场景\n- 目标车制动场景\n\n建议完善AEB系统测试数据以获取更高评分。",
"suggestion": "安全配置优化建议:\n\n1. 提供AEB系统测试数据\n2. 补充FCW预警功能测试报告\n3. 添加安全气囊展开时间数据\n4. 完善驾驶员疲劳监测系统说明(如有)",
},
}
# 预设系统统计数据
MOCK_SYSTEM_STATS: Dict[str, int] = {
"docs": 5,
"chunks": 510,
"vectors": 510,
"segments": 0,
}
# 预设系统配置
MOCK_SYSTEM_CONFIG: Dict[str, Any] = {
"llm": {
"model": "qwen-max",
},
"embedding": {
"model": "text-embedding-v3",
"dimension": 1536,
},
"milvus": {
"host": "localhost",
"port": 19530,
},
"retrieval": {
"vector_top_k": 10,
"final_top_k": 5,
},
}
def get_mock_documents() -> List[Dict[str, Any]]:
"""获取预设法规文档列表"""
return MOCK_DOCUMENTS
def get_mock_quick_questions() -> List[Dict[str, str]]:
"""获取预设快捷问题"""
return MOCK_QUICK_QUESTIONS
def get_mock_retrieval(query: str, top_k: int = 5) -> List[Dict[str, Any]]:
"""根据查询关键词返回预设检索结果"""
results = []
for keyword, data in MOCK_RAG_ANSWERS.items():
if keyword in query:
for retrieval_id in data.get("retrieval_ids", []):
for item in MOCK_RETRIEVAL_RESULTS:
if item["id"] == retrieval_id:
results.append({
"id": item["id"],
"score": item["score"],
"preview": item["preview"],
"doc_name": item["doc_name"],
"clause": item["clause"],
})
break
if not results:
results = MOCK_RETRIEVAL_RESULTS[:top_k]
return results[:top_k]
def get_mock_rag_answer(query: str) -> str:
"""根据查询关键词返回预设答案"""
for keyword, data in MOCK_RAG_ANSWERS.items():
if keyword in query:
return data["text"]
return "抱歉,暂未找到与您问题直接相关的法规内容。请尝试更具体的问题,或联系交通管理部门获取详细信息。\n\n您可以尝试询问电动自行车、驾驶证、超速处罚、年检、电池安全、碰撞测试、AEB系统、高速公路规则等话题。"
def get_mock_compliance_result(task_id: str) -> Dict[str, Any]:
"""获取预设合规分析结果"""
result = MOCK_COMPLIANCE_RESULT.copy()
result["task_id"] = task_id
return result
def get_mock_compliance_chat_response(intent: str, query: str) -> str:
"""获取预设合规对话响应"""
responses = MOCK_COMPLIANCE_CHAT_RESPONSES.get(intent, {})
if "合规" in query or "符合" in query:
return responses.get("compliance", "根据相关法规分析,该段落的合规性需进一步评估。")
elif "解读" in query or "什么" in query or "如何" in query:
return responses.get("interpretation", "法规要求详细解读如下...")
elif "修改" in query or "建议" in query or "完善" in query:
return responses.get("suggestion", "建议进行以下修改以提升合规性...")
return f"关于您的问题,{intent}部分涉及多条相关法规。您可以进一步询问合规性评估或修改建议。"
def generate_task_id() -> str:
"""生成任务ID"""
return f"task-{uuid.uuid4().hex[:8]}"
def generate_doc_id() -> str:
"""生成文档ID"""
return f"doc-{uuid.uuid4().hex[:8]}"