mirror of
https://github.com/ikechan8370/chatgpt-plugin.git
synced 2025-12-16 21:37:11 +00:00
feat: support search for gemini2: #chatgpt开启gemini搜索 #chatgpt开启代码执行 暂时不可并存
This commit is contained in:
parent
8fc2ca5621
commit
5f6c4e5abb
5 changed files with 118 additions and 13 deletions
|
|
@ -341,6 +341,11 @@ export class ChatgptManagement extends plugin {
|
|||
reg: '^#chatgpt(开启|关闭)(工具箱|后台服务)$',
|
||||
fnc: 'switchToolbox',
|
||||
permission: 'master'
|
||||
},
|
||||
{
|
||||
reg: '^#chatgpt(开启|关闭)gemini(搜索|代码执行)$',
|
||||
fnc: 'geminiOpenSearchCE',
|
||||
permission: 'master'
|
||||
}
|
||||
]
|
||||
})
|
||||
|
|
@ -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('操作成功')
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
@ -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}>}
|
||||
*/
|
||||
|
|
@ -163,15 +189,15 @@ 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 = [
|
||||
{
|
||||
body.tools.push({
|
||||
function_declarations: this.tools.map(tool => tool.function())
|
||||
// codeExecution: {}
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
// ANY要笑死人的效果
|
||||
body.tool_config = {
|
||||
function_calling_config: {
|
||||
|
|
@ -179,6 +205,12 @@ export class CustomGoogleGeminiClient extends GoogleGeminiClient {
|
|||
}
|
||||
}
|
||||
}
|
||||
if (opt.search) {
|
||||
body.tools.push({ google_search: {} })
|
||||
}
|
||||
if (opt.codeExecution) {
|
||||
body.tools.push({ code_execution: {} })
|
||||
}
|
||||
if (opt.image) {
|
||||
delete body.tools
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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 = {}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue