Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Q
qjclaw-dmg
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
AI-甘富林
qjclaw-dmg
Commits
657746b3
Commit
657746b3
authored
Apr 29, 2026
by
AI-甘富林
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat(client): add xhs feishu runtime settings
parent
48d00eba
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
323 additions
and
23 deletions
+323
-23
ipc.ts
apps/desktop/src/main/ipc.ts
+48
-8
app-config.ts
apps/desktop/src/main/services/app-config.ts
+35
-3
project-model-runtime.ts
apps/desktop/src/main/services/project-model-runtime.ts
+22
-2
secrets.ts
apps/desktop/src/main/services/secrets.ts
+51
-3
App.tsx
apps/ui/src/App.tsx
+86
-3
styles.css
apps/ui/src/styles.css
+65
-4
index.ts
packages/shared-types/src/index.ts
+16
-0
No files found.
apps/desktop/src/main/ipc.ts
View file @
657746b3
...
...
@@ -536,7 +536,11 @@ export function registerDesktopIpc(services: MainServices): RegisteredDesktopIpc
digitalHumanQiniuSecretKey,
videoAnalyzerApiKey,
replicationBriefApiKey,
vectCutApiKey
vectCutApiKey,
xhsFeishuAppId,
xhsFeishuAppSecret,
xhsFeishuAppToken,
xhsFeishuTableId
] = await Promise.all([
secretManager.getApiKey(),
getEffectiveGatewayToken(config),
...
...
@@ -550,7 +554,11 @@ export function registerDesktopIpc(services: MainServices): RegisteredDesktopIpc
secretManager.getDigitalHumanQiniuSecretKey(),
secretManager.getVideoAnalyzerApiKey(),
secretManager.getReplicationBriefApiKey(),
secretManager.getVectCutApiKey()
secretManager.getVectCutApiKey(),
secretManager.getXhsFeishuAppId(),
secretManager.getXhsFeishuAppSecret(),
secretManager.getXhsFeishuAppToken(),
secretManager.getXhsFeishuTableId()
]);
const nextConfig: AppConfig = {
...
...
@@ -593,6 +601,12 @@ export function registerDesktopIpc(services: MainServices): RegisteredDesktopIpc
...config.douyinRuntimeConfig.vectcut,
apiKeyConfigured: Boolean(vectCutApiKey)
}
},
xhsFeishuConfig: {
appIdConfigured: Boolean(xhsFeishuAppId),
appSecretConfigured: Boolean(xhsFeishuAppSecret),
appTokenConfigured: Boolean(xhsFeishuAppToken),
tableIdConfigured: Boolean(xhsFeishuTableId)
}
};
...
...
@@ -608,7 +622,11 @@ export function registerDesktopIpc(services: MainServices): RegisteredDesktopIpc
|| nextConfig.expertModelConfig.digitalHuman.qiniuSecretKeyConfigured !== config.expertModelConfig.digitalHuman.qiniuSecretKeyConfigured
|| nextConfig.douyinRuntimeConfig.videoAnalyzer.apiKeyConfigured !== config.douyinRuntimeConfig.videoAnalyzer.apiKeyConfigured
|| nextConfig.douyinRuntimeConfig.replicationBrief.apiKeyConfigured !== config.douyinRuntimeConfig.replicationBrief.apiKeyConfigured
|| nextConfig.douyinRuntimeConfig.vectcut.apiKeyConfigured !== config.douyinRuntimeConfig.vectcut.apiKeyConfigured;
|| nextConfig.douyinRuntimeConfig.vectcut.apiKeyConfigured !== config.douyinRuntimeConfig.vectcut.apiKeyConfigured
|| nextConfig.xhsFeishuConfig.appIdConfigured !== config.xhsFeishuConfig.appIdConfigured
|| nextConfig.xhsFeishuConfig.appSecretConfigured !== config.xhsFeishuConfig.appSecretConfigured
|| nextConfig.xhsFeishuConfig.appTokenConfigured !== config.xhsFeishuConfig.appTokenConfigured
|| nextConfig.xhsFeishuConfig.tableIdConfigured !== config.xhsFeishuConfig.tableIdConfigured;
if (secretStateChanged) {
await configService.persist({
...
...
@@ -636,7 +654,11 @@ export function registerDesktopIpc(services: MainServices): RegisteredDesktopIpc
digitalHumanQiniuSecretKey,
videoAnalyzerApiKey,
replicationBriefApiKey,
vectCutApiKey
vectCutApiKey,
xhsFeishuAppId,
xhsFeishuAppSecret,
xhsFeishuAppToken,
xhsFeishuTableId
] = await Promise.all([
secretManager.getCopywritingModelApiKey(),
secretManager.getImageModelApiKey(),
...
...
@@ -647,7 +669,11 @@ export function registerDesktopIpc(services: MainServices): RegisteredDesktopIpc
secretManager.getDigitalHumanQiniuSecretKey(),
secretManager.getVideoAnalyzerApiKey(),
secretManager.getReplicationBriefApiKey(),
secretManager.getVectCutApiKey()
secretManager.getVectCutApiKey(),
secretManager.getXhsFeishuAppId(),
secretManager.getXhsFeishuAppSecret(),
secretManager.getXhsFeishuAppToken(),
secretManager.getXhsFeishuTableId()
]);
const runtime = buildProjectModelRuntime(projectId, config, {
copywritingApiKey,
...
...
@@ -659,7 +685,11 @@ export function registerDesktopIpc(services: MainServices): RegisteredDesktopIpc
digitalHumanQiniuSecretKey,
videoAnalyzerApiKey,
replicationBriefApiKey,
vectCutApiKey
vectCutApiKey,
xhsFeishuAppId,
xhsFeishuAppSecret,
xhsFeishuAppToken,
xhsFeishuTableId
});
const envFilePath = await materializeProjectModelRuntime(projectRoot, runtime);
...
...
@@ -1033,6 +1063,18 @@ export function registerDesktopIpc(services: MainServices): RegisteredDesktopIpc
if (typeof input.douyinRuntimeConfig?.vectcut?.apiKey === "
string
") {
await secretManager.setVectCutApiKey(input.douyinRuntimeConfig.vectcut.apiKey || undefined);
}
if (typeof input.xhsFeishuConfig?.appId === "
string
") {
await secretManager.setXhsFeishuAppId(input.xhsFeishuConfig.appId || undefined);
}
if (typeof input.xhsFeishuConfig?.appSecret === "
string
") {
await secretManager.setXhsFeishuAppSecret(input.xhsFeishuConfig.appSecret || undefined);
}
if (typeof input.xhsFeishuConfig?.appToken === "
string
") {
await secretManager.setXhsFeishuAppToken(input.xhsFeishuConfig.appToken || undefined);
}
if (typeof input.xhsFeishuConfig?.tableId === "
string
") {
await secretManager.setXhsFeishuTableId(input.xhsFeishuConfig.tableId || undefined);
}
if (
config.setupMode === "
direct
-
provider
"
|| previousConfig.setupMode !== config.setupMode
...
...
@@ -2360,5 +2402,3 @@ export function registerDesktopIpc(services: MainServices): RegisteredDesktopIpc
apps/desktop/src/main/services/app-config.ts
View file @
657746b3
...
...
@@ -12,7 +12,8 @@ import {
type
ModelEndpointConfig
,
type
RuntimeModePreference
,
type
SaveConfigInput
,
type
SetupMode
type
SetupMode
,
type
XhsFeishuConfig
}
from
"@qjclaw/shared-types"
;
export
type
RuntimeCloudApiBaseUrlSource
=
"config"
|
"env"
|
"default"
;
...
...
@@ -74,6 +75,7 @@ interface LegacyConfig {
apiKeyConfigured
?:
boolean
;
};
};
xhsFeishuConfig
?:
Partial
<
XhsFeishuConfig
>
;
}
function
normalizeGatewayUrl
(
raw
:
string
):
string
{
...
...
@@ -206,6 +208,15 @@ function createDefaultDouyinRuntimeConfig(): DouyinRuntimeConfig {
};
}
function
createDefaultXhsFeishuConfig
():
XhsFeishuConfig
{
return
{
appIdConfigured
:
false
,
appSecretConfigured
:
false
,
appTokenConfigured
:
false
,
tableIdConfigured
:
false
};
}
function
mergeExpertModelConfig
(
current
:
ExpertModelConfig
,
input
?:
SaveConfigInput
[
"expertModelConfig"
]
...
...
@@ -277,6 +288,18 @@ function mergeDouyinRuntimeConfig(
};
}
function
mergeXhsFeishuConfig
(
current
:
XhsFeishuConfig
,
input
?:
SaveConfigInput
[
"xhsFeishuConfig"
]
):
XhsFeishuConfig
{
return
{
appIdConfigured
:
typeof
input
?.
appId
===
"string"
?
Boolean
(
input
.
appId
.
trim
())
:
current
.
appIdConfigured
,
appSecretConfigured
:
typeof
input
?.
appSecret
===
"string"
?
Boolean
(
input
.
appSecret
.
trim
())
:
current
.
appSecretConfigured
,
appTokenConfigured
:
typeof
input
?.
appToken
===
"string"
?
Boolean
(
input
.
appToken
.
trim
())
:
current
.
appTokenConfigured
,
tableIdConfigured
:
typeof
input
?.
tableId
===
"string"
?
Boolean
(
input
.
tableId
.
trim
())
:
current
.
tableIdConfigured
};
}
export
function
getRuntimeCloudApiTarget
(
config
:
Pick
<
AppConfig
,
"runtimeCloudApiBaseUrl"
>
):
RuntimeCloudApiTarget
{
return
resolveRuntimeCloudApiTarget
(
config
.
runtimeCloudApiBaseUrl
);
}
...
...
@@ -310,7 +333,8 @@ export class AppConfigService {
runtimeCloudApiBaseUrl
:
migrateDeprecatedRuntimeCloudApiBaseUrl
(
input
.
runtimeCloudApiBaseUrl
),
runtimeMode
:
normalizeRuntimeMode
(
input
.
runtimeMode
),
expertModelConfig
:
mergeExpertModelConfig
(
current
.
expertModelConfig
,
input
.
expertModelConfig
),
douyinRuntimeConfig
:
mergeDouyinRuntimeConfig
(
current
.
douyinRuntimeConfig
,
input
.
douyinRuntimeConfig
)
douyinRuntimeConfig
:
mergeDouyinRuntimeConfig
(
current
.
douyinRuntimeConfig
,
input
.
douyinRuntimeConfig
),
xhsFeishuConfig
:
mergeXhsFeishuConfig
(
current
.
xhsFeishuConfig
,
input
.
xhsFeishuConfig
)
};
await
this
.
writeConfig
(
config
);
...
...
@@ -347,13 +371,15 @@ export class AppConfigService {
runtimeCloudApiBaseUrl
:
""
,
runtimeMode
:
normalizeRuntimeMode
(
process
.
env
.
QJCLAW_RUNTIME_MODE
),
expertModelConfig
:
createDefaultExpertModelConfig
(),
douyinRuntimeConfig
:
createDefaultDouyinRuntimeConfig
()
douyinRuntimeConfig
:
createDefaultDouyinRuntimeConfig
(),
xhsFeishuConfig
:
createDefaultXhsFeishuConfig
()
};
}
private
normalizeConfig
(
config
:
LegacyConfig
):
AppConfig
{
const
defaultExpertModelConfig
=
createDefaultExpertModelConfig
();
const
defaultDouyinRuntimeConfig
=
createDefaultDouyinRuntimeConfig
();
const
defaultXhsFeishuConfig
=
createDefaultXhsFeishuConfig
();
return
{
setupMode
:
normalizeSetupMode
(
config
.
setupMode
),
provider
:
config
.
provider
??
"openai"
,
...
...
@@ -415,6 +441,12 @@ export class AppConfigService {
: defaultDouyinRuntimeConfig.vectcut.fileBaseUrl,
apiKeyConfigured: Boolean(config.douyinRuntimeConfig?.vectcut?.apiKeyConfigured)
}
},
xhsFeishuConfig: {
appIdConfigured: Boolean(config.xhsFeishuConfig?.appIdConfigured ?? defaultXhsFeishuConfig.appIdConfigured),
appSecretConfigured: Boolean(config.xhsFeishuConfig?.appSecretConfigured ?? defaultXhsFeishuConfig.appSecretConfigured),
appTokenConfigured: Boolean(config.xhsFeishuConfig?.appTokenConfigured ?? defaultXhsFeishuConfig.appTokenConfigured),
tableIdConfigured: Boolean(config.xhsFeishuConfig?.tableIdConfigured ?? defaultXhsFeishuConfig.tableIdConfigured)
}
};
}
...
...
apps/desktop/src/main/services/project-model-runtime.ts
View file @
657746b3
...
...
@@ -13,6 +13,10 @@ export interface ProjectModelRuntimeSecrets {
videoAnalyzerApiKey
?:
string
;
replicationBriefApiKey
?:
string
;
vectCutApiKey
?:
string
;
xhsFeishuAppId
?:
string
;
xhsFeishuAppSecret
?:
string
;
xhsFeishuAppToken
?:
string
;
xhsFeishuTableId
?:
string
;
}
export
interface
ProjectModelRuntimePreparation
{
...
...
@@ -107,7 +111,7 @@ export function validateProjectModelRuntime(
const
copywritingBaseUrl
=
normalizeOpenAiCompatibleBaseUrl
(
config
.
expertModelConfig
.
copywriting
.
baseUrl
);
const
copywritingModelId
=
normalizeValue
(
config
.
expertModelConfig
.
copywriting
.
modelId
);
const
copywritingApiKey
=
normalizeValue
(
secrets
.
copywritingApiKey
);
const
imageBaseUrl
=
withoutTrailingSlash
(
config
.
expertModelConfig
.
image
.
baseUrl
);
const
imageBaseUrl
=
normalizeArkBaseUrl
(
config
.
expertModelConfig
.
image
.
baseUrl
);
const
imageModelId
=
normalizeValue
(
config
.
expertModelConfig
.
image
.
modelId
);
const
imageApiKey
=
normalizeValue
(
secrets
.
imageApiKey
);
...
...
@@ -219,7 +223,7 @@ export function buildProjectModelRuntime(
const
copywritingBaseUrl
=
normalizeOpenAiCompatibleBaseUrl
(
config
.
expertModelConfig
.
copywriting
.
baseUrl
);
const
copywritingModelId
=
normalizeValue
(
config
.
expertModelConfig
.
copywriting
.
modelId
);
const
copywritingApiKey
=
normalizeValue
(
secrets
.
copywritingApiKey
);
const
imageBaseUrl
=
withoutTrailingSlash
(
config
.
expertModelConfig
.
image
.
baseUrl
);
const
imageBaseUrl
=
normalizeArkBaseUrl
(
config
.
expertModelConfig
.
image
.
baseUrl
);
const
imageModelId
=
normalizeValue
(
config
.
expertModelConfig
.
image
.
modelId
);
const
imageApiKey
=
normalizeValue
(
secrets
.
imageApiKey
);
const
videoBaseUrl
=
withoutTrailingSlash
(
config
.
expertModelConfig
.
video
.
baseUrl
);
...
...
@@ -238,6 +242,10 @@ export function buildProjectModelRuntime(
const
vectCutBaseUrl
=
withoutTrailingSlash
(
config
.
douyinRuntimeConfig
.
vectcut
.
baseUrl
);
const
vectCutFileBaseUrl
=
withoutTrailingSlash
(
config
.
douyinRuntimeConfig
.
vectcut
.
fileBaseUrl
);
const
vectCutApiKey
=
normalizeValue
(
secrets
.
vectCutApiKey
);
const
xhsFeishuAppId
=
normalizeValue
(
secrets
.
xhsFeishuAppId
);
const
xhsFeishuAppSecret
=
normalizeValue
(
secrets
.
xhsFeishuAppSecret
);
const
xhsFeishuAppToken
=
normalizeValue
(
secrets
.
xhsFeishuAppToken
);
const
xhsFeishuTableId
=
normalizeValue
(
secrets
.
xhsFeishuTableId
);
const
env
:
Record
<
string
,
string
>
=
{};
if
(
XHS_PROJECT_IDS
.
has
(
normalizedProjectId
))
{
...
...
@@ -263,6 +271,18 @@ export function buildProjectModelRuntime(
if
(
imageModelId
)
{
env
.
XHS_IMAGE_MODEL
=
imageModelId
;
}
if
(
xhsFeishuAppId
)
{
env
.
FEISHU_APP_ID
=
xhsFeishuAppId
;
}
if
(
xhsFeishuAppSecret
)
{
env
.
FEISHU_APP_SECRET
=
xhsFeishuAppSecret
;
}
if
(
xhsFeishuAppToken
)
{
env
.
FEISHU_APP_TOKEN
=
xhsFeishuAppToken
;
}
if
(
xhsFeishuTableId
)
{
env
.
FEISHU_TABLE_ID
=
xhsFeishuTableId
;
}
}
if
(
DOUYIN_PROJECT_IDS
.
has
(
normalizedProjectId
))
{
...
...
apps/desktop/src/main/services/secrets.ts
View file @
657746b3
...
...
@@ -17,6 +17,10 @@ interface SecretRecord {
videoAnalyzerApiKey
?:
string
;
replicationBriefApiKey
?:
string
;
vectCutApiKey
?:
string
;
xhsFeishuAppId
?:
string
;
xhsFeishuAppSecret
?:
string
;
xhsFeishuAppToken
?:
string
;
xhsFeishuTableId
?:
string
;
}
interface
SecretAccessor
{
...
...
@@ -38,7 +42,11 @@ type SecretName =
|
"digitalHumanQiniuSecretKey"
|
"videoAnalyzerApiKey"
|
"replicationBriefApiKey"
|
"vectCutApiKey"
;
|
"vectCutApiKey"
|
"xhsFeishuAppId"
|
"xhsFeishuAppSecret"
|
"xhsFeishuAppToken"
|
"xhsFeishuTableId"
;
type
KeytarModule
=
typeof
import
(
"keytar"
);
const
KEYTAR_SERVICE
=
"QianjiangClaw"
;
...
...
@@ -57,7 +65,11 @@ const KEYTAR_ACCOUNT_MAP: Record<SecretName, string> = {
digitalHumanQiniuSecretKey
:
"digital-human-qiniu-secret-key"
,
videoAnalyzerApiKey
:
"douyin-video-analyzer-api-key"
,
replicationBriefApiKey
:
"douyin-replication-brief-api-key"
,
vectCutApiKey
:
"douyin-vectcut-api-key"
vectCutApiKey
:
"douyin-vectcut-api-key"
,
xhsFeishuAppId
:
"xhs-feishu-app-id"
,
xhsFeishuAppSecret
:
"xhs-feishu-app-secret"
,
xhsFeishuAppToken
:
"xhs-feishu-app-token"
,
xhsFeishuTableId
:
"xhs-feishu-table-id"
};
class
FileSecretStore
implements
SecretAccessor
{
...
...
@@ -277,6 +289,38 @@ export class SecretManager {
return
this
.
store
.
get
(
"vectCutApiKey"
);
}
async
setXhsFeishuAppId
(
value
?:
string
):
Promise
<
void
>
{
await
this
.
store
.
set
(
"xhsFeishuAppId"
,
value
);
}
async
getXhsFeishuAppId
():
Promise
<
string
|
undefined
>
{
return
this
.
store
.
get
(
"xhsFeishuAppId"
);
}
async
setXhsFeishuAppSecret
(
value
?:
string
):
Promise
<
void
>
{
await
this
.
store
.
set
(
"xhsFeishuAppSecret"
,
value
);
}
async
getXhsFeishuAppSecret
():
Promise
<
string
|
undefined
>
{
return
this
.
store
.
get
(
"xhsFeishuAppSecret"
);
}
async
setXhsFeishuAppToken
(
value
?:
string
):
Promise
<
void
>
{
await
this
.
store
.
set
(
"xhsFeishuAppToken"
,
value
);
}
async
getXhsFeishuAppToken
():
Promise
<
string
|
undefined
>
{
return
this
.
store
.
get
(
"xhsFeishuAppToken"
);
}
async
setXhsFeishuTableId
(
value
?:
string
):
Promise
<
void
>
{
await
this
.
store
.
set
(
"xhsFeishuTableId"
,
value
);
}
async
getXhsFeishuTableId
():
Promise
<
string
|
undefined
>
{
return
this
.
store
.
get
(
"xhsFeishuTableId"
);
}
private
async
tryLoadKeytar
():
Promise
<
KeytarModule
|
null
>
{
try
{
const
imported
=
await
import
(
"keytar"
);
...
...
@@ -301,7 +345,11 @@ export class SecretManager {
"digitalHumanQiniuSecretKey"
,
"videoAnalyzerApiKey"
,
"replicationBriefApiKey"
,
"vectCutApiKey"
"vectCutApiKey"
,
"xhsFeishuAppId"
,
"xhsFeishuAppSecret"
,
"xhsFeishuAppToken"
,
"xhsFeishuTableId"
]
as
const
)
{
const
existing
=
await
this
.
store
.
get
(
secretName
);
if
(
existing
)
{
...
...
apps/ui/src/App.tsx
View file @
657746b3
...
...
@@ -1253,10 +1253,12 @@ declare global {
workspacePath
?:
string
;
expertModelConfig
?:
SaveConfigInput
[
"expertModelConfig"
];
douyinRuntimeConfig
?:
SaveConfigInput
[
"douyinRuntimeConfig"
];
xhsFeishuConfig
?:
SaveConfigInput
[
"xhsFeishuConfig"
];
}):
Promise
<
{
workspacePath
:
string
;
expertModelConfig
:
AppConfig
[
"expertModelConfig"
];
douyinRuntimeConfig
:
AppConfig
[
"douyinRuntimeConfig"
];
xhsFeishuConfig
:
AppConfig
[
"xhsFeishuConfig"
];
apiKeyConfigured
:
boolean
;
}
>
;
createProjectSession
(
projectId
?:
string
,
title
?:
string
):
Promise
<
SessionSummary
>
;
...
...
@@ -2093,6 +2095,10 @@ export default function App() {
const [vectcutBaseUrlDraft, setVectcutBaseUrlDraft] = useState("");
const [vectcutFileBaseUrlDraft, setVectcutFileBaseUrlDraft] = useState("");
const [vectcutApiKeyDraft, setVectcutApiKeyDraft] = useState("");
const [xhsFeishuAppIdDraft, setXhsFeishuAppIdDraft] = useState("");
const [xhsFeishuAppSecretDraft, setXhsFeishuAppSecretDraft] = useState("");
const [xhsFeishuAppTokenDraft, setXhsFeishuAppTokenDraft] = useState("");
const [xhsFeishuTableIdDraft, setXhsFeishuTableIdDraft] = useState("");
const [refreshing, setRefreshing] = useState(false);
const [saving, setSaving] = useState(false);
const [sendPhase, setSendPhase] = useState<SendPhase>("idle");
...
...
@@ -2222,6 +2228,12 @@ export default function App() {
const sending = sendPhase !== "idle";
const canSend = isBound && hasConversationProject && (prompt.trim().length > 0 || composerAttachments.length > 0) && !sending && !saving;
const hasPendingLobsterKey = lobsterKeyDraft.trim().length > 0;
const hasPendingXhsFeishuConfig = Boolean(
xhsFeishuAppIdDraft.trim()
|| xhsFeishuAppSecretDraft.trim()
|| xhsFeishuAppTokenDraft.trim()
|| xhsFeishuTableIdDraft.trim()
);
const hasPendingModelKeys = Boolean(
imageModelApiKeyDraft.trim()
|| videoModelApiKeyDraft.trim()
...
...
@@ -2949,10 +2961,12 @@ export default function App() {
workspacePath?: string;
expertModelConfig?: SaveConfigInput["expertModelConfig"];
douyinRuntimeConfig?: SaveConfigInput["douyinRuntimeConfig"];
xhsFeishuConfig?: SaveConfigInput["xhsFeishuConfig"];
}) => {
const nextWorkspacePath = options?.workspacePath;
const nextExpertModelConfig = options?.expertModelConfig;
const nextDouyinRuntimeConfig = options?.douyinRuntimeConfig;
const nextXhsFeishuConfig = options?.xhsFeishuConfig;
if (typeof nextWorkspacePath === "string") {
setWorkspacePathDraft(nextWorkspacePath);
}
...
...
@@ -2986,6 +3000,12 @@ export default function App() {
setVectcutFileBaseUrlDraft(nextDouyinRuntimeConfig.vectcut.fileBaseUrl ?? "");
setVectcutApiKeyDraft(nextDouyinRuntimeConfig.vectcut.apiKey ?? "");
}
if (nextXhsFeishuConfig) {
setXhsFeishuAppIdDraft(nextXhsFeishuConfig.appId ?? "");
setXhsFeishuAppSecretDraft(nextXhsFeishuConfig.appSecret ?? "");
setXhsFeishuAppTokenDraft(nextXhsFeishuConfig.appToken ?? "");
setXhsFeishuTableIdDraft(nextXhsFeishuConfig.tableId ?? "");
}
if (typeof options?.lobsterKey === "string") {
setLobsterKeyDraft(options.lobsterKey);
}
...
...
@@ -2994,7 +3014,8 @@ export default function App() {
lobsterKey: options?.lobsterKey,
workspacePath: nextWorkspacePath,
expertModelConfig: nextExpertModelConfig,
douyinRuntimeConfig: nextDouyinRuntimeConfig
douyinRuntimeConfig: nextDouyinRuntimeConfig,
xhsFeishuConfig: nextXhsFeishuConfig
});
const latestConfig = await desktopApi.config.load();
...
...
@@ -3010,12 +3031,17 @@ export default function App() {
setVideoAnalyzerApiKeyDraft("");
setReplicationBriefApiKeyDraft("");
setVectcutApiKeyDraft("");
setXhsFeishuAppIdDraft("");
setXhsFeishuAppSecretDraft("");
setXhsFeishuAppTokenDraft("");
setXhsFeishuTableIdDraft("");
await waitForSmokeConfigPublish(latestConfig.expertModelConfig);
return {
workspacePath: latestConfig.workspacePath,
expertModelConfig: latestConfig.expertModelConfig,
douyinRuntimeConfig: latestConfig.douyinRuntimeConfig,
xhsFeishuConfig: latestConfig.xhsFeishuConfig,
apiKeyConfigured: latestConfig.apiKeyConfigured
};
},
...
...
@@ -3517,6 +3543,7 @@ export default function App() {
workspacePath?: string;
expertModelConfig?: SaveConfigInput["expertModelConfig"];
douyinRuntimeConfig?: SaveConfigInput["douyinRuntimeConfig"];
xhsFeishuConfig?: SaveConfigInput["xhsFeishuConfig"];
successMessage?: string;
}) {
if (!config) {
...
...
@@ -3559,6 +3586,12 @@ export default function App() {
apiKey: vectcutApiKeyDraft.trim() || undefined
}
};
const resolvedXhsFeishuConfig = options?.xhsFeishuConfig ?? {
appId: xhsFeishuAppIdDraft.trim() || undefined,
appSecret: xhsFeishuAppSecretDraft.trim() || undefined,
appToken: xhsFeishuAppTokenDraft.trim() || undefined,
tableId: xhsFeishuTableIdDraft.trim() || undefined
};
const input: SaveConfigInput = {
setupMode: config.setupMode,
provider: config.provider,
...
...
@@ -3571,6 +3604,7 @@ export default function App() {
runtimeMode: "bundled-runtime",
expertModelConfig: resolvedExpertModelConfig,
douyinRuntimeConfig: resolvedDouyinRuntimeConfig,
xhsFeishuConfig: resolvedXhsFeishuConfig,
...(trimmedLobsterKey ? { apiKey: trimmedLobsterKey } : {})
};
...
...
@@ -3593,6 +3627,10 @@ export default function App() {
setVideoAnalyzerApiKeyDraft("");
setReplicationBriefApiKeyDraft("");
setVectcutApiKeyDraft("");
setXhsFeishuAppIdDraft("");
setXhsFeishuAppSecretDraft("");
setXhsFeishuAppTokenDraft("");
setXhsFeishuTableIdDraft("");
setInfoText(options?.successMessage ?? (trimmedLobsterKey ? ui.saveSuccessPending : ui.saveSuccessApplied));
void refresh(false);
} catch (error) {
...
...
@@ -4913,8 +4951,8 @@ export default function App() {
) : null}
</div>
</aside>
<div className={"main-shell" + (isConversationView ? " conversation-main-layout" : "")}>
{
!isConversationView && viewMode !== "knowledge
" ? (
<div className={"main-shell" + (isConversationView ? " conversation-main-layout" : "")
+ (viewMode === "settings" ? " settings-main-shell" : "")
}>
{
viewMode === "plugins
" ? (
<div className="page-topbar">
<div className="page-copy">
<h2>{pageTitle}</h2>
...
...
@@ -5079,6 +5117,51 @@ export default function App() {
</div>
</div>
</section>
<section className="panel settings-panel settings-panel-secondary settings-panel-xhs-feishu">
<div className="settings-section-card settings-section-card-compact">
<div className="settings-section-headline">
<div>
<span className="settings-section-kicker">小红书飞书配置</span>
</div>
<StatusChip tone={
config?.xhsFeishuConfig.appIdConfigured
&& config?.xhsFeishuConfig.appSecretConfigured
&& config?.xhsFeishuConfig.appTokenConfigured
&& config?.xhsFeishuConfig.tableIdConfigured
? "positive"
: "warning"
}>
{config?.xhsFeishuConfig.appIdConfigured
&& config?.xhsFeishuConfig.appSecretConfigured
&& config?.xhsFeishuConfig.appTokenConfigured
&& config?.xhsFeishuConfig.tableIdConfigured
? "已配置"
: "未配置"}
</StatusChip>
</div>
<div className="settings-field-grid settings-field-grid-xhs-feishu">
<label className="settings-input-label">
<span className="settings-input-label-text">FEISHU_APP_ID</span>
<input type="password" value={xhsFeishuAppIdDraft} placeholder={config?.xhsFeishuConfig.appIdConfigured ? "留空则保持当前已保存密钥" : "请输入 App ID"} onChange={(event) => setXhsFeishuAppIdDraft(event.target.value)} />
</label>
<label className="settings-input-label">
<span className="settings-input-label-text">FEISHU_APP_SECRET</span>
<input type="password" value={xhsFeishuAppSecretDraft} placeholder={config?.xhsFeishuConfig.appSecretConfigured ? "留空则保持当前已保存密钥" : "请输入 App Secret"} onChange={(event) => setXhsFeishuAppSecretDraft(event.target.value)} />
</label>
<label className="settings-input-label">
<span className="settings-input-label-text">FEISHU_APP_TOKEN</span>
<input type="password" value={xhsFeishuAppTokenDraft} placeholder={config?.xhsFeishuConfig.appTokenConfigured ? "留空则保持当前已保存密钥" : "请输入 App Token"} onChange={(event) => setXhsFeishuAppTokenDraft(event.target.value)} />
</label>
<label className="settings-input-label">
<span className="settings-input-label-text">FEISHU_TABLE_ID</span>
<input type="password" value={xhsFeishuTableIdDraft} placeholder={config?.xhsFeishuConfig.tableIdConfigured ? "留空则保持当前已保存密钥" : "请输入 Table ID"} onChange={(event) => setXhsFeishuTableIdDraft(event.target.value)} />
</label>
</div>
<div className="button-row settings-actions">
<button className="settings-primary-button" disabled={saving || !hasPendingXhsFeishuConfig} onClick={() => void saveConfig()}>{saving ? ui.saving : "保存"}</button>
</div>
</div>
</section>
<section className="panel settings-panel settings-panel-models">
<div className="settings-section-card settings-section-card-models">
<div className="settings-section-headline settings-section-headline-minimal">
...
...
apps/ui/src/styles.css
View file @
657746b3
...
...
@@ -3251,6 +3251,11 @@ button.secondary {
gap
:
14px
;
}
.main-shell.settings-main-shell
{
padding-top
:
8px
;
gap
:
0
;
}
.page-topbar
{
align-items
:
center
;
min-height
:
72px
;
...
...
@@ -4108,11 +4113,11 @@ button.secondary {
min-height
:
0
;
display
:
grid
;
gap
:
10px
;
grid-template-columns
:
repeat
(
2
,
minmax
(
0
,
1
fr
));
grid-template-rows
:
minmax
(
164px
,
0.43
fr
)
minmax
(
0
,
1.57
fr
);
grid-template-columns
:
repeat
(
3
,
minmax
(
0
,
1
fr
));
grid-template-rows
:
minmax
(
236px
,
0.58
fr
)
minmax
(
0
,
1.42
fr
);
grid-template-areas
:
"connection diagnostics"
"models models"
;
"connection diagnostics
xhs-feishu
"
"models models
models
"
;
overflow
:
hidden
;
}
...
...
@@ -4124,6 +4129,26 @@ button.secondary {
grid-area
:
diagnostics
;
}
.settings-panel-xhs-feishu
{
grid-area
:
xhs-feishu
;
}
.settings-panel-xhs-feishu
.settings-section-card-compact
{
grid-template-rows
:
auto
auto
auto
;
align-content
:
start
;
gap
:
7px
;
padding
:
8px
;
}
.settings-panel-xhs-feishu
.settings-section-headline
{
align-items
:
center
;
}
.settings-panel-xhs-feishu
.settings-section-kicker
{
min-height
:
22px
;
padding-inline
:
9px
;
}
.settings-panel-models
{
grid-area
:
models
;
}
...
...
@@ -4403,6 +4428,32 @@ button.secondary {
grid-template-columns
:
repeat
(
2
,
minmax
(
0
,
1
fr
));
}
.settings-field-grid-xhs-feishu
{
grid-template-columns
:
repeat
(
2
,
minmax
(
0
,
1
fr
));
gap
:
7px
;
align-content
:
start
;
}
.settings-field-grid-xhs-feishu
.settings-input-label
{
gap
:
3px
;
}
.settings-field-grid-xhs-feishu
.settings-input-label
input
{
min-height
:
34px
;
padding
:
7px
10px
;
}
.settings-panel-xhs-feishu
.settings-actions
{
margin-top
:
0
;
align-items
:
center
;
}
.settings-panel-xhs-feishu
.settings-primary-button
{
min-height
:
30px
;
padding
:
6px
14px
;
font-size
:
12px
;
}
.settings-panel
.status-chip
{
min-height
:
24px
;
padding
:
0
9px
;
...
...
@@ -4500,6 +4551,15 @@ button.secondary {
}
@media
(
max-width
:
1180px
)
{
.settings-console-grid
{
grid-template-columns
:
repeat
(
2
,
minmax
(
0
,
1
fr
));
grid-template-rows
:
minmax
(
164px
,
auto
)
minmax
(
210px
,
auto
)
minmax
(
0
,
1
fr
);
grid-template-areas
:
"connection diagnostics"
"xhs-feishu xhs-feishu"
"models models"
;
}
.model-config-grid-four
{
grid-template-columns
:
repeat
(
2
,
minmax
(
0
,
1
fr
));
grid-auto-rows
:
minmax
(
188px
,
auto
);
...
...
@@ -4536,6 +4596,7 @@ button.secondary {
grid-template-areas
:
"connection"
"diagnostics"
"xhs-feishu"
"models"
;
overflow
:
visible
;
}
...
...
packages/shared-types/src/index.ts
View file @
657746b3
...
...
@@ -589,6 +589,13 @@ export interface DouyinRuntimeConfig {
vectcut
:
VectCutModelConfig
;
}
export
interface
XhsFeishuConfig
{
appIdConfigured
:
boolean
;
appSecretConfigured
:
boolean
;
appTokenConfigured
:
boolean
;
tableIdConfigured
:
boolean
;
}
export
const
FIXED_EXPERT_MODEL_ENDPOINTS
=
{
copywriting
:
{
baseUrl
:
"https://dashscope.aliyuncs.com/compatible-mode/v1"
,
...
...
@@ -645,6 +652,7 @@ export interface AppConfig {
runtimeMode
:
RuntimeModePreference
;
expertModelConfig
:
ExpertModelConfig
;
douyinRuntimeConfig
:
DouyinRuntimeConfig
;
xhsFeishuConfig
:
XhsFeishuConfig
;
}
export
interface
DiagnosticsExportResult
{
...
...
@@ -678,6 +686,13 @@ export interface VectCutModelInput {
apiKey
?:
string
;
}
export
interface
XhsFeishuConfigInput
{
appId
?:
string
;
appSecret
?:
string
;
appToken
?:
string
;
tableId
?:
string
;
}
export
interface
SaveConfigInput
{
setupMode
:
SetupMode
;
provider
:
string
;
...
...
@@ -702,6 +717,7 @@ export interface SaveConfigInput {
replicationBrief
?:
DouyinTextModelInput
;
vectcut
?:
VectCutModelInput
;
};
xhsFeishuConfig
?:
XhsFeishuConfigInput
;
}
export
interface
AuthSessionSummary
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment