mirror of
https://github.com/coaidev/coai.git
synced 2025-05-28 09:20:18 +09:00
update api platform
This commit is contained in:
parent
a378a572fb
commit
467e041f85
@ -5,7 +5,14 @@ import { Button } from "./components/ui/button.tsx";
|
||||
import router from "./router.ts";
|
||||
import I18nProvider from "./components/I18nProvider.tsx";
|
||||
import ProjectLink from "./components/ProjectLink.tsx";
|
||||
import { BadgeCent, Boxes, CalendarPlus, Cloud, Menu } from "lucide-react";
|
||||
import {
|
||||
BadgeCent,
|
||||
Boxes,
|
||||
CalendarPlus,
|
||||
Cloud,
|
||||
Menu,
|
||||
Plug,
|
||||
} from "lucide-react";
|
||||
import { Provider, useDispatch, useSelector } from "react-redux";
|
||||
import { toggleMenu } from "./store/menu.ts";
|
||||
import store from "./store/index.ts";
|
||||
@ -31,8 +38,10 @@ import Quota from "./routes/Quota.tsx";
|
||||
import { openDialog as openQuotaDialog, quotaSelector } from "./store/quota.ts";
|
||||
import { openDialog as openPackageDialog } from "./store/package.ts";
|
||||
import { openDialog as openSub } from "./store/subscription.ts";
|
||||
import { openDialog as openApiDialog } from "./store/api.ts";
|
||||
import Package from "./routes/Package.tsx";
|
||||
import Subscription from "./routes/Subscription.tsx";
|
||||
import ApiKey from "./routes/ApiKey.tsx";
|
||||
|
||||
function Settings() {
|
||||
const { t } = useTranslation();
|
||||
@ -69,6 +78,10 @@ function Settings() {
|
||||
<Boxes className={`h-4 w-4 mr-1`} />
|
||||
{t("pkg.title")}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={() => dispatch(openApiDialog())}>
|
||||
<Plug className={`h-4 w-4 mr-1`} />
|
||||
{t("api.title")}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem asChild>
|
||||
<Button
|
||||
@ -133,6 +146,7 @@ function App() {
|
||||
<RouterProvider router={router} />
|
||||
<Toaster />
|
||||
<Quota />
|
||||
<ApiKey />
|
||||
<Package />
|
||||
<Subscription />
|
||||
</Provider>
|
||||
|
27
app/src/assets/api.less
Normal file
27
app/src/assets/api.less
Normal file
@ -0,0 +1,27 @@
|
||||
.api-dialog {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
height: max-content;
|
||||
padding: 24px 0 12px;
|
||||
gap: 24px;
|
||||
}
|
||||
|
||||
.api-wrapper {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 6px;
|
||||
width: 100%;
|
||||
|
||||
input {
|
||||
text-align: center;
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
button {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
}
|
@ -131,13 +131,14 @@
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
font-size: 2rem;
|
||||
font-size: min(2rem, 7vw);
|
||||
gap: 12px;
|
||||
user-select: none;
|
||||
white-space: nowrap;
|
||||
|
||||
img {
|
||||
width: 3rem;
|
||||
height: 3rem;
|
||||
width: min(3rem, 14vw);
|
||||
height: min(3rem, 14vw);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ export const supportModels: string[] = [
|
||||
"Claude-2",
|
||||
"Claude-2-100k",
|
||||
"SparkDesk 讯飞星火",
|
||||
"Palm2"
|
||||
"Palm2",
|
||||
// "Claude-2",
|
||||
// "Claude-2-100k",
|
||||
];
|
||||
@ -32,7 +32,7 @@ export const supportModelConvertor: Record<string, string> = {
|
||||
"Claude-2": "claude-1",
|
||||
"Claude-2-100k": "claude-2", // not claude-2-100k
|
||||
"SparkDesk 讯飞星火": "spark-desk",
|
||||
"Palm2": "chat-bison-001"
|
||||
"Palm2": "chat-bison-001",
|
||||
};
|
||||
|
||||
export function login() {
|
||||
|
@ -22,6 +22,11 @@ type BuySubscriptionResponse = {
|
||||
error: string;
|
||||
};
|
||||
|
||||
type ApiKeyResponse = {
|
||||
status: boolean;
|
||||
key: string;
|
||||
};
|
||||
|
||||
export async function buyQuota(quota: number): Promise<QuotaResponse> {
|
||||
try {
|
||||
const resp = await axios.post(`/buy`, { quota });
|
||||
@ -77,3 +82,19 @@ export async function buySubscription(
|
||||
return { status: false, error: "network error" };
|
||||
}
|
||||
}
|
||||
|
||||
export async function getKey(): Promise<ApiKeyResponse> {
|
||||
try {
|
||||
const resp = await axios.get(`/apikey`);
|
||||
if (resp.data.status === false) {
|
||||
return { status: false, key: "" };
|
||||
}
|
||||
return {
|
||||
status: resp.data.status,
|
||||
key: resp.data.key,
|
||||
};
|
||||
} catch (e) {
|
||||
console.debug(e);
|
||||
return { status: false, key: "" };
|
||||
}
|
||||
}
|
||||
|
@ -2,8 +2,11 @@ import axios from "axios";
|
||||
import type { ConversationInstance } from "./types.ts";
|
||||
import { setHistory } from "../store/chat.ts";
|
||||
import { manager } from "./manager.ts";
|
||||
import { AppDispatch } from "../store";
|
||||
|
||||
export async function updateConversationList(dispatch: any): Promise<void> {
|
||||
export async function updateConversationList(
|
||||
dispatch: AppDispatch,
|
||||
): Promise<void> {
|
||||
const resp = await axios.get("/conversation/list");
|
||||
|
||||
dispatch(
|
||||
@ -24,7 +27,7 @@ export async function loadConversation(
|
||||
}
|
||||
|
||||
export async function deleteConversation(
|
||||
dispatch: any,
|
||||
dispatch: AppDispatch,
|
||||
id: number,
|
||||
): Promise<boolean> {
|
||||
const resp = await axios.get(`/conversation/delete?id=${id}`);
|
||||
@ -34,7 +37,7 @@ export async function deleteConversation(
|
||||
}
|
||||
|
||||
export async function toggleConversation(
|
||||
dispatch: any,
|
||||
dispatch: AppDispatch,
|
||||
id: number,
|
||||
): Promise<void> {
|
||||
return manager.toggle(dispatch, id);
|
||||
|
@ -9,12 +9,13 @@ import {
|
||||
} from "../store/chat.ts";
|
||||
import { useShared } from "../utils.ts";
|
||||
import { ChatProps } from "./connection.ts";
|
||||
import {supportModelConvertor} from "../conf.ts";
|
||||
import { supportModelConvertor } from "../conf.ts";
|
||||
import { AppDispatch } from "../store";
|
||||
|
||||
export class Manager {
|
||||
conversations: Record<number, Conversation>;
|
||||
current: number;
|
||||
dispatch: any;
|
||||
dispatch?: AppDispatch;
|
||||
|
||||
public constructor() {
|
||||
this.conversations = {};
|
||||
@ -22,7 +23,7 @@ export class Manager {
|
||||
this.current = -1;
|
||||
}
|
||||
|
||||
public setDispatch(dispatch: any): void {
|
||||
public setDispatch(dispatch: AppDispatch): void {
|
||||
this.dispatch = dispatch;
|
||||
}
|
||||
|
||||
@ -30,7 +31,7 @@ export class Manager {
|
||||
console.debug(
|
||||
`[manager] conversation receive message (id: ${idx}, length: ${message.length})`,
|
||||
);
|
||||
if (idx === this.current) this.dispatch(setMessages(message));
|
||||
if (idx === this.current) this.dispatch?.(setMessages(message));
|
||||
}
|
||||
|
||||
public getCurrent(): number {
|
||||
@ -57,24 +58,20 @@ export class Manager {
|
||||
instance.load(res.message);
|
||||
}
|
||||
|
||||
public async toggle(dispatch: any, id: number): Promise<void> {
|
||||
public async toggle(dispatch: AppDispatch, id: number): Promise<void> {
|
||||
if (!this.conversations[id]) await this.add(id);
|
||||
this.current = id;
|
||||
dispatch(setCurrent(id));
|
||||
dispatch(setMessages(this.get(id)!.copyMessages()));
|
||||
}
|
||||
|
||||
public async delete(dispatch: any, id: number): Promise<void> {
|
||||
public async delete(dispatch: AppDispatch, id: number): Promise<void> {
|
||||
if (this.getCurrent() === id) await this.toggle(dispatch, -1);
|
||||
dispatch(removeHistory(id));
|
||||
if (this.conversations[id]) delete this.conversations[id];
|
||||
}
|
||||
|
||||
public async send(
|
||||
t: any,
|
||||
auth: boolean,
|
||||
props: ChatProps,
|
||||
): Promise<boolean> {
|
||||
public async send(t: any, auth: boolean, props: ChatProps): Promise<boolean> {
|
||||
props.model = supportModelConvertor[props.model.trim()];
|
||||
const id = this.getCurrent();
|
||||
if (!this.conversations[id]) return false;
|
||||
@ -89,7 +86,7 @@ export class Manager {
|
||||
`[manager] raise new conversation (name: ${props.message})`,
|
||||
);
|
||||
const { hook, useHook } = useShared<number>();
|
||||
this.dispatch(
|
||||
this.dispatch?.(
|
||||
addHistory({
|
||||
message: props.message,
|
||||
hook,
|
||||
|
@ -27,6 +27,7 @@ const resources = {
|
||||
"There was an error logging you in. Please try again.",
|
||||
"request-failed":
|
||||
"Request failed. Please check your network and try again.",
|
||||
close: "Close",
|
||||
conversation: {
|
||||
title: "Conversation",
|
||||
empty: "Empty",
|
||||
@ -154,6 +155,12 @@ const resources = {
|
||||
empty: "generating...",
|
||||
download: "Download {{name}} format",
|
||||
},
|
||||
api: {
|
||||
title: "API Settings",
|
||||
copied: "Copied",
|
||||
"copied-description": "API key has been copied to clipboard",
|
||||
"learn-more": "Learn more",
|
||||
},
|
||||
},
|
||||
},
|
||||
cn: {
|
||||
@ -175,6 +182,7 @@ const resources = {
|
||||
"server-error": "服务器错误",
|
||||
"server-error-prompt": "登录出错,请重试。",
|
||||
"request-failed": "请求失败,请检查您的网络并重试。",
|
||||
close: "关闭",
|
||||
conversation: {
|
||||
title: "会话",
|
||||
empty: "空空如也",
|
||||
@ -294,6 +302,12 @@ const resources = {
|
||||
empty: "生成中...",
|
||||
download: "下载 {{name}} 格式",
|
||||
},
|
||||
api: {
|
||||
title: "API 设置",
|
||||
copied: "复制成功",
|
||||
"copied-description": "API 密钥已复制到剪贴板",
|
||||
"learn-more": "了解更多",
|
||||
},
|
||||
},
|
||||
},
|
||||
ru: {
|
||||
@ -318,6 +332,7 @@ const resources = {
|
||||
"При входе произошла ошибка. Пожалуйста, попробуйте еще раз.",
|
||||
"request-failed":
|
||||
"Ошибка запроса. Пожалуйста, проверьте свою сеть и попробуйте еще раз.",
|
||||
close: "Закрыть",
|
||||
conversation: {
|
||||
title: "Разговор",
|
||||
empty: "Пусто",
|
||||
@ -445,6 +460,12 @@ const resources = {
|
||||
empty: "генерация...",
|
||||
download: "Загрузить {{name}} формат",
|
||||
},
|
||||
api: {
|
||||
title: "Настройки API",
|
||||
copied: "Скопировано",
|
||||
"copied-description": "Ключ API скопирован в буфер обмена",
|
||||
"learn-more": "Узнать больше",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
71
app/src/routes/ApiKey.tsx
Normal file
71
app/src/routes/ApiKey.tsx
Normal file
@ -0,0 +1,71 @@
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from "../components/ui/dialog.tsx";
|
||||
import { Button } from "../components/ui/button.tsx";
|
||||
import "../assets/api.less";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import {
|
||||
closeDialog,
|
||||
dialogSelector,
|
||||
setDialog,
|
||||
keySelector,
|
||||
} from "../store/api.ts";
|
||||
import {Input} from "../components/ui/input.tsx";
|
||||
import {Copy, ExternalLink} from "lucide-react";
|
||||
import {useToast} from "../components/ui/use-toast.ts";
|
||||
import {copyClipboard} from "../utils.ts";
|
||||
|
||||
function Package() {
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useDispatch();
|
||||
const open = useSelector(dialogSelector);
|
||||
const key = useSelector(keySelector);
|
||||
const { toast } = useToast();
|
||||
|
||||
async function copyKey() {
|
||||
await copyClipboard(key);
|
||||
toast({
|
||||
title: t("api.copied"),
|
||||
description: t("api.copied-description"),
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={(open) => dispatch(setDialog(open))}>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>{t("api.title")}</DialogTitle>
|
||||
<DialogDescription asChild>
|
||||
<div className={`api-dialog`}>
|
||||
<div className={`api-wrapper`}>
|
||||
<Input value={key} />
|
||||
<Button variant={`default`} size={`icon`} onClick={copyKey}>
|
||||
<Copy className={`h-4 w-4`} />
|
||||
</Button>
|
||||
</div>
|
||||
<Button variant={`outline`} asChild>
|
||||
<a href={`https://docs.chatnio.net`} target={`_blank`}>
|
||||
<ExternalLink className={`h-4 w-4 mr-2`} />
|
||||
{t("buy.learn-more")}
|
||||
</a>
|
||||
</Button>
|
||||
</div>
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<DialogFooter>
|
||||
<Button variant={`outline`} onClick={() => dispatch(closeDialog())}>
|
||||
{t("close")}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
|
||||
export default Package;
|
@ -177,25 +177,28 @@ function Generation() {
|
||||
|
||||
return (
|
||||
<div className={`generation-page`}>
|
||||
<div className={`generation-container`}>
|
||||
<Button
|
||||
className={`action`}
|
||||
variant={`ghost`}
|
||||
size={`icon`}
|
||||
onClick={() => router.navigate("/")}
|
||||
disabled={state}
|
||||
>
|
||||
<ChevronLeft className={`h-5 w-5 back`} />
|
||||
</Button>
|
||||
<Wrapper
|
||||
onSend={(prompt: string, model: string) => {
|
||||
console.debug(
|
||||
`[generation] create generation request (prompt: ${prompt}, model: ${supportModelConvertor[model]})`,
|
||||
);
|
||||
return manager.generateWithBlock(prompt, supportModelConvertor[model]);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div className={`generation-container`}>
|
||||
<Button
|
||||
className={`action`}
|
||||
variant={`ghost`}
|
||||
size={`icon`}
|
||||
onClick={() => router.navigate("/")}
|
||||
disabled={state}
|
||||
>
|
||||
<ChevronLeft className={`h-5 w-5 back`} />
|
||||
</Button>
|
||||
<Wrapper
|
||||
onSend={(prompt: string, model: string) => {
|
||||
console.debug(
|
||||
`[generation] create generation request (prompt: ${prompt}, model: ${supportModelConvertor[model]})`,
|
||||
);
|
||||
return manager.generateWithBlock(
|
||||
prompt,
|
||||
supportModelConvertor[model],
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ import {
|
||||
} from "../components/ui/tooltip.tsx";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import type { RootState } from "../store";
|
||||
import {selectAuthenticated, selectInit} from "../store/auth.ts";
|
||||
import { selectAuthenticated, selectInit } from "../store/auth.ts";
|
||||
import { login, supportModels } from "../conf.ts";
|
||||
import {
|
||||
deleteConversation,
|
||||
@ -171,7 +171,9 @@ function SideBar() {
|
||||
<AlertDialogDescription>
|
||||
{t("conversation.remove-description")}
|
||||
<strong className={`conversation-name`}>
|
||||
{ extractMessage(filterMessage(removeConversation?.name || "")) }
|
||||
{extractMessage(
|
||||
filterMessage(removeConversation?.name || ""),
|
||||
)}
|
||||
</strong>
|
||||
{t("end")}
|
||||
</AlertDialogDescription>
|
||||
@ -298,15 +300,20 @@ function ChatWrapper() {
|
||||
clearEvent?.();
|
||||
}
|
||||
|
||||
async function processSend(data: string, auth: boolean, model: string, web: boolean): Promise<boolean> {
|
||||
async function processSend(
|
||||
data: string,
|
||||
auth: boolean,
|
||||
model: string,
|
||||
web: boolean,
|
||||
): Promise<boolean> {
|
||||
const message: string = formatMessage(file, data);
|
||||
if (message.length > 0 && data.trim().length > 0) {
|
||||
if (await manager.send(t, auth, { message, web, model })) {
|
||||
clearFile();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
async function handleSend(auth: boolean, model: string, web: boolean) {
|
||||
|
40
app/src/store/api.ts
Normal file
40
app/src/store/api.ts
Normal file
@ -0,0 +1,40 @@
|
||||
import { createSlice } from "@reduxjs/toolkit";
|
||||
import { getKey } from "../conversation/addition.ts";
|
||||
import { AppDispatch } from "./index.ts";
|
||||
|
||||
export const apiSlice = createSlice({
|
||||
name: "api",
|
||||
initialState: {
|
||||
dialog: false,
|
||||
key: "",
|
||||
},
|
||||
reducers: {
|
||||
toggleDialog: (state) => {
|
||||
state.dialog = !state.dialog;
|
||||
},
|
||||
setDialog: (state, action) => {
|
||||
state.dialog = action.payload as boolean;
|
||||
},
|
||||
openDialog: (state) => {
|
||||
state.dialog = true;
|
||||
},
|
||||
closeDialog: (state) => {
|
||||
state.dialog = false;
|
||||
},
|
||||
setKey: (state, action) => {
|
||||
state.key = action.payload as string;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const { toggleDialog, setDialog, openDialog, closeDialog, setKey } =
|
||||
apiSlice.actions;
|
||||
export default apiSlice.reducer;
|
||||
|
||||
export const dialogSelector = (state: any): boolean => state.api.dialog;
|
||||
export const keySelector = (state: any): string => state.api.key;
|
||||
|
||||
export const getPackage = async (dispatch: AppDispatch) => {
|
||||
const response = await getKey();
|
||||
if (response.status) dispatch(setKey(response.key));
|
||||
};
|
@ -1,6 +1,7 @@
|
||||
import { createSlice } from "@reduxjs/toolkit";
|
||||
import axios from "axios";
|
||||
import { tokenField } from "../conf.ts";
|
||||
import { AppDispatch } from "./index.ts";
|
||||
|
||||
export const authSlice = createSlice({
|
||||
name: "auth",
|
||||
@ -37,7 +38,11 @@ export const authSlice = createSlice({
|
||||
},
|
||||
});
|
||||
|
||||
export function validateToken(dispatch: any, token: string, hook?: () => any) {
|
||||
export function validateToken(
|
||||
dispatch: AppDispatch,
|
||||
token: string,
|
||||
hook?: () => any,
|
||||
) {
|
||||
token = token.trim();
|
||||
dispatch(setToken(token));
|
||||
|
||||
|
@ -5,6 +5,7 @@ import chatReducer from "./chat";
|
||||
import quotaReducer from "./quota";
|
||||
import packageReducer from "./package";
|
||||
import subscriptionReducer from "./subscription";
|
||||
import apiReducer from "./api";
|
||||
|
||||
const store = configureStore({
|
||||
reducer: {
|
||||
@ -14,6 +15,7 @@ const store = configureStore({
|
||||
quota: quotaReducer,
|
||||
package: packageReducer,
|
||||
subscription: subscriptionReducer,
|
||||
api: apiReducer,
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { createSlice } from "@reduxjs/toolkit";
|
||||
import { getPackage } from "../conversation/addition.ts";
|
||||
import { AppDispatch } from "./index.ts";
|
||||
|
||||
export const packageSlice = createSlice({
|
||||
name: "package",
|
||||
@ -41,7 +42,7 @@ export const dialogSelector = (state: any): boolean => state.package.dialog;
|
||||
export const certSelector = (state: any): boolean => state.package.cert;
|
||||
export const teenagerSelector = (state: any): boolean => state.package.teenager;
|
||||
|
||||
const refreshPackage = async (dispatch: any) => {
|
||||
const refreshPackage = async (dispatch: AppDispatch) => {
|
||||
const current = new Date().getTime(); //@ts-ignore
|
||||
if (window.hasOwnProperty("package") && current - window.package < 2500)
|
||||
return; //@ts-ignore
|
||||
@ -51,7 +52,7 @@ const refreshPackage = async (dispatch: any) => {
|
||||
if (response.status) dispatch(refreshState(response));
|
||||
};
|
||||
|
||||
export const refreshPackageTask = (dispatch: any) => {
|
||||
export const refreshPackageTask = (dispatch: AppDispatch) => {
|
||||
setInterval(() => refreshPackage(dispatch), 20000);
|
||||
refreshPackage(dispatch).then();
|
||||
};
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { createSlice } from "@reduxjs/toolkit";
|
||||
import { RootState } from "./index.ts";
|
||||
import { AppDispatch, RootState } from "./index.ts";
|
||||
import axios from "axios";
|
||||
|
||||
export const quotaSlice = createSlice({
|
||||
@ -50,7 +50,7 @@ export const quotaValueSelector = (state: RootState): number =>
|
||||
export const quotaSelector = (state: RootState): string =>
|
||||
state.quota.quota.toFixed(2);
|
||||
|
||||
const refreshQuota = async (dispatch: any) => {
|
||||
const refreshQuota = async (dispatch: AppDispatch) => {
|
||||
const current = new Date().getTime(); //@ts-ignore
|
||||
if (window.hasOwnProperty("quota") && current - window.quota < 2500) return; //@ts-ignore
|
||||
window.quota = current;
|
||||
@ -59,7 +59,7 @@ const refreshQuota = async (dispatch: any) => {
|
||||
if (response.data.status) dispatch(setQuota(response.data.quota));
|
||||
};
|
||||
|
||||
export const refreshQuotaTask = (dispatch: any) => {
|
||||
export const refreshQuotaTask = (dispatch: AppDispatch) => {
|
||||
setInterval(() => refreshQuota(dispatch), 5000);
|
||||
refreshQuota(dispatch).then();
|
||||
};
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { createSlice } from "@reduxjs/toolkit";
|
||||
import { getSubscription } from "../conversation/addition.ts";
|
||||
import { AppDispatch } from "./index.ts";
|
||||
|
||||
export const subscriptionSlice = createSlice({
|
||||
name: "subscription",
|
||||
@ -44,7 +45,7 @@ export const isSubscribedSelector = (state: any): boolean =>
|
||||
export const expiredSelector = (state: any): number =>
|
||||
state.subscription.expired;
|
||||
|
||||
export const refreshSubscription = async (dispatch: any) => {
|
||||
export const refreshSubscription = async (dispatch: AppDispatch) => {
|
||||
const current = new Date().getTime(); //@ts-ignore
|
||||
if (
|
||||
window.hasOwnProperty("subscription") && //@ts-ignore
|
||||
@ -57,7 +58,7 @@ export const refreshSubscription = async (dispatch: any) => {
|
||||
if (response.status) dispatch(updateSubscription(response));
|
||||
};
|
||||
|
||||
export const refreshSubscriptionTask = (dispatch: any) => {
|
||||
export const refreshSubscriptionTask = (dispatch: AppDispatch) => {
|
||||
setInterval(() => refreshSubscription(dispatch), 20000);
|
||||
refreshSubscription(dispatch).then();
|
||||
};
|
||||
|
@ -161,7 +161,11 @@ export function filterMessage(message: string): string {
|
||||
return message.replace(/```file\n\[\[.*]]\n[\s\S]*?\n```\n\n/g, "");
|
||||
}
|
||||
|
||||
export function extractMessage(message: string, length: number = 50, flow: string = "...") {
|
||||
export function extractMessage(
|
||||
message: string,
|
||||
length: number = 50,
|
||||
flow: string = "...",
|
||||
) {
|
||||
return message.length > length ? message.slice(0, length) + flow : message;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user