mirror of
https://github.com/coaidev/coai.git
synced 2025-05-23 06:50:14 +09:00
fix adapter of select group in mobile
This commit is contained in:
parent
9e20d56ba2
commit
edae895fc3
@ -319,12 +319,12 @@
|
||||
}
|
||||
|
||||
.input-options {
|
||||
width: max-content;
|
||||
margin: 16px auto 2px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
flex-wrap: nowrap;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 4px;
|
||||
height: min-content;
|
||||
}
|
||||
|
@ -8,6 +8,14 @@
|
||||
user-select: none;
|
||||
justify-content: center;
|
||||
|
||||
&.mobile {
|
||||
text-align: center;
|
||||
|
||||
& span {
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
|
||||
.select-group-item {
|
||||
padding: 0.35rem 0.5rem;
|
||||
border-radius: 4px;
|
||||
|
@ -1,3 +1,13 @@
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "./ui/select";
|
||||
import { mobile } from "../utils.ts";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
type SelectGroupProps = {
|
||||
current: string;
|
||||
list: string[];
|
||||
@ -5,7 +15,30 @@ type SelectGroupProps = {
|
||||
};
|
||||
|
||||
function SelectGroup(props: SelectGroupProps) {
|
||||
return (
|
||||
const [state, setState] = useState(mobile);
|
||||
useEffect(() => {
|
||||
window.addEventListener("resize", () => {
|
||||
setState(mobile);
|
||||
});
|
||||
}, []);
|
||||
|
||||
return state ? (
|
||||
<Select
|
||||
value={props.current}
|
||||
onValueChange={(value: string) => props.onChange?.(value)}
|
||||
>
|
||||
<SelectTrigger className="select-group mobile">
|
||||
<SelectValue placeholder={props.current} />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{props.list.map((select: string, idx: number) => (
|
||||
<SelectItem key={idx} value={select}>
|
||||
{select}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
) : (
|
||||
<div className={`select-group`}>
|
||||
{props.list.map((select: string, idx: number) => (
|
||||
<div
|
||||
|
@ -1,7 +1,7 @@
|
||||
import axios from "axios";
|
||||
|
||||
export const version: string = "2.7.0";
|
||||
export const deploy: boolean = true;
|
||||
export const version: string = "2.8.0";
|
||||
export const deploy: boolean = false;
|
||||
export let rest_api: string = "http://localhost:8094";
|
||||
export let ws_api: string = "ws://localhost:8094";
|
||||
|
||||
@ -11,6 +11,14 @@ if (deploy) {
|
||||
}
|
||||
|
||||
export const tokenField = deploy ? "token" : "token-dev";
|
||||
export const supportModels: string[] = [
|
||||
"GPT-3.5",
|
||||
"GPT-3.5-16k",
|
||||
"GPT-4",
|
||||
"GPT-4-32k",
|
||||
"Claude-2",
|
||||
"Claude-2-100k",
|
||||
];
|
||||
|
||||
export function login() {
|
||||
location.href = "https://deeptrain.lightxi.com/login?app=chatnio";
|
||||
|
@ -1,4 +1,4 @@
|
||||
import {ws_api} from "../conf.ts";
|
||||
import { ws_api } from "../conf.ts";
|
||||
|
||||
export const endpoint = `${ws_api}/generation/create`;
|
||||
|
||||
@ -6,7 +6,7 @@ export type GenerationForm = {
|
||||
token: string;
|
||||
prompt: string;
|
||||
model: string;
|
||||
}
|
||||
};
|
||||
|
||||
export type GenerationSegmentResponse = {
|
||||
message: string;
|
||||
@ -14,12 +14,12 @@ export type GenerationSegmentResponse = {
|
||||
end: boolean;
|
||||
error: string;
|
||||
hash: string;
|
||||
}
|
||||
};
|
||||
|
||||
export type MessageEvent = {
|
||||
message: string;
|
||||
quota: number;
|
||||
}
|
||||
};
|
||||
|
||||
export class GenerationManager {
|
||||
protected processing: boolean;
|
||||
@ -31,88 +31,92 @@ export class GenerationManager {
|
||||
protected onFinished?: (hash: string) => void;
|
||||
|
||||
constructor() {
|
||||
this.processing = false;
|
||||
this.processing = false;
|
||||
this.connection = null;
|
||||
this.message = "";
|
||||
}
|
||||
|
||||
public setProcessingChangeHandler(
|
||||
handler: (processing: boolean) => void,
|
||||
): void {
|
||||
this.onProcessingChange = handler;
|
||||
}
|
||||
|
||||
public setMessageHandler(handler: (message: MessageEvent) => void): void {
|
||||
this.onMessage = handler;
|
||||
}
|
||||
|
||||
public setErrorHandler(handler: (error: string) => void): void {
|
||||
this.onError = handler;
|
||||
}
|
||||
|
||||
public setFinishedHandler(handler: (hash: string) => void): void {
|
||||
this.onFinished = handler;
|
||||
}
|
||||
|
||||
public isProcessing(): boolean {
|
||||
return this.processing;
|
||||
}
|
||||
|
||||
protected setProcessing(processing: boolean): boolean {
|
||||
this.processing = processing;
|
||||
if (!processing) {
|
||||
this.connection = null;
|
||||
this.message = "";
|
||||
}
|
||||
this.onProcessingChange?.(processing);
|
||||
return processing;
|
||||
}
|
||||
|
||||
public setProcessingChangeHandler(handler: (processing: boolean) => void): void {
|
||||
this.onProcessingChange = handler;
|
||||
public getConnection(): WebSocket | null {
|
||||
return this.connection;
|
||||
}
|
||||
|
||||
protected handleMessage(message: GenerationSegmentResponse): void {
|
||||
if (message.error && message.end) {
|
||||
this.onError?.(message.error);
|
||||
this.setProcessing(false);
|
||||
return;
|
||||
}
|
||||
|
||||
public setMessageHandler(handler: (message: MessageEvent) => void): void {
|
||||
this.onMessage = handler;
|
||||
}
|
||||
this.message += message.message;
|
||||
this.onMessage?.({
|
||||
message: this.message,
|
||||
quota: message.quota,
|
||||
});
|
||||
|
||||
public setErrorHandler(handler: (error: string) => void): void {
|
||||
this.onError = handler;
|
||||
if (message.end) {
|
||||
this.onFinished?.(message.hash);
|
||||
this.setProcessing(false);
|
||||
}
|
||||
}
|
||||
|
||||
public setFinishedHandler(handler: (hash: string) => void): void {
|
||||
this.onFinished = handler;
|
||||
}
|
||||
|
||||
public isProcessing(): boolean {
|
||||
return this.processing;
|
||||
}
|
||||
|
||||
protected setProcessing(processing: boolean): boolean {
|
||||
this.processing = processing;
|
||||
if (!processing) {
|
||||
this.connection = null;
|
||||
this.message = "";
|
||||
}
|
||||
this.onProcessingChange?.(processing);
|
||||
return processing;
|
||||
}
|
||||
|
||||
public getConnection(): WebSocket | null {
|
||||
return this.connection;
|
||||
}
|
||||
|
||||
protected handleMessage(message: GenerationSegmentResponse): void {
|
||||
if (message.error && message.end) {
|
||||
this.onError?.(message.error);
|
||||
public generate(prompt: string, model: string) {
|
||||
this.setProcessing(true);
|
||||
const token = localStorage.getItem("token") || "";
|
||||
if (token) {
|
||||
this.connection = new WebSocket(endpoint);
|
||||
this.connection.onopen = () => {
|
||||
this.connection?.send(
|
||||
JSON.stringify({ token, prompt, model } as GenerationForm),
|
||||
);
|
||||
};
|
||||
this.connection.onmessage = (event) => {
|
||||
this.handleMessage(JSON.parse(event.data) as GenerationSegmentResponse);
|
||||
};
|
||||
this.connection.onclose = () => {
|
||||
this.setProcessing(false);
|
||||
return;
|
||||
}
|
||||
|
||||
this.message += message.message;
|
||||
this.onMessage?.({
|
||||
message: this.message,
|
||||
quota: message.quota,
|
||||
});
|
||||
|
||||
if (message.end) {
|
||||
this.onFinished?.(message.hash);
|
||||
this.setProcessing(false);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public generate(prompt: string, model: string) {
|
||||
this.setProcessing(true);
|
||||
const token = localStorage.getItem("token") || "";
|
||||
if (token) {
|
||||
this.connection = new WebSocket(endpoint);
|
||||
this.connection.onopen = () => {
|
||||
this.connection?.send(JSON.stringify({ token, prompt, model } as GenerationForm));
|
||||
};
|
||||
this.connection.onmessage = (event) => {
|
||||
this.handleMessage(JSON.parse(event.data) as GenerationSegmentResponse);
|
||||
};
|
||||
this.connection.onclose = () => {
|
||||
this.setProcessing(false);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public generateWithBlock(prompt: string, model: string): boolean {
|
||||
if (this.isProcessing()) {
|
||||
return false;
|
||||
}
|
||||
this.generate(prompt, model);
|
||||
return true;
|
||||
public generateWithBlock(prompt: string, model: string): boolean {
|
||||
if (this.isProcessing()) {
|
||||
return false;
|
||||
}
|
||||
this.generate(prompt, model);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
export const manager = new GenerationManager();
|
||||
|
@ -143,16 +143,17 @@ const resources = {
|
||||
"max-length-prompt":
|
||||
"The content has been truncated due to the context length limit",
|
||||
},
|
||||
"generate": {
|
||||
"title": "AI Project Generator",
|
||||
generate: {
|
||||
title: "AI Project Generator",
|
||||
"input-placeholder": "generate a python game",
|
||||
"failed": "Generate failed",
|
||||
"reason": "Reason: ",
|
||||
"success": "Generate success",
|
||||
"success-prompt": "Project generated successfully! Please select the download format.",
|
||||
"empty": "generating...",
|
||||
"download": "Download {{name}} format",
|
||||
}
|
||||
failed: "Generate failed",
|
||||
reason: "Reason: ",
|
||||
success: "Generate success",
|
||||
"success-prompt":
|
||||
"Project generated successfully! Please select the download format.",
|
||||
empty: "generating...",
|
||||
download: "Download {{name}} format",
|
||||
},
|
||||
},
|
||||
},
|
||||
cn: {
|
||||
@ -283,16 +284,16 @@ const resources = {
|
||||
"max-length": "内容过长",
|
||||
"max-length-prompt": "由于上下文长度限制,内容已被截取",
|
||||
},
|
||||
"generate": {
|
||||
"title": "AI 项目生成器",
|
||||
generate: {
|
||||
title: "AI 项目生成器",
|
||||
"input-placeholder": "生成一个python小游戏",
|
||||
"failed": "生成失败",
|
||||
"reason": "原因:",
|
||||
"success": "生成成功",
|
||||
failed: "生成失败",
|
||||
reason: "原因:",
|
||||
success: "生成成功",
|
||||
"success-prompt": "成功生成项目!请选择下载格式。",
|
||||
"empty": "生成中...",
|
||||
"download": "下载 {{name}} 格式",
|
||||
}
|
||||
empty: "生成中...",
|
||||
download: "下载 {{name}} 格式",
|
||||
},
|
||||
},
|
||||
},
|
||||
ru: {
|
||||
@ -436,13 +437,14 @@ const resources = {
|
||||
generate: {
|
||||
title: "Генератор AI проектов",
|
||||
"input-placeholder": "сгенерировать python игру",
|
||||
"failed": "Генерация не удалась",
|
||||
"reason": "Причина: ",
|
||||
"success": "Генерация успешна",
|
||||
"success-prompt": "Проект успешно сгенерирован! Пожалуйста, выберите формат загрузки.",
|
||||
"empty": "генерация...",
|
||||
"download": "Загрузить {{name}} формат",
|
||||
}
|
||||
failed: "Генерация не удалась",
|
||||
reason: "Причина: ",
|
||||
success: "Генерация успешна",
|
||||
"success-prompt":
|
||||
"Проект успешно сгенерирован! Пожалуйста, выберите формат загрузки.",
|
||||
empty: "генерация...",
|
||||
download: "Загрузить {{name}} формат",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
@ -1,18 +1,18 @@
|
||||
import "../assets/generation.less";
|
||||
import {useDispatch, useSelector} from "react-redux";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { selectAuthenticated } from "../store/auth.ts";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Button } from "../components/ui/button.tsx";
|
||||
import {ChevronLeft, Cloud, FileDown, Info, LogIn, Send} from "lucide-react";
|
||||
import {login, rest_api} from "../conf.ts";
|
||||
import { ChevronLeft, Cloud, FileDown, Info, LogIn, Send } from "lucide-react";
|
||||
import { login, rest_api, supportModels } from "../conf.ts";
|
||||
import router from "../router.ts";
|
||||
import { Input } from "../components/ui/input.tsx";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import SelectGroup from "../components/SelectGroup.tsx";
|
||||
import {manager} from "../conversation/generation.ts";
|
||||
import {useToast} from "../components/ui/use-toast.ts";
|
||||
import {handleGenerationData} from "../utils.ts";
|
||||
import {selectModel, setModel} from "../store/chat.ts";
|
||||
import { manager } from "../conversation/generation.ts";
|
||||
import { useToast } from "../components/ui/use-toast.ts";
|
||||
import { handleGenerationData } from "../utils.ts";
|
||||
import { selectModel, setModel } from "../store/chat.ts";
|
||||
|
||||
type WrapperProps = {
|
||||
onSend?: (value: string, model: string) => boolean;
|
||||
@ -22,10 +22,10 @@ function Wrapper({ onSend }: WrapperProps) {
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useDispatch();
|
||||
const ref = useRef(null);
|
||||
const [ stayed, setStayed ] = useState<boolean>(false);
|
||||
const [ hash, setHash ] = useState<string>("");
|
||||
const [ data, setData ] = useState<string>("");
|
||||
const [ quota, setQuota ] = useState<number>(0);
|
||||
const [stayed, setStayed] = useState<boolean>(false);
|
||||
const [hash, setHash] = useState<string>("");
|
||||
const [data, setData] = useState<string>("");
|
||||
const [quota, setQuota] = useState<number>(0);
|
||||
const model = useSelector(selectModel);
|
||||
const modelRef = useRef(model);
|
||||
const auth = useSelector(selectAuthenticated);
|
||||
@ -45,21 +45,21 @@ function Wrapper({ onSend }: WrapperProps) {
|
||||
manager.setMessageHandler(({ message, quota }) => {
|
||||
setData(message);
|
||||
setQuota(quota);
|
||||
})
|
||||
});
|
||||
|
||||
manager.setErrorHandler((err: string) => {
|
||||
toast({
|
||||
title: t('generate.failed'),
|
||||
description: `${t('generate.reason')} ${err}`,
|
||||
})
|
||||
})
|
||||
title: t("generate.failed"),
|
||||
description: `${t("generate.reason")} ${err}`,
|
||||
});
|
||||
});
|
||||
manager.setFinishedHandler((hash: string) => {
|
||||
toast({
|
||||
title: t('generate.success'),
|
||||
description: t('generate.success-prompt'),
|
||||
})
|
||||
title: t("generate.success"),
|
||||
description: t("generate.success-prompt"),
|
||||
});
|
||||
setHash(hash);
|
||||
})
|
||||
});
|
||||
|
||||
function handleSend(model: string = "gpt-3.5-16k") {
|
||||
const target = ref.current as HTMLInputElement | null;
|
||||
@ -81,15 +81,19 @@ function Wrapper({ onSend }: WrapperProps) {
|
||||
target.focus();
|
||||
target.removeEventListener("keydown", () => {});
|
||||
target.addEventListener("keydown", (e) => {
|
||||
if (e.key === "Enter") {
|
||||
// cannot use model here, because model is not updated
|
||||
handleSend(modelRef.current);
|
||||
}
|
||||
});
|
||||
if (e.key === "Enter") {
|
||||
// cannot use model here, because model is not updated
|
||||
handleSend(modelRef.current);
|
||||
}
|
||||
});
|
||||
|
||||
return () => {
|
||||
ref.current && (ref.current as HTMLInputElement).removeEventListener("keydown", () => {});
|
||||
}
|
||||
ref.current &&
|
||||
(ref.current as HTMLInputElement).removeEventListener(
|
||||
"keydown",
|
||||
() => {},
|
||||
);
|
||||
};
|
||||
}, [ref]);
|
||||
|
||||
useEffect(() => {
|
||||
@ -98,35 +102,48 @@ function Wrapper({ onSend }: WrapperProps) {
|
||||
|
||||
return (
|
||||
<div className={`generation-wrapper`}>
|
||||
{
|
||||
stayed ?
|
||||
<div className={`box`}>
|
||||
{ quota > 0 && <div className={`quota-box`}>
|
||||
{stayed ? (
|
||||
<div className={`box`}>
|
||||
{quota > 0 && (
|
||||
<div className={`quota-box`}>
|
||||
<Cloud className={`h-4 w-4 mr-2`} />
|
||||
{quota}
|
||||
</div> }
|
||||
<pre className={`message-box`}>
|
||||
{ handleGenerationData(data) || t('generate.empty') }
|
||||
</pre>
|
||||
{
|
||||
hash.length > 0 &&
|
||||
<div className={`hash-box`}>
|
||||
<a className={`download-box`} href={`${rest_api}/generation/download/tar?hash=${hash}`}>
|
||||
<FileDown className={`h-6 w-6`} />
|
||||
<p>{ t('generate.download', { name: "tar.gz"}) }</p>
|
||||
</a>
|
||||
<a className={`download-box`} href={`${rest_api}/generation/download/zip?hash=${hash}`}>
|
||||
<FileDown className={`h-6 w-6`} />
|
||||
<p>{ t('generate.download', { name: "zip"}) }</p>
|
||||
</a>
|
||||
|
||||
</div>
|
||||
}
|
||||
</div> :
|
||||
<div className={`product`}><img src={`/favicon.ico`} alt={""} />AI Code Generator</div>
|
||||
}
|
||||
</div>
|
||||
)}
|
||||
<pre className={`message-box`}>
|
||||
{handleGenerationData(data) || t("generate.empty")}
|
||||
</pre>
|
||||
{hash.length > 0 && (
|
||||
<div className={`hash-box`}>
|
||||
<a
|
||||
className={`download-box`}
|
||||
href={`${rest_api}/generation/download/tar?hash=${hash}`}
|
||||
>
|
||||
<FileDown className={`h-6 w-6`} />
|
||||
<p>{t("generate.download", { name: "tar.gz" })}</p>
|
||||
</a>
|
||||
<a
|
||||
className={`download-box`}
|
||||
href={`${rest_api}/generation/download/zip?hash=${hash}`}
|
||||
>
|
||||
<FileDown className={`h-6 w-6`} />
|
||||
<p>{t("generate.download", { name: "zip" })}</p>
|
||||
</a>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
<div className={`product`}>
|
||||
<img src={`/favicon.ico`} alt={""} />
|
||||
AI Code Generator
|
||||
</div>
|
||||
)}
|
||||
<div className={`generate-box`}>
|
||||
<Input className={`input`} ref={ref} placeholder={t('generate.input-placeholder')} />
|
||||
<Input
|
||||
className={`input`}
|
||||
ref={ref}
|
||||
placeholder={t("generate.input-placeholder")}
|
||||
/>
|
||||
<Button
|
||||
size={`icon`}
|
||||
className={`action`}
|
||||
@ -139,7 +156,7 @@ function Wrapper({ onSend }: WrapperProps) {
|
||||
<div className={`model-box`}>
|
||||
<SelectGroup
|
||||
current={model}
|
||||
list={["GPT-3.5", "GPT-3.5-16k", "GPT-4", "GPT-4-32k"]}
|
||||
list={supportModels}
|
||||
onChange={(value: string) => {
|
||||
dispatch(setModel(value));
|
||||
}}
|
||||
@ -149,7 +166,7 @@ function Wrapper({ onSend }: WrapperProps) {
|
||||
);
|
||||
}
|
||||
function Generation() {
|
||||
const [ state, setState ] = useState(false);
|
||||
const [state, setState] = useState(false);
|
||||
const { t } = useTranslation();
|
||||
const auth = useSelector(selectAuthenticated);
|
||||
|
||||
@ -170,7 +187,9 @@ function Generation() {
|
||||
</Button>
|
||||
<Wrapper
|
||||
onSend={(prompt: string, model: string) => {
|
||||
console.debug(`[generation] create generation request (prompt: ${prompt}, model: ${model.toLowerCase()})`);
|
||||
console.debug(
|
||||
`[generation] create generation request (prompt: ${prompt}, model: ${model.toLowerCase()})`,
|
||||
);
|
||||
return manager.generateWithBlock(prompt, model.toLowerCase());
|
||||
}}
|
||||
/>
|
||||
|
@ -3,7 +3,9 @@ import "../assets/chat.less";
|
||||
import { Input } from "../components/ui/input.tsx";
|
||||
import { Toggle } from "../components/ui/toggle.tsx";
|
||||
import {
|
||||
ChevronDown, ChevronRight, FolderKanban,
|
||||
ChevronDown,
|
||||
ChevronRight,
|
||||
FolderKanban,
|
||||
Globe,
|
||||
LogIn,
|
||||
MessageSquare,
|
||||
@ -21,7 +23,7 @@ import {
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import type { RootState } from "../store";
|
||||
import { selectAuthenticated } from "../store/auth.ts";
|
||||
import { login } from "../conf.ts";
|
||||
import { login, supportModels } from "../conf.ts";
|
||||
import {
|
||||
deleteConversation,
|
||||
toggleConversation,
|
||||
@ -35,7 +37,7 @@ import {
|
||||
useAnimation,
|
||||
useEffectAsync,
|
||||
} from "../utils.ts";
|
||||
import {toast, useToast} from "../components/ui/use-toast.ts";
|
||||
import { toast, useToast } from "../components/ui/use-toast.ts";
|
||||
import { ConversationInstance, Message } from "../conversation/types.ts";
|
||||
import {
|
||||
selectCurrent,
|
||||
@ -315,17 +317,20 @@ function ChatWrapper() {
|
||||
return (
|
||||
<div className={`chat-container`}>
|
||||
<div className={`chat-wrapper`}>
|
||||
{
|
||||
messages.length > 0 ?
|
||||
<ChatInterface /> :
|
||||
<div className={`chat-product`}>
|
||||
<Button variant={`outline`} onClick={() => router.navigate('/generate')}>
|
||||
<FolderKanban className={`h-4 w-4 mr-1.5`} />
|
||||
{ t('generate.title') }
|
||||
<ChevronRight className={`h-4 w-4 ml-2`} />
|
||||
</Button>
|
||||
</div>
|
||||
}
|
||||
{messages.length > 0 ? (
|
||||
<ChatInterface />
|
||||
) : (
|
||||
<div className={`chat-product`}>
|
||||
<Button
|
||||
variant={`outline`}
|
||||
onClick={() => router.navigate("/generate")}
|
||||
>
|
||||
<FolderKanban className={`h-4 w-4 mr-1.5`} />
|
||||
{t("generate.title")}
|
||||
<ChevronRight className={`h-4 w-4 ml-2`} />
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
<div className={`chat-input`}>
|
||||
<div className={`input-wrapper`}>
|
||||
<TooltipProvider>
|
||||
@ -385,21 +390,19 @@ function ChatWrapper() {
|
||||
</Button>
|
||||
</div>
|
||||
<div className={`input-options`}>
|
||||
<div className="flex items-center space-x-2">
|
||||
<SelectGroup
|
||||
current={model}
|
||||
list={["GPT-3.5", "GPT-3.5-16k", "GPT-4", "GPT-4-32k"]}
|
||||
onChange={(model: string) => {
|
||||
if (!auth && model !== "GPT-3.5") {
|
||||
toast({
|
||||
title: t("login-require"),
|
||||
})
|
||||
return;
|
||||
}
|
||||
dispatch(setModel(model));
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<SelectGroup
|
||||
current={model}
|
||||
list={supportModels}
|
||||
onChange={(model: string) => {
|
||||
if (!auth && model !== "GPT-3.5") {
|
||||
toast({
|
||||
title: t("login-require"),
|
||||
});
|
||||
return;
|
||||
}
|
||||
dispatch(setModel(model));
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -199,20 +199,35 @@ export function useDraggableInput(
|
||||
|
||||
export function escapeRegExp(str: string): string {
|
||||
// convert \n to [enter], \t to [tab], \r to [return], \s to [space], \" to [quote], \' to [single-quote]
|
||||
return str.replace(/\\n/g, "\n").replace(/\\t/g, "\t").replace(/\\r/g, "\r").replace(/\\s/g, " ").replace(/\\"/g, "\"").replace(/\\'/g, "'");
|
||||
return str
|
||||
.replace(/\\n/g, "\n")
|
||||
.replace(/\\t/g, "\t")
|
||||
.replace(/\\r/g, "\r")
|
||||
.replace(/\\s/g, " ")
|
||||
.replace(/\\"/g, '"')
|
||||
.replace(/\\'/g, "'");
|
||||
}
|
||||
|
||||
export function handleLine(data: string, max_line: number, end?: boolean): string {
|
||||
export function handleLine(
|
||||
data: string,
|
||||
max_line: number,
|
||||
end?: boolean,
|
||||
): string {
|
||||
const segment = data.split("\n");
|
||||
const line = segment.length;
|
||||
if (line > max_line) {
|
||||
return (end ?? true) ? segment.slice(line - max_line).join("\n") : segment.slice(0, max_line).join("\n");
|
||||
return end ?? true
|
||||
? segment.slice(line - max_line).join("\n")
|
||||
: segment.slice(0, max_line).join("\n");
|
||||
} else {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
export function handleGenerationData(data: string): string {
|
||||
data = data.replace(/{\s*"result":\s*{/g, "").trim().replace(/}\s*$/g, "");
|
||||
data = data
|
||||
.replace(/{\s*"result":\s*{/g, "")
|
||||
.trim()
|
||||
.replace(/}\s*$/g, "");
|
||||
return handleLine(escapeRegExp(data), 6);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user