feat: add project name support for Volcengine integration

This commit is contained in:
suyao 2025-11-27 01:29:02 +08:00
parent c3c577dff4
commit 531101742e
No known key found for this signature in database
17 changed files with 69 additions and 13 deletions

View File

@ -34,6 +34,7 @@ const ListFoundationModelsRequestSchema = z.object({
}) })
const ListEndpointsRequestSchema = z.object({ const ListEndpointsRequestSchema = z.object({
ProjectName: z.optional(z.string()),
PageNumber: z.optional(z.number()), PageNumber: z.optional(z.number()),
PageSize: z.optional(z.number()) PageSize: z.optional(z.number())
}) })
@ -544,8 +545,9 @@ class VolcengineService {
/** /**
* List user-created endpoints from Volcengine ARK * List user-created endpoints from Volcengine ARK
*/ */
private async listEndpoints(): Promise<ListEndpointsResponse> { private async listEndpoints(projectName?: string): Promise<ListEndpointsResponse> {
const requestBody: ListEndpointsRequest = { const requestBody: ListEndpointsRequest = {
ProjectName: projectName || 'default',
PageNumber: 1, PageNumber: 1,
PageSize: CONFIG.DEFAULT_PAGE_SIZE PageSize: CONFIG.DEFAULT_PAGE_SIZE
} }
@ -569,11 +571,11 @@ class VolcengineService {
* List all available models from Volcengine ARK * List all available models from Volcengine ARK
* Combines foundation models and user-created endpoints * Combines foundation models and user-created endpoints
*/ */
public listModels = async (): Promise<ListModelsResult> => { public listModels = async (_?: Electron.IpcMainInvokeEvent, projectName?: string): Promise<ListModelsResult> => {
try { try {
const [foundationModelsResult, endpointsResult] = await Promise.allSettled([ const [foundationModelsResult, endpointsResult] = await Promise.allSettled([
this.listFoundationModels(), this.listFoundationModels(),
this.listEndpoints() this.listEndpoints(projectName)
]) ])
const models: ModelInfo[] = [] const models: ModelInfo[] = []

View File

@ -578,10 +578,10 @@ const api = {
ipcRenderer.invoke(IpcChannel.Volcengine_SaveCredentials, accessKeyId, secretAccessKey), ipcRenderer.invoke(IpcChannel.Volcengine_SaveCredentials, accessKeyId, secretAccessKey),
hasCredentials: (): Promise<boolean> => ipcRenderer.invoke(IpcChannel.Volcengine_HasCredentials), hasCredentials: (): Promise<boolean> => ipcRenderer.invoke(IpcChannel.Volcengine_HasCredentials),
clearCredentials: (): Promise<void> => ipcRenderer.invoke(IpcChannel.Volcengine_ClearCredentials), clearCredentials: (): Promise<void> => ipcRenderer.invoke(IpcChannel.Volcengine_ClearCredentials),
listModels: (): Promise<{ listModels: (projectName?: string): Promise<{
models: Array<{ id: string; name: string; description?: string; created?: number }> models: Array<{ id: string; name: string; description?: string; created?: number }>
total?: number total?: number
}> => ipcRenderer.invoke(IpcChannel.Volcengine_ListModels), }> => ipcRenderer.invoke(IpcChannel.Volcengine_ListModels, projectName),
getAuthHeaders: (params: { getAuthHeaders: (params: {
method: 'GET' | 'POST' method: 'GET' | 'POST'
host: string host: string

View File

@ -1,5 +1,6 @@
import type OpenAI from '@cherrystudio/openai' import type OpenAI from '@cherrystudio/openai'
import { loggerService } from '@logger' import { loggerService } from '@logger'
import { getVolcengineProjectName } from '@renderer/hooks/useVolcengine'
import type { Provider } from '@renderer/types' import type { Provider } from '@renderer/types'
import { OpenAIAPIClient } from '../openai/OpenAIApiClient' import { OpenAIAPIClient } from '../openai/OpenAIApiClient'
@ -33,7 +34,8 @@ export class VolcengineAPIClient extends OpenAIAPIClient {
logger.info('Fetching models from Volcengine API using signed request') logger.info('Fetching models from Volcengine API using signed request')
const response = await window.api.volcengine.listModels() const projectName = getVolcengineProjectName()
const response = await window.api.volcengine.listModels(projectName)
if (!response || !response.models) { if (!response || !response.models) {
logger.warn('Empty response from Volcengine listModels') logger.warn('Empty response from Volcengine listModels')

View File

@ -1,5 +1,10 @@
import store, { useAppSelector } from '@renderer/store' import store, { useAppSelector } from '@renderer/store'
import { setVolcengineAccessKeyId, setVolcengineRegion, setVolcengineSecretAccessKey } from '@renderer/store/llm' import {
setVolcengineAccessKeyId,
setVolcengineProjectName,
setVolcengineRegion,
setVolcengineSecretAccessKey
} from '@renderer/store/llm'
import { useDispatch } from 'react-redux' import { useDispatch } from 'react-redux'
export function useVolcengineSettings() { export function useVolcengineSettings() {
@ -10,7 +15,8 @@ export function useVolcengineSettings() {
...settings, ...settings,
setAccessKeyId: (accessKeyId: string) => dispatch(setVolcengineAccessKeyId(accessKeyId)), setAccessKeyId: (accessKeyId: string) => dispatch(setVolcengineAccessKeyId(accessKeyId)),
setSecretAccessKey: (secretAccessKey: string) => dispatch(setVolcengineSecretAccessKey(secretAccessKey)), setSecretAccessKey: (secretAccessKey: string) => dispatch(setVolcengineSecretAccessKey(secretAccessKey)),
setRegion: (region: string) => dispatch(setVolcengineRegion(region)) setRegion: (region: string) => dispatch(setVolcengineRegion(region)),
setProjectName: (projectName: string) => dispatch(setVolcengineProjectName(projectName))
} }
} }
@ -29,3 +35,7 @@ export function getVolcengineSecretAccessKey() {
export function getVolcengineRegion() { export function getVolcengineRegion() {
return store.getState().llm.settings.volcengine.region return store.getState().llm.settings.volcengine.region
} }
export function getVolcengineProjectName() {
return store.getState().llm.settings.volcengine.projectName
}

View File

@ -4519,6 +4519,8 @@
"credentials_required": "Please fill in Access Key ID and Secret Access Key", "credentials_required": "Please fill in Access Key ID and Secret Access Key",
"credentials_saved": "Credentials saved", "credentials_saved": "Credentials saved",
"description": "Volcengine is ByteDance's cloud service platform, providing Doubao and other large language model services. Please use IAM user's Access Key for authentication, do not use the root user credentials.", "description": "Volcengine is ByteDance's cloud service platform, providing Doubao and other large language model services. Please use IAM user's Access Key for authentication, do not use the root user credentials.",
"project_name": "Project Name",
"project_name_help": "Project name for endpoint filtering, default is 'default'",
"region": "Region", "region": "Region",
"region_help": "Service region, e.g., cn-beijing", "region_help": "Service region, e.g., cn-beijing",
"save_credentials": "Save Credentials", "save_credentials": "Save Credentials",

View File

@ -4519,6 +4519,8 @@
"credentials_required": "请填写 Access Key ID 和 Secret Access Key", "credentials_required": "请填写 Access Key ID 和 Secret Access Key",
"credentials_saved": "凭证已保存", "credentials_saved": "凭证已保存",
"description": "火山引擎是字节跳动旗下的云服务平台,提供豆包等大语言模型服务。请使用 IAM 子用户的 Access Key 进行身份验证,不要使用主账号的根用户密钥。", "description": "火山引擎是字节跳动旗下的云服务平台,提供豆包等大语言模型服务。请使用 IAM 子用户的 Access Key 进行身份验证,不要使用主账号的根用户密钥。",
"project_name": "项目名称",
"project_name_help": "用于筛选推理接入点的项目名称,默认为 'default'",
"region": "地域", "region": "地域",
"region_help": "服务地域,例如 cn-beijing", "region_help": "服务地域,例如 cn-beijing",
"save_credentials": "保存凭证", "save_credentials": "保存凭证",

View File

@ -4519,6 +4519,8 @@
"credentials_required": "請填寫 Access Key ID 和 Secret Access Key", "credentials_required": "請填寫 Access Key ID 和 Secret Access Key",
"credentials_saved": "憑證已儲存", "credentials_saved": "憑證已儲存",
"description": "火山引擎是字節跳動旗下的雲端服務平台,提供豆包等大型語言模型服務。請使用 IAM 子用戶的 Access Key 進行身份驗證,不要使用主帳號的根用戶密鑰。", "description": "火山引擎是字節跳動旗下的雲端服務平台,提供豆包等大型語言模型服務。請使用 IAM 子用戶的 Access Key 進行身份驗證,不要使用主帳號的根用戶密鑰。",
"project_name": "專案名稱",
"project_name_help": "用於篩選推論接入點的專案名稱,預設為 'default'",
"region": "地區", "region": "地區",
"region_help": "服務地區,例如 cn-beijing", "region_help": "服務地區,例如 cn-beijing",
"save_credentials": "儲存憑證", "save_credentials": "儲存憑證",

View File

@ -4519,6 +4519,8 @@
"credentials_required": "[to be translated]:Please fill in Access Key ID and Secret Access Key", "credentials_required": "[to be translated]:Please fill in Access Key ID and Secret Access Key",
"credentials_saved": "[to be translated]:Credentials saved", "credentials_saved": "[to be translated]:Credentials saved",
"description": "[to be translated]:Volcengine is ByteDance's cloud service platform, providing Doubao and other large language model services. Use Access Key for authentication to fetch model list.", "description": "[to be translated]:Volcengine is ByteDance's cloud service platform, providing Doubao and other large language model services. Use Access Key for authentication to fetch model list.",
"project_name": "[to be translated]:Project Name",
"project_name_help": "[to be translated]:Project name for endpoint filtering, default is 'default'",
"region": "[to be translated]:Region", "region": "[to be translated]:Region",
"region_help": "[to be translated]:Service region, e.g., cn-beijing", "region_help": "[to be translated]:Service region, e.g., cn-beijing",
"save_credentials": "[to be translated]:Save Credentials", "save_credentials": "[to be translated]:Save Credentials",

View File

@ -4519,6 +4519,8 @@
"credentials_required": "[to be translated]:Please fill in Access Key ID and Secret Access Key", "credentials_required": "[to be translated]:Please fill in Access Key ID and Secret Access Key",
"credentials_saved": "[to be translated]:Credentials saved", "credentials_saved": "[to be translated]:Credentials saved",
"description": "[to be translated]:Volcengine is ByteDance's cloud service platform, providing Doubao and other large language model services. Use Access Key for authentication to fetch model list.", "description": "[to be translated]:Volcengine is ByteDance's cloud service platform, providing Doubao and other large language model services. Use Access Key for authentication to fetch model list.",
"project_name": "[to be translated]:Project Name",
"project_name_help": "[to be translated]:Project name for endpoint filtering, default is 'default'",
"region": "[to be translated]:Region", "region": "[to be translated]:Region",
"region_help": "[to be translated]:Service region, e.g., cn-beijing", "region_help": "[to be translated]:Service region, e.g., cn-beijing",
"save_credentials": "[to be translated]:Save Credentials", "save_credentials": "[to be translated]:Save Credentials",

View File

@ -4519,6 +4519,8 @@
"credentials_required": "[to be translated]:Please fill in Access Key ID and Secret Access Key", "credentials_required": "[to be translated]:Please fill in Access Key ID and Secret Access Key",
"credentials_saved": "[to be translated]:Credentials saved", "credentials_saved": "[to be translated]:Credentials saved",
"description": "[to be translated]:Volcengine is ByteDance's cloud service platform, providing Doubao and other large language model services. Use Access Key for authentication to fetch model list.", "description": "[to be translated]:Volcengine is ByteDance's cloud service platform, providing Doubao and other large language model services. Use Access Key for authentication to fetch model list.",
"project_name": "[to be translated]:Project Name",
"project_name_help": "[to be translated]:Project name for endpoint filtering, default is 'default'",
"region": "[to be translated]:Region", "region": "[to be translated]:Region",
"region_help": "[to be translated]:Service region, e.g., cn-beijing", "region_help": "[to be translated]:Service region, e.g., cn-beijing",
"save_credentials": "[to be translated]:Save Credentials", "save_credentials": "[to be translated]:Save Credentials",

View File

@ -4519,6 +4519,8 @@
"credentials_required": "[to be translated]:Please fill in Access Key ID and Secret Access Key", "credentials_required": "[to be translated]:Please fill in Access Key ID and Secret Access Key",
"credentials_saved": "[to be translated]:Credentials saved", "credentials_saved": "[to be translated]:Credentials saved",
"description": "[to be translated]:Volcengine is ByteDance's cloud service platform, providing Doubao and other large language model services. Use Access Key for authentication to fetch model list.", "description": "[to be translated]:Volcengine is ByteDance's cloud service platform, providing Doubao and other large language model services. Use Access Key for authentication to fetch model list.",
"project_name": "[to be translated]:Project Name",
"project_name_help": "[to be translated]:Project name for endpoint filtering, default is 'default'",
"region": "[to be translated]:Region", "region": "[to be translated]:Region",
"region_help": "[to be translated]:Service region, e.g., cn-beijing", "region_help": "[to be translated]:Service region, e.g., cn-beijing",
"save_credentials": "[to be translated]:Save Credentials", "save_credentials": "[to be translated]:Save Credentials",

View File

@ -4519,6 +4519,8 @@
"credentials_required": "[to be translated]:Please fill in Access Key ID and Secret Access Key", "credentials_required": "[to be translated]:Please fill in Access Key ID and Secret Access Key",
"credentials_saved": "[to be translated]:Credentials saved", "credentials_saved": "[to be translated]:Credentials saved",
"description": "[to be translated]:Volcengine is ByteDance's cloud service platform, providing Doubao and other large language model services. Use Access Key for authentication to fetch model list.", "description": "[to be translated]:Volcengine is ByteDance's cloud service platform, providing Doubao and other large language model services. Use Access Key for authentication to fetch model list.",
"project_name": "[to be translated]:Project Name",
"project_name_help": "[to be translated]:Project name for endpoint filtering, default is 'default'",
"region": "[to be translated]:Region", "region": "[to be translated]:Region",
"region_help": "[to be translated]:Service region, e.g., cn-beijing", "region_help": "[to be translated]:Service region, e.g., cn-beijing",
"save_credentials": "[to be translated]:Save Credentials", "save_credentials": "[to be translated]:Save Credentials",

View File

@ -4519,6 +4519,8 @@
"credentials_required": "[to be translated]:Please fill in Access Key ID and Secret Access Key", "credentials_required": "[to be translated]:Please fill in Access Key ID and Secret Access Key",
"credentials_saved": "[to be translated]:Credentials saved", "credentials_saved": "[to be translated]:Credentials saved",
"description": "[to be translated]:Volcengine is ByteDance's cloud service platform, providing Doubao and other large language model services. Use Access Key for authentication to fetch model list.", "description": "[to be translated]:Volcengine is ByteDance's cloud service platform, providing Doubao and other large language model services. Use Access Key for authentication to fetch model list.",
"project_name": "[to be translated]:Project Name",
"project_name_help": "[to be translated]:Project name for endpoint filtering, default is 'default'",
"region": "[to be translated]:Region", "region": "[to be translated]:Region",
"region_help": "[to be translated]:Service region, e.g., cn-beijing", "region_help": "[to be translated]:Service region, e.g., cn-beijing",
"save_credentials": "[to be translated]:Save Credentials", "save_credentials": "[to be translated]:Save Credentials",

View File

@ -4519,6 +4519,8 @@
"credentials_required": "[to be translated]:Please fill in Access Key ID and Secret Access Key", "credentials_required": "[to be translated]:Please fill in Access Key ID and Secret Access Key",
"credentials_saved": "[to be translated]:Credentials saved", "credentials_saved": "[to be translated]:Credentials saved",
"description": "[to be translated]:Volcengine is ByteDance's cloud service platform, providing Doubao and other large language model services. Use Access Key for authentication to fetch model list.", "description": "[to be translated]:Volcengine is ByteDance's cloud service platform, providing Doubao and other large language model services. Use Access Key for authentication to fetch model list.",
"project_name": "[to be translated]:Project Name",
"project_name_help": "[to be translated]:Project name for endpoint filtering, default is 'default'",
"region": "[to be translated]:Region", "region": "[to be translated]:Region",
"region_help": "[to be translated]:Service region, e.g., cn-beijing", "region_help": "[to be translated]:Service region, e.g., cn-beijing",
"save_credentials": "[to be translated]:Save Credentials", "save_credentials": "[to be translated]:Save Credentials",

View File

@ -10,7 +10,7 @@ import { SettingHelpLink, SettingHelpText, SettingHelpTextRow, SettingSubtitle }
const VolcengineSettings: FC = () => { const VolcengineSettings: FC = () => {
const { t } = useTranslation() const { t } = useTranslation()
const { accessKeyId, secretAccessKey, region, setAccessKeyId, setSecretAccessKey, setRegion } = const { accessKeyId, secretAccessKey, region, projectName, setAccessKeyId, setSecretAccessKey, setRegion, setProjectName } =
useVolcengineSettings() useVolcengineSettings()
const providerConfig = PROVIDER_URLS['doubao'] const providerConfig = PROVIDER_URLS['doubao']
@ -19,6 +19,7 @@ const VolcengineSettings: FC = () => {
const [localAccessKeyId, setLocalAccessKeyId] = useState(accessKeyId) const [localAccessKeyId, setLocalAccessKeyId] = useState(accessKeyId)
const [localSecretAccessKey, setLocalSecretAccessKey] = useState(secretAccessKey) const [localSecretAccessKey, setLocalSecretAccessKey] = useState(secretAccessKey)
const [localRegion, setLocalRegion] = useState(region) const [localRegion, setLocalRegion] = useState(region)
const [localProjectName, setLocalProjectName] = useState(projectName)
const [saving, setSaving] = useState(false) const [saving, setSaving] = useState(false)
const [hasCredentials, setHasCredentials] = useState(false) const [hasCredentials, setHasCredentials] = useState(false)
@ -32,7 +33,8 @@ const VolcengineSettings: FC = () => {
setLocalAccessKeyId(accessKeyId) setLocalAccessKeyId(accessKeyId)
setLocalSecretAccessKey(secretAccessKey) setLocalSecretAccessKey(secretAccessKey)
setLocalRegion(region) setLocalRegion(region)
}, [accessKeyId, secretAccessKey, region]) setLocalProjectName(projectName)
}, [accessKeyId, secretAccessKey, region, projectName])
const handleSaveCredentials = useCallback(async () => { const handleSaveCredentials = useCallback(async () => {
if (!localAccessKeyId || !localSecretAccessKey) { if (!localAccessKeyId || !localSecretAccessKey) {
@ -46,6 +48,7 @@ const VolcengineSettings: FC = () => {
setAccessKeyId(localAccessKeyId) setAccessKeyId(localAccessKeyId)
setSecretAccessKey(localSecretAccessKey) setSecretAccessKey(localSecretAccessKey)
setRegion(localRegion) setRegion(localRegion)
setProjectName(localProjectName)
// Save to secure storage via IPC // Save to secure storage via IPC
await window.api.volcengine.saveCredentials(localAccessKeyId, localSecretAccessKey) await window.api.volcengine.saveCredentials(localAccessKeyId, localSecretAccessKey)
@ -56,7 +59,7 @@ const VolcengineSettings: FC = () => {
} finally { } finally {
setSaving(false) setSaving(false)
} }
}, [localAccessKeyId, localSecretAccessKey, localRegion, setAccessKeyId, setSecretAccessKey, setRegion, t]) }, [localAccessKeyId, localSecretAccessKey, localRegion, localProjectName, setAccessKeyId, setSecretAccessKey, setRegion, setProjectName, t])
const handleClearCredentials = useCallback(async () => { const handleClearCredentials = useCallback(async () => {
try { try {
@ -122,6 +125,18 @@ const VolcengineSettings: FC = () => {
<SettingHelpText>{t('settings.provider.volcengine.region_help')}</SettingHelpText> <SettingHelpText>{t('settings.provider.volcengine.region_help')}</SettingHelpText>
</SettingHelpTextRow> </SettingHelpTextRow>
<SettingSubtitle style={{ marginTop: 15 }}>{t('settings.provider.volcengine.project_name')}</SettingSubtitle>
<Input
value={localProjectName}
placeholder="default"
onChange={(e) => setLocalProjectName(e.target.value)}
onBlur={() => setProjectName(localProjectName)}
style={{ marginTop: 5 }}
/>
<SettingHelpTextRow>
<SettingHelpText>{t('settings.provider.volcengine.project_name_help')}</SettingHelpText>
</SettingHelpTextRow>
<Space style={{ marginTop: 15 }}> <Space style={{ marginTop: 15 }}>
<Button type="primary" onClick={handleSaveCredentials} loading={saving}> <Button type="primary" onClick={handleSaveCredentials} loading={saving}>
{t('settings.provider.volcengine.save_credentials')} {t('settings.provider.volcengine.save_credentials')}

View File

@ -246,7 +246,8 @@ vi.mock('@renderer/store/llm.ts', () => {
volcengine: { volcengine: {
accessKeyId: '', accessKeyId: '',
secretAccessKey: '', secretAccessKey: '',
region: 'cn-beijing' region: 'cn-beijing',
projectName: 'default'
} }
} }
} satisfies LlmState } satisfies LlmState

View File

@ -35,6 +35,7 @@ type LlmSettings = {
accessKeyId: string accessKeyId: string
secretAccessKey: string secretAccessKey: string
region: string region: string
projectName: string
} }
} }
@ -84,7 +85,8 @@ export const initialState: LlmState = {
volcengine: { volcengine: {
accessKeyId: '', accessKeyId: '',
secretAccessKey: '', secretAccessKey: '',
region: 'cn-beijing' region: 'cn-beijing',
projectName: 'default'
} }
} }
} }
@ -235,6 +237,9 @@ const llmSlice = createSlice({
setVolcengineRegion: (state, action: PayloadAction<string>) => { setVolcengineRegion: (state, action: PayloadAction<string>) => {
state.settings.volcengine.region = action.payload state.settings.volcengine.region = action.payload
}, },
setVolcengineProjectName: (state, action: PayloadAction<string>) => {
state.settings.volcengine.projectName = action.payload
},
updateModel: ( updateModel: (
state, state,
action: PayloadAction<{ action: PayloadAction<{
@ -279,6 +284,7 @@ export const {
setVolcengineAccessKeyId, setVolcengineAccessKeyId,
setVolcengineSecretAccessKey, setVolcengineSecretAccessKey,
setVolcengineRegion, setVolcengineRegion,
setVolcengineProjectName,
updateModel updateModel
} = llmSlice.actions } = llmSlice.actions