refactor(backend): incremental architecture evolution (Task 19)
- Add common/ layer for shared capabilities (LLM, RAG, document, middleware) - Add legacy/ layer for existing business code - Move files to new structure (controllers, routes, services) - Update index.ts for new route registration - System remains fully functional
This commit is contained in:
152
backend/src/common/utils/jsonParser.ts
Normal file
152
backend/src/common/utils/jsonParser.ts
Normal file
@@ -0,0 +1,152 @@
|
||||
/**
|
||||
* Phase 3: 批处理模式 - JSON解析工具
|
||||
*
|
||||
* AI的输出可能包含额外的文字说明,需要提取JSON块并解析
|
||||
*/
|
||||
|
||||
export interface ParseResult<T = any> {
|
||||
success: boolean;
|
||||
data?: T;
|
||||
error?: string;
|
||||
rawOutput: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从AI输出中提取JSON块
|
||||
*
|
||||
* 支持的格式:
|
||||
* 1. 纯JSON:{ "key": "value" }
|
||||
* 2. 带前言:这是提取结果:\n{ "key": "value" }
|
||||
* 3. 带后缀:{ "key": "value" }\n\n以上是提取结果
|
||||
* 4. 代码块:```json\n{ "key": "value" }\n```
|
||||
*/
|
||||
export function extractJSON(text: string): string | null {
|
||||
// 尝试1:直接查找 {...} 或 [...]
|
||||
const jsonPattern = /(\{[\s\S]*\}|\[[\s\S]*\])/;
|
||||
const match = text.match(jsonPattern);
|
||||
|
||||
if (match) {
|
||||
return match[1];
|
||||
}
|
||||
|
||||
// 尝试2:查找代码块中的JSON
|
||||
const codeBlockPattern = /```(?:json)?\s*\n?([\s\S]*?)\n?```/;
|
||||
const codeMatch = text.match(codeBlockPattern);
|
||||
|
||||
if (codeMatch) {
|
||||
return codeMatch[1].trim();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析JSON字符串
|
||||
*
|
||||
* @param jsonString JSON字符串
|
||||
* @param expectedFields 期望的字段列表(可选,用于验证)
|
||||
* @returns 解析结果
|
||||
*/
|
||||
export function parseJSON<T = any>(
|
||||
jsonString: string,
|
||||
expectedFields?: string[]
|
||||
): ParseResult<T> {
|
||||
const rawOutput = jsonString;
|
||||
|
||||
try {
|
||||
// 提取JSON块
|
||||
const extracted = extractJSON(jsonString);
|
||||
|
||||
if (!extracted) {
|
||||
return {
|
||||
success: false,
|
||||
error: '未找到JSON格式的数据',
|
||||
rawOutput,
|
||||
};
|
||||
}
|
||||
|
||||
// 解析JSON
|
||||
const data = JSON.parse(extracted) as T;
|
||||
|
||||
// 验证字段(如果提供了expectedFields)
|
||||
if (expectedFields && Array.isArray(expectedFields)) {
|
||||
const missingFields: string[] = [];
|
||||
|
||||
for (const field of expectedFields) {
|
||||
if (!(field in (data as any))) {
|
||||
missingFields.push(field);
|
||||
}
|
||||
}
|
||||
|
||||
if (missingFields.length > 0) {
|
||||
console.warn(`[JsonParser] 缺少字段: ${missingFields.join(', ')}`);
|
||||
// 为缺失字段填充默认值
|
||||
for (const field of missingFields) {
|
||||
(data as any)[field] = '未提取到';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
data,
|
||||
rawOutput,
|
||||
};
|
||||
|
||||
} catch (error: any) {
|
||||
return {
|
||||
success: false,
|
||||
error: error.message,
|
||||
rawOutput,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证JSON数据是否符合模板要求
|
||||
*
|
||||
* @param data 解析后的数据
|
||||
* @param templateFields 模板字段定义
|
||||
* @returns 是否有效
|
||||
*/
|
||||
export function validateTemplateData(
|
||||
data: any,
|
||||
templateFields: Array<{ key: string; type: string }>
|
||||
): { valid: boolean; errors: string[] } {
|
||||
const errors: string[] = [];
|
||||
|
||||
if (!data || typeof data !== 'object') {
|
||||
errors.push('数据不是有效的对象');
|
||||
return { valid: false, errors };
|
||||
}
|
||||
|
||||
for (const field of templateFields) {
|
||||
const value = data[field.key];
|
||||
|
||||
// 检查字段是否存在
|
||||
if (value === undefined || value === null || value === '') {
|
||||
console.warn(`[JsonParser] 字段 ${field.key} 为空`);
|
||||
// 不算错误,只是警告
|
||||
}
|
||||
|
||||
// 类型检查(宽松)
|
||||
if (field.type === 'number' && typeof value !== 'number' && value !== '') {
|
||||
// 尝试转换
|
||||
const num = Number(value);
|
||||
if (!isNaN(num)) {
|
||||
data[field.key] = num;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return { valid: errors.length === 0, errors };
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user