chore: initialize qiming workspace repository

This commit is contained in:
Codex
2026-05-29 14:22:48 +08:00
commit bfd67a0f2c
10750 changed files with 1885711 additions and 0 deletions

View File

@@ -0,0 +1,429 @@
import { MsgItem, markdownElItem } from '@/uni_modules/uni-ai-x/types'
import { MessageInfo } from '@/types/interfaces/conversationInfo'
import { AssistantRoleEnum, MessageModeEnum, MessageTypeEnum } from '@/types/enums/agent'
import { MessageStatusEnum } from '@/types/enums/common'
/**
* SSE数据块接口 - 匹配实际返回的数据结构
*/
export interface SSEChunk {
requestId: string
messageType?: string
message_type?: string
subType?: string
sub_type?: string
eventType: string
error: string | null
data: {
id: string
role: string
type: string
text: string
time: string | null
attachments: any[] | null
think: string | null
quotedText: string | null
ext: any[] | null
finished: boolean
executeId: string | null
messageType: string
}
completed: boolean
}
/**
* 聊天数据适配器
* 用于将MessageInfo格式转换为uni-ai-x期望的MsgItem格式
*/
export class ChatDataAdapter {
/**
* 判断SSE数据块是否可以按聊天文本消息渲染
*/
static isRenderableSSEChunk(chunk: SSEChunk): boolean {
const messageType = (chunk as any).messageType || (chunk as any).message_type
if (messageType === 'acpRequestPermission') {
return false
}
const data = (chunk as any).data
if (!data || typeof data !== 'object') {
return false
}
return typeof data.id === 'string' && data.id.length > 0
}
/**
* 将SSE数据块转换为MsgItem
* @param chunk SSE数据块
* @param chatId 聊天ID
* @returns uni-ai-x的MsgItem格式
*/
static convertSSEChunkToMsgItem(chunk: SSEChunk, chatId: string): MsgItem {
console.log(`Converting SSE chunk to MsgItem:`, chunk)
const data = (chunk as any).data || {}
const msgItem: MsgItem = {
_id: data.id || this.generateId(),
from_uid: this.getFromUidFromRole(data.role || 'ASSISTANT'),
body: data.text || '',
create_time: this.parseTime(data.time) || Date.now(),
state: data.finished ? 3 : 2, // 完成状态为3未完成为2
chat_id: chatId,
markdownElList: [],
rendered: false
}
console.log(`Converted MsgItem:`, msgItem)
return msgItem
}
/**
* 将MessageInfo转换为MsgItem
* @param messageInfo 消息信息
* @returns uni-ai-x的MsgItem格式
*/
static convertToMsgItem(messageInfo: MessageInfo): MsgItem {
const msgItem: MsgItem = {
_id: messageInfo.id?.toString() || '',
from_uid: this.getFromUid(messageInfo.role),
body: messageInfo.text || '',
create_time: this.parseTime(messageInfo.time),
state: this.getMsgState(messageInfo.status),
chat_id: '', // 需要从外部传入
markdownElList: (messageInfo as any).markdownElList || [],
rendered: false,
// 传递processingList用于自定义组件渲染
processingList: messageInfo.processingList || []
}
return msgItem
}
/**
* 将MsgItem转换为MessageInfo
* @param msgItem uni-ai-x的MsgItem格式
* @returns MessageInfo格式
*/
static convertToMessageInfo(msgItem: MsgItem): MessageInfo {
const messageInfo: MessageInfo = {
id: msgItem._id,
role: this.getAssistantRole(msgItem.from_uid),
type: this.getMessageMode(msgItem.from_uid),
text: msgItem.body,
think: (msgItem as any).thinkContent || '',
time: new Date(msgItem.create_time).toISOString(),
attachments: [],
ext: [],
finished: false,
metadata: null,
messageType: MessageTypeEnum.USER,
status: this.getMessageStatus(msgItem.state),
markdownElList: msgItem.markdownElList || [],
processingList: [],
finalResult: null,
requestId: ''
}
return messageInfo
}
/**
* 批量转换MessageInfo数组为MsgItem数组
* @param messageList 消息列表
* @param chatId 聊天ID
* @returns MsgItem数组
*/
static convertMessageListToMsgItems(messageList: MessageInfo[], chatId: string = ''): MsgItem[] {
return messageList.map(message => {
const msgItem = this.convertToMsgItem(message)
msgItem.chat_id = chatId
return msgItem
})
}
/**
* 批量转换MsgItem数组为MessageInfo数组
* @param msgItems 消息项数组
* @returns MessageInfo数组
*/
static convertMsgItemsToMessageList(msgItems: MsgItem[]): MessageInfo[] {
return msgItems.map(msgItem => this.convertToMessageInfo(msgItem))
}
/**
* 处理SSE流式数据累积文本内容
* @param chunks SSE数据块数组
* @param chatId 聊天ID
* @returns 处理后的MsgItem数组
*/
static processSSEChunks(chunks: SSEChunk[], chatId: string): MsgItem[] {
const messageMap = new Map<string, MsgItem>()
chunks.forEach(chunk => {
if (!this.isRenderableSSEChunk(chunk)) {
return
}
const messageId = chunk.data.id
if (!messageMap.has(messageId)) {
// 创建新消息
const msgItem = this.convertSSEChunkToMsgItem(chunk, chatId)
messageMap.set(messageId, msgItem)
} else {
// 累积文本内容
const existingMsg = messageMap.get(messageId)!
existingMsg.body += chunk.data.text || ''
// 更新状态
if (chunk.data.finished) {
existingMsg.state = 3 // 完成状态
}
}
})
// 兼容性处理将Map值转换为数组
const result: MsgItem[] = []
messageMap.forEach((value) => {
result.push(value)
})
return result
}
/**
* 根据角色获取from_uid
* @param role 角色
* @returns from_uid
*/
private static getFromUid(role: AssistantRoleEnum): string {
switch (role) {
case AssistantRoleEnum.USER:
return 'user'
case AssistantRoleEnum.ASSISTANT:
return 'uni-ai'
case AssistantRoleEnum.SYSTEM:
return 'system'
case AssistantRoleEnum.FUNCTION:
return 'tool'
default:
return 'user'
}
}
/**
* 根据角色字符串获取from_uid
* @param role 角色字符串
* @returns from_uid
*/
private static getFromUidFromRole(role: string): string {
switch (role) {
case 'USER':
return 'user'
case 'ASSISTANT':
return 'uni-ai'
case 'SYSTEM':
return 'system'
case 'FUNCTION':
return 'tool'
default:
return 'user'
}
}
/**
* 根据from_uid获取角色
* @param fromUid from_uid
* @returns 角色
*/
private static getAssistantRole(fromUid: string): AssistantRoleEnum {
switch (fromUid) {
case 'user':
return AssistantRoleEnum.USER
case 'uni-ai':
return AssistantRoleEnum.ASSISTANT
case 'system':
return AssistantRoleEnum.SYSTEM
case 'tool':
return AssistantRoleEnum.FUNCTION
default:
return AssistantRoleEnum.USER
}
}
/**
* 根据from_uid获取消息模式
* @param fromUid from_uid
* @returns 消息模式
*/
private static getMessageMode(fromUid: string): MessageModeEnum {
switch (fromUid) {
case 'user':
return MessageModeEnum.CHAT
case 'uni-ai':
return MessageModeEnum.ANSWER
case 'system':
return MessageModeEnum.GUID
case 'tool':
return MessageModeEnum.CHAT
default:
return MessageModeEnum.CHAT
}
}
/**
* 根据消息状态获取MsgItem状态
* @param status 消息状态
* @returns MsgItem状态
*/
private static getMsgState(status?: MessageStatusEnum | null): number {
switch (status) {
case MessageStatusEnum.Loading:
return 1 // 加载中
case MessageStatusEnum.Incomplete:
return 2 // 未完成
case MessageStatusEnum.Complete:
return 3 // 完成
case MessageStatusEnum.Error:
return 4 // 错误
default:
return 3 // 默认完成
}
}
/**
* 根据MsgItem状态获取消息状态
* @param state MsgItem状态
* @returns 消息状态
*/
private static getMessageStatus(state: number): MessageStatusEnum | null {
switch (state) {
case 1:
return MessageStatusEnum.Loading
case 2:
return MessageStatusEnum.Incomplete
case 3:
return MessageStatusEnum.Complete
case 4:
return MessageStatusEnum.Error
default:
return null
}
}
/**
* 解析时间字符串为时间戳
* @param timeStr 时间字符串
* @returns 时间戳
*/
private static parseTime(timeStr: string | null): number {
if (!timeStr) return Date.now()
try {
return new Date(timeStr).getTime()
} catch (error) {
return Date.now()
}
}
/**
* 创建新的用户消息
* @param content 消息内容
* @param chatId 聊天ID
* @param attachments 附件
* @returns 新的MsgItem
*/
static createUserMessage(content: string, chatId: string, attachments: any[] = []): MsgItem {
return {
_id: this.generateId(),
from_uid: 'user',
body: content,
create_time: Date.now(),
state: 3, // 完成状态
chat_id: chatId,
markdownElList: [],
rendered: false
}
}
/**
* 创建新的AI消息
* @param content 消息内容
* @param chatId 聊天ID
* @param markdownElements markdown元素
* @returns 新的MsgItem
*/
static createAIMessage(content: string, chatId: string, markdownElements: markdownElItem[] = []): MsgItem {
return {
_id: this.generateId(),
from_uid: 'uni-ai',
body: content,
create_time: Date.now(),
state: 2, // 未完成状态
chat_id: chatId,
markdownElList: markdownElements,
rendered: false
}
}
/**
* 生成唯一ID
* @returns 唯一ID
*/
private static generateId(): string {
// #ifdef MP-WEIXIN
// 微信小程序中uni.getRandomValues返回Promise这里简化处理
return Date.now().toString() + Math.random().toString(36).substr(2, 9)
// #endif
// #ifdef H5
// 这里需要导入uuid库
return Date.now().toString() + Math.random().toString(36).substr(2, 9)
// #endif
// 默认返回值
return Date.now().toString() + Math.random().toString(36).substr(2, 9)
}
}
// 导出适配器实例
export const chatDataAdapter = new ChatDataAdapter()
/*
使用示例:
// 1. 在聊天页面中导入适配器
import { chatDataAdapter, SSEChunk } from '@/utils/chatDataAdapter'
// 2. 处理SSE流式数据
const handleSSEChunk = (chunk: SSEChunk) => {
// 解析SSE数据
const sseData = JSON.parse(chunk)
// 累积数据块
sseChunks.value.push(sseData)
// 处理并转换为MsgItem
const msgItems = chatDataAdapter.processSSEChunks(sseChunks.value, 'chat-' + conversationId.value)
// 更新渲染列表
msgItemsForRender.value = msgItems
}
// 3. 在模板中使用
<template v-for="item in msgItemsForRender" :key="item._id">
<uni-ai-x-msg v-if="item.from_uid == 'uni-ai'" :msg="item" />
<text v-else class="user-msg">{{item.body}}</text>
</template>
// 4. 处理流式响应
const handleStreamResponse = (chunk: string) => {
try {
const sseChunk: SSEChunk = JSON.parse(chunk)
handleSSEChunk(sseChunk)
} catch (error) {
console.error('解析SSE数据失败:', error)
}
}
*/