mirror of
https://github.com/ikechan8370/chatgpt-plugin.git
synced 2025-12-17 05:47:11 +00:00
fix: 实现Gemini客户端取代官方版本
This commit is contained in:
parent
6769e9d3f0
commit
bbe769f1aa
9 changed files with 431 additions and 2428 deletions
101
apps/chat.js
101
apps/chat.js
|
|
@ -77,7 +77,12 @@ import { ClaudeAIClient } from '../utils/claude.ai/index.js'
|
||||||
import { getProxy } from '../utils/proxy.js'
|
import { getProxy } from '../utils/proxy.js'
|
||||||
import { QwenApi } from '../utils/alibaba/qwen-api.js'
|
import { QwenApi } from '../utils/alibaba/qwen-api.js'
|
||||||
import { getChatHistoryGroup } from '../utils/chat.js'
|
import { getChatHistoryGroup } from '../utils/chat.js'
|
||||||
import { GoogleGeminiClient } from '../client/GoogleGeminiClient.js'
|
import { CustomGoogleGeminiClient } from '../client/CustomGoogleGeminiClient.js'
|
||||||
|
|
||||||
|
const roleMap = {
|
||||||
|
owner: 'group owner',
|
||||||
|
admin: 'group administrator'
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await import('@azure/openai')
|
await import('@azure/openai')
|
||||||
|
|
@ -98,7 +103,7 @@ try {
|
||||||
let version = Config.version
|
let version = Config.version
|
||||||
let proxy = getProxy()
|
let proxy = getProxy()
|
||||||
|
|
||||||
const originalValues = ['星火', '通义千问', '克劳德', '克劳德2', '必应', 'api', 'API', 'api3', 'API3', 'glm', '巴德']
|
const originalValues = ['星火', '通义千问', '克劳德', '克劳德2', '必应', 'api', 'API', 'api3', 'API3', 'glm', '巴德']
|
||||||
const correspondingValues = ['xh', 'qwen', 'claude', 'claude2', 'bing', 'api', 'api', 'api3', 'api3', 'chatglm', 'bard']
|
const correspondingValues = ['xh', 'qwen', 'claude', 'claude2', 'bing', 'api', 'api', 'api3', 'api3', 'chatglm', 'bard']
|
||||||
/**
|
/**
|
||||||
* 每个对话保留的时长。单个对话内ai是保留上下文的。超时后销毁对话,再次对话创建新的对话。
|
* 每个对话保留的时长。单个对话内ai是保留上下文的。超时后销毁对话,再次对话创建新的对话。
|
||||||
|
|
@ -1451,6 +1456,7 @@ export class chatgpt extends plugin {
|
||||||
async qwen (e) {
|
async qwen (e) {
|
||||||
return await this.otherMode(e, 'gemini')
|
return await this.otherMode(e, 'gemini')
|
||||||
}
|
}
|
||||||
|
|
||||||
async gemini (e) {
|
async gemini (e) {
|
||||||
return await this.otherMode(e, 'gemini')
|
return await this.otherMode(e, 'gemini')
|
||||||
}
|
}
|
||||||
|
|
@ -2040,12 +2046,92 @@ export class chatgpt extends plugin {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case 'gemini': {
|
case 'gemini': {
|
||||||
let client = new GoogleGeminiClient({
|
let client = new CustomGoogleGeminiClient({
|
||||||
e,
|
e,
|
||||||
userId: e.sender.user_id,
|
userId: e.sender.user_id,
|
||||||
key: Config.geminiKey,
|
key: Config.geminiKey,
|
||||||
model: Config.geminiModel
|
model: Config.geminiModel,
|
||||||
|
baseUrl: Config.geminiBaseUrl,
|
||||||
|
debug: Config.debug
|
||||||
})
|
})
|
||||||
|
if (Config.smartMode) {
|
||||||
|
let tools = [
|
||||||
|
new QueryStarRailTool(),
|
||||||
|
new WebsiteTool(),
|
||||||
|
new SendPictureTool(),
|
||||||
|
new SendVideoTool(),
|
||||||
|
new ImageCaptionTool(),
|
||||||
|
new SearchVideoTool(),
|
||||||
|
new SendAvatarTool(),
|
||||||
|
new SerpImageTool(),
|
||||||
|
new SearchMusicTool(),
|
||||||
|
new SendMusicTool(),
|
||||||
|
new SerpIkechan8370Tool(),
|
||||||
|
new SerpTool(),
|
||||||
|
new SendAudioMessageTool(),
|
||||||
|
new ProcessPictureTool(),
|
||||||
|
new APTool(),
|
||||||
|
new HandleMessageMsgTool(),
|
||||||
|
new SendMessageToSpecificGroupOrUserTool(),
|
||||||
|
new SendDiceTool(),
|
||||||
|
new QueryGenshinTool()
|
||||||
|
]
|
||||||
|
if (Config.amapKey) {
|
||||||
|
tools.push(new WeatherTool())
|
||||||
|
}
|
||||||
|
if (e.isGroup) {
|
||||||
|
tools.push(new QueryUserinfoTool())
|
||||||
|
if (e.member?.is_admin) {
|
||||||
|
tools.push(new EditCardTool())
|
||||||
|
tools.push(new JinyanTool())
|
||||||
|
tools.push(new KickOutTool())
|
||||||
|
}
|
||||||
|
if (e.member.is_owner) {
|
||||||
|
tools.push(new SetTitleTool())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch (Config.serpSource) {
|
||||||
|
case 'ikechan8370': {
|
||||||
|
tools.push(new SerpIkechan8370Tool())
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case 'azure': {
|
||||||
|
if (!Config.azSerpKey) {
|
||||||
|
logger.warn('未配置bing搜索密钥,转为使用ikechan8370搜索源')
|
||||||
|
tools.push(new SerpIkechan8370Tool())
|
||||||
|
} else {
|
||||||
|
tools.push(new SerpTool())
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
tools.push(new SerpIkechan8370Tool())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
client.addTools(tools)
|
||||||
|
}
|
||||||
|
let system = Config.geminiPrompt
|
||||||
|
if (Config.enableGroupContext && e.isGroup) {
|
||||||
|
let chats = await getChatHistoryGroup(e, Config.groupContextLength)
|
||||||
|
const namePlaceholder = '[name]'
|
||||||
|
const defaultBotName = 'GeminiPro'
|
||||||
|
const groupContextTip = Config.groupContextTip
|
||||||
|
let botName = e.isGroup ? (e.group.pickMember(getUin(e)).card || e.group.pickMember(getUin(e)).nickname) : e.bot.nickname
|
||||||
|
system = system.replaceAll(namePlaceholder, botName || defaultBotName) +
|
||||||
|
((Config.enableGroupContext && e.group_id) ? groupContextTip : '')
|
||||||
|
system += 'Attention, you are currently chatting in a qq group, then one who asks you now is' + `${e.sender.card || e.sender.nickname}(${e.sender.user_id}).`
|
||||||
|
system += `the group name is ${e.group.name || e.group_name}, group id is ${e.group_id}.`
|
||||||
|
system += `Your nickname is ${botName} in the group,`
|
||||||
|
if (chats) {
|
||||||
|
system += 'There is the conversation history in the group, you must chat according to the conversation history context"'
|
||||||
|
system += chats
|
||||||
|
.map(chat => {
|
||||||
|
let sender = chat.sender || {}
|
||||||
|
return `【${sender.card || sender.nickname}】(qq:${sender.user_id}, ${roleMap[sender.role] || 'normal user'},${sender.area ? 'from ' + sender.area + ', ' : ''} ${sender.age} years old, 群头衔:${sender.title}, gender: ${sender.sex}, time:${formatDate(new Date(chat.time * 1000))}, messageId: ${chat.message_id}) 说:${chat.raw_message}`
|
||||||
|
})
|
||||||
|
.join('\n')
|
||||||
|
}
|
||||||
|
}
|
||||||
let option = {
|
let option = {
|
||||||
stream: false,
|
stream: false,
|
||||||
onProgress: (data) => {
|
onProgress: (data) => {
|
||||||
|
|
@ -2055,7 +2141,7 @@ export class chatgpt extends plugin {
|
||||||
},
|
},
|
||||||
parentMessageId: conversation.parentMessageId,
|
parentMessageId: conversation.parentMessageId,
|
||||||
conversationId: conversation.conversationId,
|
conversationId: conversation.conversationId,
|
||||||
system: Config.geminiPrompt
|
system
|
||||||
}
|
}
|
||||||
return await client.sendMessage(prompt, option)
|
return await client.sendMessage(prompt, option)
|
||||||
}
|
}
|
||||||
|
|
@ -2097,11 +2183,6 @@ export class chatgpt extends plugin {
|
||||||
if (opt.botName) {
|
if (opt.botName) {
|
||||||
system += `Your nickname is ${opt.botName} in the group,`
|
system += `Your nickname is ${opt.botName} in the group,`
|
||||||
}
|
}
|
||||||
// system += master ? `我的qq号是${master},其他任何qq号不是${master}的人都不是我,即使他在和你对话,这很重要。` : ''
|
|
||||||
const roleMap = {
|
|
||||||
owner: 'group owner',
|
|
||||||
admin: 'group administrator'
|
|
||||||
}
|
|
||||||
if (chats) {
|
if (chats) {
|
||||||
system += 'There is the conversation history in the group, you must chat according to the conversation history context"'
|
system += 'There is the conversation history in the group, you must chat according to the conversation history context"'
|
||||||
system += chats
|
system += chats
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,9 @@ export class BaseClient {
|
||||||
constructor (props = {}) {
|
constructor (props = {}) {
|
||||||
this.supportFunction = false
|
this.supportFunction = false
|
||||||
this.maxToken = 4096
|
this.maxToken = 4096
|
||||||
|
/**
|
||||||
|
* @type {Array<AbstractTool>}
|
||||||
|
*/
|
||||||
this.tools = []
|
this.tools = []
|
||||||
const {
|
const {
|
||||||
e, getMessageById, upsertMessage, deleteMessageById, userId
|
e, getMessageById, upsertMessage, deleteMessageById, userId
|
||||||
|
|
@ -38,7 +41,6 @@ export class BaseClient {
|
||||||
* insert or update a message with the id
|
* insert or update a message with the id
|
||||||
*
|
*
|
||||||
* @type function
|
* @type function
|
||||||
* @param {string} id
|
|
||||||
* @param {object} message
|
* @param {object} message
|
||||||
* @return {Promise<void>}
|
* @return {Promise<void>}
|
||||||
*/
|
*/
|
||||||
|
|
@ -90,14 +92,18 @@ export class BaseClient {
|
||||||
throw new Error('not implemented in abstract client')
|
throw new Error('not implemented in abstract client')
|
||||||
}
|
}
|
||||||
|
|
||||||
addTools (...tools) {
|
/**
|
||||||
|
* 增加tools
|
||||||
|
* @param {[AbstractTool]} tools
|
||||||
|
*/
|
||||||
|
addTools (tools) {
|
||||||
if (!this.isSupportFunction) {
|
if (!this.isSupportFunction) {
|
||||||
throw new Error('function not supported')
|
throw new Error('function not supported')
|
||||||
}
|
}
|
||||||
if (!this.tools) {
|
if (!this.tools) {
|
||||||
this.tools = []
|
this.tools = []
|
||||||
}
|
}
|
||||||
this.tools.push(tools)
|
this.tools.push(...tools)
|
||||||
}
|
}
|
||||||
|
|
||||||
getTools () {
|
getTools () {
|
||||||
|
|
|
||||||
251
client/CustomGoogleGeminiClient.js
Normal file
251
client/CustomGoogleGeminiClient.js
Normal file
|
|
@ -0,0 +1,251 @@
|
||||||
|
import crypto from 'crypto'
|
||||||
|
import { GoogleGeminiClient } from './GoogleGeminiClient.js'
|
||||||
|
import { newFetch } from '../utils/proxy.js'
|
||||||
|
import _ from 'lodash'
|
||||||
|
|
||||||
|
const BASEURL = 'https://generativelanguage.googleapis.com'
|
||||||
|
|
||||||
|
export const HarmCategory = {
|
||||||
|
HARM_CATEGORY_UNSPECIFIED: 'HARM_CATEGORY_UNSPECIFIED',
|
||||||
|
HARM_CATEGORY_HATE_SPEECH: 'HARM_CATEGORY_HATE_SPEECH',
|
||||||
|
HARM_CATEGORY_SEXUALLY_EXPLICIT: 'HARM_CATEGORY_SEXUALLY_EXPLICIT',
|
||||||
|
HARM_CATEGORY_HARASSMENT: 'HARM_CATEGORY_HARASSMENT',
|
||||||
|
HARM_CATEGORY_DANGEROUS_CONTENT: 'HARM_CATEGORY_DANGEROUS_CONTENT'
|
||||||
|
}
|
||||||
|
|
||||||
|
export const HarmBlockThreshold = {
|
||||||
|
HARM_BLOCK_THRESHOLD_UNSPECIFIED: 'HARM_BLOCK_THRESHOLD_UNSPECIFIED',
|
||||||
|
BLOCK_LOW_AND_ABOVE: 'BLOCK_LOW_AND_ABOVE',
|
||||||
|
BLOCK_MEDIUM_AND_ABOVE: 'BLOCK_MEDIUM_AND_ABOVE',
|
||||||
|
BLOCK_ONLY_HIGH: 'BLOCK_ONLY_HIGH',
|
||||||
|
BLOCK_NONE: 'BLOCK_NONE'
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {{
|
||||||
|
* role: string,
|
||||||
|
* parts: Array<{
|
||||||
|
* text?: string,
|
||||||
|
* functionCall?: FunctionCall,
|
||||||
|
* functionResponse?: FunctionResponse
|
||||||
|
* }>
|
||||||
|
* }} Content
|
||||||
|
*
|
||||||
|
* Gemini消息的基本格式
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {{
|
||||||
|
* name: string,
|
||||||
|
* args: {}
|
||||||
|
* }} FunctionCall
|
||||||
|
*
|
||||||
|
* Gemini的FunctionCall
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {{
|
||||||
|
* name: string,
|
||||||
|
* response: {
|
||||||
|
* name: string,
|
||||||
|
* content: {}
|
||||||
|
* }
|
||||||
|
* }} FunctionResponse
|
||||||
|
*
|
||||||
|
* Gemini的Function执行结果包裹
|
||||||
|
* 其中response可以为任意,本项目根据官方示例封装为name和content两个字段
|
||||||
|
*/
|
||||||
|
|
||||||
|
export class CustomGoogleGeminiClient extends GoogleGeminiClient {
|
||||||
|
constructor (props) {
|
||||||
|
super(props)
|
||||||
|
this.model = props.model
|
||||||
|
this.baseUrl = props.baseUrl || BASEURL
|
||||||
|
this.supportFunction = true
|
||||||
|
this.debug = props.debug
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param text
|
||||||
|
* @param {{conversationId: string?, parentMessageId: string?, stream: boolean?, onProgress: function?, functionResponse: FunctionResponse?, system: string?}} opt
|
||||||
|
* @returns {Promise<{conversationId: string?, parentMessageId: string, text: string, id: string}>}
|
||||||
|
*/
|
||||||
|
async sendMessage (text, opt) {
|
||||||
|
let history = await this.getHistory(opt.parentMessageId)
|
||||||
|
let systemMessage = opt.system
|
||||||
|
if (systemMessage) {
|
||||||
|
history = history.reverse()
|
||||||
|
history.push({
|
||||||
|
role: 'model',
|
||||||
|
parts: [
|
||||||
|
{
|
||||||
|
text: 'ok'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
history.push({
|
||||||
|
role: 'user',
|
||||||
|
parts: [
|
||||||
|
{
|
||||||
|
text: systemMessage
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
history = history.reverse()
|
||||||
|
}
|
||||||
|
const idThis = crypto.randomUUID()
|
||||||
|
const idModel = crypto.randomUUID()
|
||||||
|
const thisMessage = opt.functionResponse
|
||||||
|
? {
|
||||||
|
role: 'function',
|
||||||
|
parts: [{
|
||||||
|
functionResponse: opt.functionResponse
|
||||||
|
}],
|
||||||
|
id: idThis,
|
||||||
|
parentMessageId: opt.parentMessageId || undefined
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
role: 'user',
|
||||||
|
parts: [{ text }],
|
||||||
|
id: idThis,
|
||||||
|
parentMessageId: opt.parentMessageId || undefined
|
||||||
|
}
|
||||||
|
history.push(_.cloneDeep(thisMessage))
|
||||||
|
let url = `${this.baseUrl}/v1beta/models/gemini-pro:generateContent?key=${this._key}`
|
||||||
|
let body = {
|
||||||
|
// 不去兼容官方的简单格式了,直接用,免得function还要转换
|
||||||
|
/**
|
||||||
|
* @type Array<Content>
|
||||||
|
*/
|
||||||
|
contents: history,
|
||||||
|
safetySettings: [
|
||||||
|
{
|
||||||
|
category: HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT,
|
||||||
|
threshold: HarmBlockThreshold.BLOCK_NONE
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: HarmCategory.HARM_CATEGORY_HARASSMENT,
|
||||||
|
threshold: HarmBlockThreshold.BLOCK_NONE
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT,
|
||||||
|
threshold: HarmBlockThreshold.BLOCK_NONE
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: HarmCategory.HARM_CATEGORY_HATE_SPEECH,
|
||||||
|
threshold: HarmBlockThreshold.BLOCK_NONE
|
||||||
|
}
|
||||||
|
],
|
||||||
|
generationConfig: {
|
||||||
|
maxOutputTokens: 1000,
|
||||||
|
temperature: 0.9,
|
||||||
|
topP: 0.95,
|
||||||
|
topK: 16
|
||||||
|
},
|
||||||
|
tools: [
|
||||||
|
{
|
||||||
|
functionDeclarations: this.tools.map(tool => tool.function())
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
body.contents.forEach(content => {
|
||||||
|
delete content.id
|
||||||
|
delete content.parentMessageId
|
||||||
|
delete content.conversationId
|
||||||
|
})
|
||||||
|
let result = await newFetch(url, {
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify(body)
|
||||||
|
})
|
||||||
|
if (result.status !== 200) {
|
||||||
|
throw new Error(await result.text())
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @type {Content | undefined}
|
||||||
|
*/
|
||||||
|
let responseContent
|
||||||
|
/**
|
||||||
|
* @type {{candidates: Array<{content: Content}>}}
|
||||||
|
*/
|
||||||
|
let response = await result.json()
|
||||||
|
if (this.debug) {
|
||||||
|
console.log(JSON.stringify(response))
|
||||||
|
}
|
||||||
|
responseContent = response.candidates[0].content
|
||||||
|
if (responseContent.parts[0].functionCall) {
|
||||||
|
// functionCall
|
||||||
|
const functionCall = responseContent.parts[0].functionCall
|
||||||
|
// Gemini有时候只回复一个空的functionCall,无语死了
|
||||||
|
if (functionCall.name) {
|
||||||
|
logger.info(JSON.stringify(functionCall))
|
||||||
|
const funcName = functionCall.name
|
||||||
|
let chosenTool = this.tools.find(t => t.name === funcName)
|
||||||
|
/**
|
||||||
|
* @type {FunctionResponse}
|
||||||
|
*/
|
||||||
|
let functionResponse = {
|
||||||
|
name: funcName,
|
||||||
|
response: {
|
||||||
|
name: funcName,
|
||||||
|
content: null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!chosenTool) {
|
||||||
|
// 根本没有这个工具!
|
||||||
|
functionResponse.response.content = {
|
||||||
|
error: `Function ${funcName} doesn't exist`
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// execute function
|
||||||
|
try {
|
||||||
|
functionResponse.response.content = await chosenTool.func(functionCall.args, this.e)
|
||||||
|
if (this.debug) {
|
||||||
|
logger.info(JSON.stringify(functionResponse.response.content))
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
logger.error(err)
|
||||||
|
functionResponse.response.content = {
|
||||||
|
error: `Function execute error: ${err.message}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let responseOpt = _.cloneDeep(opt)
|
||||||
|
responseOpt.parentMessageId = idModel
|
||||||
|
responseOpt.functionResponse = functionResponse
|
||||||
|
// 递归直到返回text
|
||||||
|
// 先把这轮的消息存下来
|
||||||
|
await this.upsertMessage(thisMessage)
|
||||||
|
const respMessage = Object.assign(responseContent, {
|
||||||
|
id: idModel,
|
||||||
|
parentMessageId: idThis
|
||||||
|
})
|
||||||
|
await this.upsertMessage(respMessage)
|
||||||
|
return await this.sendMessage('', responseOpt)
|
||||||
|
} else {
|
||||||
|
// 谷歌抽风了,瞎调函数,不保存这轮,直接返回
|
||||||
|
return {
|
||||||
|
text: '',
|
||||||
|
conversationId: '',
|
||||||
|
parentMessageId: opt.parentMessageId,
|
||||||
|
id: '',
|
||||||
|
error: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (responseContent) {
|
||||||
|
await this.upsertMessage(thisMessage)
|
||||||
|
const respMessage = Object.assign(responseContent, {
|
||||||
|
id: idModel,
|
||||||
|
parentMessageId: idThis
|
||||||
|
})
|
||||||
|
await this.upsertMessage(respMessage)
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
text: responseContent.parts[0].text,
|
||||||
|
conversationId: '',
|
||||||
|
parentMessageId: idThis,
|
||||||
|
id: idModel
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
10
client/GoogleGeminiClientTest.js
Normal file
10
client/GoogleGeminiClientTest.js
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
import { GoogleGeminiClient } from './GoogleGeminiClient.js'
|
||||||
|
|
||||||
|
async function test () {
|
||||||
|
const client = new GoogleGeminiClient({
|
||||||
|
e: {},
|
||||||
|
userId: 'test',
|
||||||
|
key: 'AIzaSyBZEC3SLp0CVDnNY8WoRT7hn0LB8zn8dFA',
|
||||||
|
model: 'gemini-pro'
|
||||||
|
})
|
||||||
|
}
|
||||||
1483
package-lock.json
generated
1483
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -165,6 +165,8 @@ const defaultConfig = {
|
||||||
geminiKey: '',
|
geminiKey: '',
|
||||||
geminiModel: 'gemini-pro',
|
geminiModel: 'gemini-pro',
|
||||||
geminiPrompt: 'You are Gemini. Your answer shouldn\'t be too verbose. Prefer to answer in Chinese.',
|
geminiPrompt: 'You are Gemini. Your answer shouldn\'t be too verbose. Prefer to answer in Chinese.',
|
||||||
|
// origin: https://generativelanguage.googleapis.com
|
||||||
|
geminiBaseUrl: 'https://gemini.ikechan8370.com',
|
||||||
version: 'v2.7.8'
|
version: 'v2.7.8'
|
||||||
}
|
}
|
||||||
const _path = process.cwd()
|
const _path = process.cwd()
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
// workaround for ver 7.x and ver 5.x
|
// workaround for ver 7.x and ver 5.x
|
||||||
import HttpsProxyAgent from 'https-proxy-agent'
|
import HttpsProxyAgent from 'https-proxy-agent'
|
||||||
|
import { Config } from './config.js'
|
||||||
|
import fetch from 'node-fetch'
|
||||||
|
|
||||||
let proxy = HttpsProxyAgent
|
let proxy = HttpsProxyAgent
|
||||||
if (typeof proxy !== 'function') {
|
if (typeof proxy !== 'function') {
|
||||||
|
|
@ -15,3 +17,17 @@ if (typeof proxy !== 'function') {
|
||||||
export function getProxy () {
|
export function getProxy () {
|
||||||
return proxy
|
return proxy
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const newFetch = (url, options = {}) => {
|
||||||
|
const defaultOptions = Config.proxy
|
||||||
|
? {
|
||||||
|
agent: proxy(Config.proxy)
|
||||||
|
}
|
||||||
|
: {}
|
||||||
|
const mergedOptions = {
|
||||||
|
...defaultOptions,
|
||||||
|
...options
|
||||||
|
}
|
||||||
|
|
||||||
|
return fetch(url, mergedOptions)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ export class SerpIkechan8370Tool extends AbstractTool {
|
||||||
|
|
||||||
func = async function (opts) {
|
func = async function (opts) {
|
||||||
let { q, source } = opts
|
let { q, source } = opts
|
||||||
if (!source) {
|
if (!source || !['google', 'bing', 'baidu'].includes(source)) {
|
||||||
source = 'bing'
|
source = 'bing'
|
||||||
}
|
}
|
||||||
let serpRes = await fetch(`https://serp.ikechan8370.com/${source}?q=${encodeURIComponent(q)}&lang=zh-CN&limit=5`, {
|
let serpRes = await fetch(`https://serp.ikechan8370.com/${source}?q=${encodeURIComponent(q)}&lang=zh-CN&limit=5`, {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue