123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240 |
- import { currentHost } from '@/utils/location'
- /**
- * 转义处理响应值为 data: 的 json 字符串
- * 如: 科大讯飞星火、Kimi Moonshot 等大模型的 response
- */
- export const createParser = () => {
- let keepAliveShown = false
- const resetKeepAliveParser = () => {
- keepAliveShown = false
- }
- const parseJsonLikeData = (content) => {
- // 若是终止信号,则直接结束
- if (content === '[DONE]') {
- // 重置 keepAlive 标志
- keepAliveShown = false
- return {
- done: true
- }
- }
- if (content.startsWith('data: ')) {
- keepAliveShown = false
- const dataString = content.substring(6).trim()
- if (dataString === '[DONE]') {
- return {
- done: true
- }
- }
- try {
- return JSON.parse(dataString)
- } catch (error) {
- console.error('JSON 解析错误:', error)
- }
- }
- // 尝试直接解析 JSON 字符串
- try {
- const trimmedContent = content.trim()
- if (trimmedContent === ': keep-alive') {
- // 如果还没有显示过 keep-alive 提示,则显示
- if (!keepAliveShown) {
- keepAliveShown = true
- return {
- isWaitQueuing: true
- }
- } else {
- return null
- }
- }
- if (!trimmedContent) {
- return null
- }
- if (trimmedContent.startsWith('{') && trimmedContent.endsWith('}')) {
- return JSON.parse(trimmedContent)
- }
- if (trimmedContent.startsWith('[') && trimmedContent.endsWith(']')) {
- return JSON.parse(trimmedContent)
- }
- } catch (error) {
- console.error('尝试直接解析 JSON 失败:', error)
- }
- return null
- }
- return {
- resetKeepAliveParser,
- parseJsonLikeData
- }
- }
- export const createStreamThinkTransformer = () => {
- let isThinking = false
- const resetThinkTransformer = () => {
- isThinking = false
- }
- const transformStreamThinkData = (content) => {
- const stream = parseJsonLikeData(content)
- if (stream && stream.done) {
- return {
- done: true
- }
- }
- // DeepSeek 存在限速问题,这里做一个简单处理
- // https://api-docs.deepseek.com/zh-cn/quick_start/rate_limit
- if (stream && stream.isWaitQueuing) {
- return {
- isWaitQueuing: stream.isWaitQueuing
- }
- }
- if (!stream || !stream.choices || stream.choices.length === 0) {
- return {
- content: ''
- }
- }
- const delta = stream.choices[0].delta
- const contentText = delta.content || ''
- const reasoningText = delta.reasoning_content || ''
- let transformedContent = ''
- // 开始处理推理过程
- if (delta.content === null && delta.reasoning_content !== null) {
- if (!isThinking) {
- transformedContent += '<think>'
- isThinking = true
- }
- transformedContent += reasoningText
- }
- // 当 content 出现时,说明推理结束
- else if (delta.content !== null && delta.reasoning_content === null) {
- if (isThinking) {
- transformedContent += '</think>\n\n'
- isThinking = false
- }
- transformedContent += contentText
- }
- // 当为普通模型,即不包含推理字段时,直接追加 content
- else if (delta.content !== null && delta.reasoning_content === undefined) {
- isThinking = false
- transformedContent += contentText
- }
- return {
- content: transformedContent
- }
- }
- return {
- resetThinkTransformer,
- transformStreamThinkData
- }
- }
- const { resetKeepAliveParser, parseJsonLikeData } = createParser()
- const { resetThinkTransformer, transformStreamThinkData } = createStreamThinkTransformer()
- /**
- * 处理大模型调用暂停、异常或结束后触发的操作
- */
- export const triggerModelTermination = () => {
- resetKeepAliveParser()
- resetThinkTransformer()
- }
- type ContentResult = {
- content: any
- } | {
- done: boolean
- }
- type DoneResult = {
- content: any
- isWaitQueuing?: any
- } & {
- done: boolean
- }
- export type CrossTransformFunction = (readValue: Uint8Array | string, textDecoder: TextDecoder) => DoneResult
- export type TransformFunction = (readValue: Uint8Array | string, textDecoder: TextDecoder) => ContentResult
- interface TypesModelLLM {
- // 模型昵称
- label: string
- // 模型标识符
- modelName: string
- // Stream 结果转换器
- transformStreamValue: TransformFunction
- // 每个大模型调用的 API 请求
- chatFetch: (text: string) => Promise<Response>
- }
- /** ---------------- 大模型映射列表 & Response Transform 用于处理不同类型流的值转换器 ---------------- */
- /**
- * Mock 模拟模型的 name
- */
- export const defaultMockModelName = 'standard'
- /**
- * 项目默认使用模型,按需修改此字段即可
- */
- // export const defaultModelName = 'spark'
- export const defaultModelName = defaultMockModelName
- export const modelMappingList: TypesModelLLM[] = [
- {
- label: '🧪 模拟数据模型',
- modelName: 'standard',
- transformStreamValue(readValue, textDecoder) {
- let content = ''
- if (readValue instanceof Uint8Array) {
- content = textDecoder.decode(readValue, {
- stream: true
- })
- } else {
- content = readValue
- }
- return {
- content
- }
- },
- // Mock Event Stream 用于模拟读取大模型接口 Mock 数据
- async chatFetch(text): Promise<Response> {
- const formData = new FormData()
- const history = localStorage.getItem('kaConversationsChatList') || '[]'
- const payload = {
- client_id: `${ Date.now() + 10 }`,
- prompt: text,
- history
- }
- Object.entries(payload).forEach(([key, value]) => {
- formData.append(key, value)
- })
- const res = await fetch(`${ currentHost.baseApi }/chat`, {
- method: 'POST',
- body: formData
- })
- return res
- }
- }
- ]
|