feat: add function call model type

This commit is contained in:
kangfenmao 2025-03-11 19:42:46 +08:00
parent 85160c2d29
commit 74567d5e17
14 changed files with 41 additions and 60 deletions

View File

@ -69,7 +69,7 @@ export default defineConfig({
} }
}, },
optimizeDeps: { optimizeDeps: {
exclude: ['chunk-PZ64DZKH.js', 'chunk-JMKENWIY.js', 'chunk-UXYB6GHG.js'] exclude: ['chunk-PZ64DZKH.js', 'chunk-JMKENWIY.js', 'chunk-UXYB6GHG.js', 'chunk-ALDIEZMG.js']
} }
} }
}) })

View File

@ -28,7 +28,6 @@ export default class MCPService extends EventEmitter {
constructor() { constructor() {
super() super()
this.createServerLoadingPromise() this.createServerLoadingPromise()
this.requestServers()
} }
/** /**
@ -40,19 +39,6 @@ export default class MCPService extends EventEmitter {
}) })
} }
/**
* Request server data from renderer process Redux
*/
public requestServers(): void {
const mainWindow = windowService.getMainWindow()
if (mainWindow) {
log.info('[MCP] Requesting servers from Redux')
mainWindow.webContents.send('mcp:request-servers')
} else {
log.warn('[MCP] Main window not available, cannot request servers')
}
}
/** /**
* Set servers received from Redux and trigger initialization if needed * Set servers received from Redux and trigger initialization if needed
*/ */

View File

@ -9,7 +9,7 @@ const ToolsCallingIcon: FC<React.DetailedHTMLProps<React.HTMLAttributes<HTMLElem
return ( return (
<Container> <Container>
<Tooltip title={t('models.tool_calling')} placement="top"> <Tooltip title={t('models.function_calling')} placement="top">
<Icon {...(props as any)} /> <Icon {...(props as any)} />
</Tooltip> </Tooltip>
</Container> </Container>

View File

@ -1,7 +1,7 @@
import { import {
isEmbeddingModel, isEmbeddingModel,
isFunctionCallingModel,
isReasoningModel, isReasoningModel,
isToolCallingModel,
isVisionModel, isVisionModel,
isWebSearchModel isWebSearchModel
} from '@renderer/config/models' } from '@renderer/config/models'
@ -31,7 +31,7 @@ const ModelTags: FC<ModelTagsProps> = ({ model, showFree = true, showReasoning =
{isVisionModel(model) && <VisionIcon />} {isVisionModel(model) && <VisionIcon />}
{isWebSearchModel(model) && <WebSearchIcon />} {isWebSearchModel(model) && <WebSearchIcon />}
{showReasoning && isReasoningModel(model) && <ReasoningIcon />} {showReasoning && isReasoningModel(model) && <ReasoningIcon />}
{showToolsCalling && isToolCallingModel(model) && <ToolsCallingIcon />} {showToolsCalling && isFunctionCallingModel(model) && <ToolsCallingIcon />}
{isEmbeddingModel(model) && <Tag color="orange">{t('models.embedding')}</Tag>} {isEmbeddingModel(model) && <Tag color="orange">{t('models.embedding')}</Tag>}
{showFree && isFreeModel(model) && <Tag color="green">{t('models.free')}</Tag>} {showFree && isFreeModel(model) && <Tag color="green">{t('models.free')}</Tag>}
</Container> </Container>

View File

@ -178,14 +178,18 @@ export const EMBEDDING_REGEX = /(?:^text-|embed|bge-|e5-|LLM2Vec|retrieval|uae-|
export const NOT_SUPPORTED_REGEX = /(?:^tts|rerank|whisper|speech)/i export const NOT_SUPPORTED_REGEX = /(?:^tts|rerank|whisper|speech)/i
// Tool calling models // Tool calling models
export const TOOL_CALLING_MODELS = ['gpt-4o', 'gpt-4o-mini', 'gpt-4', 'gpt-4.5', 'claude', 'qwen'] export const FUNCTION_CALLING_MODELS = ['gpt-4o', 'gpt-4o-mini', 'gpt-4', 'gpt-4.5', 'claude', 'qwen']
export const TOOL_CALLING_REGEX = new RegExp(`\\b(?:${TOOL_CALLING_MODELS.join('|')})\\b`, 'i') export const FUNCTION_CALLING_REGEX = new RegExp(`\\b(?:${FUNCTION_CALLING_MODELS.join('|')})\\b`, 'i')
export function isToolCallingModel(model: Model): boolean { export function isFunctionCallingModel(model: Model): boolean {
if (model.type?.includes('function_calling')) {
return true
}
if (['gemini', 'deepseek', 'anthropic'].includes(model.provider)) { if (['gemini', 'deepseek', 'anthropic'].includes(model.provider)) {
return true return true
} }
return TOOL_CALLING_REGEX.test(model.id) return FUNCTION_CALLING_REGEX.test(model.id)
} }
export function getModelLogo(modelId: string) { export function getModelLogo(modelId: string) {
@ -1741,21 +1745,7 @@ export const SYSTEM_MODELS: Record<string, Model[]> = {
group: 'Jina' group: 'Jina'
} }
], ],
//加前缀是为了展示图标 xirang: [],
xirang: [
{
id: 'xirang-4bd107bff85941239e27b1509eccfe98',
provider: 'xirang',
name: 'DeepSeek-R1',
group: 'xirang'
},
{
id: 'xirang-9dc913a037774fc0b248376905c85da5',
provider: 'xirang',
name: 'DeepSeek-V3',
group: 'xirang'
}
],
'tencent-cloud-ti': [ 'tencent-cloud-ti': [
{ {
id: 'deepseek-r1', id: 'deepseek-r1',

View File

@ -5,12 +5,6 @@ import { useEffect } from 'react'
const ipcRenderer = window.electron.ipcRenderer const ipcRenderer = window.electron.ipcRenderer
// Set up IPC listener for main process requests
ipcRenderer.on('mcp:request-servers', () => {
const servers = store.getState().mcp.servers
ipcRenderer.send('mcp:servers-from-renderer', servers)
})
// Listen for server changes from main process // Listen for server changes from main process
ipcRenderer.on('mcp:servers-changed', (_event, servers) => { ipcRenderer.on('mcp:servers-changed', (_event, servers) => {
store.dispatch(setMCPServers(servers)) store.dispatch(setMCPServers(servers))

View File

@ -505,13 +505,14 @@
"reasoning": "Reasoning", "reasoning": "Reasoning",
"search": "Search models...", "search": "Search models...",
"stream_output": "Stream output", "stream_output": "Stream output",
"tool_calling": "Tool Calling", "function_calling": "Function Calling",
"type": { "type": {
"embedding": "Embedding", "embedding": "Embedding",
"reasoning": "Reasoning", "reasoning": "Reasoning",
"select": "Select Model Types", "select": "Select Model Types",
"text": "Text", "text": "Text",
"vision": "Vision" "vision": "Vision",
"function_calling": "Function Calling"
}, },
"vision": "Vision", "vision": "Vision",
"websearch": "WebSearch" "websearch": "WebSearch"

View File

@ -505,13 +505,14 @@
"reasoning": "推論", "reasoning": "推論",
"search": "モデルを検索...", "search": "モデルを検索...",
"stream_output": "ストリーム出力", "stream_output": "ストリーム出力",
"tool_calling": "ツールコール", "function_calling": "関数呼び出し",
"type": { "type": {
"embedding": "埋め込み", "embedding": "埋め込み",
"reasoning": "推論", "reasoning": "推論",
"select": "モデルタイプを選択", "select": "モデルタイプを選択",
"text": "テキスト", "text": "テキスト",
"vision": "画像" "vision": "画像",
"function_calling": "関数呼び出し"
}, },
"vision": "画像", "vision": "画像",
"websearch": "ウェブ検索" "websearch": "ウェブ検索"

View File

@ -505,13 +505,14 @@
"reasoning": "Рассуждение", "reasoning": "Рассуждение",
"search": "Поиск моделей...", "search": "Поиск моделей...",
"stream_output": "Потоковый вывод", "stream_output": "Потоковый вывод",
"tool_calling": "Инструмент вызова", "function_calling": "Вызов функции",
"type": { "type": {
"embedding": "Встраиваемые", "embedding": "Встраиваемые",
"reasoning": "Рассуждение", "reasoning": "Рассуждение",
"select": "Выберите тип модели", "select": "Выберите тип модели",
"text": "Текст", "text": "Текст",
"vision": "Изображение" "vision": "Изображение",
"function_calling": "Вызов функции"
}, },
"vision": "Визуальные", "vision": "Визуальные",
"websearch": "Веб-поисковые" "websearch": "Веб-поисковые"

View File

@ -505,13 +505,14 @@
"reasoning": "推理", "reasoning": "推理",
"search": "搜索模型...", "search": "搜索模型...",
"stream_output": "流式输出", "stream_output": "流式输出",
"tool_calling": "工具调用", "function_calling": "函数调用",
"type": { "type": {
"embedding": "嵌入", "embedding": "嵌入",
"reasoning": "推理", "reasoning": "推理",
"select": "选择模型类型", "select": "选择模型类型",
"text": "文本", "text": "文本",
"vision": "图像" "vision": "图像",
"function_calling": "函数调用"
}, },
"vision": "视觉", "vision": "视觉",
"websearch": "联网" "websearch": "联网"

View File

@ -505,13 +505,14 @@
"reasoning": "推理", "reasoning": "推理",
"search": "搜尋模型...", "search": "搜尋模型...",
"stream_output": "串流輸出", "stream_output": "串流輸出",
"tool_calling": "工具調用", "function_calling": "函數調用",
"type": { "type": {
"embedding": "嵌入", "embedding": "嵌入",
"reasoning": "推理", "reasoning": "推理",
"select": "選擇模型類型", "select": "選擇模型類型",
"text": "文字", "text": "文字",
"vision": "影像" "vision": "影像",
"function_calling": "函數調用"
}, },
"vision": "視覺", "vision": "視覺",
"websearch": "網路搜尋" "websearch": "網路搜尋"

View File

@ -8,7 +8,7 @@ import { useKnowledgeFiles } from '@renderer/hooks/useKnowledgeFiles'
import { reset } from '@renderer/services/BackupService' import { reset } from '@renderer/services/BackupService'
import { AppInfo } from '@renderer/types' import { AppInfo } from '@renderer/types'
import { formatFileSize } from '@renderer/utils' import { formatFileSize } from '@renderer/utils'
import { Button, Modal, Typography } from 'antd' import { Button, Typography } from 'antd'
import { FC, useEffect, useState } from 'react' import { FC, useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import styled from 'styled-components' import styled from 'styled-components'
@ -49,7 +49,7 @@ const DataSettings: FC = () => {
} }
const handleClearCache = () => { const handleClearCache = () => {
Modal.confirm({ window.modal.confirm({
title: t('settings.data.clear_cache.title'), title: t('settings.data.clear_cache.title'),
content: t('settings.data.clear_cache.confirm'), content: t('settings.data.clear_cache.confirm'),
okText: t('settings.data.clear_cache.button'), okText: t('settings.data.clear_cache.button'),
@ -69,7 +69,7 @@ const DataSettings: FC = () => {
} }
const handleRemoveAllFiles = () => { const handleRemoveAllFiles = () => {
Modal.confirm({ window.modal.confirm({
centered: true, centered: true,
title: t('settings.data.app_knowledge.remove_all') + ` (${formatFileSize(size)}) `, title: t('settings.data.app_knowledge.remove_all') + ` (${formatFileSize(size)}) `,
content: t('settings.data.app_knowledge.remove_all_confirm'), content: t('settings.data.app_knowledge.remove_all_confirm'),

View File

@ -1,5 +1,5 @@
import { DownOutlined, UpOutlined } from '@ant-design/icons' import { DownOutlined, UpOutlined } from '@ant-design/icons'
import { isEmbeddingModel, isReasoningModel, isVisionModel } from '@renderer/config/models' import { isEmbeddingModel, isFunctionCallingModel, isReasoningModel, isVisionModel } from '@renderer/config/models'
import { Model, ModelType } from '@renderer/types' import { Model, ModelType } from '@renderer/types'
import { getDefaultGroupName } from '@renderer/utils' import { getDefaultGroupName } from '@renderer/utils'
import { Button, Checkbox, Divider, Flex, Form, Input, Modal } from 'antd' import { Button, Checkbox, Divider, Flex, Form, Input, Modal } from 'antd'
@ -112,14 +112,15 @@ const ModelEditContent: FC<ModelEditContentProps> = ({ model, onUpdateModel, ope
const defaultTypes = [ const defaultTypes = [
...(isVisionModel(model) ? ['vision'] : []), ...(isVisionModel(model) ? ['vision'] : []),
...(isEmbeddingModel(model) ? ['embedding'] : []), ...(isEmbeddingModel(model) ? ['embedding'] : []),
...(isReasoningModel(model) ? ['reasoning'] : []) ...(isReasoningModel(model) ? ['reasoning'] : []),
...(isFunctionCallingModel(model) ? ['tools'] : [])
] as ModelType[] ] as ModelType[]
// 合并现有选择和默认类型 // 合并现有选择和默认类型
const selectedTypes = [...new Set([...(model.type || []), ...defaultTypes])] const selectedTypes = [...new Set([...(model.type || []), ...defaultTypes])]
const showTypeConfirmModal = (type: string) => { const showTypeConfirmModal = (type: string) => {
Modal.confirm({ window.modal.confirm({
title: t('settings.moresetting.warn'), title: t('settings.moresetting.warn'),
content: t('settings.moresetting.check.warn'), content: t('settings.moresetting.check.warn'),
okText: t('settings.moresetting.check.confirm'), okText: t('settings.moresetting.check.confirm'),
@ -161,6 +162,11 @@ const ModelEditContent: FC<ModelEditContentProps> = ({ model, onUpdateModel, ope
label: t('models.type.reasoning'), label: t('models.type.reasoning'),
value: 'reasoning', value: 'reasoning',
disabled: isReasoningModel(model) && !selectedTypes.includes('reasoning') disabled: isReasoningModel(model) && !selectedTypes.includes('reasoning')
},
{
label: t('models.type.function_calling'),
value: 'function_calling',
disabled: isFunctionCallingModel(model) && !selectedTypes.includes('function_calling')
} }
]} ]}
/> />

View File

@ -119,7 +119,7 @@ export type Provider = {
export type ProviderType = 'openai' | 'anthropic' | 'gemini' | 'qwenlm' | 'azure-openai' export type ProviderType = 'openai' | 'anthropic' | 'gemini' | 'qwenlm' | 'azure-openai'
export type ModelType = 'text' | 'vision' | 'embedding' | 'reasoning' export type ModelType = 'text' | 'vision' | 'embedding' | 'reasoning' | 'function_calling'
export type Model = { export type Model = {
id: string id: string