feat: AI 图片记账、自定义交易渠道与淘宝/京东账单导入
- AI 图片记账:多图上传由视觉模型识别,SSE 实时推送进度,提取 rawData,按「类型+金额+时间」检测重复,支持缩略图与来源图片查看 - 自定义交易渠道:新增 t_channel 与渠道管理页,支持新建/改名/删除,并接入统计、导出与 AI 查询/记账/建议提示词 - AI 建议:单条建议新增交易渠道推荐(推荐已有渠道 / AI 新建渠道) - 账单导入:新增淘宝(xlsx)、京东(CSV)解析器 - 交易:新增批量创建接口,导入时按去重键兜底跳过重复 - 运行目录统一经 AppHome 解析,图片与数据文件落盘规范化 - 前端:AI 记账方式偏好记忆、AI 按钮与输入框对齐、来源图片弹窗支持加载原图
This commit is contained in:
+47
-1
@@ -8,6 +8,7 @@ export interface AiConfig {
|
||||
hasApiKey: boolean
|
||||
baseUrl: string
|
||||
model: string
|
||||
visionModel: string
|
||||
}
|
||||
|
||||
/** AI 建议新建的标签 */
|
||||
@@ -27,6 +28,8 @@ export interface AiSuggestion {
|
||||
newCategoryIcon: string | null
|
||||
tagIds: number[]
|
||||
tagNames: string[]
|
||||
channel: string | null
|
||||
channelName: string | null
|
||||
newTags: AiNewTag[]
|
||||
reason: string
|
||||
}
|
||||
@@ -37,7 +40,7 @@ export function getAiConfig() {
|
||||
}
|
||||
|
||||
/** 保存 AI 配置,apiKey 留空表示不修改原值 */
|
||||
export function saveAiConfig(data: { enabled: boolean; apiKey?: string; baseUrl?: string; model?: string }) {
|
||||
export function saveAiConfig(data: { enabled: boolean; apiKey?: string; baseUrl?: string; model?: string; visionModel?: string }) {
|
||||
return request.put('/ai/config', data)
|
||||
}
|
||||
|
||||
@@ -77,6 +80,17 @@ export function parseTagByAi(text: string) {
|
||||
return request.post('/ai/tag', { text }, { timeout: 60000 })
|
||||
}
|
||||
|
||||
/** AI 生成的交易渠道建议 */
|
||||
export interface AiChannelResult {
|
||||
name: string
|
||||
reason: string
|
||||
}
|
||||
|
||||
/** 根据自然语言描述生成交易渠道(调用大模型,超时放宽) */
|
||||
export function parseChannelByAi(text: string) {
|
||||
return request.post('/ai/channel', { text }, { timeout: 60000 })
|
||||
}
|
||||
|
||||
/** 根据表单当前内容生成单条分类与标签建议(调用大模型,超时放宽) */
|
||||
export function suggestOneByAi(data: { type: string; amount?: number | null; channel?: string; remark?: string }) {
|
||||
return request.post('/ai/suggest-one', data, { timeout: 60000 })
|
||||
@@ -213,6 +227,14 @@ export interface AiRecordResult {
|
||||
tagIds: number[]
|
||||
tagNames: string[]
|
||||
unmatched: string[]
|
||||
/** 图片记账时由模型提取的原始字段 JSON 文本,文本记账为 null */
|
||||
rawData: string | null
|
||||
/** 来源图片序号(图片记账,从 1 开始),文本记账为 null */
|
||||
imageIndex: number | null
|
||||
/** 来源图片ID(图片记账),文本记账为 null */
|
||||
imageId: number | null
|
||||
/** 是否疑似重复:与已有记录或本批其它记录的类型、金额、时间一致 */
|
||||
duplicate: boolean | null
|
||||
}
|
||||
|
||||
/** 将自然语言记账内容解析为交易记录 */
|
||||
@@ -220,6 +242,30 @@ export function parseRecordByAi(text: string) {
|
||||
return request.post('/ai/record', { text }, { timeout: 120000 })
|
||||
}
|
||||
|
||||
/** 图片记账解析结果 */
|
||||
export interface AiRecordImageResult {
|
||||
/** 保存的图片ID列表,按上传顺序排列 */
|
||||
imageIds: number[]
|
||||
summary: string
|
||||
records: AiRecordResult[]
|
||||
unmatched: string[]
|
||||
}
|
||||
|
||||
/** 上传一至多张账单/支付截图,由 AI 一次性识别并生成多条交易记录(调用视觉模型,超时放宽) */
|
||||
export function parseRecordByImage(files: File[], hint?: string) {
|
||||
const formData = new FormData()
|
||||
for (const file of files) {
|
||||
formData.append('files', file)
|
||||
}
|
||||
if (hint) formData.append('hint', hint)
|
||||
return request.post('/ai/record/image', formData, { timeout: 180000 })
|
||||
}
|
||||
|
||||
/** 获取 AI 记账图片(blob,经鉴权头请求,避免 token 出现在 URL;thumbnail=true 返回压缩缩略图,默认原图) */
|
||||
export function getAiImageBlob(id: number, thumbnail = false) {
|
||||
return request.get(`/ai/image/${id}${thumbnail ? '?thumbnail=true' : ''}`, { responseType: 'blob', timeout: 30000 })
|
||||
}
|
||||
|
||||
/** AI 使用累计汇总 */
|
||||
export interface AiUsageSummary {
|
||||
totalCalls: number
|
||||
|
||||
Reference in New Issue
Block a user