3.2 KiB
图片 URL 长相 真实图片 URL 大概是这种公开 Supabase Storage 地址: https://lehwkihwnlqkavhcspel.supabase.co/storage/v1/object/public/elio-schedules/schedules/42/a1b2c3d4.jpg 前端不用拼 URL,也不用鉴权,后端会直接返回完整 URL。前端只读: data.image?.url 消息接口 POST https://proapi.banlv-ai.com/api/chat/send 响应 data 固定字段: { "reply": "这是我昨天傍晚的照片,那会儿在外面走了走。", "audioUrl": "", "messageId": "msg_123", "timestamp": 1782271808947, "isGuest": false, "image": { "type": "elio_schedule", "url": "https://lehwkihwnlqkavhcspel.supabase.co/storage/v1/object/public/elio-schedules/schedules/42/a1b2c3d4.jpg" }, "lockDetail": { "locked": false, "showContent": true, "showUpgrade": false, "reason": null, "hint": null, "detail": null } } 前端用法: const d = res.data
if (d.lockDetail?.showContent !== false && d.reply) { renderText(d.reply) }
if (d.image?.url) { renderImage(d.image.url) }
if (d.audioUrl) { renderAudio(d.audioUrl) }
if (d.lockDetail?.showUpgrade) { showVipPaywall(d.lockDetail.hint) } image.type 目前主要是 elio_schedule,无图时: "image": { "type": null, "url": null } 被限额/需要充值时: { "reply": "", "image": { "type": null, "url": null }, "lockDetail": { "locked": true, "showContent": false, "showUpgrade": true, "reason": "daily_limit", "hint": "免费消息额度已用完,开通会员后可以继续聊天。", "detail": { "type": "daily_msg_limit", "usedToday": 3, "limit": 3 } } } 历史接口 GET https://proapi.banlv-ai.com/api/chat/history?limit=50&offset=0 响应结构: { "messages": [ { "role": "user", "type": "text", "content": "你最近在干嘛", "id": "msg_1", "created_at": "2026-06-24T10:00:00Z", "audioUrl": null, "image": { "type": null, "url": null }, "lockDetail": { "locked": false, "showContent": true, "showUpgrade": false, "reason": null, "hint": null, "detail": null } }, { "role": "assistant", "type": "text", "content": "", "id": "msg_2", "created_at": "2026-06-24T10:00:03Z", "audioUrl": null, "image": { "type": null, "url": null }, "lockDetail": { "locked": true, "showContent": false, "showUpgrade": true, "reason": "private_message", "hint": "他好像想说什么悄悄话,解锁会员才能看到…", "detail": { "messageId": "msg_2" } } } ], "total": 200, "limit": 50, "offset": 0, "isVip": false } 历史前端用法: for (const m of data.messages) { if (m.lockDetail?.showContent === false) { renderLockedCard(m.lockDetail.hint) if (m.lockDetail?.showUpgrade) showVipEntry() continue }
renderMessage(m.role, m.content)
if (m.image?.url) renderImage(m.image.url) if (m.audioUrl) renderAudio(m.audioUrl) } 前端不要再读这些旧字段:mode、relationshipStage、currentMood、intimacyChange、newIntimacy、voiceUrl、imageUrl、imageType、privateLocked、privateHint。统一是 audioUrl、image.url、lockDetail。