feat(web): add OCR service and update travel reimbursement view
- web/src/services/ocr.js: add OCR service API client - web/src/views/scripts/TravelReimbursementCreateView.js: update travel form script with OCR integration
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { computed, nextTick, onMounted, ref } from 'vue'
|
||||
|
||||
import { useSystemState } from '../../composables/useSystemState.js'
|
||||
import { recognizeOcrFiles } from '../../services/ocr.js'
|
||||
import { runOrchestrator } from '../../services/orchestrator.js'
|
||||
|
||||
const DEFAULT_REQUEST = {
|
||||
@@ -128,6 +129,26 @@ function buildMessageMeta(payload, fileNames = []) {
|
||||
return items
|
||||
}
|
||||
|
||||
function normalizeOcrDocuments(payload) {
|
||||
const documents = Array.isArray(payload?.documents) ? payload.documents : []
|
||||
return documents.slice(0, 5).map((item) => ({
|
||||
filename: item.filename,
|
||||
summary: item.summary,
|
||||
text: String(item.text || '').slice(0, 240),
|
||||
avg_score: Number(item.avg_score || 0),
|
||||
line_count: Number(item.line_count || 0),
|
||||
warnings: Array.isArray(item.warnings) ? item.warnings : []
|
||||
}))
|
||||
}
|
||||
|
||||
function buildOcrSummary(payload) {
|
||||
const parts = normalizeOcrDocuments(payload)
|
||||
.map((item) => `${item.filename}:${item.summary || item.text}`)
|
||||
.filter(Boolean)
|
||||
|
||||
return parts.join(';')
|
||||
}
|
||||
|
||||
function buildWelcomeInsight(entrySource, linkedRequest) {
|
||||
return {
|
||||
intent: 'welcome',
|
||||
@@ -360,7 +381,7 @@ export default {
|
||||
submitComposer()
|
||||
}
|
||||
|
||||
function buildBackendMessage(rawText, fileNames) {
|
||||
function buildBackendMessage(rawText, fileNames, ocrSummary = '') {
|
||||
const parts = []
|
||||
const normalizedText = String(rawText || '').trim()
|
||||
|
||||
@@ -374,6 +395,10 @@ export default {
|
||||
parts.push(`附件名称:${fileNames.join('、')}`)
|
||||
}
|
||||
|
||||
if (ocrSummary) {
|
||||
parts.push(`OCR摘要:${ocrSummary}`)
|
||||
}
|
||||
|
||||
if (props.entrySource === 'detail') {
|
||||
parts.push(`关联单号:${linkedRequest.value.id}`)
|
||||
}
|
||||
@@ -389,7 +414,6 @@ export default {
|
||||
const fileNames = files.map((file) => file.name)
|
||||
const userText =
|
||||
rawText || `我上传了 ${fileNames.length} 份票据,请帮我识别并给出报销建议。`
|
||||
const backendMessage = buildBackendMessage(rawText, fileNames)
|
||||
|
||||
messages.value.push(createMessage('user', userText, fileNames))
|
||||
|
||||
@@ -409,6 +433,21 @@ export default {
|
||||
|
||||
try {
|
||||
const user = currentUser.value || {}
|
||||
let ocrPayload = null
|
||||
let ocrSummary = ''
|
||||
let ocrDocuments = []
|
||||
|
||||
if (files.length) {
|
||||
try {
|
||||
ocrPayload = await recognizeOcrFiles(files)
|
||||
ocrSummary = buildOcrSummary(ocrPayload)
|
||||
ocrDocuments = normalizeOcrDocuments(ocrPayload)
|
||||
} catch (error) {
|
||||
console.warn('OCR request failed:', error)
|
||||
}
|
||||
}
|
||||
|
||||
const backendMessage = buildBackendMessage(rawText, fileNames, ocrSummary)
|
||||
const payload = await runOrchestrator({
|
||||
source: 'user_message',
|
||||
user_id: user.username || user.name || 'anonymous',
|
||||
@@ -421,7 +460,9 @@ export default {
|
||||
entry_source: props.entrySource,
|
||||
request_context: linkedRequest.value,
|
||||
attachment_names: fileNames,
|
||||
attachment_count: fileNames.length
|
||||
attachment_count: fileNames.length,
|
||||
ocr_summary: ocrSummary,
|
||||
ocr_documents: ocrDocuments
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user