Merge pull request #61 from devchat-ai/sync_server_config
Sync config from server
This commit is contained in:
commit
f78ab29e18
@ -54,10 +54,14 @@ class MessageUtil {
|
||||
}
|
||||
|
||||
// Handle a received message
|
||||
handleMessage(message: { command: string | number }) {
|
||||
handleMessage(message: { command: string | number } & Record<string, any>) {
|
||||
if (!('command' in message)) {
|
||||
throw new Error('Missing required field: command');
|
||||
}
|
||||
|
||||
const handlers = this.handlers[message.command];
|
||||
if (handlers) {
|
||||
handlers.forEach((handler: (arg0: { command: string | number }) => any) =>
|
||||
handlers.forEach((handler: (arg0: { command: string | number } & Record<string, any>) => any) =>
|
||||
handler(message)
|
||||
);
|
||||
}
|
||||
|
@ -302,6 +302,18 @@ const JStoIdea = {
|
||||
};
|
||||
window.JSJavaBridge.callJava(JSON.stringify(params));
|
||||
},
|
||||
readServerConfigBase: () => {
|
||||
// 获取完整的用户设置
|
||||
const params = {
|
||||
action: "getServerSetting/request",
|
||||
metadata: {
|
||||
callback: "IdeaToJSMessage",
|
||||
},
|
||||
payload: {},
|
||||
};
|
||||
window.JSJavaBridge.callJava(JSON.stringify(params));
|
||||
},
|
||||
|
||||
saveConfig: (data) => {
|
||||
const params = {
|
||||
action: "updateSetting/request",
|
||||
@ -314,6 +326,19 @@ const JStoIdea = {
|
||||
console.log("ready to call java: ", JSON.stringify(params));
|
||||
window.JSJavaBridge.callJava(JSON.stringify(params));
|
||||
},
|
||||
|
||||
writeServerConfigBase: (data) => {
|
||||
const params = {
|
||||
action: "updateServerSetting/request",
|
||||
metadata: {
|
||||
callback: "IdeaToJSMessage",
|
||||
},
|
||||
payload: data,
|
||||
};
|
||||
|
||||
console.log("ready to call java: ", JSON.stringify(params));
|
||||
window.JSJavaBridge.callJava(JSON.stringify(params));
|
||||
},
|
||||
};
|
||||
|
||||
class IdeaBridge {
|
||||
@ -462,6 +487,15 @@ class IdeaBridge {
|
||||
});
|
||||
}
|
||||
|
||||
resviceServerSettings(res) {
|
||||
// 获取用户设置的回调
|
||||
const setting = res?.payload || {};
|
||||
|
||||
this.executeHandlers("readServerConfigBase", {
|
||||
value: setting,
|
||||
});
|
||||
}
|
||||
|
||||
resviceCommandList(res) {
|
||||
this.executeHandlers("regCommandList", {
|
||||
result: res.payload.commands,
|
||||
@ -601,10 +635,17 @@ class IdeaBridge {
|
||||
case "readConfig":
|
||||
JStoIdea.readConfig();
|
||||
break;
|
||||
case "readServerConfigBase":
|
||||
JStoIdea.readServerConfigBase();
|
||||
break;
|
||||
case "writeConfig":
|
||||
// 保存用户设置
|
||||
JStoIdea.saveConfig(message.value);
|
||||
break;
|
||||
case "writeServerConfigBase":
|
||||
// 保存用户设置
|
||||
JStoIdea.writeServerConfigBase(message.value);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -26,14 +26,59 @@ export default function App() {
|
||||
};
|
||||
|
||||
const getConfig = () => {
|
||||
// 比较函数
|
||||
const compare_func = (configs: any) => {
|
||||
const [serverConfig, userConfig] = config.updateConfig(configs.server_config, configs.server_config_base, configs.user_config);
|
||||
if (serverConfig) {
|
||||
// save server config as base
|
||||
MessageUtil.sendMessage({ command: "writeServerConfigBase", value: serverConfig });
|
||||
}
|
||||
|
||||
// set user config
|
||||
config.setConfig(userConfig);
|
||||
};
|
||||
|
||||
// 结果记录
|
||||
let configs = {};
|
||||
let configCount = 0;
|
||||
|
||||
// 处理函数
|
||||
const handleConfig = (key: string, data: { value: any }) => {
|
||||
console.log("-----> receive:", key);
|
||||
configs[key] = {...data.value};
|
||||
configCount++;
|
||||
checkConfigs();
|
||||
};
|
||||
|
||||
// 检查是否所有配置都已准备好
|
||||
const checkConfigs = () => {
|
||||
if (configCount === 3) {
|
||||
compare_func(configs);
|
||||
setReady(true); // 假设setReady是一个函数,用于设置应用状态为准备就绪
|
||||
}
|
||||
};
|
||||
|
||||
// 注册处理函数
|
||||
MessageUtil.registerHandler("readConfig", (data: { value: any }) => {
|
||||
console.log("readConfig registerHandler: ", data);
|
||||
config.setConfig(data.value);
|
||||
APIUtil.config(config.getAPIBase(), config.getUserKey())
|
||||
config.refreshModelList();
|
||||
setReady(true);
|
||||
config.fetchServerConfig();
|
||||
handleConfig("user_config", data);
|
||||
});
|
||||
MessageUtil.sendMessage({ command: "readConfig", key: "" });
|
||||
MessageUtil.registerHandler("readServerConfigBase", (data: { value: any }) => handleConfig("server_config_base", data));
|
||||
MessageUtil.registerHandler("readServerConfig", (data: { value: any }) => handleConfig("server_config", data));
|
||||
|
||||
MessageUtil.registerHandler(
|
||||
"reloadConfig",
|
||||
(data: { value: any }) => {
|
||||
configs = {};
|
||||
configCount = 0;
|
||||
|
||||
// 发送消息
|
||||
MessageUtil.sendMessage({ command: "readConfig", key: "" });
|
||||
MessageUtil.sendMessage({ command: "readServerConfigBase", key: "" });
|
||||
});
|
||||
MessageUtil.handleMessage({ command: "reloadConfig" });
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -113,7 +113,7 @@ const Config = observer(() => {
|
||||
useEffect(() => {
|
||||
MessageUtil.registerHandler("updateSetting", (data) => {
|
||||
// 保存后的回调
|
||||
MessageUtil.sendMessage({ command: "readConfig" });
|
||||
MessageUtil.handleMessage({ command: "reloadConfig" });
|
||||
});
|
||||
if (router.currentRoute !== "config") {return;}
|
||||
const modelArray = config.modelsTemplate.map((item) => ({
|
||||
@ -160,8 +160,7 @@ const Config = observer(() => {
|
||||
key: "",
|
||||
});
|
||||
setTimeout(() => {
|
||||
config.setTemplate([], "");
|
||||
MessageUtil.sendMessage({ command: "readConfig", key: "" });
|
||||
MessageUtil.handleMessage({ command: "reloadConfig" });
|
||||
}, 1000);
|
||||
};
|
||||
|
||||
|
@ -9,20 +9,44 @@ const defaultAPIBase = [
|
||||
"https://api.devchat-ai.cn/v1",
|
||||
];
|
||||
|
||||
export const fetchLLMs = async ({modelsUrl,devchatApiKey}) => {
|
||||
return new Promise<{data:any}>((resolve, reject) => {
|
||||
// 添加 header: "Authorization: Bearer ${devchatApiKey}"
|
||||
axios.get(`${modelsUrl}/models`, { headers: { 'Authorization': `Bearer ${devchatApiKey}` }}).then((res) => {
|
||||
// 获取 models 模版列表
|
||||
if (res?.data?.data && Array.isArray(res?.data?.data)) {
|
||||
resolve(res.data);
|
||||
}
|
||||
}).catch((e) => {
|
||||
console.error("fetchLLMs error:", e);
|
||||
reject(e);
|
||||
});
|
||||
|
||||
function deepCopy(obj) {
|
||||
let copy = Array.isArray(obj) ? [] : {};
|
||||
|
||||
for (let key in obj) {
|
||||
if (obj.hasOwnProperty(key)) {
|
||||
if (typeof obj[key] === 'object' && obj[key] !== null) {
|
||||
copy[key] = deepCopy(obj[key]); // 递归调用
|
||||
} else {
|
||||
copy[key] = obj[key];
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
export const fetchServerConfigUtil = async ({ modelsUrl, devchatApiKey }) => {
|
||||
try {
|
||||
const response = await axios.get(`${modelsUrl}/models`, {
|
||||
headers: { 'Authorization': `Bearer ${devchatApiKey}` }
|
||||
});
|
||||
|
||||
if (response.status === 200) {
|
||||
if (response.data.data && Array.isArray(response.data.data)) {
|
||||
// change data to models key
|
||||
response.data.models = response.data.data;
|
||||
delete response.data.data;
|
||||
}
|
||||
return response.data;
|
||||
} else {
|
||||
console.error("fetchServerConfig error: Non-200 status code", response.status);
|
||||
return undefined;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("fetchServerConfig error:", e);
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
|
||||
export const Model = types.model({
|
||||
@ -53,11 +77,27 @@ export const ConfigStore = types
|
||||
provider: "devchat",
|
||||
})
|
||||
.actions((self) => {
|
||||
const setTemplate = (value: any, provider: string) => {
|
||||
const setTemplate = (value: any,) => {
|
||||
const provider = self.provider;
|
||||
const list: any[] = [];
|
||||
|
||||
for (const name in value) {
|
||||
if (value.hasOwnProperty(name)) {
|
||||
const item: any = { name };
|
||||
for (const key in value[name]) {
|
||||
if (value[name].hasOwnProperty(key)) {
|
||||
item[key] = value[name][key];
|
||||
}
|
||||
}
|
||||
list.push(item);
|
||||
}
|
||||
}
|
||||
value = list;
|
||||
|
||||
const models = value
|
||||
.map((item) => {
|
||||
return {
|
||||
name: item.model ?? item.id,
|
||||
name: item.name,
|
||||
max_input_tokens: item.max_input_tokens ?? 6000,
|
||||
provider: provider,
|
||||
stream: true,
|
||||
@ -112,47 +152,100 @@ export const ConfigStore = types
|
||||
}
|
||||
return "";
|
||||
},
|
||||
updateConfig(server_config: any, server_config_base: any, user_config: any) {
|
||||
console.log("----->:::updateConfig");
|
||||
// 如果server_config没有获取到,那么直接返回
|
||||
if (!server_config || !server_config.models) {
|
||||
return [undefined, user_config];
|
||||
}
|
||||
if (server_config_base === undefined) {
|
||||
server_config_base = {};
|
||||
}
|
||||
if (server_config_base.models === undefined) {
|
||||
server_config_base.models = {};
|
||||
}
|
||||
// 将 server_config 转换为本地配置存储的格式
|
||||
const localConfig: any = {"models": {}};
|
||||
server_config.models.forEach((model: any) => {
|
||||
const modelConfig: any = {};
|
||||
for (const key in model) {
|
||||
if (key !== 'model') {
|
||||
modelConfig[key] = model[key];
|
||||
}
|
||||
}
|
||||
localConfig["models"][model.model || model.id] = modelConfig;
|
||||
});
|
||||
|
||||
// 合并 config 部分,不假设具体的配置项名称
|
||||
for (const key in server_config.config) {
|
||||
localConfig[key] = server_config.config[key];
|
||||
}
|
||||
|
||||
// 使用子函数处理对比和更新
|
||||
const userConfigNew = this.compareConfigs(localConfig, server_config_base, user_config);
|
||||
|
||||
return [localConfig, userConfigNew];
|
||||
},
|
||||
compareConfigs(localConfig: any, baseConfig: any, userConfigIn: any) {
|
||||
let userConfig = { ...userConfigIn };
|
||||
|
||||
for (const key in localConfig) {
|
||||
if (baseConfig.hasOwnProperty(key) && userConfig.hasOwnProperty(key)) {
|
||||
// 递归比较对象的每个叶子结点
|
||||
if (typeof localConfig[key] === 'object' && !Array.isArray(localConfig[key]) && localConfig[key] !== null) {
|
||||
userConfig[key] = this.compareConfigs(localConfig[key], baseConfig[key], userConfig[key]);
|
||||
} else {
|
||||
if (localConfig[key] !== baseConfig[key]) {
|
||||
// 检查用户配置中是否存在该条目
|
||||
if (!userConfig[key] || JSON.stringify(userConfig[key]) === JSON.stringify(baseConfig[key])) {
|
||||
userConfig[key] = localConfig[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 新增的配置项
|
||||
if (!userConfig[key]) {
|
||||
if (!Object.isExtensible(userConfig)) {
|
||||
// 如果 userConfig 不可扩展,创建一个新的可扩展对象
|
||||
userConfig = { ...userConfig };
|
||||
}
|
||||
userConfig[key] = localConfig[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 处理删除的配置项,仅针对 models 下的 model
|
||||
if (localConfig.models ) {
|
||||
const localModels = localConfig.models;
|
||||
const userModels = userConfig.models;
|
||||
|
||||
for (const modelKey in userModels) {
|
||||
if (!localModels.hasOwnProperty(modelKey)) {
|
||||
// 删除的 model,从 userConfig 中移除
|
||||
delete userModels[modelKey];
|
||||
}
|
||||
}
|
||||
}
|
||||
return userConfig;
|
||||
},
|
||||
setConfig: function (data) {
|
||||
this.setTemplate(data.models);
|
||||
this.updateSettle(false);
|
||||
let needUpdate = false;
|
||||
const newConfig = { ...data };
|
||||
const newConfig: any = deepCopy(data);
|
||||
newConfig.models = newConfig.models || {};
|
||||
newConfig.providers = newConfig.providers || {};
|
||||
newConfig.providers.openai = newConfig.providers.openai || {
|
||||
api_key: "",
|
||||
api_base: "",
|
||||
};
|
||||
newConfig.providers.devchat = newConfig.providers.devchat || {
|
||||
api_key: "",
|
||||
api_base: "",
|
||||
};
|
||||
|
||||
self.modelsTemplate.forEach((item) => {
|
||||
const currentModel: any = {
|
||||
...item,
|
||||
if (!newConfig.providers.openai) {
|
||||
newConfig.providers.openai = {
|
||||
api_key: "",
|
||||
api_base: "",
|
||||
};
|
||||
delete currentModel.name;
|
||||
|
||||
if (!newConfig.models[item.name]) {
|
||||
newConfig.models[item.name] = {
|
||||
...currentModel,
|
||||
};
|
||||
needUpdate = true;
|
||||
}
|
||||
|
||||
if (newConfig.models[item.name].provider !== currentModel.provider) {
|
||||
needUpdate = true;
|
||||
newConfig.models[item.name].provider = currentModel.provider;
|
||||
}
|
||||
// 只有之前配置过 openai 的,provider 才可以是 openai
|
||||
if (
|
||||
newConfig.models[item.name].provider === "openai" &&
|
||||
!newConfig.providers.openai.api_key
|
||||
) {
|
||||
needUpdate = true;
|
||||
newConfig.models[item.name].provider = "devchat";
|
||||
}
|
||||
});
|
||||
}
|
||||
if (!newConfig.providers.devchat) {
|
||||
newConfig.providers.devchat = {
|
||||
api_key: "",
|
||||
api_base: "",
|
||||
};
|
||||
}
|
||||
|
||||
// 尝试获取 devchat 的 api_base
|
||||
self.provider = "devchat";
|
||||
@ -172,40 +265,30 @@ export const ConfigStore = types
|
||||
self.devchatApiKey = "1234";
|
||||
self.provider = "devchat";
|
||||
}
|
||||
|
||||
const modelsChat = self.modelsTemplate.filter(model => model.category === "chat");
|
||||
|
||||
if (modelsChat.length > 0 && modelsChat.find((item) => item.name === newConfig.default_model) === undefined) {
|
||||
const defaultModelName = 'qwen-72b-chat'
|
||||
newConfig.default_model = modelsChat.some(x => x.name === defaultModelName) ? defaultModelName : modelsChat[0].name;
|
||||
needUpdate = true;
|
||||
}
|
||||
|
||||
if (!defaultAPIBase.includes(newConfig.providers.devchat.api_base)) {
|
||||
newConfig.providers.devchat.cumstom_api_base =
|
||||
newConfig.providers.devchat.api_base;
|
||||
newConfig.providers.devchat.api_base = "custom";
|
||||
}
|
||||
if (this.checkAndSetCompletionDefaults(newConfig)) {
|
||||
needUpdate = true;
|
||||
}
|
||||
|
||||
self.config = newConfig;
|
||||
self.defaultModel = newConfig.default_model;
|
||||
if (needUpdate) {
|
||||
this.writeConfig();
|
||||
}
|
||||
this.writeConfig();
|
||||
this.updateSettle(true);
|
||||
},
|
||||
refreshModelList: flow(function* (){
|
||||
fetchServerConfig: flow(function* (){
|
||||
try {
|
||||
if (self.modelsTemplate.length === 0) {
|
||||
const { data } = yield fetchLLMs({modelsUrl:self.modelsUrl,devchatApiKey:self.devchatApiKey});
|
||||
setTemplate(data,self.provider);
|
||||
MessageUtil.sendMessage({ command: "readConfig", key: "" });
|
||||
const data = yield fetchServerConfigUtil({ modelsUrl: self.modelsUrl, devchatApiKey: self.devchatApiKey });
|
||||
if (data !== undefined) {
|
||||
MessageUtil.handleMessage({ command: "readServerConfig", value: data });
|
||||
} else {
|
||||
console.log("fetchLLMs error: Failed to fetch server config");
|
||||
MessageUtil.handleMessage({ command: "readServerConfig", value: undefined });
|
||||
}
|
||||
} catch (e) {
|
||||
console.log("fetchLLMs error:", e);
|
||||
MessageUtil.handleMessage({ command: "readServerConfig", value: undefined });
|
||||
}
|
||||
}),
|
||||
checkAndSetCompletionDefaults: (newConfig) => {
|
||||
@ -244,10 +327,6 @@ export const ConfigStore = types
|
||||
value: writeConfig,
|
||||
key: "",
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
MessageUtil.sendMessage({ command: "readConfig", key: "" });
|
||||
}, 1000);
|
||||
},
|
||||
setConfigValue: function (key: string, value: any) {
|
||||
if (key === "default_model") {
|
||||
|
Loading…
x
Reference in New Issue
Block a user