Compare commits

..

21 Commits

Author SHA1 Message Date
kangfenmao
ebf61b1ce9 feat: plugins 2024-12-30 23:45:47 +08:00
kangfenmao
1a68587684 fix: Microsoft Visual C++ Redistributable #577 2024-12-30 15:07:31 +08:00
kangfenmao
47c455b125 feat: 增加保持并发送的功能 #527 2024-12-30 14:09:59 +08:00
kangfenmao
96124cf58e feat: 增加genspark小程序 #578 2024-12-30 13:10:27 +08:00
juzeon
ef975add01 fix: 修复zh-tw语言文件中的乱码 (#579) 2024-12-30 11:49:40 +08:00
n2yt584v2t4nh7y
ed49066bab feat: 添加自定义API参数功能 (#564)
* add custom api parameters

* allow more data types for custom api parameters

* pass parameter to api payload

* add custom parameter settings to sidebar

* remove unnecessary object and array types

* extract API custom parameter method to BaseProvider

* add i18n for custom parameter settings

---------

Co-authored-by: 亢奋猫 <kangfenmao@qq.com>
2024-12-29 20:19:07 +08:00
kangfenmao
e7545c5a94 feat: 用户自定义话题总结Prompt #562
close #562
2024-12-29 10:20:45 +08:00
kangfenmao
fc35df65b8 feat: add release notes pages 2024-12-29 09:49:22 +08:00
littel_penguin66
56ca81d245 Fix incorrect synchronization behavior of webdav auto sync (#568) 2024-12-29 08:44:21 +08:00
kangfenmao
6bc1f4b640 chore(version): 0.9.2 2024-12-27 23:03:17 +08:00
kangfenmao
ccb216e76a fix: 模型名后面标注一下服务商 #557 2024-12-27 18:09:22 +08:00
kangfenmao
60931b85ff fix: model settings params step size 2024-12-27 16:47:44 +08:00
kangfenmao
dc1dbc7bb6 feat: add jina provider 2024-12-27 16:29:17 +08:00
kangfenmao
5d2efbd62b fix: 需要只发送图片功能 #538 2024-12-27 14:40:44 +08:00
sommermorgentraum
5337017648 feat: Add capabilities for user to load custom CSS #548 2024-12-27 14:11:12 +08:00
kangfenmao
c409256ae9 fix: azure openai embedding 2024-12-27 14:02:53 +08:00
kangfenmao
4ac608052c chore: update dependencies and improve project structure 2024-12-27 12:42:17 +08:00
kangfenmao
5e6aaabb23 fix: 小程序中增加 github copilot #547 2024-12-27 12:10:41 +08:00
kangfenmao
8812daeeee fix: 某些输出包含 sub 无法正常显示 #545 2024-12-27 11:54:11 +08:00
kangfenmao
13e3a8478c feat: added topic message update and search state management 2024-12-27 11:48:12 +08:00
kangfenmao
8687985ccb feat: add windows platform support for node file detection and npm package download 2024-12-26 12:38:51 +08:00
69 changed files with 1390 additions and 349 deletions

47
build/nsis-installer.nsh Normal file
View File

@@ -0,0 +1,47 @@
;Inspired by:
; https://gist.github.com/bogdibota/062919938e1ed388b3db5ea31f52955c
; https://stackoverflow.com/questions/34177547/detect-if-visual-c-redistributable-for-visual-studio-2013-is-installed
; https://stackoverflow.com/a/54391388
; https://github.com/GitCommons/cpp-redist-nsis/blob/main/installer.nsh
;Find latests downloads here:
; https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist
!include LogicLib.nsh
; https://github.com/electron-userland/electron-builder/issues/1122
!ifndef BUILD_UNINSTALLER
Function checkVCRedist
ReadRegDWORD $0 HKLM "SOFTWARE\Microsoft\VisualStudio\14.0\VC\Runtimes\x64" "Installed"
FunctionEnd
!endif
!macro customInit
Push $0
Call checkVCRedist
${If} $0 != "1"
MessageBox MB_YESNO "\
NOTE: ${PRODUCT_NAME} requires $\r$\n\
'Microsoft Visual C++ Redistributable'$\r$\n\
to function properly.$\r$\n$\r$\n\
Download and install now?" /SD IDYES IDYES InstallVCRedist IDNO DontInstall
InstallVCRedist:
inetc::get /CAPTION " " /BANNER "Downloading Microsoft Visual C++ Redistributable..." "https://aka.ms/vs/17/release/vc_redist.x64.exe" "$TEMP\vc_redist.x64.exe"
ExecWait "$TEMP\vc_redist.x64.exe /install /norestart"
;IfErrors InstallError ContinueInstall ; vc_redist exit code is unreliable :(
Call checkVCRedist
${If} $0 == "1"
Goto ContinueInstall
${EndIf}
;InstallError:
MessageBox MB_ICONSTOP "\
There was an unexpected error installing$\r$\n\
Microsoft Visual C++ Redistributable.$\r$\n\
The installation of ${PRODUCT_NAME} cannot continue."
DontInstall:
Abort
${EndIf}
ContinueInstall:
Pop $0
!macroend

View File

@@ -39,6 +39,7 @@ nsis:
createDesktopShortcut: always
allowToChangeInstallationDirectory: true
oneClick: false
include: build/nsis-installer.nsh
mac:
entitlementsInherit: build/entitlements.mac.plist
notarize: false
@@ -77,4 +78,4 @@ afterPack: scripts/after-pack.js
afterSign: scripts/notarize.js
releaseInfo:
releaseNotes: |
增加知识库功能
增加 Genspark 小程序

View File

@@ -50,7 +50,7 @@ export default defineConfig({
}
},
optimizeDeps: {
exclude: []
exclude: ['chunk-QH6N6I7P.js', 'chunk-PB73W2YU.js']
}
}
})

View File

@@ -1,6 +1,6 @@
{
"name": "CherryStudio",
"version": "0.9.1",
"version": "0.9.2",
"private": true,
"description": "A powerful AI assistant for producer.",
"main": "./out/main/index.js",
@@ -25,6 +25,7 @@
"typecheck": "npm run typecheck:node && npm run typecheck:web",
"start": "electron-vite preview",
"dev": "electron-vite dev",
"build:check": "yarn typecheck",
"build": "npm run typecheck && electron-vite build",
"postinstall": "electron-builder install-app-deps",
"build:unpack": "dotenv npm run build && electron-builder --dir",
@@ -93,8 +94,8 @@
"@types/react-infinite-scroll-component": "^5.0.0",
"@types/tinycolor2": "^1",
"@vitejs/plugin-react": "^4.2.1",
"antd": "^5.18.3",
"axios": "^1.7.3",
"antd": "^5.22.5",
"axios": "^1.7.9",
"browser-image-compression": "^2.0.2",
"dayjs": "^1.11.11",
"dexie": "^4.0.8",

View File

@@ -0,0 +1,202 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Github Releases Timeline</title>
<link href="https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css" rel="stylesheet" />
<script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>
<script src="https://cdn.jsdelivr.net/npm/markdown-it@13.0.1/dist/markdown-it.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/typography@0.5.10/dist/typography.min.css"></script>
</head>
<body id="app">
<div :class="isDark ? 'dark-bg' : 'bg'" class="min-h-screen">
<div class="max-w-3xl mx-auto py-12 px-4">
<h1 class="text-3xl font-bold mb-8" :class="isDark ? 'text-white' : 'text-gray-900'">Release Timeline</h1>
<!-- Loading状态 -->
<div v-if="loading" class="text-center py-8">
<div class="inline-block animate-spin rounded-full h-8 w-8 border-4"
:class="isDark ? 'border-gray-700 border-t-blue-500' : 'border-gray-300 border-t-blue-500'"></div>
</div>
<!-- Error 状态 -->
<div v-else-if="error" class="text-red-500 text-center py-8">{{ error }}</div>
<!-- Release 列表 -->
<div v-else class="space-y-8">
<div v-for="release in releases" :key="release.id" class="relative pl-8"
:class="isDark ? 'border-l-2 border-gray-700' : 'border-l-2 border-gray-200'">
<div class="absolute -left-2 top-0 w-4 h-4 rounded-full bg-green-500"></div>
<div class="rounded-lg shadow-sm p-6 transition-shadow"
:class="isDark ? 'bg-black hover:shadow-md hover:shadow-black' : 'bg-white hover:shadow-md'">
<div class="flex items-start justify-between mb-4">
<div>
<h2 class="text-xl font-semibold" :class="isDark ? 'text-white' : 'text-gray-900'">
{{ release.name || release.tag_name }}
</h2>
<p class="text-sm mt-1" :class="isDark ? 'text-gray-400' : 'text-gray-500'">
{{ formatDate(release.published_at) }}
</p>
</div>
<span class="inline-flex items-center px-3 py-1 rounded-full text-sm font-medium"
:class="isDark ? 'bg-green-900 text-green-200' : 'bg-green-100 text-green-800'">
{{ release.tag_name }}
</span>
</div>
<div class="prose" :class="isDark ? 'text-gray-300 dark-prose' : 'text-gray-600'"
v-html="renderMarkdown(release.body)"></div>
</div>
</div>
</div>
</div>
</div>
<script>
const md = window.markdownit({
breaks: true,
linkify: true
})
const { createApp } = Vue
createApp({
data() {
return {
releases: [],
loading: true,
error: null,
isDark: false
}
},
methods: {
async fetchReleases() {
try {
this.loading = true
this.error = null
const response = await fetch('https://api.github.com/repos/kangfenmao/cherry-studio/releases')
if (!response.ok) {
throw new Error('Failed to fetch releases')
}
this.releases = await response.json()
} catch (err) {
this.error = 'Error loading releases: ' + err.message
} finally {
this.loading = false
}
},
formatDate(dateString) {
return new Date(dateString).toLocaleDateString('en-US', {
year: 'numeric',
month: 'long',
day: 'numeric'
})
},
renderMarkdown(content) {
if (!content) return ''
return md.render(content)
},
initTheme() {
// 从 URL 参数获取主题设置
const url = new URL(window.location.href)
const theme = url.searchParams.get('theme')
this.isDark = theme === 'dark'
}
},
mounted() {
this.initTheme()
this.fetchReleases()
}
}).mount('#app')
</script>
<style>
/* 基础的 Markdown 样式 */
.prose {
line-height: 1.6;
}
.prose h1 {
font-size: 1.5em;
margin: 1em 0;
}
.prose h2 {
font-size: 1.3em;
margin: 0.8em 0;
}
.prose h3 {
font-size: 1.1em;
margin: 0.6em 0;
}
.prose ul {
list-style-type: disc;
margin-left: 1.5em;
margin-bottom: 1em;
}
.prose ol {
list-style-type: decimal;
margin-left: 1.5em;
margin-bottom: 1em;
}
.prose code {
padding: 0.2em 0.4em;
border-radius: 0.2em;
font-size: 0.9em;
}
.dark .prose code {
background-color: #1f2937;
}
.prose code {
background-color: #f3f4f6;
}
.prose pre code {
display: block;
padding: 1em;
overflow-x: auto;
}
.prose a {
color: #3b82f6;
text-decoration: underline;
}
.dark .prose a {
color: #60a5fa;
}
.prose blockquote {
border-left: 4px solid #e5e7eb;
padding-left: 1em;
margin: 1em 0;
}
.dark .prose blockquote {
border-left-color: #374151;
color: #9ca3af;
}
.dark .prose {
color: #e5e7eb;
}
.dark-bg {
background-color: #151515;
}
.bg {
background-color: #f2f2f2;
}
</style>
</body>
</html>

View File

@@ -26,6 +26,11 @@ exports.default = async function (context) {
const _arch = arch === Arch.arm64 ? ['linux-arm64-gnu', 'linux-arm64-musl'] : ['linux-x64-gnu', 'linux-x64-musl']
removeDifferentArchNodeFiles(node_modules_path, '@libsql', _arch)
}
if (platform === 'windows') {
const node_modules_path = path.join(context.appOutDir, 'resources', 'app.asar.unpacked', 'node_modules')
removeDifferentArchNodeFiles(node_modules_path, '@libsql', ['win32-x64-msvc'])
}
}
function removeDifferentArchNodeFiles(nodeModulesPath, packageName, arch) {

View File

@@ -27,6 +27,13 @@ async function downloadNpm(platform) {
'https://registry.npmjs.org/@libsql/linux-x64-musl/-/linux-x64-musl-0.4.7.tgz'
)
}
if (!platform || platform === 'windows') {
downloadNpmPackage(
'@libsql/win32-x64-msvc',
'https://registry.npmjs.org/@libsql/win32-x64-msvc/-/win32-x64-msvc-0.4.7.tgz'
)
}
}
const platformArg = process.argv[2]

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

@@ -9,7 +9,8 @@ import { DocxLoader, ExcelLoader, PptLoader } from '@llm-tools/embedjs-loader-ms
import { PdfLoader } from '@llm-tools/embedjs-loader-pdf'
import { SitemapLoader } from '@llm-tools/embedjs-loader-sitemap'
import { WebLoader } from '@llm-tools/embedjs-loader-web'
import { OpenAiEmbeddings } from '@llm-tools/embedjs-openai'
import { AzureOpenAiEmbeddings, OpenAiEmbeddings } from '@llm-tools/embedjs-openai'
import { getInstanceName } from '@main/utils'
import { FileType, KnowledgeBaseParams, KnowledgeItem } from '@types'
import { app } from 'electron'
@@ -30,19 +31,29 @@ class KnowledgeService {
id,
model,
apiKey,
apiVersion,
baseURL,
dimensions
}: KnowledgeBaseParams): Promise<RAGApplication> => {
return new RAGApplicationBuilder()
.setModel('NO_MODEL')
.setEmbeddingModel(
new OpenAiEmbeddings({
model,
apiKey,
configuration: { baseURL },
dimensions,
batchSize: 20
})
apiVersion
? new AzureOpenAiEmbeddings({
azureOpenAIApiKey: apiKey,
azureOpenAIApiVersion: apiVersion,
azureOpenAIApiDeploymentName: model,
azureOpenAIApiInstanceName: getInstanceName(baseURL),
dimensions,
batchSize: 15
})
: new OpenAiEmbeddings({
model,
apiKey,
configuration: { baseURL },
dimensions,
batchSize: 15
})
)
.setVectorDatabase(new LibSqlDb({ path: path.join(this.storageDir, id) }))
.build()

View File

@@ -14,3 +14,11 @@ export function getDataPath() {
}
return dataPath
}
export function getInstanceName(baseURL: string) {
try {
return new URL(baseURL).host.split('.')[0]
} catch (error) {
return ''
}
}

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)
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

View File

@@ -58,8 +58,8 @@ const PopoverContent = styled(Scrollbar)``
const AppsContainer = styled.div`
display: grid;
grid-template-columns: repeat(6, 1fr);
gap: 25px 35px;
grid-template-columns: repeat(6, minmax(90px, 1fr));
gap: 25px;
`
export default AppStorePopover

View File

@@ -115,7 +115,7 @@ const PopupContainer: React.FC<PopupContainerProps> = ({ model, resolve }) => {
.flatMap((p) => p.models || [])
.filter((m) => pinnedModels.includes(getModelUniqId(m)))
.map((m) => ({
key: getModelUniqId(m),
key: getModelUniqId(m) + '_pinned',
label: (
<ModelItem>
{m?.name} {isVisionModel(m) && <VisionIcon />}

View File

@@ -4,6 +4,7 @@ import { TextAreaProps } from 'antd/lib/input'
import { TextAreaRef } from 'antd/lib/input/TextArea'
import { useEffect, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
import styled from 'styled-components'
import { TopView } from '../TopView'
@@ -11,13 +12,14 @@ interface ShowParams {
text: string
textareaProps?: TextAreaProps
modalProps?: ModalProps
children?: (props: { onOk?: () => void; onCancel?: () => void }) => React.ReactNode
}
interface Props extends ShowParams {
resolve: (data: any) => void
}
const PopupContainer: React.FC<Props> = ({ text, textareaProps, modalProps, resolve }) => {
const PopupContainer: React.FC<Props> = ({ text, textareaProps, modalProps, resolve, children }) => {
const [open, setOpen] = useState(true)
const { t } = useTranslation()
const [textValue, setTextValue] = useState(text)
@@ -73,12 +75,17 @@ const PopupContainer: React.FC<Props> = ({ text, textareaProps, modalProps, reso
onInput={resizeTextArea}
onChange={(e) => setTextValue(e.target.value)}
/>
<ChildrenContainer>{children && children({ onOk, onCancel })}</ChildrenContainer>
</Modal>
)
}
const TopViewKey = 'TextEditPopup'
const ChildrenContainer = styled.div`
position: relative;
`
export default class TextEditPopup {
static topviewId = 0
static hide() {

View File

@@ -6,6 +6,8 @@ import DoubaoAppLogo from '@renderer/assets/images/apps/doubao.png'
import DuckDuckGoAppLogo from '@renderer/assets/images/apps/duckduckgo.webp'
import FeloAppLogo from '@renderer/assets/images/apps/felo.png'
import GeminiAppLogo from '@renderer/assets/images/apps/gemini.png'
import GensparkLogo from '@renderer/assets/images/apps/genspark.jpg'
import GithubCopilotLogo from '@renderer/assets/images/apps/github-copilot.webp'
import HuggingChatLogo from '@renderer/assets/images/apps/huggingchat.svg'
import KimiAppLogo from '@renderer/assets/images/apps/kimi.jpg'
import MetasoAppLogo from '@renderer/assets/images/apps/metaso.webp'
@@ -223,6 +225,18 @@ const _apps: MinAppType[] = [
logo: ThinkAnyLogo,
url: 'https://thinkany.ai/',
bodered: true
},
{
id: 'github-copilot',
name: 'GitHub Copilot',
logo: GithubCopilotLogo,
url: 'https://github.com/copilot'
},
{
id: 'genspark',
name: 'Genspark',
logo: GensparkLogo,
url: 'https://www.genspark.ai/'
}
]

View File

@@ -152,7 +152,7 @@ export const VISION_REGEX = new RegExp(
)
export const TEXT_TO_IMAGE_REGEX = /flux|diffusion|stabilityai|sd-|dall|cogview/i
export const EMBEDDING_REGEX = /(?:^text-|embed|rerank|davinci|babbage|bge-|base|retrieval|uae-|gte-)/i
export const EMBEDDING_REGEX = /(?:^text-|embed|rerank|davinci|babbage|bge-|e5-|LLM2Vec|retrieval|uae-|gte-|jina)/i
export const NOT_SUPPORTED_REGEX = /(?:^tts|rerank|whisper|speech)/i
export function getModelLogo(modelId: string) {
@@ -700,7 +700,56 @@ export const SYSTEM_MODELS: Record<string, Model[]> = {
group: 'Mistral'
}
],
jina: [],
jina: [
{
id: 'jina-clip-v1',
provider: 'jina',
name: 'jina-clip-v1',
group: 'Jina Clip'
},
{
id: 'jina-clip-v2',
provider: 'jina',
name: 'jina-clip-v2',
group: 'Jina Clip'
},
{
id: 'jina-embeddings-v2-base-en',
provider: 'jina',
name: 'jina-embeddings-v2-base-en',
group: 'Jina Embeddings V2'
},
{
id: 'jina-embeddings-v2-base-es',
provider: 'jina',
name: 'jina-embeddings-v2-base-es',
group: 'Jina Embeddings V2'
},
{
id: 'jina-embeddings-v2-base-de',
provider: 'jina',
name: 'jina-embeddings-v2-base-de',
group: 'Jina Embeddings V2'
},
{
id: 'jina-embeddings-v2-base-zh',
provider: 'jina',
name: 'jina-embeddings-v2-base-zh',
group: 'Jina Embeddings V2'
},
{
id: 'jina-embeddings-v2-base-code',
provider: 'jina',
name: 'jina-embeddings-v2-base-code',
group: 'Jina Embeddings V2'
},
{
id: 'jina-embeddings-v3',
provider: 'jina',
name: 'jina-embeddings-v3',
group: 'Jina Embeddings V3'
}
],
aihubmix: [
{
id: 'gpt-4o-mini',

View File

@@ -45,7 +45,7 @@ export const AGENT_PROMPT = `
`
export const SUMMARIZE_PROMPT =
'你是一名擅长会话的助理,你需要将用户的会话总结为 10 个字以内的标题,不要使用标点符号和其他特殊符号'
'你是一名擅长会话的助理,你需要将用户的会话总结为 10 个字以内的标题,标题语言与用户的首要语言一致,不要使用标点符号和其他特殊符号'
export const TRANSLATE_PROMPT =
'You are a translation expert. Translate from input language to {{target_language}}, provide the translation result directly without any explanation and keep original format. Do not translate if the target language is the same as the source language.'

View File

@@ -16,8 +16,16 @@ import useUpdateHandler from './useUpdateHandler'
export function useAppInit() {
const dispatch = useAppDispatch()
const { proxyUrl, language, windowStyle, manualUpdateCheck, proxyMode, webdavAutoSync, webdavSyncInterval } =
useSettings()
const {
proxyUrl,
language,
windowStyle,
manualUpdateCheck,
proxyMode,
webdavAutoSync,
webdavSyncInterval,
customCss
} = useSettings()
const { minappShow } = useRuntime()
const { setDefaultModel, setTopicNamingModel, setTranslateModel } = useDefaultModel()
const avatar = useLiveQuery(() => db.settings.get('image://avatar'))
@@ -83,4 +91,18 @@ export function useAppInit() {
useEffect(() => {
import('@renderer/queue/KnowledgeQueue')
}, [])
useEffect(() => {
const oldCustomCss = document.getElementById('user-defined-custom-css')
if (oldCustomCss) {
oldCustomCss.remove()
}
if (customCss) {
const style = document.createElement('style')
style.id = 'user-defined-custom-css'
style.textContent = customCss
document.head.appendChild(style)
}
}, [customCss])
}

View File

@@ -1,3 +1,4 @@
import { db } from '@renderer/databases'
import { getDefaultTopic } from '@renderer/services/AssistantService'
import { useAppDispatch, useAppSelector } from '@renderer/store'
import {
@@ -50,8 +51,20 @@ export function useAssistant(id: string) {
dispatch(removeTopic({ assistantId: assistant.id, topic }))
},
moveTopic: (topic: Topic, toAssistant: Assistant) => {
dispatch(addTopic({ assistantId: toAssistant.id, topic: { ...topic } }))
dispatch(addTopic({ assistantId: toAssistant.id, topic: { ...topic, assistantId: toAssistant.id } }))
dispatch(removeTopic({ assistantId: assistant.id, topic }))
// update topic messages in database
db.topics
.where('id')
.equals(topic.id)
.modify((dbTopic) => {
if (dbTopic.messages) {
dbTopic.messages = dbTopic.messages.map((message) => ({
...message,
assistantId: toAssistant.id
}))
}
})
},
updateTopic: (topic: Topic) => dispatch(updateTopic({ assistantId: assistant.id, topic })),
updateTopics: (topics: Topic[]) => dispatch(updateTopics({ assistantId: assistant.id, topics })),

View File

@@ -1,8 +1,9 @@
import { useAppDispatch, useAppSelector } from '@renderer/store'
import store, { useAppDispatch, useAppSelector } from '@renderer/store'
import {
SendMessageShortcut,
setSendMessageShortcut as _setSendMessageShortcut,
setTheme,
SettingsState,
setTopicPosition,
setTray,
setWindowStyle
@@ -41,3 +42,7 @@ export function useMessageStyle() {
isBubbleStyle
}
}
export const getStoreSetting = (key: keyof SettingsState) => {
return store.getState().settings[key]
}

View File

@@ -112,7 +112,8 @@
"topics.list": "Topic List",
"topics.move_to": "Move to",
"topics.title": "Topics",
"translate": "Translate"
"translate": "Translate",
"resend": "Resend"
},
"common": {
"and": "and",
@@ -381,6 +382,8 @@
"display.sidebar.files.icon": "Show Files icon",
"display.sidebar.title": "Sidebar Settings",
"display.topic.title": "Topic Settings",
"display.custom.css": "Custom CSS",
"display.custom.css.placeholder": "/* Put custom CSS here */",
"input.auto_translate_with_space": "Quickly translate with 3 spaces",
"messages.divider": "Show divider between messages",
"messages.input.paste_long_text_as_file": "Paste long text as file",
@@ -415,6 +418,7 @@
"models.translate_model_prompt_title": "Translate Model Prompt",
"models.topic_naming_model_setting_title": "Topic Naming Model Settings",
"models.enable_topic_naming": "Topic Auto Naming",
"models.topic_naming_prompt": "Topic Naming Prompt",
"provider": {
"add.name": "Provider Name",
"add.name.placeholder": "Example: OpenAI",
@@ -583,7 +587,18 @@
"embedding": "Embedding",
"embedding_model": "Embedding Model",
"embedding_model_tooltip": "Add in Settings->Model Provider->Manage",
"dimensions": "Dimensions {{dimensions}}"
"dimensions": "Dimensions {{dimensions}}",
"custom_parameters": "Custom Parameters",
"add_parameter": "Add Parameter",
"parameter_name": "Parameter Name",
"parameter_type": {
"string": "Text",
"number": "Number",
"boolean": "Boolean"
}
},
"prompts": {
"summarize": "You are an assistant who is good at conversation. You need to summarize the user's conversation into a title of 10 characters or less, ensuring it matches the user's primary language without using punctuation or other special symbols."
}
}
}

View File

@@ -112,7 +112,8 @@
"topics.list": "トピックリスト",
"topics.move_to": "移動先",
"topics.title": "トピック",
"translate": "翻訳"
"translate": "翻訳",
"resend": "再送信"
},
"common": {
"and": "と",
@@ -379,6 +380,8 @@
"display.sidebar.files.icon": "ファイルのアイコンを表示",
"display.sidebar.title": "サイドバー設定",
"display.topic.title": "トピック設定",
"display.custom.css": "カスタムCSS",
"display.custom.css.placeholder": "/* ここにカスタムCSSを入力 */",
"input.auto_translate_with_space": "スペースを3回押して翻訳",
"messages.divider": "メッセージ間に区切り線を表示",
"messages.input.paste_long_text_as_file": "長いテキストをファイルとして貼り付け",
@@ -413,6 +416,7 @@
"models.translate_model_prompt_title": "翻訳モデルのプロンプト",
"models.topic_naming_model_setting_title": "トピック命名モデルの設定",
"models.enable_topic_naming": "トピックの自動命名",
"models.topic_naming_prompt": "トピック命名プロンプト",
"provider": {
"add.name": "プロバイダー名",
"add.name.placeholder": "例OpenAI",
@@ -565,7 +569,19 @@
"free": "無料モデル",
"embedding": "埋め込みモデル",
"embedding_model": "埋め込みモデル",
"embedding_model_tooltip": "設定->モデルサービス->管理で追加"
"embedding_model_tooltip": "設定->モデルサービス->管理で追加",
"dimensions": "{{dimensions}} 次元",
"custom_parameters": "カスタムパラメータ",
"add_parameter": "パラメータを追加",
"parameter_name": "パラメータ名",
"parameter_type": {
"string": "テキスト",
"number": "数値",
"boolean": "真偽値"
}
},
"prompts": {
"summarize": "あなたは会話を得意とするアシスタントです。ユーザーの会話を10文字以内のタイトルに要約し、ユーザーの主言語と一致していることを確認してください。句読点や特殊記号は使用しないでください。"
}
}
}

View File

@@ -112,7 +112,8 @@
"topics.list": "Список топиков",
"topics.move_to": "Переместить в",
"topics.title": "Топики",
"translate": "Перевести"
"translate": "Перевести",
"resend": "Переотправить"
},
"common": {
"and": "и",
@@ -381,6 +382,8 @@
"display.sidebar.files.icon": "Показывать иконку файлов",
"display.sidebar.title": "Настройки боковой панели",
"display.topic.title": "Настройки топиков",
"display.custom.css": "Пользовательский CSS",
"display.custom.css.placeholder": "/* Здесь введите пользовательский CSS */",
"input.auto_translate_with_space": "Быстрый перевод с помощью 3-х пробелов",
"messages.divider": "Показывать разделитель между сообщениями",
"messages.input.paste_long_text_as_file": "Вставлять длинный текст как файл",
@@ -415,6 +418,7 @@
"models.translate_model_prompt_title": "Модель перевода",
"models.topic_naming_model_setting_title": "Настройки модели именования топика",
"models.enable_topic_naming": "Автоматическое переименование топика",
"models.topic_naming_prompt": "Подсказка для именования топика",
"provider": {
"add.name": "Имя провайдера",
"add.name.placeholder": "Пример: OpenAI",
@@ -583,7 +587,18 @@
"embedding": "Встраиваемые модели",
"embedding_model": "Встраиваемые модели",
"embedding_model_tooltip": "Добавьте в настройки->модель сервиса->управление",
"dimensions": "{{dimensions}} мер"
"dimensions": "{{dimensions}} мер",
"custom_parameters": "Пользовательские параметры",
"add_parameter": "Добавить параметр",
"parameter_name": "Имя параметра",
"parameter_type": {
"string": "Текст",
"number": "Число",
"boolean": "Логическое"
}
},
"prompts": {
"summarize": "Вы - эксперт в общении, который суммирует разговоры пользователя в 10-символьном заголовке, совпадающем с языком пользователя, без использования знаков препинания и других специальных символов"
}
}
}

View File

@@ -112,7 +112,8 @@
"topics.list": "话题列表",
"topics.move_to": "移动到",
"topics.title": "话题",
"translate": "翻译"
"translate": "翻译",
"resend": "重新发送"
},
"common": {
"and": "和",
@@ -382,6 +383,8 @@
"display.sidebar.files.icon": "显示文件图标",
"display.sidebar.title": "侧边栏设置",
"display.topic.title": "话题设置",
"display.custom.css": "自定义 CSS",
"display.custom.css.placeholder": "/* 这里写自定义CSS */",
"input.auto_translate_with_space": "快速敲击3次空格翻译",
"messages.divider": "消息分割线",
"messages.input.paste_long_text_as_file": "长文本粘贴为文件",
@@ -416,6 +419,7 @@
"models.translate_model_prompt_title": "翻译模型提示词",
"models.topic_naming_model_setting_title": "话题命名模型设置",
"models.enable_topic_naming": "话题自动重命名",
"models.topic_naming_prompt": "话题命名提示词",
"provider": {
"add.name": "提供商名称",
"add.name.placeholder": "例如 OpenAI",
@@ -572,7 +576,18 @@
"embedding": "嵌入模型",
"embedding_model": "嵌入模型",
"embedding_model_tooltip": "在设置->模型服务中点击管理按钮添加",
"dimensions": "{{dimensions}} 维"
"dimensions": "{{dimensions}} 维",
"custom_parameters": "自定义参数",
"add_parameter": "添加参数",
"parameter_name": "参数名称",
"parameter_type": {
"string": "文本",
"number": "数字",
"boolean": "布尔值"
}
},
"prompts": {
"summarize": "你是一名擅长会话的助理,你需要将用户的会话总结为 10 个字以内的标题,标题语言与用户的首要语言一致,不要使用标点符号和其他特殊符号"
}
}
}

View File

@@ -112,7 +112,8 @@
"topics.list": "話題列表",
"topics.move_to": "移動到",
"topics.title": "話題",
"translate": "翻譯"
"translate": "翻譯",
"resend": "重新發送"
},
"common": {
"and": "與",
@@ -167,7 +168,7 @@
"conversation_details": "會話詳情",
"conversation_history": "會話歷史",
"created": "創建時間",
"last_updated": "最後<EFBFBD><EFBFBD>新",
"last_updated": "最後新",
"messages": "訊息數",
"user": "用戶"
},
@@ -381,6 +382,8 @@
"display.sidebar.files.icon": "顯示文件圖示",
"display.sidebar.title": "側邊欄設定",
"display.topic.title": "話題設定",
"display.custom.css": "自定義 CSS",
"display.custom.css.placeholder": "/* 這裡寫自定義 CSS */",
"input.auto_translate_with_space": "快速敲擊3次空格翻譯",
"messages.divider": "訊息間顯示分隔線",
"messages.input.paste_long_text_as_file": "將長文本貼上為檔案",
@@ -415,6 +418,7 @@
"models.translate_model_prompt_title": "翻譯模型提示詞",
"models.topic_naming_model_setting_title": "話題命名模型設定",
"models.enable_topic_naming": "話題自動重命名",
"models.topic_naming_prompt": "話題命名提示詞",
"provider": {
"add.name": "提供者名稱",
"add.name.placeholder": "例如OpenAI",
@@ -571,7 +575,18 @@
"embedding": "嵌入模型",
"embedding_model": "嵌入模型",
"embedding_model_tooltip": "在设置->模型服务中点击管理按钮添加",
"dimensions": "{{dimensions}} 維"
"dimensions": "{{dimensions}} 維",
"custom_parameters": "自定義參數",
"add_parameter": "添加參數",
"parameter_name": "參數名稱",
"parameter_type": {
"string": "文字",
"number": "數字",
"boolean": "布林值"
}
},
"prompts": {
"summarize": "你是一名擅長會話的助理,你需要將用戶的會話總結為 10 個字以內的標題,標題語言與用戶的首要語言一致,不要使用標點符號和其他特殊符號"
}
}
}

View File

@@ -1,6 +1,6 @@
import { DeleteOutlined, EditOutlined, PlusOutlined, SortAscendingOutlined } from '@ant-design/icons'
import AssistantSettingsPopup from '@renderer/components/AssistantSettings'
import { useAgents } from '@renderer/hooks/useAgents'
import AssistantSettingsPopup from '@renderer/pages/settings/AssistantSettings'
import { createAssistantFromAgent } from '@renderer/services/AssistantService'
import { Agent } from '@renderer/types'
import { Col } from 'antd'

View File

@@ -36,8 +36,6 @@ const Container = styled.div`
justify-content: center;
align-items: center;
cursor: pointer;
max-width: 80px;
width: 72px;
overflow: hidden;
`

View File

@@ -74,12 +74,12 @@ const ContentContainer = styled.div`
const AppsContainer = styled.div`
display: flex;
min-width: 950px;
max-width: 950px;
flex-direction: row;
flex-wrap: wrap;
align-content: flex-start;
gap: 50px;
min-width: 930px;
max-width: 930px;
max-height: 500px;
display: grid;
grid-template-columns: repeat(8, minmax(90px, 1fr));
gap: 25px 25px;
`
export default AppsPage

View File

@@ -21,6 +21,7 @@ let _message: Message | undefined
const TopicsPage: FC = () => {
const { t } = useTranslation()
const [search, setSearch] = useState(_search)
const [searchKeywords, setSearchKeywords] = useState(_search)
const [stack, setStack] = useState<Route[]>(_stack)
const [topic, setTopic] = useState<Topic | undefined>(_topic)
const [message, setMessage] = useState<Message | undefined>(_message)
@@ -40,6 +41,7 @@ const TopicsPage: FC = () => {
}
const onSearch = () => {
setSearchKeywords(search)
setStack(['topics', 'search'])
setTopic(undefined)
}
@@ -84,7 +86,7 @@ const TopicsPage: FC = () => {
/>
<TopicMessages topic={topic} style={{ display: isShow('topic') }} />
<SearchResults
keywords={isShow('search') ? search : ''}
keywords={isShow('search') ? searchKeywords : ''}
onMessageClick={onMessageClick}
onTopicClick={onTopicClick}
style={{ display: isShow('search') }}

View File

@@ -1,5 +1,6 @@
import { ArrowRightOutlined } from '@ant-design/icons'
import { HStack } from '@renderer/components/Layout'
import { useSettings } from '@renderer/hooks/useSettings'
import { default as MessageItem } from '@renderer/pages/home/Messages/Message'
import { locateToMessage } from '@renderer/services/MessagesService'
import NavigationService from '@renderer/services/NavigationService'
@@ -15,6 +16,7 @@ interface Props extends React.HTMLAttributes<HTMLDivElement> {
const SearchMessage: FC<Props> = ({ message, ...props }) => {
const navigate = NavigationService.navigate!
const { messageStyle } = useSettings()
const { t } = useTranslation()
if (!message) {
@@ -22,7 +24,7 @@ const SearchMessage: FC<Props> = ({ message, ...props }) => {
}
return (
<MessagesContainer {...props}>
<MessagesContainer {...props} className={messageStyle}>
<ContainerWrapper style={{ paddingTop: 20, paddingBottom: 20, position: 'relative' }}>
<MessageItem message={message} />
<Button
@@ -45,6 +47,7 @@ const SearchMessage: FC<Props> = ({ message, ...props }) => {
const MessagesContainer = styled.div`
width: 100%;
display: flex;
flex: 1;
flex-direction: column;
align-items: center;
overflow-y: scroll;

View File

@@ -90,6 +90,7 @@ const Inputbar: FC<Props> = ({ assistant: _assistant, setActiveTopic }) => {
[estimateTextTokens, showInputEstimatedTokens, text]
)
const newTopicShortcut = useShortcutDisplay('new_topic')
const inputEmpty = isEmpty(text.trim()) && files.length === 0
_text = text
_files = files
@@ -100,7 +101,7 @@ const Inputbar: FC<Props> = ({ assistant: _assistant, setActiveTopic }) => {
return
}
if (isEmpty(text.trim())) {
if (inputEmpty) {
return
}
@@ -131,7 +132,7 @@ const Inputbar: FC<Props> = ({ assistant: _assistant, setActiveTopic }) => {
setTimeout(() => resizeTextArea(), 0)
setExpend(false)
}, [assistant.id, assistant.topics, generating, files, text, selectedKnowledgeBase])
}, [generating, inputEmpty, text, assistant.id, assistant.topics, selectedKnowledgeBase, files])
const translate = async () => {
if (isTranslating) {
@@ -492,7 +493,7 @@ const Inputbar: FC<Props> = ({ assistant: _assistant, setActiveTopic }) => {
</ToolbarButton>
</Tooltip>
)}
{!generating && <SendMessageButton sendMessage={sendMessage} disabled={generating || !text} />}
{!generating && <SendMessageButton sendMessage={sendMessage} disabled={generating || inputEmpty} />}
</ToolbarMenu>
</Toolbar>
</InputBarContainer>

View File

@@ -19,7 +19,7 @@ import ImagePreview from './ImagePreview'
import Link from './Link'
const ALLOWED_ELEMENTS =
/<(style|p|div|span|b|i|strong|em|ul|ol|li|table|tr|td|th|thead|tbody|h[1-6]|blockquote|pre|code|br|hr|svg|path|circle|rect|line|polyline|polygon|text|g|defs|title|desc|tspan)/i
/<(style|p|div|span|b|i|strong|em|ul|ol|li|table|tr|td|th|thead|tbody|h[1-6]|blockquote|pre|code|br|hr|svg|path|circle|rect|line|polyline|polygon|text|g|defs|title|desc|tspan|sub|sup)/i
interface Props {
message: Message

View File

@@ -86,9 +86,12 @@ const MessageItem: FC<Props> = ({
}
useEffect(() => {
const unsubscribes = [EventEmitter.on(EVENT_NAMES.LOCATE_MESSAGE + ':' + message.id, messageHighlightHandler)]
const unsubscribes = [
EventEmitter.on(EVENT_NAMES.LOCATE_MESSAGE + ':' + message.id, messageHighlightHandler),
EventEmitter.on(EVENT_NAMES.RESEND_MESSAGE + ':' + message.id, onEditMessage)
]
return () => unsubscribes.forEach((unsub) => unsub())
}, [message])
}, [message, onEditMessage])
useEffect(() => {
if (message.role === 'user' && !message.usage) {
@@ -178,6 +181,7 @@ const MessageItem: FC<Props> = ({
setModel={setModel}
onEditMessage={onEditMessage}
onDeleteMessage={onDeleteMessage}
onGetMessages={onGetMessages}
/>
</MessageFooter>
)}

View File

@@ -15,7 +15,7 @@ import { EVENT_NAMES, EventEmitter } from '@renderer/services/EventService'
import { translateText } from '@renderer/services/TranslateService'
import { Message, Model } from '@renderer/types'
import { removeTrailingDoubleSpaces } from '@renderer/utils'
import { Dropdown, Popconfirm, Tooltip } from 'antd'
import { Button, Dropdown, Popconfirm, Tooltip } from 'antd'
import dayjs from 'dayjs'
import { FC, useCallback, useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next'
@@ -31,6 +31,7 @@ interface Props {
setModel: (model: Model) => void
onEditMessage?: (message: Message) => void
onDeleteMessage?: (message: Message) => void
onGetMessages?: () => Message[]
}
const MessageMenubar: FC<Props> = (props) => {
@@ -43,7 +44,8 @@ const MessageMenubar: FC<Props> = (props) => {
assistantModel,
setModel,
onEditMessage,
onDeleteMessage
onDeleteMessage,
onGetMessages
} = props
const { t } = useTranslation()
const [copied, setCopied] = useState(false)
@@ -75,10 +77,43 @@ const MessageMenubar: FC<Props> = (props) => {
})
}, [index, t])
const onResend = useCallback(() => {
const _messages = onGetMessages?.() || []
const index = _messages.findIndex((m) => m.id === message.id)
const nextIndex = index + 1
const nextMessage = _messages[nextIndex]
if (nextMessage && nextMessage.role === 'assistant') {
EventEmitter.emit(EVENT_NAMES.RESEND_MESSAGE + ':' + nextMessage.id, {
...nextMessage,
content: '',
status: 'sending',
modelId: assistantModel?.id || model?.id,
translatedContent: undefined
})
}
}, [assistantModel?.id, message.id, model?.id, onGetMessages])
const onEdit = useCallback(async () => {
const editedText = await TextEditPopup.show({ text: message.content })
let resendMessage = false
const editedText = await TextEditPopup.show({
text: message.content,
children: (props) => (
<ReSendButton
icon={<i className="iconfont icon-ic_send" style={{ color: 'var(--color-primary)' }} />}
onClick={() => {
props.onOk?.()
resendMessage = true
}}>
{t('chat.resend')}
</ReSendButton>
)
})
editedText && onEditMessage?.({ ...message, content: editedText })
}, [message, onEditMessage])
resendMessage && onResend()
}, [message, onEditMessage, onResend, t])
const handleTranslate = useCallback(
async (language: string) => {
@@ -287,4 +322,10 @@ const ActionButton = styled.div`
}
`
const ReSendButton = styled(Button)`
position: absolute;
top: 10px;
left: 0;
`
export default MessageMenubar

View File

@@ -1,4 +1,4 @@
import AssistantSettingsPopup from '@renderer/components/AssistantSettings'
import AssistantSettingsPopup from '@renderer/pages/settings/AssistantSettings'
import { Assistant } from '@renderer/types'
import { FC } from 'react'
import { useTranslation } from 'react-i18next'

View File

@@ -1,6 +1,5 @@
import { FormOutlined, SearchOutlined } from '@ant-design/icons'
import { Navbar, NavbarLeft, NavbarRight } from '@renderer/components/app/Navbar'
import AssistantSettingsPopup from '@renderer/components/AssistantSettings'
import { HStack } from '@renderer/components/Layout'
import AppStorePopover from '@renderer/components/Popups/AppStorePopover'
import SearchPopup from '@renderer/components/Popups/SearchPopup'
@@ -9,6 +8,7 @@ import { useAssistant } from '@renderer/hooks/useAssistant'
import { useSettings } from '@renderer/hooks/useSettings'
import { useShortcut } from '@renderer/hooks/useShortcuts'
import { useShowAssistants, useShowTopics } from '@renderer/hooks/useStore'
import AssistantSettingsPopup from '@renderer/pages/settings/AssistantSettings'
import { EVENT_NAMES, EventEmitter } from '@renderer/services/EventService'
import { Assistant, Topic } from '@renderer/types'
import { FC } from 'react'

View File

@@ -1,11 +1,11 @@
import { DeleteOutlined, EditOutlined, MinusCircleOutlined, PlusOutlined, SaveOutlined } from '@ant-design/icons'
import AssistantSettingsPopup from '@renderer/components/AssistantSettings'
import DragableList from '@renderer/components/DragableList'
import CopyIcon from '@renderer/components/Icons/CopyIcon'
import Scrollbar from '@renderer/components/Scrollbar'
import { useAgents } from '@renderer/hooks/useAgents'
import { useAssistant, useAssistants } from '@renderer/hooks/useAssistant'
import { useSettings } from '@renderer/hooks/useSettings'
import AssistantSettingsPopup from '@renderer/pages/settings/AssistantSettings'
import { getDefaultTopic } from '@renderer/services/AssistantService'
import { EVENT_NAMES, EventEmitter } from '@renderer/services/EventService'
import { useAppSelector } from '@renderer/store'

View File

@@ -1,4 +1,4 @@
import { CheckOutlined, QuestionCircleOutlined, ReloadOutlined } from '@ant-design/icons'
import { CheckOutlined, DeleteOutlined, PlusOutlined, QuestionCircleOutlined, ReloadOutlined } from '@ant-design/icons'
import { HStack } from '@renderer/components/Layout'
import Scrollbar from '@renderer/components/Scrollbar'
import {
@@ -29,7 +29,7 @@ import {
setShowMessageDivider
} from '@renderer/store/settings'
import { Assistant, AssistantSettings, ThemeMode } from '@renderer/types'
import { Col, InputNumber, Row, Select, Slider, Switch, Tooltip } from 'antd'
import { Button, Col, Input, InputNumber, Row, Select, Slider, Switch, Tooltip } from 'antd'
import { FC, useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
import styled from 'styled-components'
@@ -102,7 +102,8 @@ const SettingsTab: FC<Props> = (props) => {
maxTokens: DEFAULT_MAX_TOKENS,
streamOutput: true,
hideMessages: false,
autoResetModel: false
autoResetModel: false,
customParameters: []
}
})
}
@@ -202,6 +203,106 @@ const SettingsTab: FC<Props> = (props) => {
/>
</Col>
</Row>
{assistant?.settings?.customParameters?.map((param, index) => (
<ParameterCard key={index}>
<Row align="middle" gutter={8} style={{ marginBottom: 8 }}>
<Col span={14}>
<Input
placeholder={t('models.parameter_name')}
value={param.name}
onChange={(e) => {
const newParams = [...(assistant?.settings?.customParameters || [])]
newParams[index] = { ...param, name: e.target.value }
onUpdateAssistantSettings({ customParameters: newParams })
}}
/>
</Col>
<Col span={10}>
<Select
value={param.type}
onChange={(value: 'string' | 'number' | 'boolean') => {
const newParams = [...(assistant?.settings?.customParameters || [])]
let defaultValue: any = ''
switch (value) {
case 'number':
defaultValue = 0
break
case 'boolean':
defaultValue = false
break
default:
defaultValue = ''
}
newParams[index] = { ...param, type: value, value: defaultValue }
onUpdateAssistantSettings({ customParameters: newParams })
}}
style={{ width: '100%' }}>
<Select.Option value="string">{t('models.parameter_type.string')}</Select.Option>
<Select.Option value="number">{t('models.parameter_type.number')}</Select.Option>
<Select.Option value="boolean">{t('models.parameter_type.boolean')}</Select.Option>
</Select>
</Col>
</Row>
<Row align="middle" gutter={10}>
<Col span={20}>
{param.type === 'boolean' ? (
<Switch
checked={param.value as boolean}
onChange={(checked) => {
const newParams = [...(assistant?.settings?.customParameters || [])]
newParams[index] = { ...param, value: checked }
onUpdateAssistantSettings({ customParameters: newParams })
}}
/>
) : param.type === 'number' ? (
<InputNumber
style={{ width: '100%' }}
value={param.value as number}
onChange={(value) => {
const newParams = [...(assistant?.settings?.customParameters || [])]
newParams[index] = { ...param, value: value || 0 }
onUpdateAssistantSettings({ customParameters: newParams })
}}
step={0.01}
/>
) : (
<Input
value={typeof param.value === 'string' ? param.value : JSON.stringify(param.value)}
onChange={(e) => {
const newParams = [...(assistant?.settings?.customParameters || [])]
newParams[index] = { ...param, value: e.target.value }
onUpdateAssistantSettings({ customParameters: newParams })
}}
/>
)}
</Col>
<Col span={4}>
<Button
icon={<DeleteOutlined />}
onClick={() => {
const newParams = [...(assistant?.settings?.customParameters || [])]
newParams.splice(index, 1)
onUpdateAssistantSettings({ customParameters: newParams })
}}
danger
style={{ width: '100%' }}
/>
</Col>
</Row>
</ParameterCard>
))}
<Button
icon={<PlusOutlined />}
onClick={() => {
const newParams = [
...(assistant?.settings?.customParameters || []),
{ name: '', value: '', type: 'string' as const }
]
onUpdateAssistantSettings({ customParameters: newParams })
}}
style={{ marginBottom: 0, width: '100%', borderStyle: 'dashed' }}>
{t('models.add_parameter')}
</Button>
</SettingGroup>
<SettingGroup>
<SettingSubtitle style={{ marginTop: 0 }}>{t('settings.messages.title')}</SettingSubtitle>
@@ -418,4 +519,15 @@ export const SettingGroup = styled.div<{ theme?: ThemeMode }>`
background: var(--color-group-background);
`
const ParameterCard = styled.div`
margin-bottom: 8px;
padding: 8px;
border: 1px solid var(--color-border);
border-radius: 6px;
background: var(--color-background);
&:last-child {
margin-bottom: 12px;
}
`
export default SettingsTab

View File

@@ -4,6 +4,7 @@ import SelectModelPopup from '@renderer/components/Popups/SelectModelPopup'
import { isLocalAi } from '@renderer/config/env'
import { isVisionModel } from '@renderer/config/models'
import { useAssistant } from '@renderer/hooks/useAssistant'
import { getProviderByModel } from '@renderer/services/AssistantService'
import { Assistant } from '@renderer/types'
import { Button } from 'antd'
import { FC } from 'react'
@@ -32,9 +33,14 @@ const SelectModelButton: FC<Props> = ({ assistant }) => {
return (
<DropdownButton size="small" type="default" onClick={onSelectModel}>
<ModelAvatar model={model} size={20} />
<ModelName>{model ? model.name : t('button.select_model')}</ModelName>
{isVisionModel(model) && <VisionIcon style={{ marginLeft: 0 }} />}
<ButtonContent>
<ModelAvatar model={model} size={20} />
<ModelName>
{model ? model.name : t('button.select_model')} |{' '}
{t(`provider.${model?.provider}`, { defaultValue: getProviderByModel(model)?.name })}
</ModelName>
{isVisionModel(model) && <VisionIcon style={{ marginLeft: 0 }} />}
</ButtonContent>
</DropdownButton>
)
}
@@ -49,6 +55,12 @@ const DropdownButton = styled(Button)`
border: 1px solid transparent;
`
const ButtonContent = styled.div`
display: flex;
align-items: center;
gap: 5px;
`
const ModelName = styled.span`
margin-left: -2px;
font-weight: 500;

View File

@@ -10,6 +10,7 @@ import { useSettings } from '@renderer/hooks/useSettings'
import { useAppDispatch } from '@renderer/store'
import { setUpdateState } from '@renderer/store/runtime'
import { setManualUpdateCheck } from '@renderer/store/settings'
import { ThemeMode } from '@renderer/types'
import { compareVersions, runAsyncFunction } from '@renderer/utils'
import { Avatar, Button, Progress, Row, Switch, Tag } from 'antd'
import { debounce } from 'lodash'
@@ -71,6 +72,15 @@ const AboutSettings: FC = () => {
})
}
const showReleases = async () => {
const { appPath } = await window.api.getAppInfo()
MinApp.start({
name: t('settings.about.releases.title'),
url: `file://${appPath}/resources/cherry-studio/releases.html?theme=${theme === ThemeMode.dark ? 'dark' : 'light'}`,
logo: AppLogo
})
}
const hasNewVersion = update?.info?.version && version ? compareVersions(update.info.version, version) > 0 : false
useEffect(() => {
@@ -158,16 +168,7 @@ const AboutSettings: FC = () => {
<SoundOutlined />
{t('settings.about.releases.title')}
</SettingRowTitle>
<Button
onClick={() =>
MinApp.start({
name: t('settings.about.releases.title'),
url: 'https://github.com/kangfenmao/cherry-studio/releases',
logo: AppLogo
})
}>
{t('settings.about.releases.button')}
</Button>
<Button onClick={showReleases}>{t('settings.about.releases.button')}</Button>
</SettingRow>
<SettingDivider />
<SettingRow>

View File

@@ -1,16 +1,15 @@
import { PlusOutlined, QuestionCircleOutlined } from '@ant-design/icons'
import { DeleteOutlined, PlusOutlined, QuestionCircleOutlined } from '@ant-design/icons'
import ModelAvatar from '@renderer/components/Avatar/ModelAvatar'
import { HStack } from '@renderer/components/Layout'
import SelectModelPopup from '@renderer/components/Popups/SelectModelPopup'
import { DEFAULT_CONTEXTCOUNT, DEFAULT_TEMPERATURE } from '@renderer/config/constant'
import { SettingRow } from '@renderer/pages/settings'
import { Assistant, AssistantSettings } from '@renderer/types'
import { Button, Col, Divider, InputNumber, Row, Slider, Switch, Tooltip } from 'antd'
import { Button, Col, Divider, Input, InputNumber, Row, Select, Slider, Switch, Tooltip } from 'antd'
import { FC, useState } from 'react'
import { useTranslation } from 'react-i18next'
import styled from 'styled-components'
import ModelAvatar from '../Avatar/ModelAvatar'
import SelectModelPopup from '../Popups/SelectModelPopup'
interface Props {
assistant: Assistant
updateAssistant: (assistant: Assistant) => void
@@ -26,6 +25,13 @@ const AssistantModelSettings: FC<Props> = ({ assistant, updateAssistant, updateA
const [streamOutput, setStreamOutput] = useState(assistant?.settings?.streamOutput ?? true)
const [defaultModel, setDefaultModel] = useState(assistant?.defaultModel)
const [topP, setTopP] = useState(assistant?.settings?.topP ?? 1)
const [customParameters, setCustomParameters] = useState<
Array<{
name: string
value: string | number | boolean
type: 'string' | 'number' | 'boolean'
}>
>(assistant?.settings?.customParameters ?? [])
const { t } = useTranslation()
const onTemperatureChange = (value) => {
@@ -52,6 +58,77 @@ const AssistantModelSettings: FC<Props> = ({ assistant, updateAssistant, updateA
}
}
const onAddCustomParameter = () => {
const newParam = { name: '', value: '', type: 'string' as const }
const newParams = [...customParameters, newParam]
setCustomParameters(newParams)
updateAssistantSettings({ customParameters: newParams })
}
const onUpdateCustomParameter = (
index: number,
field: 'name' | 'value' | 'type',
value: string | number | boolean
) => {
const newParams = [...customParameters]
if (field === 'type') {
let defaultValue: any = ''
switch (value) {
case 'number':
defaultValue = 0
break
case 'boolean':
defaultValue = false
break
default:
defaultValue = ''
}
newParams[index] = {
...newParams[index],
type: value as any,
value: defaultValue
}
} else {
newParams[index] = { ...newParams[index], [field]: value }
}
setCustomParameters(newParams)
updateAssistantSettings({ customParameters: newParams })
}
const renderParameterValueInput = (param: (typeof customParameters)[0], index: number) => {
switch (param.type) {
case 'number':
return (
<InputNumber
style={{ width: '100%' }}
value={param.value as number}
onChange={(value) => onUpdateCustomParameter(index, 'value', value || 0)}
step={0.01}
/>
)
case 'boolean':
return (
<Switch
checked={param.value as boolean}
onChange={(checked) => onUpdateCustomParameter(index, 'value', checked)}
/>
)
default:
return (
<Input
value={param.value as string}
onChange={(e) => onUpdateCustomParameter(index, 'value', e.target.value)}
/>
)
}
}
const onDeleteCustomParameter = (index: number) => {
const newParams = customParameters.filter((_, i) => i !== index)
setCustomParameters(newParams)
updateAssistantSettings({ customParameters: newParams })
}
const onReset = () => {
setTemperature(DEFAULT_TEMPERATURE)
setContextCount(DEFAULT_CONTEXTCOUNT)
@@ -59,13 +136,15 @@ const AssistantModelSettings: FC<Props> = ({ assistant, updateAssistant, updateA
setMaxTokens(0)
setStreamOutput(true)
setTopP(1)
setCustomParameters([])
updateAssistantSettings({
temperature: DEFAULT_TEMPERATURE,
contextCount: DEFAULT_CONTEXTCOUNT,
enableMaxTokens: false,
maxTokens: 0,
streamOutput: true,
topP: 1
topP: 1,
customParameters: []
})
}
@@ -126,14 +205,14 @@ const AssistantModelSettings: FC<Props> = ({ assistant, updateAssistant, updateA
onChangeComplete={onTemperatureChange}
value={typeof temperature === 'number' ? temperature : 0}
marks={{ 0: '0', 0.7: '0.7', 2: '2' }}
step={0.1}
step={0.01}
/>
</Col>
<Col span={3}>
<InputNumber
min={0}
max={2}
step={0.1}
step={0.01}
value={temperature}
onChange={onTemperatureChange}
style={{ width: '100%' }}
@@ -155,7 +234,7 @@ const AssistantModelSettings: FC<Props> = ({ assistant, updateAssistant, updateA
onChangeComplete={onTopPChange}
value={typeof topP === 'number' ? topP : 1}
marks={{ 0: '0', 1: '1' }}
step={0.1}
step={0.01}
/>
</Col>
<Col span={3}>
@@ -250,6 +329,38 @@ const AssistantModelSettings: FC<Props> = ({ assistant, updateAssistant, updateA
}}
/>
</SettingRow>
<Divider style={{ margin: '10px 0' }} />
<SettingRow style={{ minHeight: 30 }}>
<Label>{t('models.custom_parameters')}</Label>
<Button icon={<PlusOutlined />} onClick={onAddCustomParameter}>
{t('models.add_parameter')}
</Button>
</SettingRow>
{customParameters.map((param, index) => (
<Row key={index} align="middle" gutter={10} style={{ marginTop: 10 }}>
<Col span={6}>
<Input
placeholder={t('models.parameter_name')}
value={param.name}
onChange={(e) => onUpdateCustomParameter(index, 'name', e.target.value)}
/>
</Col>
<Col span={4}>
<Select
value={param.type}
onChange={(value) => onUpdateCustomParameter(index, 'type', value)}
style={{ width: '100%' }}>
<Select.Option value="string">{t('models.parameter_type.string')}</Select.Option>
<Select.Option value="number">{t('models.parameter_type.number')}</Select.Option>
<Select.Option value="boolean">{t('models.parameter_type.boolean')}</Select.Option>
</Select>
</Col>
<Col span={11}>{renderParameterValueInput(param, index)}</Col>
<Col span={3}>
<Button icon={<DeleteOutlined />} onClick={() => onDeleteCustomParameter(index)} danger />
</Col>
</Row>
))}
<Divider style={{ margin: '15px 0' }} />
<HStack justifyContent="flex-end">
<Button onClick={onReset} style={{ width: 80 }} danger type="primary">

View File

@@ -1,3 +1,4 @@
import { Box, HStack } from '@renderer/components/Layout'
import { Assistant, AssistantSettings } from '@renderer/types'
import { Button, Input } from 'antd'
import TextArea from 'antd/es/input/TextArea'
@@ -5,8 +6,6 @@ import { useState } from 'react'
import { useTranslation } from 'react-i18next'
import styled from 'styled-components'
import { Box, HStack } from '../Layout'
interface Props {
assistant: Assistant
updateAssistant: (assistant: Assistant) => void

View File

@@ -1,3 +1,5 @@
import { HStack } from '@renderer/components/Layout'
import { TopView } from '@renderer/components/TopView'
import { useAgent } from '@renderer/hooks/useAgents'
import { useAssistant } from '@renderer/hooks/useAssistant'
import { Assistant } from '@renderer/types'
@@ -6,8 +8,6 @@ import { useState } from 'react'
import { useTranslation } from 'react-i18next'
import styled from 'styled-components'
import { HStack } from '../Layout'
import { TopView } from '../TopView'
import AssistantMessagesSettings from './AssistantMessagesSettings'
import AssistantModelSettings from './AssistantModelSettings'
import AssistantPromptSettings from './AssistantPromptSettings'

View File

@@ -1,7 +1,7 @@
import { FolderOpenOutlined, SaveOutlined } from '@ant-design/icons'
import { HStack } from '@renderer/components/Layout'
import { useSettings } from '@renderer/hooks/useSettings'
import { backupToWebdav, restoreFromWebdav } from '@renderer/services/BackupService'
import { backupToWebdav, restoreFromWebdav, startAutoSync, stopAutoSync } from '@renderer/services/BackupService'
import { useAppDispatch } from '@renderer/store'
import {
setWebdavAutoSync,
@@ -66,6 +66,11 @@ const WebDavSettings: FC = () => {
const onToggleAutoSync = (checked: boolean) => {
dispatch(setWebdavAutoSync(checked))
if (checked) {
startAutoSync()
} else {
stopAutoSync()
}
}
const onSyncIntervalChange = (value: number) => {

View File

@@ -4,12 +4,13 @@ import { useSettings } from '@renderer/hooks/useSettings'
import { useAppDispatch } from '@renderer/store'
import {
setClickAssistantToShowTopic,
setCustomCss,
setShowFilesIcon,
setShowMinappIcon,
setShowTopicTime
} from '@renderer/store/settings'
import { ThemeMode } from '@renderer/types'
import { Select, Switch } from 'antd'
import { Input, Select, Switch } from 'antd'
import { FC } from 'react'
import { useTranslation } from 'react-i18next'
@@ -26,7 +27,8 @@ const DisplaySettings: FC = () => {
topicPosition,
setTopicPosition,
clickAssistantToShowTopic,
showTopicTime
showTopicTime,
customCss
} = useSettings()
const { theme: themeMode } = useTheme()
@@ -111,6 +113,19 @@ const DisplaySettings: FC = () => {
<Switch checked={showFilesIcon} onChange={(value) => dispatch(setShowFilesIcon(value))} />
</SettingRow>
</SettingGroup>
<SettingGroup theme={theme}>
<SettingTitle>{t('settings.display.custom.css')}</SettingTitle>
<SettingDivider />
<Input.TextArea
defaultValue={customCss}
onBlur={(e) => dispatch(setCustomCss(e.target.value))}
placeholder={t('settings.display.custom.css.placeholder')}
style={{
minHeight: 200,
fontFamily: 'monospace'
}}
/>
</SettingGroup>
</SettingContainer>
)
}

View File

@@ -116,14 +116,14 @@ const AssistantSettings: FC = () => {
onChangeComplete={onTemperatureChange}
value={typeof temperature === 'number' ? temperature : 0}
marks={{ 0: '0', 0.7: '0.7', 2: '2' }}
step={0.1}
step={0.01}
/>
</Col>
<Col span={3}>
<InputNumber
min={0}
max={2}
step={0.1}
step={0.01}
value={temperature}
onChange={onTemperatureChange}
style={{ width: '100%' }}
@@ -145,7 +145,7 @@ const AssistantSettings: FC = () => {
onChangeComplete={onTopPChange}
value={typeof topP === 'number' ? topP : 1}
marks={{ 0: '0', 0.5: '0.5', 1: '1' }}
step={0.1}
step={0.01}
/>
</Col>
<Col span={3}>

View File

@@ -1,8 +1,8 @@
import { HStack } from '@renderer/components/Layout'
import { useSettings } from '@renderer/hooks/useSettings'
import { useAppDispatch } from '@renderer/store'
import { setEnableTopicNaming } from '@renderer/store/settings'
import { Divider, Modal, Switch } from 'antd'
import { setEnableTopicNaming, setTopicNamingPrompt } from '@renderer/store/settings'
import { Button, Divider, Input, Modal, Switch } from 'antd'
import { useState } from 'react'
import { useTranslation } from 'react-i18next'
@@ -15,7 +15,7 @@ interface Props {
const PopupContainer: React.FC<Props> = ({ resolve }) => {
const [open, setOpen] = useState(true)
const { t } = useTranslation()
const { enableTopicNaming } = useSettings()
const { enableTopicNaming, topicNamingPrompt } = useSettings()
const dispatch = useAppDispatch()
const onOk = () => {
@@ -30,6 +30,10 @@ const PopupContainer: React.FC<Props> = ({ resolve }) => {
resolve({})
}
const handleReset = () => {
dispatch(setTopicNamingPrompt(''))
}
TopicNamingModalPopup.hide = onCancel
return (
@@ -47,6 +51,21 @@ const PopupContainer: React.FC<Props> = ({ resolve }) => {
<div>{t('settings.models.enable_topic_naming')}</div>
<Switch checked={enableTopicNaming} onChange={(v) => dispatch(setEnableTopicNaming(v))} />
</HStack>
<Divider style={{ margin: '10px 0' }} />
<div style={{ marginBottom: 20 }}>
<div style={{ marginBottom: 10 }}>{t('settings.models.topic_naming_prompt')}</div>
<Input.TextArea
rows={4}
value={topicNamingPrompt || t('prompts.summarize')}
onChange={(e) => dispatch(setTopicNamingPrompt(e.target.value.trim()))}
placeholder={t('prompts.summarize')}
/>
{topicNamingPrompt && (
<Button style={{ marginTop: 10 }} onClick={handleReset}>
{t('common.reset')}
</Button>
)}
</div>
</Modal>
)
}

View File

@@ -7,7 +7,7 @@ import { useProvider } from '@renderer/hooks/useProvider'
import { fetchModels } from '@renderer/services/ApiService'
import { Model, Provider } from '@renderer/types'
import { getDefaultGroupName, isFreeModel, runAsyncFunction } from '@renderer/utils'
import { Avatar, Button, Empty, Flex, Modal, Popover, Radio, Tag } from 'antd'
import { Avatar, Button, Empty, Flex, Modal, Popover, Radio, Tag, Tooltip } from 'antd'
import Search from 'antd/es/input/Search'
import { groupBy, isEmpty, uniqBy } from 'lodash'
import { useEffect, useState } from 'react'
@@ -153,7 +153,9 @@ const PopupContainer: React.FC<Props> = ({ provider: _provider, resolve }) => {
{model.name[0].toUpperCase()}
</Avatar>
<ListItemName>
{model.name}
<Tooltip title={model.id} placement="top">
<span style={{ cursor: 'help' }}>{model.name}</span>
</Tooltip>
{isVisionModel(model) && <VisionIcon />}
{isWebSearchModel(model) && <WebSearchIcon />}
{isFreeModel(model) && (
@@ -196,9 +198,9 @@ const PopupContainer: React.FC<Props> = ({ provider: _provider, resolve }) => {
const SearchContainer = styled.div`
display: flex;
flex-direction: column;
gap: 12px;
gap: 15px;
padding: 0 22px;
padding-bottom: 20px;
padding-bottom: 10px;
margin-top: -10px;
.ant-radio-group {

View File

@@ -2,7 +2,8 @@ import Anthropic from '@anthropic-ai/sdk'
import { MessageCreateParamsNonStreaming, MessageParam } from '@anthropic-ai/sdk/resources'
import { DEFAULT_MAX_TOKENS } from '@renderer/config/constant'
import { isEmbeddingModel } from '@renderer/config/models'
import { SUMMARIZE_PROMPT } from '@renderer/config/prompts'
import { getStoreSetting } from '@renderer/hooks/useSettings'
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'
@@ -86,7 +87,8 @@ export default class AnthropicProvider extends BaseProvider {
max_tokens: maxTokens || DEFAULT_MAX_TOKENS,
temperature: assistant?.settings?.temperature,
top_p: assistant?.settings?.topP,
system: assistant.prompt
system: assistant.prompt,
...this.getCustomParameters(assistant)
}
let time_first_token_millsec = 0
@@ -188,7 +190,7 @@ export default class AnthropicProvider extends BaseProvider {
const systemMessage = {
role: 'system',
content: SUMMARIZE_PROMPT
content: (getStoreSetting('topicNamingPrompt') as string) || i18n.t('prompts.summarize')
}
const userMessage = {

View File

@@ -98,4 +98,16 @@ export default abstract class BaseProvider {
return REFERENCE_PROMPT.replace('{question}', message.content).replace('{references}', references)
}
protected getCustomParameters(assistant: Assistant) {
return (
assistant?.settings?.customParameters?.reduce(
(acc, param) => ({
...acc,
[param.name]: param.value
}),
{}
) || {}
)
}
}

View File

@@ -9,7 +9,8 @@ import {
TextPart
} from '@google/generative-ai'
import { isEmbeddingModel, isWebSearchModel } from '@renderer/config/models'
import { SUMMARIZE_PROMPT } from '@renderer/config/prompts'
import { getStoreSetting } from '@renderer/hooks/useSettings'
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'
@@ -95,7 +96,8 @@ export default class GeminiProvider extends BaseProvider {
generationConfig: {
maxOutputTokens: maxTokens,
temperature: assistant?.settings?.temperature,
topP: assistant?.settings?.topP
topP: assistant?.settings?.topP,
...this.getCustomParameters(assistant)
},
safetySettings: [
{ category: HarmCategory.HARM_CATEGORY_HATE_SPEECH, threshold: HarmBlockThreshold.BLOCK_NONE },
@@ -198,7 +200,7 @@ export default class GeminiProvider extends BaseProvider {
const systemMessage = {
role: 'system',
content: SUMMARIZE_PROMPT
content: (getStoreSetting('topicNamingPrompt') as string) || i18n.t('prompts.summarize')
}
const userMessage = {

View File

@@ -1,8 +1,11 @@
import { isEmbeddingModel, isSupportedModel, isVisionModel } from '@renderer/config/models'
import { SUMMARIZE_PROMPT } from '@renderer/config/prompts'
import { getStoreSetting } from '@renderer/hooks/useSettings'
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'
@@ -10,7 +13,8 @@ import OpenAI, { AzureOpenAI } from 'openai'
import {
ChatCompletionContentPart,
ChatCompletionCreateParamsNonStreaming,
ChatCompletionMessageParam
ChatCompletionMessageParam,
ChatCompletionTool
} from 'openai/resources'
import { CompletionsParams } from '.'
@@ -41,7 +45,7 @@ export default class OpenAIProvider extends BaseProvider {
}
private get isNotSupportFiles() {
const providers = ['deepseek', 'baichuan', 'minimax', 'doubao']
const providers = ['deepseek', 'baichuan', 'minimax']
return providers.includes(this.provider.id)
}
@@ -132,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()
@@ -147,11 +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,
@@ -219,7 +239,7 @@ export default class OpenAIProvider extends BaseProvider {
const systemMessage = {
role: 'system',
content: SUMMARIZE_PROMPT
content: getStoreSetting('topicNamingPrompt') || i18n.t('prompts.summarize')
}
const userMessage = {

View File

@@ -7,44 +7,10 @@ import { KnowledgeItem } from '@renderer/types'
class KnowledgeQueue {
private processing: Map<string, boolean> = new Map()
private pollingInterval: NodeJS.Timeout | null = null
// private readonly POLLING_INTERVAL = 5000
private readonly MAX_RETRIES = 2
private readonly MAX_RETRIES = 1
constructor() {
this.checkAllBases().catch(console.error)
this.startPolling()
}
private startPolling(): void {
if (this.pollingInterval) return
const state = store.getState()
state.knowledge.bases.forEach((base) => {
base.items.forEach((item) => {
if (item.processingStatus === 'processing') {
store.dispatch(
updateItemProcessingStatus({
baseId: base.id,
itemId: item.id,
status: 'pending',
progress: 0
})
)
}
})
})
// this.pollingInterval = setInterval(() => {
// this.checkAllBases()
// }, this.POLLING_INTERVAL)
}
private stopPolling(): void {
if (this.pollingInterval) {
clearInterval(this.pollingInterval)
this.pollingInterval = null
}
}
public async checkAllBases(): Promise<void> {
@@ -111,7 +77,6 @@ class KnowledgeQueue {
}
stopAllProcessing(): void {
this.stopPolling()
for (const baseId of this.processing.keys()) {
this.processing.set(baseId, false)
}

View File

@@ -100,7 +100,8 @@ export const getAssistantSettings = (assistant: Assistant): AssistantSettings =>
maxTokens: getAssistantMaxTokens(),
streamOutput: assistant?.settings?.streamOutput ?? true,
hideMessages: assistant?.settings?.hideMessages ?? false,
autoResetModel: assistant?.settings?.autoResetModel ?? false
autoResetModel: assistant?.settings?.autoResetModel ?? false,
customParameters: assistant?.settings?.customParameters ?? []
}
}

View File

@@ -59,6 +59,10 @@ export async function reset() {
// 备份到 webdav
export async function backupToWebdav({ showMessage = true }: { showMessage?: boolean } = {}) {
if (isManualBackupRunning) {
console.log('[Backup] Manual backup already in progress')
return
}
const { webdavHost, webdavUser, webdavPass, webdavPath } = store.getState().settings
const backupData = await getBackupData()
@@ -83,6 +87,8 @@ export async function backupToWebdav({ showMessage = true }: { showMessage?: boo
title: i18n.t('message.backup.failed'),
content: error.message
})
} finally {
isManualBackupRunning = false
}
}
@@ -109,40 +115,69 @@ export async function restoreFromWebdav() {
}
}
let syncInterval: NodeJS.Timeout | null = null
export function startAutoSync() {
const { webdavAutoSync, webdavHost, webdavSyncInterval } = store.getState().settings
let autoSyncStarted = false
let syncTimeout: NodeJS.Timeout | null = null
let isAutoBackupRunning = false
let isManualBackupRunning = false
if (syncInterval) {
stopAutoSync()
export function startAutoSync() {
if (autoSyncStarted) {
return
}
if (webdavAutoSync && webdavHost) {
console.log('[AutoSync] Starting auto sync with interval:', webdavSyncInterval, 'minutes')
const { webdavAutoSync, webdavHost, webdavSyncInterval } = store.getState().settings
const performBackup = async () => {
try {
console.log('[AutoSync] Performing backup...')
await backupToWebdav({ showMessage: false })
window.message.success({ content: i18n.t('message.backup.success'), key: 'webdav-sync' })
} catch (error) {
console.error('[AutoSync] Backup failed:', error)
window.message.error({ content: i18n.t('message.backup.failed'), key: 'webdav-sync' })
}
if (!webdavAutoSync || !webdavHost || webdavSyncInterval <= 0) {
console.log('[AutoSync] Invalid sync settings, auto sync disabled')
return
}
autoSyncStarted = true
stopAutoSync()
scheduleNextBackup()
function scheduleNextBackup() {
if (syncTimeout) {
clearTimeout(syncTimeout)
syncTimeout = null
}
syncInterval = setInterval(performBackup, webdavSyncInterval * 60 * 1000)
syncTimeout = setTimeout(performAutoBackup, webdavSyncInterval * 60 * 1000)
console.log(`[AutoSync] Next sync scheduled in ${webdavSyncInterval} minutes`)
}
console.log(`[AutoSync] Sync interval set up: ${webdavSyncInterval} minutes`)
async function performAutoBackup() {
if (isAutoBackupRunning || isManualBackupRunning) {
console.log('[AutoSync] Backup already in progress, rescheduling')
scheduleNextBackup()
return
}
isAutoBackupRunning = true
try {
console.log('[AutoSync] Performing auto backup...')
await backupToWebdav({ showMessage: false })
window.message.success({ content: i18n.t('message.backup.success'), key: 'webdav-auto-sync' })
} catch (error) {
console.error('[AutoSync] Auto backup failed:', error)
window.message.error({ content: i18n.t('message.backup.failed'), key: 'webdav-auto-sync' })
} finally {
isAutoBackupRunning = false
scheduleNextBackup()
}
}
}
export function stopAutoSync() {
if (syncInterval) {
if (syncTimeout) {
console.log('[AutoSync] Stopping auto sync')
clearInterval(syncInterval)
syncInterval = null
clearTimeout(syncTimeout)
syncTimeout = null
}
isAutoBackupRunning = false
autoSyncStarted = false
}
async function getBackupData() {

View File

@@ -20,5 +20,6 @@ export const EVENT_NAMES = {
NEW_BRANCH: 'NEW_BRANCH',
EXPORT_TOPIC_IMAGE: 'EXPORT_TOPIC_IMAGE',
LOCATE_MESSAGE: 'LOCATE_MESSAGE',
ADD_NEW_TOPIC: 'ADD_NEW_TOPIC'
ADD_NEW_TOPIC: 'ADD_NEW_TOPIC',
RESEND_MESSAGE: 'RESEND_MESSAGE'
}

View File

@@ -25,6 +25,7 @@ export const getKnowledgeBaseParams = (base: KnowledgeBase): KnowledgeBaseParams
model: base.model.id,
dimensions: base.dimensions,
apiKey: aiProvider.getApiKey(),
apiVersion: provider.apiVersion,
baseURL: host
}
}

View File

@@ -28,7 +28,7 @@ const persistedReducer = persistReducer(
{
key: 'cherry-studio',
storage,
version: 49,
version: 51,
blacklist: ['runtime'],
migrate
},

View File

@@ -304,15 +304,16 @@ const initialState: LlmState = {
isSystem: true,
enabled: false
},
// {
// id: 'jina',
// name: 'Jina',
// apiKey: '',
// apiHost: 'https://api.jina.ai',
// models: SYSTEM_MODELS.jina,
// isSystem: true,
// enabled: false
// },
{
id: 'jina',
name: 'Jina',
type: 'openai',
apiKey: '',
apiHost: 'https://api.jina.ai',
models: SYSTEM_MODELS.jina,
isSystem: true,
enabled: false
},
{
id: 'aihubmix',
name: 'AiHubMix',

View File

@@ -659,15 +659,6 @@ const migrateConfig = {
isSystem: true,
enabled: false
}
// {
// id: 'jina',
// name: 'Jina',
// apiKey: '',
// apiHost: 'https://api.jina.ai',
// models: SYSTEM_MODELS.jina,
// isSystem: true,
// enabled: false
// }
]
}
}
@@ -767,6 +758,23 @@ const migrateConfig = {
]
}
return state
},
'50': (state: RootState) => {
state.llm.providers.push({
id: 'jina',
name: 'Jina',
type: 'openai',
apiKey: '',
apiHost: 'https://api.jina.ai',
models: SYSTEM_MODELS.jina,
isSystem: true,
enabled: false
})
return state
},
'51': (state: RootState) => {
state.settings.topicNamingPrompt = ''
return state
}
}

View File

@@ -44,6 +44,8 @@ export interface SettingsState {
// Sidebar icons
showMinappIcon: boolean
showFilesIcon: boolean
customCss: string
topicNamingPrompt: string
}
const initialState: SettingsState = {
@@ -83,7 +85,9 @@ const initialState: SettingsState = {
autoTranslateWithSpace: false,
enableTopicNaming: true,
showMinappIcon: true,
showFilesIcon: true
showFilesIcon: true,
customCss: '',
topicNamingPrompt: ''
}
const settingsSlice = createSlice({
@@ -207,6 +211,12 @@ const settingsSlice = createSlice({
},
setPasteLongTextThreshold: (state, action: PayloadAction<number>) => {
state.pasteLongTextThreshold = action.payload
},
setCustomCss: (state, action: PayloadAction<string>) => {
state.customCss = action.payload
},
setTopicNamingPrompt: (state, action: PayloadAction<string>) => {
state.topicNamingPrompt = action.payload
}
}
})
@@ -250,7 +260,9 @@ export const {
setEnableTopicNaming,
setShowMinappIcon,
setShowFilesIcon,
setPasteLongTextThreshold
setPasteLongTextThreshold,
setCustomCss,
setTopicNamingPrompt
} = settingsSlice.actions
export default settingsSlice.reducer

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

@@ -30,6 +30,11 @@ export type AssistantSettings = {
streamOutput: boolean
hideMessages: boolean
autoResetModel: boolean
customParameters?: {
name: string
value: string | number | boolean
type: 'string' | 'number' | 'boolean'
}[]
}
export type Agent = Omit<Assistant, 'model'>
@@ -216,5 +221,6 @@ export type KnowledgeBaseParams = {
model: string
dimensions: number
apiKey: string
apiVersion?: string
baseURL: string
}

433
yarn.lock
View File

@@ -31,9 +31,9 @@ __metadata:
languageName: node
linkType: hard
"@ant-design/cssinjs-utils@npm:^1.0.3":
version: 1.0.3
resolution: "@ant-design/cssinjs-utils@npm:1.0.3"
"@ant-design/cssinjs-utils@npm:^1.1.3":
version: 1.1.3
resolution: "@ant-design/cssinjs-utils@npm:1.1.3"
dependencies:
"@ant-design/cssinjs": "npm:^1.21.0"
"@babel/runtime": "npm:^7.23.2"
@@ -41,7 +41,7 @@ __metadata:
peerDependencies:
react: ">=16.9.0"
react-dom: ">=16.9.0"
checksum: 10c0/928909125ec88c631577d1ecfdad652e8c1ca948a474605feda0dcd83127d1c401b1c0ec29847062b02f0f6f55d6ff6e22bb82a7c89550c10b21c0192d2065df
checksum: 10c0/e8a443a613689c4e984f5cf44b799f6288a6debf9a35cafb27a0411ef77ae335ba5ace7a38efd8e04f04ac897ddf24c81f0ad6615ac586f2616cb7f2b72f6176
languageName: node
linkType: hard
@@ -63,6 +63,24 @@ __metadata:
languageName: node
linkType: hard
"@ant-design/cssinjs@npm:^1.21.1":
version: 1.22.1
resolution: "@ant-design/cssinjs@npm:1.22.1"
dependencies:
"@babel/runtime": "npm:^7.11.1"
"@emotion/hash": "npm:^0.8.0"
"@emotion/unitless": "npm:^0.7.5"
classnames: "npm:^2.3.1"
csstype: "npm:^3.1.3"
rc-util: "npm:^5.35.0"
stylis: "npm:^4.3.4"
peerDependencies:
react: ">=16.0.0"
react-dom: ">=16.0.0"
checksum: 10c0/2c97d6ed9e701232b9c86c8139ef0c2760552c8a257bf85d03dadc057d945ec93b7a9946b06aecfe7ad5e28763ac4ca00765a4338ac4f4526b9b1c37da6d1a36
languageName: node
linkType: hard
"@ant-design/fast-color@npm:^2.0.6":
version: 2.0.6
resolution: "@ant-design/fast-color@npm:2.0.6"
@@ -79,9 +97,9 @@ __metadata:
languageName: node
linkType: hard
"@ant-design/icons@npm:^5.4.0":
version: 5.4.0
resolution: "@ant-design/icons@npm:5.4.0"
"@ant-design/icons@npm:^5.5.2":
version: 5.5.2
resolution: "@ant-design/icons@npm:5.5.2"
dependencies:
"@ant-design/colors": "npm:^7.0.0"
"@ant-design/icons-svg": "npm:^4.4.0"
@@ -91,7 +109,7 @@ __metadata:
peerDependencies:
react: ">=16.0.0"
react-dom: ">=16.0.0"
checksum: 10c0/fcd310c0f9b88d716cbb7c450e6e7b40b0686e3c902e8c50f117492a1677c6a98f2f9bef55ff7e1ee997e19d5d81959379c1a6bb4fd2412365b252e3e92b9456
checksum: 10c0/e7003113dc872880d5a6f9cd05dcfabb0d6486cd9dedb687821f3b1ed91505c9550653554a0dafca121ac340167e37a70ec27e89d4931347625be6f732a79c32
languageName: node
linkType: hard
@@ -330,7 +348,7 @@ __metadata:
languageName: node
linkType: hard
"@babel/runtime@npm:^7.10.1, @babel/runtime@npm:^7.10.4, @babel/runtime@npm:^7.11.1, @babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.12.1, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.16.7, @babel/runtime@npm:^7.18.0, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.20.0, @babel/runtime@npm:^7.20.7, @babel/runtime@npm:^7.21.0, @babel/runtime@npm:^7.22.5, @babel/runtime@npm:^7.23.2, @babel/runtime@npm:^7.23.6, @babel/runtime@npm:^7.23.9, @babel/runtime@npm:^7.24.1, @babel/runtime@npm:^7.24.4, @babel/runtime@npm:^7.24.7, @babel/runtime@npm:^7.24.8, @babel/runtime@npm:^7.7.2, @babel/runtime@npm:^7.9.2":
"@babel/runtime@npm:^7.10.1, @babel/runtime@npm:^7.10.4, @babel/runtime@npm:^7.11.1, @babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.12.1, @babel/runtime@npm:^7.16.7, @babel/runtime@npm:^7.18.0, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.20.0, @babel/runtime@npm:^7.20.7, @babel/runtime@npm:^7.21.0, @babel/runtime@npm:^7.22.5, @babel/runtime@npm:^7.23.2, @babel/runtime@npm:^7.23.6, @babel/runtime@npm:^7.23.9, @babel/runtime@npm:^7.24.1, @babel/runtime@npm:^7.24.4, @babel/runtime@npm:^7.24.7, @babel/runtime@npm:^7.24.8, @babel/runtime@npm:^7.7.2, @babel/runtime@npm:^7.9.2":
version: 7.25.6
resolution: "@babel/runtime@npm:7.25.6"
dependencies:
@@ -339,6 +357,15 @@ __metadata:
languageName: node
linkType: hard
"@babel/runtime@npm:^7.25.7":
version: 7.26.0
resolution: "@babel/runtime@npm:7.26.0"
dependencies:
regenerator-runtime: "npm:^0.14.0"
checksum: 10c0/12c01357e0345f89f4f7e8c0e81921f2a3e3e101f06e8eaa18a382b517376520cd2fa8c237726eb094dab25532855df28a7baaf1c26342b52782f6936b07c287
languageName: node
linkType: hard
"@babel/template@npm:^7.25.0":
version: 7.25.0
resolution: "@babel/template@npm:7.25.0"
@@ -1907,7 +1934,7 @@ __metadata:
languageName: node
linkType: hard
"@rc-component/trigger@npm:^2.0.0, @rc-component/trigger@npm:^2.1.1, @rc-component/trigger@npm:^2.2.2":
"@rc-component/trigger@npm:^2.0.0, @rc-component/trigger@npm:^2.1.1":
version: 2.2.3
resolution: "@rc-component/trigger@npm:2.2.3"
dependencies:
@@ -1924,6 +1951,23 @@ __metadata:
languageName: node
linkType: hard
"@rc-component/trigger@npm:^2.2.6":
version: 2.2.6
resolution: "@rc-component/trigger@npm:2.2.6"
dependencies:
"@babel/runtime": "npm:^7.23.2"
"@rc-component/portal": "npm:^1.1.0"
classnames: "npm:^2.3.2"
rc-motion: "npm:^2.0.0"
rc-resize-observer: "npm:^1.3.1"
rc-util: "npm:^5.44.0"
peerDependencies:
react: ">=16.9.0"
react-dom: ">=16.9.0"
checksum: 10c0/e7ef14099fac74a58301ccf65a003ddaefb6f2a410c950c8354e0d63fd13e21e3a1f32dd4e73a11c7c0c6199e66629f7f3e31c09d887198b974d35805c4de8e1
languageName: node
linkType: hard
"@reduxjs/toolkit@npm:^2.2.5":
version: 2.2.7
resolution: "@reduxjs/toolkit@npm:2.2.7"
@@ -2821,9 +2865,9 @@ __metadata:
"@types/tinycolor2": "npm:^1"
"@vitejs/plugin-react": "npm:^4.2.1"
adm-zip: "npm:^0.5.16"
antd: "npm:^5.18.3"
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"
@@ -3073,63 +3117,63 @@ __metadata:
languageName: node
linkType: hard
"antd@npm:^5.18.3":
version: 5.20.6
resolution: "antd@npm:5.20.6"
"antd@npm:^5.22.5":
version: 5.22.6
resolution: "antd@npm:5.22.6"
dependencies:
"@ant-design/colors": "npm:^7.1.0"
"@ant-design/cssinjs": "npm:^1.21.0"
"@ant-design/cssinjs-utils": "npm:^1.0.3"
"@ant-design/icons": "npm:^5.4.0"
"@ant-design/cssinjs": "npm:^1.21.1"
"@ant-design/cssinjs-utils": "npm:^1.1.3"
"@ant-design/icons": "npm:^5.5.2"
"@ant-design/react-slick": "npm:~1.1.2"
"@babel/runtime": "npm:^7.24.8"
"@babel/runtime": "npm:^7.25.7"
"@ctrl/tinycolor": "npm:^3.6.1"
"@rc-component/color-picker": "npm:~2.0.1"
"@rc-component/mutate-observer": "npm:^1.1.0"
"@rc-component/qrcode": "npm:~1.0.0"
"@rc-component/tour": "npm:~1.15.1"
"@rc-component/trigger": "npm:^2.2.2"
"@rc-component/trigger": "npm:^2.2.6"
classnames: "npm:^2.5.1"
copy-to-clipboard: "npm:^3.3.3"
dayjs: "npm:^1.11.11"
rc-cascader: "npm:~3.28.1"
rc-cascader: "npm:~3.30.0"
rc-checkbox: "npm:~3.3.0"
rc-collapse: "npm:~3.7.3"
rc-dialog: "npm:~9.5.2"
rc-collapse: "npm:~3.9.0"
rc-dialog: "npm:~9.6.0"
rc-drawer: "npm:~7.2.0"
rc-dropdown: "npm:~4.2.0"
rc-field-form: "npm:~2.4.0"
rc-image: "npm:~7.9.0"
rc-input: "npm:~1.6.3"
rc-input-number: "npm:~9.2.0"
rc-mentions: "npm:~2.15.0"
rc-menu: "npm:~9.14.1"
rc-motion: "npm:^2.9.2"
rc-notification: "npm:~5.6.0"
rc-pagination: "npm:~4.2.0"
rc-picker: "npm:~4.6.14"
rc-dropdown: "npm:~4.2.1"
rc-field-form: "npm:~2.7.0"
rc-image: "npm:~7.11.0"
rc-input: "npm:~1.6.4"
rc-input-number: "npm:~9.3.0"
rc-mentions: "npm:~2.17.0"
rc-menu: "npm:~9.16.0"
rc-motion: "npm:^2.9.5"
rc-notification: "npm:~5.6.2"
rc-pagination: "npm:~5.0.0"
rc-picker: "npm:~4.8.3"
rc-progress: "npm:~4.0.0"
rc-rate: "npm:~2.13.0"
rc-resize-observer: "npm:^1.4.0"
rc-segmented: "npm:~2.3.0"
rc-select: "npm:~14.15.2"
rc-slider: "npm:~11.1.5"
rc-resize-observer: "npm:^1.4.3"
rc-segmented: "npm:~2.5.0"
rc-select: "npm:~14.16.4"
rc-slider: "npm:~11.1.7"
rc-steps: "npm:~6.0.1"
rc-switch: "npm:~4.1.0"
rc-table: "npm:~7.45.7"
rc-tabs: "npm:~15.1.1"
rc-textarea: "npm:~1.8.1"
rc-tooltip: "npm:~6.2.0"
rc-tree: "npm:~5.9.0"
rc-tree-select: "npm:~5.23.0"
rc-upload: "npm:~4.7.0"
rc-util: "npm:^5.43.0"
rc-table: "npm:~7.49.0"
rc-tabs: "npm:~15.4.0"
rc-textarea: "npm:~1.8.2"
rc-tooltip: "npm:~6.2.1"
rc-tree: "npm:~5.10.1"
rc-tree-select: "npm:~5.24.5"
rc-upload: "npm:~4.8.1"
rc-util: "npm:^5.44.2"
scroll-into-view-if-needed: "npm:^3.1.0"
throttle-debounce: "npm:^5.0.2"
peerDependencies:
react: ">=16.9.0"
react-dom: ">=16.9.0"
checksum: 10c0/b1aae736c68e443fcf5e0903089fb652f4add5c9400aab1d99a27693c1a683a6d9a6567cce717f1200c56a80e57ce0e408c9beac0d3a6b58fa7de4f858ca6f06
checksum: 10c0/32d3b3a6e58939dee7e1d4ab139a3d5770bca43b1054279671fe91c1196631b5a99f5a4c6f92e70757542e6586486405b5b6b26c7daee3ff7eae141e0f095596
languageName: node
linkType: hard
@@ -3297,13 +3341,6 @@ __metadata:
languageName: node
linkType: hard
"array-tree-filter@npm:^2.1.0":
version: 2.1.0
resolution: "array-tree-filter@npm:2.1.0"
checksum: 10c0/6fd1677522b20d10fd918e446db40c3e313eac9ed77ca8a5ea45f43b69c40300655c69760c159fd2cd189985323231a5077858c59fa3ca9c6c2439635eb8557e
languageName: node
linkType: hard
"array-union@npm:^2.1.0":
version: 2.1.0
resolution: "array-union@npm:2.1.0"
@@ -3469,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
@@ -10742,20 +10779,19 @@ __metadata:
languageName: node
linkType: hard
"rc-cascader@npm:~3.28.1":
version: 3.28.1
resolution: "rc-cascader@npm:3.28.1"
"rc-cascader@npm:~3.30.0":
version: 3.30.0
resolution: "rc-cascader@npm:3.30.0"
dependencies:
"@babel/runtime": "npm:^7.12.5"
array-tree-filter: "npm:^2.1.0"
"@babel/runtime": "npm:^7.25.7"
classnames: "npm:^2.3.1"
rc-select: "npm:~14.15.0"
rc-tree: "npm:~5.9.0"
rc-util: "npm:^5.37.0"
rc-select: "npm:~14.16.2"
rc-tree: "npm:~5.10.1"
rc-util: "npm:^5.43.0"
peerDependencies:
react: ">=16.9.0"
react-dom: ">=16.9.0"
checksum: 10c0/ffa13db0728d7021e3d0b6586e681c029ca1f112e78f4c2c0b1becd66386ef2e3201d02880e06867dfbc77b75bee624766d7fad95e0a26d204451657fb7d2d76
checksum: 10c0/4cd3c5043eaa53a6cb28fc77934d6b23004f68efe03c247c9b05cee468565592b35d80d6d739514d697c6e41f084d3cf9abd992dde6b2f52b3ac3d35a173b234
languageName: node
linkType: hard
@@ -10773,9 +10809,9 @@ __metadata:
languageName: node
linkType: hard
"rc-collapse@npm:~3.7.3":
version: 3.7.3
resolution: "rc-collapse@npm:3.7.3"
"rc-collapse@npm:~3.9.0":
version: 3.9.0
resolution: "rc-collapse@npm:3.9.0"
dependencies:
"@babel/runtime": "npm:^7.10.1"
classnames: "npm:2.x"
@@ -10784,13 +10820,13 @@ __metadata:
peerDependencies:
react: ">=16.9.0"
react-dom: ">=16.9.0"
checksum: 10c0/6e5ff193eb22e88a21871759e99814837f6c0732fb375f57e5ed3aa94a6253a5337cf5179aa10bfc9930500d536dfa262180f435ea2c41eea4ace4f3b3e148ac
checksum: 10c0/68d2c7a6614fea2bf4a30a39e67d5b74b933fd25e31762cd810ff0f7bcf7e57676db6c3c1389461d5d18be4a68b9cfeda65321a8d1f5978ec2a5aa3d7b9010cc
languageName: node
linkType: hard
"rc-dialog@npm:~9.5.2":
version: 9.5.2
resolution: "rc-dialog@npm:9.5.2"
"rc-dialog@npm:~9.6.0":
version: 9.6.0
resolution: "rc-dialog@npm:9.6.0"
dependencies:
"@babel/runtime": "npm:^7.10.1"
"@rc-component/portal": "npm:^1.0.0-8"
@@ -10800,7 +10836,7 @@ __metadata:
peerDependencies:
react: ">=16.9.0"
react-dom: ">=16.9.0"
checksum: 10c0/e5854b2b99d4336f8c1125f63bb66da6b25959502866fb74c32cede5cad4ee6aa62dba6de79a16082812605193d83d99409f6372b161c2b906e68b9645d7031e
checksum: 10c0/19e9acef746baa25c3167a961919123b0b457288188c18bc4d468ae31144bf750d6d6468dd3be43b376eba42ddda26fef1aac8ae9bd016f5d0428ffee0c615e7
languageName: node
linkType: hard
@@ -10835,9 +10871,24 @@ __metadata:
languageName: node
linkType: hard
"rc-field-form@npm:~2.4.0":
version: 2.4.0
resolution: "rc-field-form@npm:2.4.0"
"rc-dropdown@npm:~4.2.1":
version: 4.2.1
resolution: "rc-dropdown@npm:4.2.1"
dependencies:
"@babel/runtime": "npm:^7.18.3"
"@rc-component/trigger": "npm:^2.0.0"
classnames: "npm:^2.2.6"
rc-util: "npm:^5.44.1"
peerDependencies:
react: ">=16.11.0"
react-dom: ">=16.11.0"
checksum: 10c0/ec980e6c9f8bbba53e895002a0c3a28f294ae07f3ebc6c9a9cb80c7e1bb74ba9f0e0c4b9c23f487fdf8c5a4531000e05b5b43744ef506f0fd869165486768817
languageName: node
linkType: hard
"rc-field-form@npm:~2.7.0":
version: 2.7.0
resolution: "rc-field-form@npm:2.7.0"
dependencies:
"@babel/runtime": "npm:^7.18.0"
"@rc-component/async-validator": "npm:^5.0.3"
@@ -10845,30 +10896,30 @@ __metadata:
peerDependencies:
react: ">=16.9.0"
react-dom: ">=16.9.0"
checksum: 10c0/79365813fb0166c109e81e3bde2c979db26bb97dcc418f6170266f7d5f6f11d25c27938f857a695b6921a16cb43b805f1fd4e9fa73cb2a918618a08fef82fed7
checksum: 10c0/8b5ba3d4ef2680751235797710da822b96225ba1fd1a0098d4c9b7723ac1e0a8eb07c70a6ca216c0b2f8f45f1035f849b924f13c6386e215ec1d854927a504a2
languageName: node
linkType: hard
"rc-image@npm:~7.9.0":
version: 7.9.0
resolution: "rc-image@npm:7.9.0"
"rc-image@npm:~7.11.0":
version: 7.11.0
resolution: "rc-image@npm:7.11.0"
dependencies:
"@babel/runtime": "npm:^7.11.2"
"@rc-component/portal": "npm:^1.0.2"
classnames: "npm:^2.2.6"
rc-dialog: "npm:~9.5.2"
rc-dialog: "npm:~9.6.0"
rc-motion: "npm:^2.6.2"
rc-util: "npm:^5.34.1"
peerDependencies:
react: ">=16.9.0"
react-dom: ">=16.9.0"
checksum: 10c0/fd04b8b66447d6c55f6fb298723582b80e51ddf364d7ae9560431f3f6a11622b97f1870755014d22994fadfbaaa21dda80444eee717409300853c1f65764d5b1
checksum: 10c0/e0350bdfa531bbf4cdc23bb834fe46fee78f10739ef740ae3b880ea4e529674edb60074defcdb651d9b4aab305f0b971b08dd8739cf6409bb28dadcefca20808
languageName: node
linkType: hard
"rc-input-number@npm:~9.2.0":
version: 9.2.0
resolution: "rc-input-number@npm:9.2.0"
"rc-input-number@npm:~9.3.0":
version: 9.3.0
resolution: "rc-input-number@npm:9.3.0"
dependencies:
"@babel/runtime": "npm:^7.10.1"
"@rc-component/mini-decimal": "npm:^1.0.1"
@@ -10878,11 +10929,11 @@ __metadata:
peerDependencies:
react: ">=16.9.0"
react-dom: ">=16.9.0"
checksum: 10c0/6053fd1585f65f0a48d2e98bdf83000981b28c3581dc390d8ae9cb2c4c90a2c559bfe8bbb7f0a376eea0ab4dcfe83c758e0cf09023a2fdf2e49eecc5145c8f79
checksum: 10c0/1f69eddf066d120c47f23c840531626cb8868b6943b85a596bf96ca19564646422f321fe31d8d635324052c38f2ace1ed72d775db73968344eb0770ec666bbe2
languageName: node
linkType: hard
"rc-input@npm:~1.6.0, rc-input@npm:~1.6.3":
"rc-input@npm:~1.6.0":
version: 1.6.3
resolution: "rc-input@npm:1.6.3"
dependencies:
@@ -10896,27 +10947,41 @@ __metadata:
languageName: node
linkType: hard
"rc-mentions@npm:~2.15.0":
version: 2.15.0
resolution: "rc-mentions@npm:2.15.0"
"rc-input@npm:~1.6.4":
version: 1.6.4
resolution: "rc-input@npm:1.6.4"
dependencies:
"@babel/runtime": "npm:^7.11.1"
classnames: "npm:^2.2.1"
rc-util: "npm:^5.18.1"
peerDependencies:
react: ">=16.0.0"
react-dom: ">=16.0.0"
checksum: 10c0/3e3f0a25c1319aebcd29536aff426dd6f47766ca6751711a9d5670cb979f066dda4efaf4c59206c81c37d4470c1c53d6d67f606ab15b82c98e8b7762f9147638
languageName: node
linkType: hard
"rc-mentions@npm:~2.17.0":
version: 2.17.0
resolution: "rc-mentions@npm:2.17.0"
dependencies:
"@babel/runtime": "npm:^7.22.5"
"@rc-component/trigger": "npm:^2.0.0"
classnames: "npm:^2.2.6"
rc-input: "npm:~1.6.0"
rc-menu: "npm:~9.14.0"
rc-menu: "npm:~9.16.0"
rc-textarea: "npm:~1.8.0"
rc-util: "npm:^5.34.1"
peerDependencies:
react: ">=16.9.0"
react-dom: ">=16.9.0"
checksum: 10c0/5987090f496d7f6959e1d99a8d37410c7232347124e0e206f5abe628ac55bd7adc6d7b730769b7431067c0cb99eeda0389487768430d21163fd1241c848abdfc
checksum: 10c0/975dd37e5c0f33b77d1638cff3a6da6e89c2ac82fb1f4aea459a7073f501f520345dacd827ab3c37f81b877779e7b38d09b1c9f5b44f0e339a23004bbed9163f
languageName: node
linkType: hard
"rc-menu@npm:~9.14.0, rc-menu@npm:~9.14.1":
version: 9.14.1
resolution: "rc-menu@npm:9.14.1"
"rc-menu@npm:~9.16.0":
version: 9.16.0
resolution: "rc-menu@npm:9.16.0"
dependencies:
"@babel/runtime": "npm:^7.10.1"
"@rc-component/trigger": "npm:^2.0.0"
@@ -10927,11 +10992,11 @@ __metadata:
peerDependencies:
react: ">=16.9.0"
react-dom: ">=16.9.0"
checksum: 10c0/821c4016d64b83fb3035c0abfe83c6203f6ae885e9fbb7d4f78e7db5ae390cb67398bac7fd667ff738c4dccb447d9a35ac0bdf0f2bc4816def2b33cdb8a16861
checksum: 10c0/e3552653027a1f01b2ad81068e55e4af84cbe28ed82c83ecb0fd14dff50f77070e7e9a1d5dcf5e23197dfda11552b4a1fe2a0ebc6c1d6686eb695379d39f3112
languageName: node
linkType: hard
"rc-motion@npm:^2.0.0, rc-motion@npm:^2.0.1, rc-motion@npm:^2.3.0, rc-motion@npm:^2.3.4, rc-motion@npm:^2.4.3, rc-motion@npm:^2.4.4, rc-motion@npm:^2.6.1, rc-motion@npm:^2.6.2, rc-motion@npm:^2.9.0, rc-motion@npm:^2.9.2":
"rc-motion@npm:^2.0.0, rc-motion@npm:^2.0.1, rc-motion@npm:^2.3.0, rc-motion@npm:^2.3.4, rc-motion@npm:^2.4.3, rc-motion@npm:^2.4.4, rc-motion@npm:^2.6.1, rc-motion@npm:^2.6.2, rc-motion@npm:^2.9.0":
version: 2.9.2
resolution: "rc-motion@npm:2.9.2"
dependencies:
@@ -10945,9 +11010,23 @@ __metadata:
languageName: node
linkType: hard
"rc-notification@npm:~5.6.0":
version: 5.6.0
resolution: "rc-notification@npm:5.6.0"
"rc-motion@npm:^2.9.5":
version: 2.9.5
resolution: "rc-motion@npm:2.9.5"
dependencies:
"@babel/runtime": "npm:^7.11.1"
classnames: "npm:^2.2.1"
rc-util: "npm:^5.44.0"
peerDependencies:
react: ">=16.9.0"
react-dom: ">=16.9.0"
checksum: 10c0/84b12b2443dc1b929c8a688e8c9834a44cf88897402e9363fcea80b77f2803b2de83b24dac5873a8695304827e02fb3103c74349d0451ed247cb366553f9d88e
languageName: node
linkType: hard
"rc-notification@npm:~5.6.2":
version: 5.6.2
resolution: "rc-notification@npm:5.6.2"
dependencies:
"@babel/runtime": "npm:^7.10.1"
classnames: "npm:2.x"
@@ -10956,7 +11035,7 @@ __metadata:
peerDependencies:
react: ">=16.9.0"
react-dom: ">=16.9.0"
checksum: 10c0/754b158716564a90a96480646fd95ce02b54b25dc88a6b7fd7d4cbfd53f6fcd95aa97fe9267356f66a678ec38c8a04282217c5b909904949b4bdd3a7fd1b7480
checksum: 10c0/ce4237ac23a04e6e07ec2610544938c64f08b3035360dccda6f17b6a6494f71fc8a588ae39542c5e06fa1ba96fc95084290a34b7f47f245ee8a23f944376d69c
languageName: node
linkType: hard
@@ -10975,9 +11054,9 @@ __metadata:
languageName: node
linkType: hard
"rc-pagination@npm:~4.2.0":
version: 4.2.0
resolution: "rc-pagination@npm:4.2.0"
"rc-pagination@npm:~5.0.0":
version: 5.0.0
resolution: "rc-pagination@npm:5.0.0"
dependencies:
"@babel/runtime": "npm:^7.10.1"
classnames: "npm:^2.3.2"
@@ -10985,13 +11064,13 @@ __metadata:
peerDependencies:
react: ">=16.9.0"
react-dom: ">=16.9.0"
checksum: 10c0/fa5ea867a81c850df4a583f10979865420856ac50d17fc1a92824c82844580b476e333f396928e02a160e672eaec77bcc66330962f07e53bdc8b55ffd303da8c
checksum: 10c0/62d54fd43b549f63ee7ef8ab8b8b378b8ceb2508ca6e081364fb36868a60047bc90ad5407e1fc4095b4bdbdef41967238a59a17a2a960809c663ded3049d0e0d
languageName: node
linkType: hard
"rc-picker@npm:~4.6.14":
version: 4.6.14
resolution: "rc-picker@npm:4.6.14"
"rc-picker@npm:~4.8.3":
version: 4.8.3
resolution: "rc-picker@npm:4.8.3"
dependencies:
"@babel/runtime": "npm:^7.24.7"
"@rc-component/trigger": "npm:^2.0.0"
@@ -11015,7 +11094,7 @@ __metadata:
optional: true
moment:
optional: true
checksum: 10c0/e58e8548ae2db77c61771531b1fed093353ac368e2c059c22bf24096b5fb70660c155a5a083fc0558d4a74fc34e8270053acbde11dff5bf9c4d3380ad5738248
checksum: 10c0/581bd2f40e05e26db1233435df26cce0a4df6a1ed79419d38ebfbc12d1e239d99809e2e4d14c761489c211289eed0df30c0e140e8a8ec2e1968c0dc76e243c6f
languageName: node
linkType: hard
@@ -11062,9 +11141,24 @@ __metadata:
languageName: node
linkType: hard
"rc-segmented@npm:~2.3.0":
version: 2.3.0
resolution: "rc-segmented@npm:2.3.0"
"rc-resize-observer@npm:^1.4.3":
version: 1.4.3
resolution: "rc-resize-observer@npm:1.4.3"
dependencies:
"@babel/runtime": "npm:^7.20.7"
classnames: "npm:^2.2.1"
rc-util: "npm:^5.44.1"
resize-observer-polyfill: "npm:^1.5.1"
peerDependencies:
react: ">=16.9.0"
react-dom: ">=16.9.0"
checksum: 10c0/93073c9ef5cc704f9d99307f58f8eeccabb953edf4e8a056b090104fc28ed19b77c2a32bd88ca2e0407fbedeb266d1985e655b35b8bc36b04d243e9d0471c911
languageName: node
linkType: hard
"rc-segmented@npm:~2.5.0":
version: 2.5.0
resolution: "rc-segmented@npm:2.5.0"
dependencies:
"@babel/runtime": "npm:^7.11.1"
classnames: "npm:^2.2.1"
@@ -11073,13 +11167,13 @@ __metadata:
peerDependencies:
react: ">=16.0.0"
react-dom: ">=16.0.0"
checksum: 10c0/8d5f99ca55f1a1b0f3de66801a456e35c8c41a94a8d1b90a98aeb622cc95c86a7430449f2b3384d497f68641f92af0e3bd2689bfb7bbaf6543882cfc12e6c42f
checksum: 10c0/c0f760989fdff4cddfa66e4441f4ea219a452fd70a80b4b11e326b6d243584cb1b1a078078c7c62792c7468ad12fe5cfad8ecaf7affaac9bb42a580072e1658e
languageName: node
linkType: hard
"rc-select@npm:~14.15.0, rc-select@npm:~14.15.2":
version: 14.15.2
resolution: "rc-select@npm:14.15.2"
"rc-select@npm:~14.16.2, rc-select@npm:~14.16.4":
version: 14.16.4
resolution: "rc-select@npm:14.16.4"
dependencies:
"@babel/runtime": "npm:^7.10.1"
"@rc-component/trigger": "npm:^2.1.1"
@@ -11091,13 +11185,13 @@ __metadata:
peerDependencies:
react: "*"
react-dom: "*"
checksum: 10c0/00151da840002e30ee2b1f372c416e8370495524cf46e587eeb903fce2d1fd43167774a49cb7aed3e9816d2a200b46150c7d1fdcb1b17a21ca19d3a3cf930792
checksum: 10c0/39c184191d576d3ad963af2d9d240b1740c96c817ad9e9138770acf2e0bfbc4bb0c8ba408f6702c15f5d25aad48fcee962b996c6e0e1d5013329fee5e8927cb0
languageName: node
linkType: hard
"rc-slider@npm:~11.1.5":
version: 11.1.5
resolution: "rc-slider@npm:11.1.5"
"rc-slider@npm:~11.1.7":
version: 11.1.7
resolution: "rc-slider@npm:11.1.7"
dependencies:
"@babel/runtime": "npm:^7.10.1"
classnames: "npm:^2.2.5"
@@ -11105,7 +11199,7 @@ __metadata:
peerDependencies:
react: ">=16.9.0"
react-dom: ">=16.9.0"
checksum: 10c0/2d20330d7d2a9722c4732010fd2f10183f808cd8fe7122ffc0a899020f1d479171a60dc95ccda6c17d15345d2447553e2df883cfad5f6d9f9248fff5eeb1af8e
checksum: 10c0/ddb870a8f9982565c3ab4e7ece12a224c4d6f1983a0760d516561fa8963c2bc6d9e25bed6b87cad007b3d4962194398e1490231d0b5ab062262c0ea0ba734b85
languageName: node
linkType: hard
@@ -11137,42 +11231,42 @@ __metadata:
languageName: node
linkType: hard
"rc-table@npm:~7.45.7":
version: 7.45.7
resolution: "rc-table@npm:7.45.7"
"rc-table@npm:~7.49.0":
version: 7.49.0
resolution: "rc-table@npm:7.49.0"
dependencies:
"@babel/runtime": "npm:^7.10.1"
"@rc-component/context": "npm:^1.4.0"
classnames: "npm:^2.2.5"
rc-resize-observer: "npm:^1.1.0"
rc-util: "npm:^5.37.0"
rc-util: "npm:^5.41.0"
rc-virtual-list: "npm:^3.14.2"
peerDependencies:
react: ">=16.9.0"
react-dom: ">=16.9.0"
checksum: 10c0/18803454e2d4f2dcbbc8d6c5cf8b0445c35f586106d389db503601f4b17e941765c1fda53555a2120af4b122b9a88ccde30c28bb4d6a2fd96f9daa5438ff16a5
checksum: 10c0/463edd9f971c9334d50e1928758d12689be3a55e97a0b45d10802f53efdab8b996bd12efb210a2442dcaa23511ead2c494371e2177fdc7695ee4831942496027
languageName: node
linkType: hard
"rc-tabs@npm:~15.1.1":
version: 15.1.1
resolution: "rc-tabs@npm:15.1.1"
"rc-tabs@npm:~15.4.0":
version: 15.4.0
resolution: "rc-tabs@npm:15.4.0"
dependencies:
"@babel/runtime": "npm:^7.11.2"
classnames: "npm:2.x"
rc-dropdown: "npm:~4.2.0"
rc-menu: "npm:~9.14.0"
rc-menu: "npm:~9.16.0"
rc-motion: "npm:^2.6.2"
rc-resize-observer: "npm:^1.0.0"
rc-util: "npm:^5.34.1"
peerDependencies:
react: ">=16.9.0"
react-dom: ">=16.9.0"
checksum: 10c0/b6115747f23f94d31fa6b2de381e6e7db38f18a121cdf15ffaec8008faa9da6c7e8d6253c998f817b6e453532ca6e3577b0b7ab9bf4ec3de541eaad32fac50f7
checksum: 10c0/75628e5681819ebbd56347cee33654bf3af3f49b2dcc7bd7952c43053dc2394d52e10956fc317b3803064d60aeb8f3316d9112b16b76c61a6af9e3326c9bc8f1
languageName: node
linkType: hard
"rc-textarea@npm:~1.8.0, rc-textarea@npm:~1.8.1":
"rc-textarea@npm:~1.8.0":
version: 1.8.1
resolution: "rc-textarea@npm:1.8.1"
dependencies:
@@ -11188,9 +11282,25 @@ __metadata:
languageName: node
linkType: hard
"rc-tooltip@npm:~6.2.0":
version: 6.2.0
resolution: "rc-tooltip@npm:6.2.0"
"rc-textarea@npm:~1.8.2":
version: 1.8.2
resolution: "rc-textarea@npm:1.8.2"
dependencies:
"@babel/runtime": "npm:^7.10.1"
classnames: "npm:^2.2.1"
rc-input: "npm:~1.6.0"
rc-resize-observer: "npm:^1.0.0"
rc-util: "npm:^5.27.0"
peerDependencies:
react: ">=16.9.0"
react-dom: ">=16.9.0"
checksum: 10c0/bd547309735d3ec22a1cec930965ec8f5d861379c81de7616377e61cdbfe43e248291dfd45a477e2c84a42641b03c7a4c4ca3f9ef730ee47b3731b5b22aca170
languageName: node
linkType: hard
"rc-tooltip@npm:~6.2.1":
version: 6.2.1
resolution: "rc-tooltip@npm:6.2.1"
dependencies:
"@babel/runtime": "npm:^7.11.2"
"@rc-component/trigger": "npm:^2.0.0"
@@ -11198,29 +11308,29 @@ __metadata:
peerDependencies:
react: ">=16.9.0"
react-dom: ">=16.9.0"
checksum: 10c0/5f1f8e51fbb156acb3ebea52f509e61b3c0679869d73f0238bcd6d585fcef3cb5f544b5064cac417fb7137218ac81cf9223dc6d87d2e7820a56c72e9f279198e
checksum: 10c0/879341bcb7c162faa51b187482947c4f7d67b223f3999cf4a0fc5f4ffd15030086cef05b32464203c6ea7d07fc9f68cca85d806bf65ffdb91a5e7a76e46c839d
languageName: node
linkType: hard
"rc-tree-select@npm:~5.23.0":
version: 5.23.0
resolution: "rc-tree-select@npm:5.23.0"
"rc-tree-select@npm:~5.24.5":
version: 5.24.5
resolution: "rc-tree-select@npm:5.24.5"
dependencies:
"@babel/runtime": "npm:^7.10.1"
"@babel/runtime": "npm:^7.25.7"
classnames: "npm:2.x"
rc-select: "npm:~14.15.0"
rc-tree: "npm:~5.9.0"
rc-util: "npm:^5.16.1"
rc-select: "npm:~14.16.2"
rc-tree: "npm:~5.10.1"
rc-util: "npm:^5.43.0"
peerDependencies:
react: "*"
react-dom: "*"
checksum: 10c0/6e054b168f0970686cd3afeefca3ec09138c6c81ea2243c059c446500220fceca1471d91db3231f7759a0f3e05014dcd0f80a5a78306c189b70896b3117a256c
checksum: 10c0/a1e12ca34f895f26de11d9113c5f9a010340439f15cef48d81c7ff3479c886e66495dcfd774331fcc225da125b6c515c1193c7318d01e79246b39b86c9c2a522
languageName: node
linkType: hard
"rc-tree@npm:~5.9.0":
version: 5.9.0
resolution: "rc-tree@npm:5.9.0"
"rc-tree@npm:~5.10.1":
version: 5.10.1
resolution: "rc-tree@npm:5.10.1"
dependencies:
"@babel/runtime": "npm:^7.10.1"
classnames: "npm:2.x"
@@ -11230,13 +11340,13 @@ __metadata:
peerDependencies:
react: "*"
react-dom: "*"
checksum: 10c0/07cb1126910739060170be6348835bb39cfdf0ddf6fffbbfda2eca49cadee9233fd2031a0cabce07e4874df29ccdc1168b47695dec5e03ecfe502c0fa49712a9
checksum: 10c0/fc08051271bcd33d59bd5e2f14f8c52e00fc70081bcfd11f2199209ad45077c4664429e746baf239ba1c8b6e122a0de67e5ab109a4436cdaa0fa2d297db890e9
languageName: node
linkType: hard
"rc-upload@npm:~4.7.0":
version: 4.7.0
resolution: "rc-upload@npm:4.7.0"
"rc-upload@npm:~4.8.1":
version: 4.8.1
resolution: "rc-upload@npm:4.8.1"
dependencies:
"@babel/runtime": "npm:^7.18.3"
classnames: "npm:^2.2.5"
@@ -11244,7 +11354,7 @@ __metadata:
peerDependencies:
react: ">=16.9.0"
react-dom: ">=16.9.0"
checksum: 10c0/d6ff664361b26fcf66825f0f2d43fb67c18ed13938055e967e60c6af190a3c976a10ed85d17799dfef669c025072e73f9549157591119860b01b76df00245d0e
checksum: 10c0/27555e114c1705b88558312beeda4b8d3e74d192c09f5a41d161045cbe621d372973acaffff8b9c79ebfe495962e2bf96aedffc9fadc96b5e7c7b5cd1af98b99
languageName: node
linkType: hard
@@ -11261,6 +11371,19 @@ __metadata:
languageName: node
linkType: hard
"rc-util@npm:^5.41.0, rc-util@npm:^5.44.0, rc-util@npm:^5.44.1, rc-util@npm:^5.44.2":
version: 5.44.3
resolution: "rc-util@npm:5.44.3"
dependencies:
"@babel/runtime": "npm:^7.18.3"
react-is: "npm:^18.2.0"
peerDependencies:
react: ">=16.9.0"
react-dom: ">=16.9.0"
checksum: 10c0/9b6b737cb1995cba7a936bd6c10d521b422cd62987af3b130d2f0b45f3505491b51f66b0252aeca23b1000998d18294f942abca16f455fd8023709756a3fbd01
languageName: node
linkType: hard
"rc-virtual-list@npm:^3.14.2, rc-virtual-list@npm:^3.5.1, rc-virtual-list@npm:^3.5.2":
version: 3.14.5
resolution: "rc-virtual-list@npm:3.14.5"
@@ -12870,7 +12993,7 @@ __metadata:
languageName: node
linkType: hard
"stylis@npm:^4.3.3":
"stylis@npm:^4.3.3, stylis@npm:^4.3.4":
version: 4.3.4
resolution: "stylis@npm:4.3.4"
checksum: 10c0/4899c2674cd2538e314257abd1ba7ea3c2176439659ddac6593c78192cfd4a06f814a0a4fc69bc7f8fcc6b997e13d383dd9b578b71074746a0fb86045a83e42d