add 小程序支持角色切换
This commit is contained in:
@@ -88,6 +88,30 @@ interface DeviceAiMessageListResponse {
|
||||
next_cursor?: number | null
|
||||
}
|
||||
|
||||
interface DeviceAiConversationItem {
|
||||
conversation_id: number
|
||||
role_key: string
|
||||
role_name: string
|
||||
role_description?: string | null
|
||||
message_count: number
|
||||
last_message_preview?: string | null
|
||||
last_message_at?: string | null
|
||||
created_at: string
|
||||
updated_at: string
|
||||
}
|
||||
|
||||
interface DeviceAiConversationListResponse {
|
||||
items: DeviceAiConversationItem[]
|
||||
total: number
|
||||
next_cursor?: number | null
|
||||
}
|
||||
|
||||
interface DeviceRoleSummary {
|
||||
role_key: string
|
||||
name: string
|
||||
description?: string | null
|
||||
}
|
||||
|
||||
interface ChildConversationItem {
|
||||
conversation_id: number
|
||||
conversation_type: number
|
||||
@@ -161,6 +185,8 @@ const AI_ROLE_META: Record<string, { name: string; icon: string; description: st
|
||||
assistant: { name: 'AI', icon: '🤖', description: '孩子与 AI 的历史交流' },
|
||||
}
|
||||
|
||||
type AiMeta = { name: string; icon: string; description: string }
|
||||
|
||||
export function isParentChildConversation(conversationTypeName?: string | null): boolean {
|
||||
return conversationTypeName === PARENT_CHILD_CONVERSATION_TYPE_NAME
|
||||
}
|
||||
@@ -225,7 +251,16 @@ function createClientMessageId(): string {
|
||||
return `parent-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`
|
||||
}
|
||||
|
||||
function getAiMeta(roleKey?: string): { name: string; icon: string; description: string } {
|
||||
function getAiMeta(roleKey?: string, roleName?: string | null, roleDescription?: string | null): AiMeta {
|
||||
const normalizedRoleName = String(roleName || '').trim()
|
||||
const normalizedRoleDescription = String(roleDescription || '').trim()
|
||||
if (normalizedRoleName) {
|
||||
return {
|
||||
name: normalizedRoleName,
|
||||
icon: '🤖',
|
||||
description: normalizedRoleDescription || `孩子与 ${normalizedRoleName} 的历史交流`,
|
||||
}
|
||||
}
|
||||
if (roleKey && AI_ROLE_META[roleKey]) return AI_ROLE_META[roleKey]
|
||||
return {
|
||||
name: roleKey || 'AI',
|
||||
@@ -234,6 +269,21 @@ function getAiMeta(roleKey?: string): { name: string; icon: string; description:
|
||||
}
|
||||
}
|
||||
|
||||
async function getRoleMetaMap(): Promise<Record<string, AiMeta>> {
|
||||
try {
|
||||
const roles = await request<DeviceRoleSummary[]>('/banban/roles')
|
||||
return roles.reduce<Record<string, AiMeta>>((result, role) => {
|
||||
const roleKey = String(role.role_key || '').trim()
|
||||
if (!roleKey) return result
|
||||
result[roleKey] = getAiMeta(roleKey, role.name, role.description)
|
||||
return result
|
||||
}, {})
|
||||
} catch (error: any) {
|
||||
if (error?.status === 404) return {}
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
function getParticipantDisplayName(type: string, id?: string, name?: string | null): string {
|
||||
if (name && name.trim()) return name.trim()
|
||||
if (type === 'child') return id ? `儿童 ${id}` : '儿童'
|
||||
@@ -276,6 +326,21 @@ async function getDeviceMessages(context?: BindingContext): Promise<DeviceAiMess
|
||||
}
|
||||
}
|
||||
|
||||
async function getDeviceAiConversations(context?: BindingContext): Promise<DeviceAiConversationItem[]> {
|
||||
const { deviceId } = context || (await getBindingContext())
|
||||
if (!deviceId) return []
|
||||
|
||||
try {
|
||||
const response = await request<DeviceAiConversationListResponse>(
|
||||
`/banban/devices/${deviceId}/ai-conversations?limit=100`
|
||||
)
|
||||
return response.items || []
|
||||
} catch (error: any) {
|
||||
if (error?.status === 404) return []
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
async function getChildConversations(context?: BindingContext): Promise<ChildConversationItem[]> {
|
||||
const { childId } = context || (await getBindingContext())
|
||||
if (!childId) return []
|
||||
@@ -330,8 +395,10 @@ function toImConversation(item: ChildConversationItem, context: BindingContext):
|
||||
}
|
||||
}
|
||||
|
||||
function toAiConversation(item: DeviceAiMessageItem, context: BindingContext): ChatConversation {
|
||||
const meta = getAiMeta(item.role_key)
|
||||
function toAiConversation(item: DeviceAiConversationItem, context: BindingContext, roleMetaMap: Record<string, AiMeta>): ChatConversation {
|
||||
const meta = roleMetaMap[item.role_key] || getAiMeta(item.role_key, item.role_name, item.role_description)
|
||||
const lastMessage = item.last_message_preview || (item.message_count > 0 ? '暂无内容' : '这个会话还没有消息')
|
||||
const sortAt = item.last_message_at || item.updated_at || item.created_at
|
||||
|
||||
return {
|
||||
id: item.conversation_id,
|
||||
@@ -342,9 +409,9 @@ function toAiConversation(item: DeviceAiMessageItem, context: BindingContext): C
|
||||
avatar: meta.icon,
|
||||
typeLabel: PEER_META.ai.label,
|
||||
description: meta.description,
|
||||
lastMessage: item.content || '暂无消息',
|
||||
time: formatListTime(item.created_at),
|
||||
sortAt: item.created_at,
|
||||
lastMessage,
|
||||
time: formatListTime(sortAt),
|
||||
sortAt,
|
||||
roleKey: item.role_key,
|
||||
conversationTypeName: 'ai',
|
||||
peerId: item.role_key,
|
||||
@@ -386,19 +453,16 @@ function createSyntheticParentConversation(context: BindingContext): ChatConvers
|
||||
|
||||
export async function getConversations(): Promise<ChatConversation[]> {
|
||||
const context = await getBindingContext()
|
||||
const [imConversationItems, aiMessages] = await Promise.all([getChildConversations(context), getDeviceMessages(context)])
|
||||
const [imConversationItems, aiConversations, roleMetaMap] = await Promise.all([
|
||||
getChildConversations(context),
|
||||
getDeviceAiConversations(context),
|
||||
getRoleMetaMap(),
|
||||
])
|
||||
const imConversations = imConversationItems.map((item) => toImConversation(item, context))
|
||||
const aiConversationMap = new Map<number, DeviceAiMessageItem>()
|
||||
|
||||
for (const item of aiMessages) {
|
||||
if (!aiConversationMap.has(item.conversation_id)) {
|
||||
aiConversationMap.set(item.conversation_id, item)
|
||||
}
|
||||
}
|
||||
|
||||
const conversations = [
|
||||
...imConversations,
|
||||
...Array.from(aiConversationMap.values()).map((item) => toAiConversation(item, context)),
|
||||
...aiConversations.map((item) => toAiConversation(item, context, roleMetaMap)),
|
||||
]
|
||||
|
||||
const hasParentConversation = conversations.some(
|
||||
@@ -429,30 +493,33 @@ export async function getMessages(
|
||||
const context = await getBindingContext()
|
||||
|
||||
if (source === 'ai') {
|
||||
const items = await getDeviceMessages(context)
|
||||
const [items, roleMetaMap] = await Promise.all([getDeviceMessages(context), getRoleMetaMap()])
|
||||
return items
|
||||
.filter((item) => item.conversation_id === conversationId)
|
||||
.slice()
|
||||
.reverse()
|
||||
.map((item) => ({
|
||||
id: item.id,
|
||||
type: item.is_user ? 'user' : 'peer',
|
||||
content: item.content || '暂无内容',
|
||||
time: formatDetailTime(item.created_at),
|
||||
conversationId: item.conversation_id,
|
||||
contentType: 1,
|
||||
mediaUrl: null,
|
||||
mediaDurationMs: null,
|
||||
mediaMimeType: null,
|
||||
mediaTranscriptText: null,
|
||||
senderType: item.is_user ? 'device' : 'ai',
|
||||
senderId: item.is_user ? context.deviceId : item.role_key,
|
||||
receiverType: item.is_user ? 'ai' : 'device',
|
||||
receiverId: item.is_user ? item.role_key : context.deviceId,
|
||||
senderName: item.is_user ? context.childName || '孩子设备' : getAiMeta(item.role_key).name,
|
||||
receiverName: item.is_user ? getAiMeta(item.role_key).name : context.childName || '孩子设备',
|
||||
channelLabel: 'AI',
|
||||
}))
|
||||
.map((item) => {
|
||||
const meta = roleMetaMap[item.role_key] || getAiMeta(item.role_key)
|
||||
return {
|
||||
id: item.id,
|
||||
type: item.is_user ? 'user' : 'peer',
|
||||
content: item.content || '暂无内容',
|
||||
time: formatDetailTime(item.created_at),
|
||||
conversationId: item.conversation_id,
|
||||
contentType: 1,
|
||||
mediaUrl: null,
|
||||
mediaDurationMs: null,
|
||||
mediaMimeType: null,
|
||||
mediaTranscriptText: null,
|
||||
senderType: item.is_user ? 'device' : 'ai',
|
||||
senderId: item.is_user ? context.deviceId : item.role_key,
|
||||
receiverType: item.is_user ? 'ai' : 'device',
|
||||
receiverId: item.is_user ? item.role_key : context.deviceId,
|
||||
senderName: item.is_user ? context.childName || '孩子设备' : meta.name,
|
||||
receiverName: item.is_user ? meta.name : context.childName || '孩子设备',
|
||||
channelLabel: 'AI',
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const items = await getChildConversationMessages(conversationId, context)
|
||||
|
||||
Reference in New Issue
Block a user