Compare commits

...

1 Commits

Author SHA1 Message Date
kangfenmao
ebf61b1ce9 feat: plugins 2024-12-30 23:45:47 +08:00
8 changed files with 87 additions and 10 deletions

View File

@@ -95,7 +95,7 @@
"@types/tinycolor2": "^1",
"@vitejs/plugin-react": "^4.2.1",
"antd": "^5.22.5",
"axios": "^1.7.3",
"axios": "^1.7.9",
"browser-image-compression": "^2.0.2",
"dayjs": "^1.11.11",
"dexie": "^4.0.8",

View File

@@ -1,7 +1,9 @@
import fs from 'node:fs'
import path from 'node:path'
import vm from 'node:vm'
import { Shortcut, ThemeMode } from '@types'
import axios from 'axios'
import { BrowserWindow, ipcMain, ProxyConfig, session, shell } from 'electron'
import log from 'electron-log'
@@ -154,4 +156,10 @@ export function registerIpc(mainWindow: BrowserWindow, app: Electron.App) {
ipcMain.handle('knowledge-base:add', KnowledgeService.add)
ipcMain.handle('knowledge-base:remove', KnowledgeService.remove)
ipcMain.handle('knowledge-base:search', KnowledgeService.search)
// vm
ipcMain.handle('run-js', (_, code: string) => {
const context = vm.createContext(Object.assign({ fetch: fetch, URL: URL, axios: axios }, global))
return vm.runInContext(code, context)
})
}

View File

@@ -76,6 +76,9 @@ declare global {
remove: ({ uniqueId, base }: { uniqueId: string; base: KnowledgeBaseParams }) => Promise<void>
search: ({ search, base }: { search: string; base: KnowledgeBaseParams }) => Promise<ExtractChunkData[]>
}
vm: {
run: (code: string) => Promise<any>
}
}
}
}

View File

@@ -70,6 +70,9 @@ const api = {
ipcRenderer.invoke('knowledge-base:remove', { uniqueId, base }),
search: ({ search, base }: { search: string; base: KnowledgeBaseParams }) =>
ipcRenderer.invoke('knowledge-base:search', { search, base })
},
vm: {
run: (code: string) => ipcRenderer.invoke('run-js', code)
}
}

View File

@@ -4,6 +4,8 @@ import i18n from '@renderer/i18n'
import { getAssistantSettings, getDefaultModel, getTopNamingModel } from '@renderer/services/AssistantService'
import { EVENT_NAMES } from '@renderer/services/EventService'
import { filterContextMessages } from '@renderer/services/MessagesService'
import DuckDuckGoLiteSearch from '@renderer/tools/DuckDuckGoLiteSearch/function.json'
import DuckDuckGoLiteSearchCode from '@renderer/tools/DuckDuckGoLiteSearch/index.js?raw'
import { Assistant, FileTypes, Message, Model, Provider, Suggestion } from '@renderer/types'
import { removeQuotes } from '@renderer/utils'
import { last, takeRight } from 'lodash'
@@ -11,7 +13,8 @@ import OpenAI, { AzureOpenAI } from 'openai'
import {
ChatCompletionContentPart,
ChatCompletionCreateParamsNonStreaming,
ChatCompletionMessageParam
ChatCompletionMessageParam,
ChatCompletionTool
} from 'openai/resources'
import { CompletionsParams } from '.'
@@ -133,7 +136,6 @@ export default class OpenAIProvider extends BaseProvider {
}
const isOpenAIo1 = model.id.includes('o1-')
const isSupportStreamOutput = streamOutput
let time_first_token_millsec = 0
const start_time_millsec = new Date().getTime()
@@ -148,12 +150,28 @@ export default class OpenAIProvider extends BaseProvider {
top_p: assistant?.settings?.topP,
max_tokens: maxTokens,
keep_alive: this.keepAliveTime,
stream: isSupportStreamOutput,
stream: streamOutput,
tools: [DuckDuckGoLiteSearch as ChatCompletionTool],
...this.getCustomParameters(assistant)
})
if (!isSupportStreamOutput) {
if (!streamOutput) {
const time_completion_millsec = new Date().getTime() - start_time_millsec
stream.choices[0].message?.tool_calls?.forEach(async (toolCall) => {
const functionName = toolCall.function.name
const params = toolCall.function.arguments
console.log(functionName, DuckDuckGoLiteSearchCode)
const result = await window.api.vm.run(`
var params = ${params};
${DuckDuckGoLiteSearchCode}
`)
console.log(result)
})
return onChunk({
text: stream.choices[0].message?.content || '',
usage: stream.usage,

View File

@@ -0,0 +1,22 @@
{
"type": "function",
"function": {
"name": "DuckDuckGoLiteSearch",
"description": "A search engine useful for answering questions about current events.",
"parameters": {
"type": "object",
"properties": {
"q": {
"type": "string",
"description": "Keywords for query"
},
"kl": {
"type": "string",
"description": "Language/region code (e.g., wt-wt, us-en, uk-en)",
"default": "wt-wt"
}
},
"required": ["q"]
}
}
}

View File

@@ -0,0 +1,23 @@
new Promise((resolve, reject) => {
async function makeRequest() {
try {
const response = await axios.request({
method: 'post',
maxBodyLength: Infinity,
url: 'https://google.serper.dev/search',
headers: {
'X-API-KEY': 'fa70255d0ab3402ee2ddb6455f6b317e73588fc7',
'Content-Type': 'application/json'
},
data: params
})
console.log(JSON.stringify(response.data))
resolve(response.data)
} catch (error) {
console.log(error)
reject(error.toString())
}
}
makeRequest()
})

View File

@@ -2867,7 +2867,7 @@ __metadata:
adm-zip: "npm:^0.5.16"
antd: "npm:^5.22.5"
apache-arrow: "npm:^18.1.0"
axios: "npm:^1.7.3"
axios: "npm:^1.7.9"
browser-image-compression: "npm:^2.0.2"
dayjs: "npm:^1.11.11"
dexie: "npm:^4.0.8"
@@ -3506,14 +3506,14 @@ __metadata:
languageName: node
linkType: hard
"axios@npm:^1.7.3":
version: 1.7.7
resolution: "axios@npm:1.7.7"
"axios@npm:^1.7.9":
version: 1.7.9
resolution: "axios@npm:1.7.9"
dependencies:
follow-redirects: "npm:^1.15.6"
form-data: "npm:^4.0.0"
proxy-from-env: "npm:^1.1.0"
checksum: 10c0/4499efc89e86b0b49ffddc018798de05fab26e3bf57913818266be73279a6418c3ce8f9e934c7d2d707ab8c095e837fc6c90608fb7715b94d357720b5f568af7
checksum: 10c0/b7a41e24b59fee5f0f26c1fc844b45b17442832eb3a0fb42dd4f1430eb4abc571fe168e67913e8a1d91c993232bd1d1ab03e20e4d1fee8c6147649b576fc1b0b
languageName: node
linkType: hard