refactor: enforce 800 line source limits
This commit is contained in:
@@ -0,0 +1,246 @@
|
||||
import { filterVisibleMessageMeta } from '../../utils/assistantMessageMeta.js'
|
||||
import { resolveExpenseTypeLabel } from './travelReimbursementReviewModel.js'
|
||||
import {
|
||||
FLOW_MISSING_SLOT_LABELS,
|
||||
FLOW_STEP_FALLBACKS
|
||||
} from './travelReimbursementConversationSessionModel.js'
|
||||
|
||||
let messageSeed = 0
|
||||
|
||||
export function nowTime() {
|
||||
return new Date().toLocaleTimeString('zh-CN', {
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
hour12: false
|
||||
})
|
||||
}
|
||||
|
||||
export function createMessage(role, text, attachments = [], extras = {}) {
|
||||
messageSeed += 1
|
||||
const message = {
|
||||
id: `msg-${messageSeed}`,
|
||||
role,
|
||||
text,
|
||||
attachments,
|
||||
time: nowTime(),
|
||||
meta: [],
|
||||
citations: [],
|
||||
suggestedActions: [],
|
||||
suggestedActionsLocked: false,
|
||||
selectedSuggestedActionKey: '',
|
||||
selectedSuggestedActionLabel: '',
|
||||
querySelectionLocked: false,
|
||||
selectedQueryRecordId: '',
|
||||
queryPayload: null,
|
||||
draftPayload: null,
|
||||
reviewPayload: null,
|
||||
reviewPanelScope: '',
|
||||
riskFlags: [],
|
||||
pendingAttachmentAssociation: null,
|
||||
applicationPreview: null,
|
||||
budgetReport: null,
|
||||
stewardPlan: null,
|
||||
operationFeedback: null,
|
||||
...extras
|
||||
}
|
||||
message.meta = filterVisibleMessageMeta(message.meta)
|
||||
return message
|
||||
}
|
||||
|
||||
export function buildExpenseIntentConfirmationMessage(rawText) {
|
||||
const text = String(rawText || '').trim()
|
||||
return [
|
||||
text
|
||||
? `我看到了「${text}」这类业务事项描述。`
|
||||
: '我看到了这类业务事项描述。',
|
||||
'但现在还不能确定你是要发起报销,还是要处理其他事项,所以我先暂停后续识别。',
|
||||
'如果你是想报销,请点击下面的“我要报销”,我再继续引导你选择具体报销场景。'
|
||||
].join('\n')
|
||||
}
|
||||
|
||||
export function buildExpenseSceneSelectionMessage(rawText) {
|
||||
const text = String(rawText || '').trim()
|
||||
const hasBusinessTime = /业务发生时间|发生时间|20\d{2}[-年\/.]\d{1,2}/.test(text)
|
||||
const prefix = hasBusinessTime
|
||||
? '我已看到你提供了业务发生时间和报销意图。'
|
||||
: '我已识别到这是报销申请。'
|
||||
|
||||
return [
|
||||
`${prefix}先选一下这笔费用属于哪一类,我再按对应流程继续。`,
|
||||
'差旅和业务招待通常需要先关联申请单;交通、住宿、办公用品这类一般可以直接继续填写。',
|
||||
'选完后我会把下一步需要准备的内容整理给你。'
|
||||
].join('\n')
|
||||
}
|
||||
|
||||
export function formatMessageTime(value) {
|
||||
if (!value) {
|
||||
return nowTime()
|
||||
}
|
||||
|
||||
const parsed = new Date(value)
|
||||
if (Number.isNaN(parsed.getTime())) {
|
||||
return nowTime()
|
||||
}
|
||||
|
||||
return parsed.toLocaleTimeString('zh-CN', {
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
hour12: false
|
||||
})
|
||||
}
|
||||
|
||||
export function formatSemanticEntityValue(entity) {
|
||||
const normalizedValue = String(entity?.normalized_value || '').trim()
|
||||
const rawValue = String(entity?.value || '').trim()
|
||||
const entityType = String(entity?.type || '').trim()
|
||||
|
||||
if (entityType === 'amount') {
|
||||
const numericValue = Number(normalizedValue || rawValue)
|
||||
if (Number.isFinite(numericValue) && numericValue > 0) {
|
||||
return Number.isInteger(numericValue) ? `${numericValue}元` : `${numericValue.toFixed(2)}元`
|
||||
}
|
||||
}
|
||||
|
||||
return rawValue || normalizedValue
|
||||
}
|
||||
|
||||
export function summarizeSemanticParseDetail(semanticParse, ontologyJson = {}) {
|
||||
if (!semanticParse || typeof semanticParse !== 'object') {
|
||||
return FLOW_STEP_FALLBACKS.extraction.completedText
|
||||
}
|
||||
|
||||
const entities = Array.isArray(semanticParse.entities_json) ? semanticParse.entities_json : []
|
||||
const entityMap = new Map()
|
||||
for (const item of entities) {
|
||||
const entityType = String(item?.type || '').trim()
|
||||
if (!entityType || entityMap.has(entityType)) continue
|
||||
entityMap.set(entityType, item)
|
||||
}
|
||||
|
||||
const extractedParts = []
|
||||
const timeRange = semanticParse.time_range_json && typeof semanticParse.time_range_json === 'object'
|
||||
? semanticParse.time_range_json
|
||||
: {}
|
||||
const startDate = String(timeRange.start_date || '').trim()
|
||||
const endDate = String(timeRange.end_date || '').trim()
|
||||
if (startDate) {
|
||||
extractedParts.push(`时间 ${startDate}${endDate && endDate !== startDate ? ` 至 ${endDate}` : ''}`)
|
||||
}
|
||||
|
||||
const amountEntity = entityMap.get('amount')
|
||||
if (amountEntity) {
|
||||
const amountValue = formatSemanticEntityValue(amountEntity)
|
||||
if (amountValue) {
|
||||
extractedParts.push(`金额 ${amountValue}`)
|
||||
}
|
||||
}
|
||||
|
||||
const expenseTypeEntity = entityMap.get('expense_type')
|
||||
if (expenseTypeEntity) {
|
||||
const expenseTypeLabel = resolveExpenseTypeLabel(
|
||||
String(expenseTypeEntity?.normalized_value || '').trim(),
|
||||
String(expenseTypeEntity?.value || '').trim()
|
||||
)
|
||||
if (expenseTypeLabel) {
|
||||
extractedParts.push(`费用类型 ${expenseTypeLabel}`)
|
||||
}
|
||||
}
|
||||
|
||||
const customerEntity = entityMap.get('customer')
|
||||
if (customerEntity) {
|
||||
const customerValue = formatSemanticEntityValue(customerEntity)
|
||||
if (customerValue) {
|
||||
extractedParts.push(`客户 ${customerValue}`)
|
||||
}
|
||||
}
|
||||
|
||||
const missingSlots = Array.isArray(ontologyJson?.missing_slots) ? ontologyJson.missing_slots : []
|
||||
const missingLabels = missingSlots
|
||||
.map((item) => FLOW_MISSING_SLOT_LABELS[String(item || '').trim()] || String(item || '').trim())
|
||||
.filter(Boolean)
|
||||
|
||||
if (extractedParts.length && missingLabels.length) {
|
||||
return `已提取${extractedParts.join('、')};待补充 ${missingLabels.join('、')}`
|
||||
}
|
||||
if (extractedParts.length) {
|
||||
return `已提取${extractedParts.join('、')}`
|
||||
}
|
||||
if (missingLabels.length) {
|
||||
return `已完成信息提取;待补充 ${missingLabels.join('、')}`
|
||||
}
|
||||
return FLOW_STEP_FALLBACKS.extraction.completedText
|
||||
}
|
||||
|
||||
export function sanitizeRequest(request) {
|
||||
if (!request || typeof request !== 'object') return null
|
||||
|
||||
const normalized = {
|
||||
claimId: String(request.claimId || request.claim_id || '').trim(),
|
||||
claimNo: String(request.claimNo || request.claim_no || request.documentNo || '').trim(),
|
||||
id: String(request.id || '').trim(),
|
||||
typeLabel: String(request.typeLabel || request.category || '').trim(),
|
||||
reason: String(request.reason || request.title || '').trim(),
|
||||
entity: String(request.entity || '').trim(),
|
||||
city: String(request.city || request.location || '').trim(),
|
||||
period: String(request.period || '').trim(),
|
||||
applyTime: String(request.applyTime || request.occurredAt || '').trim(),
|
||||
amount: String(request.amount || '').trim(),
|
||||
node: String(request.node || '').trim(),
|
||||
approval: String(request.approval || '').trim(),
|
||||
travel: String(request.travel || '').trim(),
|
||||
applicationEditMode: Boolean(request.applicationEditMode || request.application_edit_mode)
|
||||
}
|
||||
|
||||
return Object.values(normalized).some(Boolean) ? normalized : null
|
||||
}
|
||||
|
||||
export function resolveStatusLabel(status) {
|
||||
if (status === 'succeeded') return '已完成'
|
||||
if (status === 'blocked') return '已阻断'
|
||||
return '失败'
|
||||
}
|
||||
|
||||
export function resolveStatusTone(status) {
|
||||
if (status === 'succeeded') return 'success'
|
||||
if (status === 'blocked') return 'warning'
|
||||
return 'note'
|
||||
}
|
||||
|
||||
export function buildMessageMeta(payload, fileNames = []) {
|
||||
const items = []
|
||||
|
||||
if (payload?.trace_summary?.degraded) {
|
||||
items.push('已降级')
|
||||
}
|
||||
|
||||
if (payload?.requires_confirmation) {
|
||||
items.push('待确认')
|
||||
}
|
||||
|
||||
if (fileNames.length) {
|
||||
items.push(`附件: ${fileNames.length}`)
|
||||
}
|
||||
|
||||
return filterVisibleMessageMeta(items)
|
||||
}
|
||||
|
||||
export function buildStoredMessageMeta(messageJson, attachmentNames = []) {
|
||||
const payload = messageJson?.orchestrator_payload
|
||||
if (payload) {
|
||||
return buildMessageMeta(payload, attachmentNames)
|
||||
}
|
||||
|
||||
const items = []
|
||||
if (messageJson?.status) {
|
||||
items.push(`状态: ${messageJson.status}`)
|
||||
}
|
||||
if (attachmentNames.length) {
|
||||
items.push(`附件: ${attachmentNames.length}`)
|
||||
}
|
||||
return filterVisibleMessageMeta(items)
|
||||
}
|
||||
|
||||
export function buildRestoredMessageId(sourceId = '') {
|
||||
const normalizedId = String(sourceId || '').trim()
|
||||
return `restored-${normalizedId || ++messageSeed}`
|
||||
}
|
||||
Reference in New Issue
Block a user