style: eslint 规则同步代码格式

This commit is contained in:
ocean-gao
2024-12-20 13:21:52 +08:00
parent 161fa63b02
commit 4b4fe29118
161 changed files with 12206 additions and 11827 deletions

View File

@@ -1,31 +1,31 @@
import { getHeaders } from '../client/api';
import { getClientConfig } from '../config/client';
import {
GoogleSafetySettingsThreshold,
ServiceProvider,
StoreKey,
ApiPath,
OPENAI_BASE_URL,
ALIBABA_BASE_URL,
ANTHROPIC_BASE_URL,
GEMINI_BASE_URL,
ApiPath,
BAIDU_BASE_URL,
BYTEDANCE_BASE_URL,
ALIBABA_BASE_URL,
TENCENT_BASE_URL,
MOONSHOT_BASE_URL,
STABILITY_BASE_URL,
IFLYTEK_BASE_URL,
XAI_BASE_URL,
CHATGLM_BASE_URL,
} from "../constant";
import { getHeaders } from "../client/api";
import { getClientConfig } from "../config/client";
import { createPersistStore } from "../utils/store";
import { ensure } from "../utils/clone";
import { DEFAULT_CONFIG } from "./config";
import { getModelProvider } from "../utils/model";
GEMINI_BASE_URL,
GoogleSafetySettingsThreshold,
IFLYTEK_BASE_URL,
MOONSHOT_BASE_URL,
OPENAI_BASE_URL,
ServiceProvider,
STABILITY_BASE_URL,
StoreKey,
TENCENT_BASE_URL,
XAI_BASE_URL,
} from '../constant';
import { ensure } from '../utils/clone';
import { getModelProvider } from '../utils/model';
import { createPersistStore } from '../utils/store';
import { DEFAULT_CONFIG } from './config';
let fetchState = 0; // 0 not fetch, 1 fetching, 2 done
const isApp = getClientConfig()?.buildMode === "export";
const isApp = getClientConfig()?.buildMode === 'export';
const DEFAULT_OPENAI_URL = isApp ? OPENAI_BASE_URL : ApiPath.OpenAI;
@@ -52,69 +52,69 @@ const DEFAULT_XAI_URL = isApp ? XAI_BASE_URL : ApiPath.XAI;
const DEFAULT_CHATGLM_URL = isApp ? CHATGLM_BASE_URL : ApiPath.ChatGLM;
const DEFAULT_ACCESS_STATE = {
accessCode: "",
accessCode: '',
useCustomConfig: false,
provider: ServiceProvider.OpenAI,
// openai
openaiUrl: DEFAULT_OPENAI_URL,
openaiApiKey: "",
openaiApiKey: '',
// azure
azureUrl: "",
azureApiKey: "",
azureApiVersion: "2023-08-01-preview",
azureUrl: '',
azureApiKey: '',
azureApiVersion: '2023-08-01-preview',
// google ai studio
googleUrl: DEFAULT_GOOGLE_URL,
googleApiKey: "",
googleApiVersion: "v1",
googleApiKey: '',
googleApiVersion: 'v1',
googleSafetySettings: GoogleSafetySettingsThreshold.BLOCK_ONLY_HIGH,
// anthropic
anthropicUrl: DEFAULT_ANTHROPIC_URL,
anthropicApiKey: "",
anthropicApiVersion: "2023-06-01",
anthropicApiKey: '',
anthropicApiVersion: '2023-06-01',
// baidu
baiduUrl: DEFAULT_BAIDU_URL,
baiduApiKey: "",
baiduSecretKey: "",
baiduApiKey: '',
baiduSecretKey: '',
// bytedance
bytedanceUrl: DEFAULT_BYTEDANCE_URL,
bytedanceApiKey: "",
bytedanceApiKey: '',
// alibaba
alibabaUrl: DEFAULT_ALIBABA_URL,
alibabaApiKey: "",
alibabaApiKey: '',
// moonshot
moonshotUrl: DEFAULT_MOONSHOT_URL,
moonshotApiKey: "",
moonshotApiKey: '',
//stability
// stability
stabilityUrl: DEFAULT_STABILITY_URL,
stabilityApiKey: "",
stabilityApiKey: '',
// tencent
tencentUrl: DEFAULT_TENCENT_URL,
tencentSecretKey: "",
tencentSecretId: "",
tencentSecretKey: '',
tencentSecretId: '',
// iflytek
iflytekUrl: DEFAULT_IFLYTEK_URL,
iflytekApiKey: "",
iflytekApiSecret: "",
iflytekApiKey: '',
iflytekApiSecret: '',
// xai
xaiUrl: DEFAULT_XAI_URL,
xaiApiKey: "",
xaiApiKey: '',
// chatglm
chatglmUrl: DEFAULT_CHATGLM_URL,
chatglmApiKey: "",
chatglmApiKey: '',
// server config
needCode: true,
@@ -122,11 +122,11 @@ const DEFAULT_ACCESS_STATE = {
hideBalanceQuery: false,
disableGPT4: false,
disableFastLink: false,
customModels: "",
defaultModel: "",
customModels: '',
defaultModel: '',
// tts config
edgeTTSVoiceName: "zh-CN-YunxiNeural",
edgeTTSVoiceName: 'zh-CN-YunxiNeural',
};
export const useAccessStore = createPersistStore(
@@ -146,50 +146,50 @@ export const useAccessStore = createPersistStore(
},
isValidOpenAI() {
return ensure(get(), ["openaiApiKey"]);
return ensure(get(), ['openaiApiKey']);
},
isValidAzure() {
return ensure(get(), ["azureUrl", "azureApiKey", "azureApiVersion"]);
return ensure(get(), ['azureUrl', 'azureApiKey', 'azureApiVersion']);
},
isValidGoogle() {
return ensure(get(), ["googleApiKey"]);
return ensure(get(), ['googleApiKey']);
},
isValidAnthropic() {
return ensure(get(), ["anthropicApiKey"]);
return ensure(get(), ['anthropicApiKey']);
},
isValidBaidu() {
return ensure(get(), ["baiduApiKey", "baiduSecretKey"]);
return ensure(get(), ['baiduApiKey', 'baiduSecretKey']);
},
isValidByteDance() {
return ensure(get(), ["bytedanceApiKey"]);
return ensure(get(), ['bytedanceApiKey']);
},
isValidAlibaba() {
return ensure(get(), ["alibabaApiKey"]);
return ensure(get(), ['alibabaApiKey']);
},
isValidTencent() {
return ensure(get(), ["tencentSecretKey", "tencentSecretId"]);
return ensure(get(), ['tencentSecretKey', 'tencentSecretId']);
},
isValidMoonshot() {
return ensure(get(), ["moonshotApiKey"]);
return ensure(get(), ['moonshotApiKey']);
},
isValidIflytek() {
return ensure(get(), ["iflytekApiKey"]);
return ensure(get(), ['iflytekApiKey']);
},
isValidXAI() {
return ensure(get(), ["xaiApiKey"]);
return ensure(get(), ['xaiApiKey']);
},
isValidChatGLM() {
return ensure(get(), ["chatglmApiKey"]);
return ensure(get(), ['chatglmApiKey']);
},
isAuthorized() {
@@ -197,36 +197,37 @@ export const useAccessStore = createPersistStore(
// has token or has code or disabled access control
return (
this.isValidOpenAI() ||
this.isValidAzure() ||
this.isValidGoogle() ||
this.isValidAnthropic() ||
this.isValidBaidu() ||
this.isValidByteDance() ||
this.isValidAlibaba() ||
this.isValidTencent() ||
this.isValidMoonshot() ||
this.isValidIflytek() ||
this.isValidXAI() ||
this.isValidChatGLM() ||
!this.enabledAccessControl() ||
(this.enabledAccessControl() && ensure(get(), ["accessCode"]))
this.isValidOpenAI()
|| this.isValidAzure()
|| this.isValidGoogle()
|| this.isValidAnthropic()
|| this.isValidBaidu()
|| this.isValidByteDance()
|| this.isValidAlibaba()
|| this.isValidTencent()
|| this.isValidMoonshot()
|| this.isValidIflytek()
|| this.isValidXAI()
|| this.isValidChatGLM()
|| !this.enabledAccessControl()
|| (this.enabledAccessControl() && ensure(get(), ['accessCode']))
);
},
fetch() {
if (fetchState > 0 || getClientConfig()?.buildMode === "export") return;
if (fetchState > 0 || getClientConfig()?.buildMode === 'export')
{ return; }
fetchState = 1;
fetch("/api/config", {
method: "post",
fetch('/api/config', {
method: 'post',
body: null,
headers: {
...getHeaders(),
},
})
.then((res) => res.json())
.then(res => res.json())
.then((res) => {
const defaultModel = res.defaultModel ?? "";
if (defaultModel !== "") {
const defaultModel = res.defaultModel ?? '';
if (defaultModel !== '') {
const [model, providerName] = getModelProvider(defaultModel);
DEFAULT_CONFIG.modelConfig.model = model;
DEFAULT_CONFIG.modelConfig.providerName = providerName as any;
@@ -235,11 +236,11 @@ export const useAccessStore = createPersistStore(
return res;
})
.then((res: DangerConfig) => {
console.log("[Config] got config from server", res);
console.log('[Config] got config from server', res);
set(() => ({ ...res }));
})
.catch(() => {
console.error("[Config] failed to fetch config");
console.error('[Config] failed to fetch config');
})
.finally(() => {
fetchState = 2;
@@ -258,7 +259,7 @@ export const useAccessStore = createPersistStore(
googleApiKey: string;
};
state.openaiApiKey = state.token;
state.azureApiVersion = "2023-08-01-preview";
state.azureApiVersion = '2023-08-01-preview';
}
return persistedState as any;

View File

@@ -1,38 +1,39 @@
import { getMessageTextContent, trimTopic } from "../utils";
import { indexedDBStorage } from "@/app/utils/indexedDB-storage";
import { nanoid } from "nanoid";
import type {
ClientApi,
MultimodalContent,
RequestMessage,
} from "../client/api";
import { getClientApi } from "../client/api";
import { ChatControllerPool } from "../client/controller";
import { showToast } from "../components/ui-lib";
} from '../client/api';
import type { ModelConfig, ModelType } from './config';
import type { Mask } from './mask';
import { indexedDBStorage } from '@/app/utils/indexedDB-storage';
import { nanoid } from 'nanoid';
import { getClientApi } from '../client/api';
import { ChatControllerPool } from '../client/controller';
import { showToast } from '../components/ui-lib';
import {
DEFAULT_INPUT_TEMPLATE,
DEFAULT_MODELS,
DEFAULT_SYSTEM_TEMPLATE,
GEMINI_SUMMARIZE_MODEL,
KnowledgeCutOffDate,
ServiceProvider,
StoreKey,
SUMMARIZE_MODEL,
GEMINI_SUMMARIZE_MODEL,
ServiceProvider,
} from "../constant";
import Locale, { getLang } from "../locales";
import { isDalle3, safeLocalStorage } from "../utils";
import { prettyObject } from "../utils/format";
import { createPersistStore } from "../utils/store";
import { estimateTokenLength } from "../utils/token";
import { ModelConfig, ModelType, useAppConfig } from "./config";
import { useAccessStore } from "./access";
import { collectModelsWithDefaultModel } from "../utils/model";
import { createEmptyMask, Mask } from "./mask";
} from '../constant';
import Locale, { getLang } from '../locales';
import { getMessageTextContent, isDalle3, safeLocalStorage, trimTopic } from '../utils';
import { prettyObject } from '../utils/format';
import { collectModelsWithDefaultModel } from '../utils/model';
import { createPersistStore } from '../utils/store';
import { estimateTokenLength } from '../utils/token';
import { useAccessStore } from './access';
import { useAppConfig } from './config';
import { createEmptyMask } from './mask';
const localStorage = safeLocalStorage();
export type ChatMessageTool = {
export interface ChatMessageTool {
id: string;
index?: number;
type?: string;
@@ -43,7 +44,7 @@ export type ChatMessageTool = {
content?: string;
isError?: boolean;
errorMsg?: string;
};
}
export type ChatMessage = RequestMessage & {
date: string;
@@ -59,8 +60,8 @@ export function createMessage(override: Partial<ChatMessage>): ChatMessage {
return {
id: nanoid(),
date: new Date().toLocaleString(),
role: "user",
content: "",
role: 'user',
content: '',
...override,
};
}
@@ -87,7 +88,7 @@ export interface ChatSession {
export const DEFAULT_TOPIC = Locale.Store.DefaultTopic;
export const BOT_HELLO: ChatMessage = createMessage({
role: "assistant",
role: 'assistant',
content: Locale.Store.BotHello,
});
@@ -95,7 +96,7 @@ function createEmptySession(): ChatSession {
return {
id: nanoid(),
topic: DEFAULT_TOPIC,
memoryPrompt: "",
memoryPrompt: '',
messages: [],
stat: {
tokenCount: 0,
@@ -114,16 +115,16 @@ function getSummarizeModel(
providerName: string,
): string[] {
// if it is using gpt-* models, force to use 4o-mini to summarize
if (currentModel.startsWith("gpt") || currentModel.startsWith("chatgpt")) {
if (currentModel.startsWith('gpt') || currentModel.startsWith('chatgpt')) {
const configStore = useAppConfig.getState();
const accessStore = useAccessStore.getState();
const allModel = collectModelsWithDefaultModel(
configStore.models,
[configStore.customModels, accessStore.customModels].join(","),
[configStore.customModels, accessStore.customModels].join(','),
accessStore.defaultModel,
);
const summarizeModel = allModel.find(
(m) => m.name === SUMMARIZE_MODEL && m.available,
m => m.name === SUMMARIZE_MODEL && m.available,
);
if (summarizeModel) {
return [
@@ -132,7 +133,7 @@ function getSummarizeModel(
];
}
}
if (currentModel.startsWith("gemini")) {
if (currentModel.startsWith('gemini')) {
return [GEMINI_SUMMARIZE_MODEL, ServiceProvider.Google];
}
return [currentModel, providerName];
@@ -146,12 +147,12 @@ function countMessages(msgs: ChatMessage[]) {
}
function fillTemplateWith(input: string, modelConfig: ModelConfig) {
const cutoff =
KnowledgeCutOffDate[modelConfig.model] ?? KnowledgeCutOffDate.default;
const cutoff
= KnowledgeCutOffDate[modelConfig.model] ?? KnowledgeCutOffDate.default;
// Find the model in the DEFAULT_MODELS array that matches the modelConfig.model
const modelInfo = DEFAULT_MODELS.find((m) => m.name === modelConfig.model);
const modelInfo = DEFAULT_MODELS.find(m => m.name === modelConfig.model);
var serviceProvider = "OpenAI";
let serviceProvider = 'OpenAI';
if (modelInfo) {
// TODO: auto detect the providerName from the modelConfig.model
@@ -165,24 +166,24 @@ function fillTemplateWith(input: string, modelConfig: ModelConfig) {
model: modelConfig.model,
time: new Date().toString(),
lang: getLang(),
input: input,
input,
};
let output = modelConfig.template ?? DEFAULT_INPUT_TEMPLATE;
// remove duplicate
if (input.startsWith(output)) {
output = "";
output = '';
}
// must contains {{input}}
const inputVar = "{{input}}";
const inputVar = '{{input}}';
if (!output.includes(inputVar)) {
output += "\n" + inputVar;
output += `\n${inputVar}`;
}
Object.entries(vars).forEach(([name, value]) => {
const regex = new RegExp(`{{${name}}}`, "g");
const regex = new RegExp(`{{${name}}}`, 'g');
output = output.replace(regex, value.toString()); // Ensure value is a string
});
@@ -192,7 +193,7 @@ function fillTemplateWith(input: string, modelConfig: ModelConfig) {
const DEFAULT_CHAT_STATE = {
sessions: [createEmptySession()],
currentSessionIndex: 0,
lastInput: "",
lastInput: '',
};
export const useChatStore = createPersistStore(
@@ -209,7 +210,8 @@ export const useChatStore = createPersistStore(
forkSession() {
// 获取当前会话
const currentSession = get().currentSession();
if (!currentSession) return;
if (!currentSession)
{ return; }
const newSession = createEmptySession();
@@ -222,7 +224,7 @@ export const useChatStore = createPersistStore(
},
};
set((state) => ({
set(state => ({
currentSessionIndex: 0,
sessions: [newSession, ...state.sessions],
}));
@@ -283,7 +285,7 @@ export const useChatStore = createPersistStore(
session.topic = mask.name;
}
set((state) => ({
set(state => ({
currentSessionIndex: 0,
sessions: [session].concat(state.sessions),
}));
@@ -300,7 +302,8 @@ export const useChatStore = createPersistStore(
const deletingLastSession = get().sessions.length === 1;
const deletedSession = get().sessions.at(index);
if (!deletedSession) return;
if (!deletedSession)
{ return; }
const sessions = get().sessions.slice();
sessions.splice(index, 1);
@@ -367,29 +370,29 @@ export const useChatStore = createPersistStore(
const modelConfig = session.mask.modelConfig;
const userContent = fillTemplateWith(content, modelConfig);
console.log("[User Input] after template: ", userContent);
console.log('[User Input] after template: ', userContent);
let mContent: string | MultimodalContent[] = userContent;
if (attachImages && attachImages.length > 0) {
mContent = [
...(userContent
? [{ type: "text" as const, text: userContent }]
? [{ type: 'text' as const, text: userContent }]
: []),
...attachImages.map((url) => ({
type: "image_url" as const,
...attachImages.map(url => ({
type: 'image_url' as const,
image_url: { url },
})),
];
}
let userMessage: ChatMessage = createMessage({
role: "user",
const userMessage: ChatMessage = createMessage({
role: 'user',
content: mContent,
});
const botMessage: ChatMessage = createMessage({
role: "assistant",
role: 'assistant',
streaming: true,
model: modelConfig.model,
});
@@ -442,7 +445,7 @@ export const useChatStore = createPersistStore(
},
onAfterTool(tool: ChatMessageTool) {
botMessage?.tools?.forEach((t, i, tools) => {
if (tool.id == t.id) {
if (tool.id === t.id) {
tools[i] = { ...tool };
}
});
@@ -451,13 +454,13 @@ export const useChatStore = createPersistStore(
});
},
onError(error) {
const isAborted = error.message?.includes?.("aborted");
botMessage.content +=
"\n\n" +
prettyObject({
error: true,
message: error.message,
});
const isAborted = error.message?.includes?.('aborted');
botMessage.content
+= `\n\n${
prettyObject({
error: true,
message: error.message,
})}`;
botMessage.streaming = false;
userMessage.isError = !isAborted;
botMessage.isError = !isAborted;
@@ -469,7 +472,7 @@ export const useChatStore = createPersistStore(
botMessage.id ?? messageIndex,
);
console.error("[Chat] failed ", error);
console.error('[Chat] failed ', error);
},
onController(controller) {
// collect controller for stop/retry
@@ -487,9 +490,9 @@ export const useChatStore = createPersistStore(
if (session.memoryPrompt.length) {
return {
role: "system",
role: 'system',
content: Locale.Store.Prompt.History(session.memoryPrompt),
date: "",
date: '',
} as ChatMessage;
}
},
@@ -505,17 +508,17 @@ export const useChatStore = createPersistStore(
const contextPrompts = session.mask.context.slice();
// system prompts, to get close to OpenAI Web ChatGPT
const shouldInjectSystemPrompts =
modelConfig.enableInjectSystemPrompts &&
(session.mask.modelConfig.model.startsWith("gpt-") ||
session.mask.modelConfig.model.startsWith("chatgpt-"));
const shouldInjectSystemPrompts
= modelConfig.enableInjectSystemPrompts
&& (session.mask.modelConfig.model.startsWith('gpt-')
|| session.mask.modelConfig.model.startsWith('chatgpt-'));
var systemPrompts: ChatMessage[] = [];
let systemPrompts: ChatMessage[] = [];
systemPrompts = shouldInjectSystemPrompts
? [
createMessage({
role: "system",
content: fillTemplateWith("", {
role: 'system',
content: fillTemplateWith('', {
...modelConfig,
template: DEFAULT_SYSTEM_TEMPLATE,
}),
@@ -524,19 +527,19 @@ export const useChatStore = createPersistStore(
: [];
if (shouldInjectSystemPrompts) {
console.log(
"[Global System Prompt] ",
systemPrompts.at(0)?.content ?? "empty",
'[Global System Prompt] ',
systemPrompts.at(0)?.content ?? 'empty',
);
}
const memoryPrompt = get().getMemoryPrompt();
// long term memory
const shouldSendLongTermMemory =
modelConfig.sendMemory &&
session.memoryPrompt &&
session.memoryPrompt.length > 0 &&
session.lastSummarizeIndex > clearContextIndex;
const longTermMemoryPrompts =
shouldSendLongTermMemory && memoryPrompt ? [memoryPrompt] : [];
const shouldSendLongTermMemory
= modelConfig.sendMemory
&& session.memoryPrompt
&& session.memoryPrompt.length > 0
&& session.lastSummarizeIndex > clearContextIndex;
const longTermMemoryPrompts
= shouldSendLongTermMemory && memoryPrompt ? [memoryPrompt] : [];
const longTermMemoryStartIndex = session.lastSummarizeIndex;
// short term memory
@@ -566,7 +569,8 @@ export const useChatStore = createPersistStore(
i -= 1
) {
const msg = messages[i];
if (!msg || msg.isError) continue;
if (!msg || msg.isError)
{ continue; }
tokenCount += estimateTokenLength(getMessageTextContent(msg));
reversedRecentMessages.push(msg);
}
@@ -596,7 +600,7 @@ export const useChatStore = createPersistStore(
resetSession(session: ChatSession) {
get().updateTargetSession(session, (session) => {
session.messages = [];
session.memoryPrompt = "";
session.memoryPrompt = '';
});
},
@@ -627,10 +631,10 @@ export const useChatStore = createPersistStore(
// should summarize topic after chating more than 50 words
const SUMMARIZE_MIN_LEN = 50;
if (
(config.enableAutoGenerateTitle &&
session.topic === DEFAULT_TOPIC &&
countMessages(messages) >= SUMMARIZE_MIN_LEN) ||
refreshTitle
(config.enableAutoGenerateTitle
&& session.topic === DEFAULT_TOPIC
&& countMessages(messages) >= SUMMARIZE_MIN_LEN)
|| refreshTitle
) {
const startIndex = Math.max(
0,
@@ -643,7 +647,7 @@ export const useChatStore = createPersistStore(
)
.concat(
createMessage({
role: "user",
role: 'user',
content: Locale.Store.Prompt.Topic,
}),
);
@@ -658,9 +662,9 @@ export const useChatStore = createPersistStore(
if (responseRes?.status === 200) {
get().updateTargetSession(
session,
(session) =>
(session.topic =
message.length > 0 ? trimTopic(message) : DEFAULT_TOPIC),
session =>
(session.topic
= message.length > 0 ? trimTopic(message) : DEFAULT_TOPIC),
);
}
},
@@ -671,7 +675,7 @@ export const useChatStore = createPersistStore(
session.clearContextIndex ?? 0,
);
let toBeSummarizedMsgs = messages
.filter((msg) => !msg.isError)
.filter(msg => !msg.isError)
.slice(summarizeIndex);
const historyMsgLength = countMessages(toBeSummarizedMsgs);
@@ -691,26 +695,27 @@ export const useChatStore = createPersistStore(
const lastSummarizeIndex = session.messages.length;
console.log(
"[Chat History] ",
'[Chat History] ',
toBeSummarizedMsgs,
historyMsgLength,
modelConfig.compressMessageLengthThreshold,
);
if (
historyMsgLength > modelConfig.compressMessageLengthThreshold &&
modelConfig.sendMemory
historyMsgLength > modelConfig.compressMessageLengthThreshold
&& modelConfig.sendMemory
) {
/** Destruct max_tokens while summarizing
/**
* Destruct max_tokens while summarizing
* this param is just shit
**/
*/
const { max_tokens, ...modelcfg } = modelConfig;
api.llm.chat({
messages: toBeSummarizedMsgs.concat(
createMessage({
role: "system",
role: 'system',
content: Locale.Store.Prompt.Summarize,
date: "",
date: '',
}),
),
config: {
@@ -724,7 +729,7 @@ export const useChatStore = createPersistStore(
},
onFinish(message, responseRes) {
if (responseRes?.status === 200) {
console.log("[Memory] ", message);
console.log('[Memory] ', message);
get().updateTargetSession(session, (session) => {
session.lastSummarizeIndex = lastSummarizeIndex;
session.memoryPrompt = message; // Update the memory prompt for stored it in local storage
@@ -732,7 +737,7 @@ export const useChatStore = createPersistStore(
}
},
onError(err) {
console.error("[Summarize] ", err);
console.error('[Summarize] ', err);
},
});
}
@@ -749,8 +754,9 @@ export const useChatStore = createPersistStore(
updater: (session: ChatSession) => void,
) {
const sessions = get().sessions;
const index = sessions.findIndex((s) => s.id === targetSession.id);
if (index < 0) return;
const index = sessions.findIndex(s => s.id === targetSession.id);
if (index < 0)
{ return; }
updater(sessions[index]);
set(() => ({ sessions }));
},
@@ -796,7 +802,7 @@ export const useChatStore = createPersistStore(
// migrate id to nanoid
newState.sessions.forEach((s) => {
s.id = nanoid();
s.messages.forEach((m) => (m.id = nanoid()));
s.messages.forEach(m => (m.id = nanoid()));
});
}
@@ -806,13 +812,13 @@ export const useChatStore = createPersistStore(
newState.sessions.forEach((s) => {
if (
// Exclude those already set by user
!s.mask.modelConfig.hasOwnProperty("enableInjectSystemPrompts")
!s.mask.modelConfig.hasOwnProperty('enableInjectSystemPrompts')
) {
// Because users may have changed this configuration,
// the user's current configuration is used instead of the default
const config = useAppConfig.getState();
s.mask.modelConfig.enableInjectSystemPrompts =
config.modelConfig.enableInjectSystemPrompts;
s.mask.modelConfig.enableInjectSystemPrompts
= config.modelConfig.enableInjectSystemPrompts;
}
});
}
@@ -822,16 +828,16 @@ export const useChatStore = createPersistStore(
newState.sessions.forEach((s) => {
const config = useAppConfig.getState();
s.mask.modelConfig.compressModel = config.modelConfig.compressModel;
s.mask.modelConfig.compressProviderName =
config.modelConfig.compressProviderName;
s.mask.modelConfig.compressProviderName
= config.modelConfig.compressProviderName;
});
}
// revert default summarize model for every session
if (version < 3.3) {
newState.sessions.forEach((s) => {
const config = useAppConfig.getState();
s.mask.modelConfig.compressModel = "";
s.mask.modelConfig.compressProviderName = "";
s.mask.modelConfig.compressModel = '';
s.mask.modelConfig.compressProviderName = '';
});
}

View File

@@ -1,39 +1,41 @@
import { LLMModel } from "../client/api";
import { DalleSize, DalleQuality, DalleStyle } from "../typing";
import { getClientConfig } from "../config/client";
import type { Voice } from 'rt-client';
import type { LLMModel } from '../client/api';
import type {
DEFAULT_TTS_ENGINES,
DEFAULT_TTS_MODELS,
DEFAULT_TTS_VOICES,
ServiceProvider,
} from '../constant';
import type { DalleQuality, DalleSize, DalleStyle } from '../typing';
import { getClientConfig } from '../config/client';
import {
DEFAULT_INPUT_TEMPLATE,
DEFAULT_MODELS,
DEFAULT_SIDEBAR_WIDTH,
DEFAULT_TTS_ENGINE,
DEFAULT_TTS_ENGINES,
DEFAULT_TTS_MODEL,
DEFAULT_TTS_MODELS,
DEFAULT_TTS_VOICE,
DEFAULT_TTS_VOICES,
StoreKey,
ServiceProvider,
} from "../constant";
import { createPersistStore } from "../utils/store";
import type { Voice } from "rt-client";
} from '../constant';
import { createPersistStore } from '../utils/store';
export type ModelType = (typeof DEFAULT_MODELS)[number]["name"];
export type ModelType = (typeof DEFAULT_MODELS)[number]['name'];
export type TTSModelType = (typeof DEFAULT_TTS_MODELS)[number];
export type TTSVoiceType = (typeof DEFAULT_TTS_VOICES)[number];
export type TTSEngineType = (typeof DEFAULT_TTS_ENGINES)[number];
export enum SubmitKey {
Enter = "Enter",
CtrlEnter = "Ctrl + Enter",
ShiftEnter = "Shift + Enter",
AltEnter = "Alt + Enter",
MetaEnter = "Meta + Enter",
Enter = 'Enter',
CtrlEnter = 'Ctrl + Enter',
ShiftEnter = 'Shift + Enter',
AltEnter = 'Alt + Enter',
MetaEnter = 'Meta + Enter',
}
export enum Theme {
Auto = "auto",
Dark = "dark",
Light = "light",
Auto = 'auto',
Dark = 'dark',
Light = 'light',
}
const config = getClientConfig();
@@ -42,9 +44,9 @@ export const DEFAULT_CONFIG = {
lastUpdate: Date.now(), // timestamp, to merge state
submitKey: SubmitKey.Enter,
avatar: "1f603",
avatar: '1f603',
fontSize: 14,
fontFamily: "",
fontFamily: '',
theme: Theme.Auto as Theme,
tightBorder: !!config?.isApp,
sendPreviewBubble: true,
@@ -60,12 +62,12 @@ export const DEFAULT_CONFIG = {
dontShowMaskSplashScreen: false, // dont show splash screen when create chat
hideBuiltinMasks: false, // dont add builtin masks
customModels: "",
customModels: '',
models: DEFAULT_MODELS as any as LLMModel[],
modelConfig: {
model: "gpt-4o-mini" as ModelType,
providerName: "OpenAI" as ServiceProvider,
model: 'gpt-4o-mini' as ModelType,
providerName: 'OpenAI' as ServiceProvider,
temperature: 0.5,
top_p: 1,
max_tokens: 4000,
@@ -74,13 +76,13 @@ export const DEFAULT_CONFIG = {
sendMemory: true,
historyMessageCount: 4,
compressMessageLengthThreshold: 1000,
compressModel: "",
compressProviderName: "",
compressModel: '',
compressProviderName: '',
enableInjectSystemPrompts: true,
template: config?.template ?? DEFAULT_INPUT_TEMPLATE,
size: "1024x1024" as DalleSize,
quality: "standard" as DalleQuality,
style: "vivid" as DalleStyle,
size: '1024x1024' as DalleSize,
quality: 'standard' as DalleQuality,
style: 'vivid' as DalleStyle,
},
ttsConfig: {
@@ -94,23 +96,23 @@ export const DEFAULT_CONFIG = {
realtimeConfig: {
enable: false,
provider: "OpenAI" as ServiceProvider,
model: "gpt-4o-realtime-preview-2024-10-01",
apiKey: "",
provider: 'OpenAI' as ServiceProvider,
model: 'gpt-4o-realtime-preview-2024-10-01',
apiKey: '',
azure: {
endpoint: "",
deployment: "",
endpoint: '',
deployment: '',
},
temperature: 0.9,
voice: "alloy" as Voice,
voice: 'alloy' as Voice,
},
};
export type ChatConfig = typeof DEFAULT_CONFIG;
export type ModelConfig = ChatConfig["modelConfig"];
export type TTSConfig = ChatConfig["ttsConfig"];
export type RealtimeConfig = ChatConfig["realtimeConfig"];
export type ModelConfig = ChatConfig['modelConfig'];
export type TTSConfig = ChatConfig['ttsConfig'];
export type RealtimeConfig = ChatConfig['realtimeConfig'];
export function limitNumber(
x: number,
@@ -199,16 +201,19 @@ export const useAppConfig = createPersistStore(
merge(persistedState, currentState) {
const state = persistedState as ChatConfig | undefined;
if (!state) return { ...currentState };
if (!state)
{ return { ...currentState }; }
const models = currentState.models.slice();
state.models.forEach((pModel) => {
const idx = models.findIndex(
(v) => v.name === pModel.name && v.provider === pModel.provider,
v => v.name === pModel.name && v.provider === pModel.provider,
);
if (idx !== -1) models[idx] = pModel;
else models.push(pModel);
if (idx !== -1)
{ models[idx] = pModel; }
else { models.push(pModel);
}
});
return { ...currentState, ...state, models: models };
return { ...currentState, ...state, models };
},
migrate(persistedState, version) {
@@ -226,7 +231,7 @@ export const useAppConfig = createPersistStore(
}
if (version < 3.5) {
state.customModels = "claude,claude-100k";
state.customModels = 'claude,claude-100k';
}
if (version < 3.6) {
@@ -242,17 +247,17 @@ export const useAppConfig = createPersistStore(
}
if (version < 3.9) {
state.modelConfig.template =
state.modelConfig.template !== DEFAULT_INPUT_TEMPLATE
state.modelConfig.template
= state.modelConfig.template !== DEFAULT_INPUT_TEMPLATE
? state.modelConfig.template
: config?.template ?? DEFAULT_INPUT_TEMPLATE;
}
if (version < 4.1) {
state.modelConfig.compressModel =
DEFAULT_CONFIG.modelConfig.compressModel;
state.modelConfig.compressProviderName =
DEFAULT_CONFIG.modelConfig.compressProviderName;
state.modelConfig.compressModel
= DEFAULT_CONFIG.modelConfig.compressModel;
state.modelConfig.compressProviderName
= DEFAULT_CONFIG.modelConfig.compressProviderName;
}
return state as any;

View File

@@ -1,5 +1,5 @@
export * from "./chat";
export * from "./update";
export * from "./access";
export * from "./config";
export * from "./plugin";
export * from './access';
export * from './chat';
export * from './config';
export * from './plugin';
export * from './update';

View File

@@ -1,12 +1,15 @@
import { BUILTIN_MASKS } from "../masks";
import { getLang, Lang } from "../locales";
import { DEFAULT_TOPIC, ChatMessage } from "./chat";
import { ModelConfig, useAppConfig } from "./config";
import { StoreKey } from "../constant";
import { nanoid } from "nanoid";
import { createPersistStore } from "../utils/store";
import type { Lang } from '../locales';
import type { ChatMessage } from './chat';
import type { ModelConfig } from './config';
import { nanoid } from 'nanoid';
import { StoreKey } from '../constant';
import { getLang } from '../locales';
import { BUILTIN_MASKS } from '../masks';
import { createPersistStore } from '../utils/store';
import { DEFAULT_TOPIC } from './chat';
import { useAppConfig } from './config';
export type Mask = {
export interface Mask {
id: string;
createdAt: number;
avatar: string;
@@ -20,7 +23,7 @@ export type Mask = {
plugin?: string[];
enableArtifacts?: boolean;
enableCodeFold?: boolean;
};
}
export const DEFAULT_MASK_STATE = {
masks: {} as Record<string, Mask>,
@@ -31,9 +34,9 @@ export type MaskState = typeof DEFAULT_MASK_STATE & {
language?: Lang | undefined;
};
export const DEFAULT_MASK_AVATAR = "gpt-bot";
export const createEmptyMask = () =>
({
export const DEFAULT_MASK_AVATAR = 'gpt-bot';
export function createEmptyMask() {
return ({
id: nanoid(),
avatar: DEFAULT_MASK_AVATAR,
name: DEFAULT_TOPIC,
@@ -45,6 +48,7 @@ export const createEmptyMask = () =>
createdAt: Date.now(),
plugin: [],
}) as Mask;
}
export const useMaskStore = createPersistStore(
{ ...DEFAULT_MASK_STATE },
@@ -68,7 +72,8 @@ export const useMaskStore = createPersistStore(
updateMask(id: string, updater: (mask: Mask) => void) {
const masks = get().masks;
const mask = masks[id];
if (!mask) return;
if (!mask)
{ return; }
const updateMask = { ...mask };
updater(updateMask);
masks[id] = updateMask;
@@ -90,9 +95,10 @@ export const useMaskStore = createPersistStore(
(a, b) => b.createdAt - a.createdAt,
);
const config = useAppConfig.getState();
if (config.hideBuiltinMasks) return userMasks;
if (config.hideBuiltinMasks)
{ return userMasks; }
const buildinMasks = BUILTIN_MASKS.map(
(m) =>
m =>
({
...m,
modelConfig: {
@@ -121,7 +127,7 @@ export const useMaskStore = createPersistStore(
// migrate mask id to nanoid
if (version < 3) {
Object.values(newState.masks).forEach((m) => (m.id = nanoid()));
Object.values(newState.masks).forEach(m => (m.id = nanoid()));
}
if (version < 3.1) {

View File

@@ -1,15 +1,15 @@
import OpenAPIClientAxios from "openapi-client-axios";
import { StoreKey } from "../constant";
import { nanoid } from "nanoid";
import { createPersistStore } from "../utils/store";
import { getClientConfig } from "../config/client";
import yaml from "js-yaml";
import { adapter, getOperationId } from "../utils";
import { useAccessStore } from "./access";
import yaml from 'js-yaml';
import { nanoid } from 'nanoid';
import OpenAPIClientAxios from 'openapi-client-axios';
import { getClientConfig } from '../config/client';
import { StoreKey } from '../constant';
import { adapter, getOperationId } from '../utils';
import { createPersistStore } from '../utils/store';
import { useAccessStore } from './access';
const isApp = getClientConfig()?.isApp !== false;
export type Plugin = {
export interface Plugin {
id: string;
createdAt: number;
title: string;
@@ -20,49 +20,50 @@ export type Plugin = {
authLocation?: string;
authHeader?: string;
authToken?: string;
};
}
export type FunctionToolItem = {
export interface FunctionToolItem {
type: string;
function: {
name: string;
description?: string;
parameters: Object;
parameters: object;
};
};
}
type FunctionToolServiceItem = {
interface FunctionToolServiceItem {
api: OpenAPIClientAxios;
length: number;
tools: FunctionToolItem[];
funcs: Record<string, Function>;
};
}
export const FunctionToolService = {
tools: {} as Record<string, FunctionToolServiceItem>,
add(plugin: Plugin, replace = false) {
if (!replace && this.tools[plugin.id]) return this.tools[plugin.id];
if (!replace && this.tools[plugin.id])
{ return this.tools[plugin.id]; }
const headerName = (
plugin?.authType == "custom" ? plugin?.authHeader : "Authorization"
plugin?.authType === 'custom' ? plugin?.authHeader : 'Authorization'
) as string;
const tokenValue =
plugin?.authType == "basic"
const tokenValue
= plugin?.authType === 'basic'
? `Basic ${plugin?.authToken}`
: plugin?.authType == "bearer"
? `Bearer ${plugin?.authToken}`
: plugin?.authToken;
const authLocation = plugin?.authLocation || "header";
: plugin?.authType === 'bearer'
? `Bearer ${plugin?.authToken}`
: plugin?.authToken;
const authLocation = plugin?.authLocation || 'header';
const definition = yaml.load(plugin.content) as any;
const serverURL = definition?.servers?.[0]?.url;
const baseURL = !isApp ? "/api/proxy" : serverURL;
const baseURL = !isApp ? '/api/proxy' : serverURL;
const headers: Record<string, string | undefined> = {
"X-Base-URL": !isApp ? serverURL : undefined,
'X-Base-URL': !isApp ? serverURL : undefined,
};
if (authLocation == "header") {
if (authLocation === 'header') {
headers[headerName] = tokenValue;
}
// try using openaiApiKey for Dalle3 Plugin.
if (!tokenValue && plugin.id === "dalle3") {
if (!tokenValue && plugin.id === 'dalle3') {
const openaiApiKey = useAccessStore.getState().openaiApiKey;
if (openaiApiKey) {
headers[headerName] = `Bearer ${openaiApiKey}`;
@@ -71,7 +72,7 @@ export const FunctionToolService = {
const api = new OpenAPIClientAxios({
definition: yaml.load(plugin.content) as any,
axiosConfigDefaults: {
adapter: (window.__TAURI__ ? adapter : ["xhr"]) as any,
adapter: (window.__TAURI__ ? adapter : ['xhr']) as any,
baseURL,
headers,
},
@@ -85,22 +86,22 @@ export const FunctionToolService = {
length: operations.length,
tools: operations.map((o) => {
// @ts-ignore
const parameters = o?.requestBody?.content["application/json"]
const parameters = o?.requestBody?.content['application/json']
?.schema || {
type: "object",
type: 'object',
properties: {},
};
if (!parameters["required"]) {
parameters["required"] = [];
if (!parameters.required) {
parameters.required = [];
}
if (o.parameters instanceof Array) {
if (Array.isArray(o.parameters)) {
o.parameters.forEach((p) => {
// @ts-ignore
if (p?.in == "query" || p?.in == "path") {
if (p?.in === 'query' || p?.in === 'path') {
// const name = `${p.in}__${p.name}`
// @ts-ignore
const name = p?.name;
parameters["properties"][name] = {
parameters.properties[name] = {
// @ts-ignore
type: p.schema.type,
// @ts-ignore
@@ -108,17 +109,17 @@ export const FunctionToolService = {
};
// @ts-ignore
if (p.required) {
parameters["required"].push(name);
parameters.required.push(name);
}
}
});
}
return {
type: "function",
type: 'function',
function: {
name: getOperationId(o),
description: o.description || o.summary,
parameters: parameters,
parameters,
},
} as FunctionToolItem;
}),
@@ -126,7 +127,7 @@ export const FunctionToolService = {
// @ts-ignore
s[getOperationId(o)] = function (args) {
const parameters: Record<string, any> = {};
if (o.parameters instanceof Array) {
if (Array.isArray(o.parameters)) {
o.parameters.forEach((p) => {
// @ts-ignore
parameters[p?.name] = args[p?.name];
@@ -134,9 +135,9 @@ export const FunctionToolService = {
delete args[p?.name];
});
}
if (authLocation == "query") {
if (authLocation === 'query') {
parameters[headerName] = tokenValue;
} else if (authLocation == "body") {
} else if (authLocation === 'body') {
args[headerName] = tokenValue;
}
// @ts-ignore if o.operationId is null, then using o.path and o.method
@@ -155,15 +156,16 @@ export const FunctionToolService = {
},
};
export const createEmptyPlugin = () =>
({
export function createEmptyPlugin() {
return ({
id: nanoid(),
title: "",
version: "1.0.0",
content: "",
title: '',
version: '1.0.0',
content: '',
builtin: false,
createdAt: Date.now(),
}) as Plugin;
}
export const DEFAULT_PLUGIN_STATE = {
plugins: {} as Record<string, Plugin>,
@@ -191,7 +193,8 @@ export const usePluginStore = createPersistStore(
updatePlugin(id: string, updater: (plugin: Plugin) => void) {
const plugins = get().plugins;
const plugin = plugins[id];
if (!plugin) return;
if (!plugin)
{ return; }
const updatePlugin = { ...plugin };
updater(updatePlugin);
plugins[id] = updatePlugin;
@@ -209,9 +212,9 @@ export const usePluginStore = createPersistStore(
getAsTools(ids: string[]) {
const plugins = get().plugins;
const selected = (ids || [])
.map((id) => plugins[id])
.filter((i) => i)
.map((p) => FunctionToolService.add(p));
.map(id => plugins[id])
.filter(i => i)
.map(p => FunctionToolService.add(p));
return [
// @ts-ignore
selected.reduce((s, i) => s.concat(i.tools), []),
@@ -232,12 +235,12 @@ export const usePluginStore = createPersistStore(
version: 1,
onRehydrateStorage(state) {
// Skip store rehydration on server side
if (typeof window === "undefined") {
if (typeof window === 'undefined') {
return;
}
fetch("./plugins.json")
.then((res) => res.json())
fetch('./plugins.json')
.then(res => res.json())
.then((res) => {
Promise.all(
res.map((item: any) =>
@@ -245,12 +248,12 @@ export const usePluginStore = createPersistStore(
state.get(item.id)
? item
: fetch(item.schema)
.then((res) => res.text())
.then((content) => ({
.then(res => res.text())
.then(content => ({
...item,
content,
}))
.catch((e) => item),
.catch(e => item),
),
).then((builtinPlugins: any) => {
builtinPlugins

View File

@@ -1,8 +1,8 @@
import Fuse from "fuse.js";
import { nanoid } from "nanoid";
import { StoreKey } from "../constant";
import { getLang } from "../locales";
import { createPersistStore } from "../utils/store";
import Fuse from 'fuse.js';
import { nanoid } from 'nanoid';
import { StoreKey } from '../constant';
import { getLang } from '../locales';
import { createPersistStore } from '../utils/store';
export interface Prompt {
id: string;
@@ -14,8 +14,8 @@ export interface Prompt {
export const SearchService = {
ready: false,
builtinEngine: new Fuse<Prompt>([], { keys: ["title"] }),
userEngine: new Fuse<Prompt>([], { keys: ["title"] }),
builtinEngine: new Fuse<Prompt>([], { keys: ['title'] }),
userEngine: new Fuse<Prompt>([], { keys: ['title'] }),
count: {
builtin: 0,
},
@@ -34,7 +34,7 @@ export const SearchService = {
},
remove(id: string) {
this.userEngine.remove((doc) => doc.id === id);
this.userEngine.remove(doc => doc.id === id);
},
add(prompt: Prompt) {
@@ -44,7 +44,7 @@ export const SearchService = {
search(text: string) {
const userResults = this.userEngine.search(text);
const builtinResults = this.builtinEngine.search(text);
return userResults.concat(builtinResults).map((v) => v.item);
return userResults.concat(builtinResults).map(v => v.item);
},
};
@@ -63,7 +63,7 @@ export const usePromptStore = createPersistStore(
prompts[prompt.id] = prompt;
set(() => ({
prompts: prompts,
prompts,
}));
return prompt.id!;
@@ -73,7 +73,7 @@ export const usePromptStore = createPersistStore(
const targetPrompt = get().prompts[id];
if (!targetPrompt) {
return SearchService.builtinPrompts.find((v) => v.id === id);
return SearchService.builtinPrompts.find(v => v.id === id);
}
return targetPrompt;
@@ -109,8 +109,8 @@ export const usePromptStore = createPersistStore(
updatePrompt(id: string, updater: (prompt: Prompt) => void) {
const prompt = get().prompts[id] ?? {
title: "",
content: "",
title: '',
content: '',
id,
};
@@ -140,7 +140,7 @@ export const usePromptStore = createPersistStore(
};
if (version < 3) {
Object.values(newState.prompts).forEach((p) => (p.id = nanoid()));
Object.values(newState.prompts).forEach(p => (p.id = nanoid()));
}
return newState as any;
@@ -148,19 +148,19 @@ export const usePromptStore = createPersistStore(
onRehydrateStorage(state) {
// Skip store rehydration on server side
if (typeof window === "undefined") {
if (typeof window === 'undefined') {
return;
}
const PROMPT_URL = "./prompts.json";
const PROMPT_URL = './prompts.json';
type PromptList = Array<[string, string]>;
fetch(PROMPT_URL)
.then((res) => res.json())
.then(res => res.json())
.then((res) => {
let fetchPrompts = [res.en, res.tw, res.cn];
if (getLang() === "cn") {
if (getLang() === 'cn') {
fetchPrompts = fetchPrompts.reverse();
}
const builtinPrompts = fetchPrompts.map((promptList: PromptList) => {
@@ -179,9 +179,9 @@ export const usePromptStore = createPersistStore(
const allPromptsForSearch = builtinPrompts
.reduce((pre, cur) => pre.concat(cur), [])
.filter((v) => !!v.title && !!v.content);
SearchService.count.builtin =
res.en.length + res.cn.length + res.tw.length;
.filter(v => !!v.title && !!v.content);
SearchService.count.builtin
= res.en.length + res.cn.length + res.tw.length;
SearchService.init(allPromptsForSearch, userPrompts);
});
},

View File

@@ -1,15 +1,15 @@
import { getBearerToken } from '@/app/client/api';
import { getModelParamBasicData, models } from '@/app/components/sd/sd-panel';
import {
Stability,
StoreKey,
ACCESS_CODE_PREFIX,
ApiPath,
} from "@/app/constant";
import { getBearerToken } from "@/app/client/api";
import { createPersistStore } from "@/app/utils/store";
import { nanoid } from "nanoid";
import { uploadImage, base64Image2Blob } from "@/app/utils/chat";
import { models, getModelParamBasicData } from "@/app/components/sd/sd-panel";
import { useAccessStore } from "./access";
Stability,
StoreKey,
} from '@/app/constant';
import { base64Image2Blob, uploadImage } from '@/app/utils/chat';
import { createPersistStore } from '@/app/utils/store';
import { nanoid } from 'nanoid';
import { useAccessStore } from './access';
const defaultModel = {
name: models[0].name,
@@ -40,124 +40,124 @@ export const useSdStore = createPersistStore<
setCurrentParams: (data: any) => void;
}
>(
DEFAULT_SD_STATE,
(set, _get) => {
function get() {
return {
..._get(),
...methods,
};
}
DEFAULT_SD_STATE,
(set, _get) => {
function get() {
return {
..._get(),
...methods,
};
}
const methods = {
getNextId() {
const id = ++_get().currentId;
set({ currentId: id });
return id;
},
sendTask(data: any, okCall?: Function) {
data = { ...data, id: nanoid(), status: "running" };
set({ draw: [data, ..._get().draw] });
this.getNextId();
this.stabilityRequestCall(data);
okCall?.();
},
stabilityRequestCall(data: any) {
const accessStore = useAccessStore.getState();
let prefix: string = ApiPath.Stability as string;
let bearerToken = "";
if (accessStore.useCustomConfig) {
prefix = accessStore.stabilityUrl || (ApiPath.Stability as string);
bearerToken = getBearerToken(accessStore.stabilityApiKey);
}
if (!bearerToken && accessStore.enabledAccessControl()) {
bearerToken = getBearerToken(
ACCESS_CODE_PREFIX + accessStore.accessCode,
);
}
const headers = {
Accept: "application/json",
Authorization: bearerToken,
const methods = {
getNextId() {
const id = ++_get().currentId;
set({ currentId: id });
return id;
},
sendTask(data: any, okCall?: Function) {
data = { ...data, id: nanoid(), status: 'running' };
set({ draw: [data, ..._get().draw] });
this.getNextId();
this.stabilityRequestCall(data);
okCall?.();
},
stabilityRequestCall(data: any) {
const accessStore = useAccessStore.getState();
let prefix: string = ApiPath.Stability as string;
let bearerToken = '';
if (accessStore.useCustomConfig) {
prefix = accessStore.stabilityUrl || (ApiPath.Stability as string);
bearerToken = getBearerToken(accessStore.stabilityApiKey);
}
if (!bearerToken && accessStore.enabledAccessControl()) {
bearerToken = getBearerToken(
ACCESS_CODE_PREFIX + accessStore.accessCode,
);
}
const headers = {
Accept: 'application/json',
Authorization: bearerToken,
};
const path = `${prefix}/${Stability.GeneratePath}/${data.model}`;
const formData = new FormData();
for (const paramsKey in data.params) {
formData.append(paramsKey, data.params[paramsKey]);
}
fetch(path, {
method: 'POST',
headers,
body: formData,
})
.then(response => response.json())
.then((resData) => {
if (resData.errors && resData.errors.length > 0) {
this.updateDraw({
...data,
status: 'error',
error: resData.errors[0],
});
this.getNextId();
return;
}
const self = this;
if (resData.finish_reason === 'SUCCESS') {
uploadImage(base64Image2Blob(resData.image, 'image/png'))
.then((img_data) => {
console.debug('uploadImage success', img_data, self);
self.updateDraw({
...data,
status: 'success',
img_data,
});
})
.catch((e) => {
console.error('uploadImage error', e);
self.updateDraw({
...data,
status: 'error',
error: JSON.stringify(e),
});
});
} else {
self.updateDraw({
...data,
status: 'error',
error: JSON.stringify(resData),
});
}
this.getNextId();
})
.catch((error) => {
this.updateDraw({ ...data, status: 'error', error: error.message });
console.error('Error:', error);
this.getNextId();
});
},
updateDraw(_draw: any) {
const draw = _get().draw || [];
draw.some((item, index) => {
if (item.id === _draw.id) {
draw[index] = _draw;
set(() => ({ draw }));
return true;
}
});
},
setCurrentModel(model: any) {
set({ currentModel: model });
},
setCurrentParams(data: any) {
set({
currentParams: data,
});
},
};
const path = `${prefix}/${Stability.GeneratePath}/${data.model}`;
const formData = new FormData();
for (let paramsKey in data.params) {
formData.append(paramsKey, data.params[paramsKey]);
}
fetch(path, {
method: "POST",
headers,
body: formData,
})
.then((response) => response.json())
.then((resData) => {
if (resData.errors && resData.errors.length > 0) {
this.updateDraw({
...data,
status: "error",
error: resData.errors[0],
});
this.getNextId();
return;
}
const self = this;
if (resData.finish_reason === "SUCCESS") {
uploadImage(base64Image2Blob(resData.image, "image/png"))
.then((img_data) => {
console.debug("uploadImage success", img_data, self);
self.updateDraw({
...data,
status: "success",
img_data,
});
})
.catch((e) => {
console.error("uploadImage error", e);
self.updateDraw({
...data,
status: "error",
error: JSON.stringify(e),
});
});
} else {
self.updateDraw({
...data,
status: "error",
error: JSON.stringify(resData),
});
}
this.getNextId();
})
.catch((error) => {
this.updateDraw({ ...data, status: "error", error: error.message });
console.error("Error:", error);
this.getNextId();
});
},
updateDraw(_draw: any) {
const draw = _get().draw || [];
draw.some((item, index) => {
if (item.id === _draw.id) {
draw[index] = _draw;
set(() => ({ draw }));
return true;
}
});
},
setCurrentModel(model: any) {
set({ currentModel: model });
},
setCurrentParams(data: any) {
set({
currentParams: data,
});
},
};
return methods;
},
{
name: StoreKey.SdList,
version: 1.0,
},
);
return methods;
},
{
name: StoreKey.SdList,
version: 1.0,
},
);

View File

@@ -1,17 +1,19 @@
import { getClientConfig } from "../config/client";
import { ApiPath, STORAGE_KEY, StoreKey } from "../constant";
import { createPersistStore } from "../utils/store";
import {
import type {
AppState,
getLocalAppState,
GetStoreState,
} from '../utils/sync';
import { showToast } from '../components/ui-lib';
import { getClientConfig } from '../config/client';
import { ApiPath, STORAGE_KEY, StoreKey } from '../constant';
import Locale from '../locales';
import { downloadAs, readFromFile } from '../utils';
import { createSyncClient, ProviderType } from '../utils/cloud';
import { createPersistStore } from '../utils/store';
import {
getLocalAppState,
mergeAppState,
setLocalAppState,
} from "../utils/sync";
import { downloadAs, readFromFile } from "../utils";
import { showToast } from "../components/ui-lib";
import Locale from "../locales";
import { createSyncClient, ProviderType } from "../utils/cloud";
} from '../utils/sync';
export interface WebDavConfig {
server: string;
@@ -28,19 +30,19 @@ const DEFAULT_SYNC_STATE = {
proxyUrl: ApiPath.Cors as string,
webdav: {
endpoint: "",
username: "",
password: "",
endpoint: '',
username: '',
password: '',
},
upstash: {
endpoint: "",
endpoint: '',
username: STORAGE_KEY,
apiKey: "",
apiKey: '',
},
lastSyncTime: 0,
lastProvider: "",
lastProvider: '',
};
export const useSyncStore = createPersistStore(
@@ -48,7 +50,7 @@ export const useSyncStore = createPersistStore(
(set, get) => ({
cloudSync() {
const config = get()[get().provider];
return Object.values(config).every((c) => c.toString().length > 0);
return Object.values(config).every(c => c.toString().length > 0);
},
markSyncTime() {
@@ -58,9 +60,9 @@ export const useSyncStore = createPersistStore(
export() {
const state = getLocalAppState();
const datePart = isApp
? `${new Date().toLocaleDateString().replace(/\//g, "_")} ${new Date()
.toLocaleTimeString()
.replace(/:/g, "_")}`
? `${new Date().toLocaleDateString().replace(/\//g, '_')} ${new Date()
.toLocaleTimeString()
.replace(/:/g, '_')}`
: new Date().toLocaleString();
const fileName = `Backup-${datePart}.json`;
@@ -77,7 +79,7 @@ export const useSyncStore = createPersistStore(
setLocalAppState(localState);
location.reload();
} catch (e) {
console.error("[Import]", e);
console.error('[Import]', e);
showToast(Locale.Settings.Sync.ImportFailed);
}
},
@@ -96,10 +98,10 @@ export const useSyncStore = createPersistStore(
try {
const remoteState = await client.get(config.username);
if (!remoteState || remoteState === "") {
if (!remoteState || remoteState === '') {
await client.set(config.username, JSON.stringify(localState));
console.log(
"[Sync] Remote state is empty, using local state instead.",
'[Sync] Remote state is empty, using local state instead.',
);
return;
} else {
@@ -110,7 +112,7 @@ export const useSyncStore = createPersistStore(
setLocalAppState(localState);
}
} catch (e) {
console.log("[Sync] failed to get remote state", e);
console.log('[Sync] failed to get remote state', e);
throw e;
}
@@ -137,10 +139,10 @@ export const useSyncStore = createPersistStore(
if (version < 1.2) {
if (
(persistedState as typeof DEFAULT_SYNC_STATE).proxyUrl ===
"/api/cors/"
(persistedState as typeof DEFAULT_SYNC_STATE).proxyUrl
=== '/api/cors/'
) {
newState.proxyUrl = "";
newState.proxyUrl = '';
}
}

View File

@@ -1,15 +1,15 @@
import { ClientApi } from '../client/api';
import { getClientConfig } from '../config/client';
import {
FETCH_COMMIT_URL,
FETCH_TAG_URL,
ModelProvider,
StoreKey,
} from "../constant";
import { getClientConfig } from "../config/client";
import { createPersistStore } from "../utils/store";
import { clientUpdate } from "../utils";
import ChatGptIcon from "../icons/chatgpt.png";
import Locale from "../locales";
import { ClientApi } from "../client/api";
} from '../constant';
import ChatGptIcon from '../icons/chatgpt.png';
import Locale from '../locales';
import { clientUpdate } from '../utils';
import { createPersistStore } from '../utils/store';
const ONE_MINUTE = 60 * 1000;
const isApp = !!getClientConfig()?.isApp;
@@ -22,15 +22,15 @@ function formatVersionDate(t: string) {
return [
year.toString(),
month.toString().padStart(2, "0"),
day.toString().padStart(2, "0"),
].join("");
month.toString().padStart(2, '0'),
day.toString().padStart(2, '0'),
].join('');
}
type VersionType = "date" | "tag";
type VersionType = 'date' | 'tag';
async function getVersion(type: VersionType) {
if (type === "date") {
if (type === 'date') {
const data = (await (await fetch(FETCH_COMMIT_URL)).json()) as {
commit: {
author: { name: string; date: string };
@@ -40,7 +40,7 @@ async function getVersion(type: VersionType) {
const remoteCommitTime = data[0].commit.author.date;
const remoteId = new Date(remoteCommitTime).getTime().toString();
return remoteId;
} else if (type === "tag") {
} else if (type === 'tag') {
const data = (await (await fetch(FETCH_TAG_URL)).json()) as {
commit: { sha: string; url: string };
name: string;
@@ -51,10 +51,10 @@ async function getVersion(type: VersionType) {
export const useUpdateStore = createPersistStore(
{
versionType: "tag" as VersionType,
versionType: 'tag' as VersionType,
lastUpdate: 0,
version: "unknown",
remoteVersion: "",
version: 'unknown',
remoteVersion: '',
used: 0,
subscription: 0,
@@ -62,7 +62,7 @@ export const useUpdateStore = createPersistStore(
},
(set, get) => ({
formatVersion(version: string) {
if (get().versionType === "date") {
if (get().versionType === 'date') {
version = formatVersionDate(version);
}
return version;
@@ -70,15 +70,16 @@ export const useUpdateStore = createPersistStore(
async getLatestVersion(force = false) {
const versionType = get().versionType;
let version =
versionType === "date"
const version
= versionType === 'date'
? getClientConfig()?.commitDate
: getClientConfig()?.version;
set(() => ({ version }));
const shouldCheck = Date.now() - get().lastUpdate > 2 * 60 * ONE_MINUTE;
if (!force && !shouldCheck) return;
if (!force && !shouldCheck)
{ return; }
set(() => ({
lastUpdate: Date.now(),
@@ -93,32 +94,32 @@ export const useUpdateStore = createPersistStore(
// Check if notification permission is granted
await window.__TAURI__?.notification
.isPermissionGranted()
.then((granted) => {
.then((granted: any) => {
if (!granted) {
return;
} else {
// Request permission to show notifications
window.__TAURI__?.notification
.requestPermission()
.then((permission) => {
if (permission === "granted") {
.then((permission: any) => {
if (permission === 'granted') {
if (version === remoteId) {
// Show a notification using Tauri
window.__TAURI__?.notification.sendNotification({
title: "NextChat",
title: 'NextChat',
body: `${Locale.Settings.Update.IsLatest}`,
icon: `${ChatGptIcon.src}`,
sound: "Default",
sound: 'Default',
});
} else {
const updateMessage =
Locale.Settings.Update.FoundUpdate(`${remoteId}`);
const updateMessage
= Locale.Settings.Update.FoundUpdate(`${remoteId}`);
// Show a notification for the new version using Tauri
window.__TAURI__?.notification.sendNotification({
title: "NextChat",
title: 'NextChat',
body: updateMessage,
icon: `${ChatGptIcon.src}`,
sound: "Default",
sound: 'Default',
});
clientUpdate();
}
@@ -127,16 +128,17 @@ export const useUpdateStore = createPersistStore(
}
});
}
console.log("[Got Upstream] ", remoteId);
console.log('[Got Upstream] ', remoteId);
} catch (error) {
console.error("[Fetch Upstream Commit Id]", error);
console.error('[Fetch Upstream Commit Id]', error);
}
},
async updateUsage(force = false) {
// only support openai for now
const overOneMinute = Date.now() - get().lastUpdateUsage >= ONE_MINUTE;
if (!overOneMinute && !force) return;
if (!overOneMinute && !force)
{ return; }
set(() => ({
lastUpdateUsage: Date.now(),