Browse Source

feat(aiChat): 支持在AI对话中传递图片URL

新增image_urls参数到ChatParams接口,修改chat_no_stream和chat_stream函数接收图片URL参数,在AI对话组件中提取页面图片URL并传递给AI请求,实现图片内容识别功能
lsc 8 hours ago
parent
commit
1a83ff2cef
2 changed files with 43 additions and 11 deletions
  1. 32 4
      src/components/CollapsibleToolbar/componets/aiChat.vue
  2. 11 7
      src/tools/aiChat.ts

+ 32 - 4
src/components/CollapsibleToolbar/componets/aiChat.vue

@@ -661,32 +661,54 @@ const sendAction = async (action: string) => {
     })
     })
     .filter(content => content.trim() !== '') || []
     .filter(content => content.trim() !== '') || []
 
 
+  // 提取所有页面中 type 为 'image' 的元素的纯文本内容
+  const allImgContents = slidesStore.slides.flatMap((slide: any) => {
+    const elements = slide.elements || []
+    return elements
+      .filter((el: any) => el.type === 'image' && el.src?.includes('https'))
+      .map((el: any) => el.src.trim().replace('https://ccrb.s3.cn-northwest-1.amazonaws.com.cn/', 'https://duimes0j49llm.cloudfront.net/'))
+      .filter((src: string) => !!src)
+  })
+  // 提取当前页面中 type 为 'image' 的元素 并且为链接
+  const imgContents = slidesStore.currentSlide?.elements
+    .filter((element: any) => element.type === 'image' && element.src.includes('https'))
+    .map((textElement: any) => textElement.src.replace('https://ccrb.s3.cn-northwest-1.amazonaws.com.cn/', 'https://duimes0j49llm.cloudfront.net/'))
   console.log('allTextContents', allTextContents)
   console.log('allTextContents', allTextContents)
   console.log('textContents', textContents)
   console.log('textContents', textContents)
+  console.log('allImgContents', allImgContents)
+  console.log('imgContents', imgContents)
+
   let prompt = ''
   let prompt = ''
   let agentid = agentid2.value
   let agentid = agentid2.value
+  const imgUrls = []
 
 
 
 
   if (gType.value === 'trigger_tool_recommend') {
   if (gType.value === 'trigger_tool_recommend') {
     agentid = agentid3.value
     agentid = agentid3.value
+    imgUrls.push(...allImgContents)
     prompt = `
     prompt = `
   #课程标题(course_title): ${props.courseTitle || ''}
   #课程标题(course_title): ${props.courseTitle || ''}
   #当前页面内容(all_pages_content): ${allTextContents.length > 0 ? allTextContents.join('\n') : '无文本内容'}
   #当前页面内容(all_pages_content): ${allTextContents.length > 0 ? allTextContents.join('\n') : '无文本内容'}
+  ${imgUrls.length ?  '识别图片内容' : ''}
   #query: ${action}
   #query: ${action}
   `
   `
   }
   }
   else if (gType.value === 'trigger_batch_tool') {
   else if (gType.value === 'trigger_batch_tool') {
     agentid = agentid4.value
     agentid = agentid4.value
+    imgUrls.push(...allImgContents)
     prompt = `
     prompt = `
   #课程标题(course_title): ${props.courseTitle || ''}
   #课程标题(course_title): ${props.courseTitle || ''}
   #当前页面内容(all_pages_content): ${allTextContents.length > 0 ? allTextContents.join('\n') : '无文本内容'}
   #当前页面内容(all_pages_content): ${allTextContents.length > 0 ? allTextContents.join('\n') : '无文本内容'}
+  ${imgUrls.length ?  '识别图片内容' : ''}
   #query: ${action}
   #query: ${action}
   `
   `
   }
   }
   else {
   else {
+    imgUrls.push(...imgContents)
     prompt = `
     prompt = `
   #课程标题(course_title): ${props.courseTitle || ''}
   #课程标题(course_title): ${props.courseTitle || ''}
   #当前页面内容(current_page_content): ${textContents.length > 0 ? textContents.join('\n') : '无文本内容'}
   #当前页面内容(current_page_content): ${textContents.length > 0 ? textContents.join('\n') : '无文本内容'}
+  ${imgUrls.length ?  '识别图片内容' : ''}
   #query: ${action}
   #query: ${action}
   `
   `
   }
   }
@@ -699,7 +721,7 @@ const sendAction = async (action: string) => {
       console.log('loadingDots.value', loadingDots.value)
       console.log('loadingDots.value', loadingDots.value)
       console.log('messages.value.at(-1).aiContent', messages.value.at(-1).aiContent)
       console.log('messages.value.at(-1).aiContent', messages.value.at(-1).aiContent)
     }, 500)
     }, 500)
-    const result = chat_no_stream(prompt, agentid, props.userid || '', lang.lang)
+    const result = chat_no_stream(prompt, agentid, props.userid || '', lang.lang, undefined, imgUrls)
     streamController.value = result
     streamController.value = result
     console.log(result)
     console.log(result)
     const content = await result.promise
     const content = await result.promise
@@ -731,7 +753,7 @@ const sendAction = async (action: string) => {
   }
   }
   else if (gType.value === 'generate_interactive_web') {
   else if (gType.value === 'generate_interactive_web') {
     agentid = agentid5.value
     agentid = agentid5.value
-    const result = chat_no_stream(prompt, agentid, props.userid || '', lang.lang)
+    const result = chat_no_stream(prompt, agentid, props.userid || '', lang.lang, undefined, imgUrls)
     streamController.value = result
     streamController.value = result
     console.log(result)
     console.log(result)
     const content = await result.promise
     const content = await result.promise
@@ -775,7 +797,7 @@ const sendAction = async (action: string) => {
       chatLoading.value = false
       chatLoading.value = false
       prevChatResult()
       prevChatResult()
     }
     }
-  }, session_name.value, messages.value.at(-1).sourceFiles?.map(file => file.id).filter(Boolean)).then(controller => {
+  }, session_name.value, messages.value.at(-1).sourceFiles?.map(file => file.id).filter(Boolean), undefined, imgUrls).then(controller => {
     streamController.value = controller
     streamController.value = controller
   }).catch(err => {
   }).catch(err => {
     chatLoading.value = false
     chatLoading.value = false
@@ -1104,13 +1126,19 @@ const createTool = async (array: any[], tool: any, index: number, slide: any) =>
     })
     })
     .filter(content => content.trim() !== '') || []
     .filter(content => content.trim() !== '') || []
   
   
+  // 提取当前页面中 type 为 'image' 的元素 并且为链接
+  const imgContents = slidesStore.currentSlide?.elements
+    .filter((element: any) => element.type === 'image' && element.src.includes('https'))
+    .map((textElement: any) => textElement.src.replace('https://ccrb.s3.cn-northwest-1.amazonaws.com.cn/', 'https://duimes0j49llm.cloudfront.net/'))
+    
   console.log('textContents', textContents)
   console.log('textContents', textContents)
   const prompt = `
   const prompt = `
       #课程标题(course_title): ${props.courseTitle || ''}
       #课程标题(course_title): ${props.courseTitle || ''}
       #当前页面内容(current_page_content): ${textContents.length > 0 ? textContents.join('\n') : '无文本内容'}
       #当前页面内容(current_page_content): ${textContents.length > 0 ? textContents.join('\n') : '无文本内容'}
+      ${imgContents.length ?  '识别图片内容' : ''}
       #query: ${action}
       #query: ${action}
       `
       `
-  const result = chat_no_stream(prompt, agentid2.value, props.userid || '', lang.lang)
+  const result = chat_no_stream(prompt, agentid2.value, props.userid || '', lang.lang, undefined, imgUrls)
   console.log(result)
   console.log(result)
   const content = await result.promise
   const content = await result.promise
   console.log('👶 创建工具:', content)
   console.log('👶 创建工具:', content)

+ 11 - 7
src/tools/aiChat.ts

@@ -22,6 +22,7 @@ interface ChatParams {
   uid: string;
   uid: string;
   session_name: string;
   session_name: string;
   tts_language: string;
   tts_language: string;
+  image_urls: string[];
 }
 }
 
 
 const DEFAULT_PARAMS: Omit<ChatParams, 'message' | 'uid' | 'stream'> = {
 const DEFAULT_PARAMS: Omit<ChatParams, 'message' | 'uid' | 'stream'> = {
@@ -30,14 +31,14 @@ const DEFAULT_PARAMS: Omit<ChatParams, 'message' | 'uid' | 'stream'> = {
   model: 'open-doubao',
   model: 'open-doubao',
   file_ids: [],
   file_ids: [],
   sound_url: '',
   sound_url: '',
-  temperature: 0.2,
-  top_p: 1,
-  max_completion_tokens: 4096,
+  // temperature: 0.2,
+  // top_p: 1,
+  // max_completion_tokens: 4096,
   session_name: 'pptSession_name',
   session_name: 'pptSession_name',
   tts_language: 'zh-CN'
   tts_language: 'zh-CN'
 }
 }
 
 
-export const chat_no_stream = (msg: string, agentId: string, userId: string, language: string, session_name?: string): { promise: Promise<string>; abort: () => void } => {
+export const chat_no_stream = (msg: string, agentId: string, userId: string, language: string, session_name?: string, imgUrls: string[] = []): { promise: Promise<string>; abort: () => void } => {
   const source = cancelToken.source()
   const source = cancelToken.source()
   
   
   const promise = (async () => {
   const promise = (async () => {
@@ -56,7 +57,8 @@ export const chat_no_stream = (msg: string, agentId: string, userId: string, lan
       model: agentData?.modelType || 'open-doubao',
       model: agentData?.modelType || 'open-doubao',
       userId: userId,
       userId: userId,
       tts_language: getTtsLanguage(language),
       tts_language: getTtsLanguage(language),
-      session_name: session_name || uuidv4()
+      session_name: session_name || uuidv4(),
+      image_urls: imgUrls
     }
     }
 
 
     try {
     try {
@@ -104,7 +106,8 @@ export const chat_stream = async (
   onMessage: (event: { type: 'message' | 'close' | 'error' | 'messageEnd'; data: string }) => void,
   onMessage: (event: { type: 'message' | 'close' | 'error' | 'messageEnd'; data: string }) => void,
   session_name?: string,
   session_name?: string,
   file_ids?: Array<string>,
   file_ids?: Array<string>,
-  model?: string
+  model?: string,
+  imgUrls: string[] = []
 ): Promise<{ abort: () => void }> => {
 ): Promise<{ abort: () => void }> => {
   const agentData = await getAgentModel(agentId)
   const agentData = await getAgentModel(agentId)
   const params: ChatParams = {
   const params: ChatParams = {
@@ -122,7 +125,8 @@ export const chat_stream = async (
     model: model || agentData?.modelType || 'open-doubao',
     model: model || agentData?.modelType || 'open-doubao',
     userId: userId,
     userId: userId,
     tts_language: getTtsLanguage(language),
     tts_language: getTtsLanguage(language),
-    session_name: session_name || uuidv4()
+    session_name: session_name || uuidv4(),
+    image_urls: imgUrls
   }
   }
 
 
   const ctrl = new AbortController()
   const ctrl = new AbortController()