feat(ai): add personal expense application memory

This commit is contained in:
caoxiaozhu
2026-07-14 17:16:23 +08:00
parent 211f85d981
commit 54754b5502
36 changed files with 3579 additions and 74 deletions

View File

@@ -16,6 +16,10 @@ from app.schemas.reimbursement import (
ExpenseApplicationPreviewActionResult,
)
from app.schemas.user_agent import UserAgentRequest
from app.services.application_system_estimate import (
apply_application_system_estimate_to_facts,
)
from app.services.expense_application_memory import ExpenseApplicationMemoryService
from app.services.expense_application_preview_decisions import (
ExpenseApplicationPreviewDecisionService,
PreviewDecisionConflictError,
@@ -53,6 +57,12 @@ class ExpenseApplicationPreviewWorkflow:
)
try:
facts = UserAgentService(self.db)._resolve_expense_application_facts(request)
memory_applications = ExpenseApplicationMemoryService(
self.db
).apply_active_transport_memory(facts, current_user)
if memory_applications:
# 交通方式会影响系统预估;记忆补空后必须在签名前重算派生字段。
apply_application_system_estimate_to_facts(facts)
issued = ExpenseApplicationPreviewDecisionService(self.db).issue(
facts,
current_user,
@@ -71,6 +81,9 @@ class ExpenseApplicationPreviewWorkflow:
expires_at=issued.decision.expires_at,
application_preview={
"fields": issued.fields,
"memoryApplications": [
item.model_dump(mode="json") for item in memory_applications
],
"decisionId": issued.decision.id,
"decisionSource": issued.decision.decision_source,
"decisionExpiresAt": issued.decision.expires_at.isoformat(),
@@ -154,6 +167,11 @@ class ExpenseApplicationPreviewWorkflow:
type(error).__name__,
)
learning_receipts = self._resolve_learning_receipts(
consumed_preview_decision_id,
current_user,
)
return ExpenseApplicationPreviewActionResponse(
status="succeeded",
conversation_id=payload.conversation_id,
@@ -179,9 +197,29 @@ class ExpenseApplicationPreviewWorkflow:
if next_preview_decision is not None
else None
),
learning_receipts=[
item.model_dump(mode="json") for item in learning_receipts
],
),
)
def _resolve_learning_receipts(
self,
preview_decision_id: str,
current_user: CurrentUserContext,
) -> list:
try:
with self.db.begin_nested():
return ExpenseApplicationMemoryService(
self.db
).learning_receipts_for_preview_decision(
preview_decision_id,
current_user,
)
except Exception:
logger.warning("个人记忆学习回执读取失败,本次申请动作保持成功。", exc_info=True)
return []
@staticmethod
def _build_action_request(
payload: ExpenseApplicationPreviewActionPayload,