Skip to content

Commit

Permalink
feat: support search for gemini2: #chatgpt开启gemini搜索 #chatgpt开启代码执行 暂…
Browse files Browse the repository at this point in the history
…时不可并存
  • Loading branch information
ikechan8370 committed Dec 12, 2024
1 parent 8fc2ca5 commit 5f6c4e5
Show file tree
Hide file tree
Showing 5 changed files with 118 additions and 13 deletions.
18 changes: 18 additions & 0 deletions apps/management.js
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,11 @@ export class ChatgptManagement extends plugin {
reg: '^#chatgpt(开启|关闭)(工具箱|后台服务)$',
fnc: 'switchToolbox',
permission: 'master'
},
{
reg: '^#chatgpt(开启|关闭)gemini(搜索|代码执行)$',
fnc: 'geminiOpenSearchCE',
permission: 'master'
}
]
})
Expand Down Expand Up @@ -1827,4 +1832,17 @@ azure语音:Azure 语音是微软 Azure 平台提供的一项语音服务,
await this.reply('好的,已经关闭工具箱')
}
}

async geminiOpenSearchCE (e) {
let msg = e.msg
let open = msg.includes('开启')
if (msg.includes('搜索')) {
Config.geminiEnableGoogleSearch = open
open && (Config.geminiEnableCodeExecution = !open)
} else {
Config.geminiEnableCodeExecution = open
open && (Config.geminiEnableGoogleSearch = !open)
}
await e.reply('操作成功')
}
}
99 changes: 88 additions & 11 deletions client/CustomGoogleGeminiClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,37 @@ export const HarmBlockThreshold = {
* parts: Array<{
* text?: string,
* functionCall?: FunctionCall,
* functionResponse?: FunctionResponse
* functionResponse?: FunctionResponse,
* executableCode?: {
* language: string,
* code: string
* },
* codeExecutionResult?: {
* outcome: string,
* output: string
* }
* }>
* }} Content
*
* Gemini消息的基本格式
*/

/**
* @typedef {{
* searchEntryPoint: {
* renderedContent: string,
* },
* groundingChunks: Array<{
* web: {
* uri: string,
* title: string
* }
* }>,
* webSearchQueries: Array<string>
* }} GroundingMetadata
* 搜索结果的元数据
*/

/**
* @typedef {{
* name: string,
Expand Down Expand Up @@ -80,7 +104,9 @@ export class CustomGoogleGeminiClient extends GoogleGeminiClient {
* temperature: number?,
* topP: number?,
* tokK: number?,
* replyPureTextCallback: Function
* replyPureTextCallback: Function,
* search: boolean,
* codeExecution: boolean
* }} opt
* @returns {Promise<{conversationId: string?, parentMessageId: string, text: string, id: string}>}
*/
Expand Down Expand Up @@ -163,22 +189,28 @@ export class CustomGoogleGeminiClient extends GoogleGeminiClient {
temperature: opt.temperature || 0.9,
topP: opt.topP || 0.95,
topK: opt.tokK || 16
}
},
tools: []
}
if (this.tools?.length > 0) {
body.tools = [
{
function_declarations: this.tools.map(tool => tool.function())
// codeExecution: {}
}
]
body.tools.push({
function_declarations: this.tools.map(tool => tool.function())
// codeExecution: {}
})

// ANY要笑死人的效果
body.tool_config = {
function_calling_config: {
mode: 'AUTO'
}
}
}
if (opt.search) {
body.tools.push({ google_search: {} })
}
if (opt.codeExecution) {
body.tools.push({ code_execution: {} })
}
if (opt.image) {
delete body.tools
}
Expand All @@ -202,13 +234,14 @@ export class CustomGoogleGeminiClient extends GoogleGeminiClient {
*/
let responseContent
/**
* @type {{candidates: Array<{content: Content}>}}
* @type {{candidates: Array<{content: Content, groundingMetadata: GroundingMetadata}>}}
*/
let response = await result.json()
if (this.debug) {
console.log(JSON.stringify(response))
}
responseContent = response.candidates[0].content
let groundingMetadata = response.candidates[0].groundingMetadata
if (responseContent.parts.find(i => i.functionCall)) {
// functionCall
const functionCall = responseContent.parts.find(i => i.functionCall).functionCall
Expand Down Expand Up @@ -265,6 +298,7 @@ export class CustomGoogleGeminiClient extends GoogleGeminiClient {
// 递归直到返回text
// 先把这轮的消息存下来
await this.upsertMessage(thisMessage)
responseContent = handleSearchResponse(responseContent).responseContent
const respMessage = Object.assign(responseContent, {
id: idModel,
parentMessageId: idThis
Expand All @@ -290,11 +324,54 @@ export class CustomGoogleGeminiClient extends GoogleGeminiClient {
})
await this.upsertMessage(respMessage)
}
let { final } = handleSearchResponse(responseContent)
try {
if (groundingMetadata?.groundingChunks) {
final += '\n参考资料\n'
groundingMetadata.groundingChunks.forEach(chunk => {
// final += `[${chunk.web.title}](${chunk.web.uri})\n`
final += `[${chunk.web.title}]\n`
})
groundingMetadata.webSearchQueries.forEach(q => {
logger.info('search query: ' + q)
})
}
} catch (err) {
logger.warn(err)
}

return {
text: responseContent.parts[0].text.trim(),
text: final,
conversationId: '',
parentMessageId: idThis,
id: idModel
}
}
}

/**
* 处理成单独的text
* @param {Content} responseContent
* @returns {{final: string, responseContent}}
*/
function handleSearchResponse (responseContent) {
let final = ''
for (let part of responseContent.parts) {
if (part.text) {
final += part.text
}
if (part.executableCode) {
final += '\n执行代码:\n' + '```' + part.executableCode.language + '\n' + part.executableCode.code.trim() + '\n```\n\n'
}
if (part.codeExecutionResult) {
final += `\n执行结果(${part.codeExecutionResult.outcome}):\n` + '```\n' + part.codeExecutionResult.output + '\n```\n\n'
}
}
responseContent.parts = [{
text: final
}]
return {
final,
responseContent
}
}
4 changes: 3 additions & 1 deletion model/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -734,7 +734,9 @@ class Core {
}
},
parentMessageId: conversation.parentMessageId,
conversationId: conversation.conversationId
conversationId: conversation.conversationId,
search: Config.geminiEnableGoogleSearch,
codeExecution: Config.geminiEnableCodeExecution
}
const image = await getImg(e)
let imageUrl = image ? image[0] : undefined
Expand Down
6 changes: 6 additions & 0 deletions utils/chat.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,13 @@ export async function getChatHistoryGroup (e, num) {
let chats = []
while (chats.length < num) {
let chatHistory = await e.group.getChatHistory(seq, 20)
if (!chatHistory || chatHistory.length === 0) {
break
}
chats.push(...chatHistory)
if (seq === chatHistory[0].seq || seq === chatHistory[0].message_id) {
break
}
seq = chatHistory[0].seq || chatHistory[0].message_id
}
chats = chats.slice(0, num)
Expand Down
4 changes: 3 additions & 1 deletion utils/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,9 @@ const defaultConfig = {
translateSource: 'openai',
enableMd: false, // 第三方md,非QQBot。需要适配器实现segment.markdown和segment.button方可使用,否则不建议开启,会造成各种错误
enableToolbox: true, // 默认关闭工具箱节省占用和加速启动
version: 'v2.8.1'
geminiEnableGoogleSearch: false,
geminiEnableCodeExecution: false,
version: 'v2.8.2'
}
const _path = process.cwd()
let config = {}
Expand Down

0 comments on commit 5f6c4e5

Please sign in to comment.