cap nhat giao dien

This commit is contained in:
quangdn-ght
2025-06-25 18:12:09 +07:00
parent cdeb27891b
commit b07760fbc9
28 changed files with 526 additions and 307 deletions

View File

@@ -510,7 +510,7 @@ export function ChatActions(props: {
const pluginStore = usePluginStore();
const session = chatStore.currentSession();
// switch themes
// Chuyển đổi giữa các chế độ giao diện sáng/tối
const theme = config.theme;
function nextTheme() {
@@ -521,11 +521,11 @@ export function ChatActions(props: {
config.update((config) => (config.theme = nextTheme));
}
// stop all responses
// Dừng tất cả các phản hồi đang chạy
const couldStop = ChatControllerPool.hasPending();
const stopAll = () => ChatControllerPool.stopAll();
// switch model
// Chuyển đổi giữa các mô hình AI
const currentModel = session.mask.modelConfig.model;
const currentProviderName =
session.mask.modelConfig?.providerName || ServiceProvider.OpenAI;
@@ -577,11 +577,11 @@ export function ChatActions(props: {
props.setUploading(false);
}
// if current model is not available
// switch to first available model
// nếu mô hình hiện tại không khả dụng
// chuyển sang mô hình khả dụng đầu tiên
const isUnavailableModel = !models.some((m) => m.name === currentModel);
if (isUnavailableModel && models.length > 0) {
// show next model to default model if exist
// hiển thị mô hình tiếp theo là mô hình mặc định nếu có
let nextModel = models.find((model) => model.isDefault) || models[0];
chatStore.updateTargetSession(session, (session) => {
session.mask.modelConfig.model = nextModel.name;
@@ -1795,9 +1795,13 @@ function _Chat() {
}}
>
{messages
// TODO
// .filter((m) => !m.isMcpResponse)
.map((message, i) => {
// Bypass rendering if message.role is "system"
if (message.role === "system") {
return null;
}
const isUser = message.role === "user";
const isContext = i < context.length;
const showActions =
@@ -1809,6 +1813,8 @@ function _Chat() {
const shouldShowClearContextDivider =
i === clearContextIndex - 1;
console.log(message.role);
return (
<Fragment key={message.id}>
<div

View File

@@ -8,30 +8,11 @@ import { ModelType } from "../store";
// import BotIconDefault from "../icons/llm-icons/chebichat.svg";
import BotIconDefault from "../icons/llm-icons/chebichat.svg";
import BotIconOpenAI from "../icons/llm-icons/chebichat.svg";
import BotIconGemini from "../icons/llm-icons/gemini.svg";
import BotIconGemma from "../icons/llm-icons/gemma.svg";
import BotIconClaude from "../icons/llm-icons/claude.svg";
import BotIconMeta from "../icons/llm-icons/meta.svg";
import BotIconMistral from "../icons/llm-icons/mistral.svg";
import BotIconDeepseek from "../icons/llm-icons/deepseek.svg";
import BotIconMoonshot from "../icons/llm-icons/moonshot.svg";
// thay bang chebichat
import BotIconQwen from "../icons/llm-icons/chebichat.svg";
import BotIconWenxin from "../icons/llm-icons/wenxin.svg";
import BotIconGrok from "../icons/llm-icons/grok.svg";
import BotIconHunyuan from "../icons/llm-icons/hunyuan.svg";
import BotIconDoubao from "../icons/llm-icons/doubao.svg";
import BotIconChatglm from "../icons/llm-icons/chatglm.svg";
export function getEmojiUrl(unified: string, style: EmojiStyle) {
// Whoever owns this Content Delivery Network (CDN), I am using your CDN to serve emojis
// Old CDN broken, so I had to switch to this one
// Author: https://github.com/H0llyW00dzZ
// Phương thức trả về đường dẫn URL của emoji dựa trên mã hóa unified và kiểu style
// CDN mới được sử dụng để phục vụ hình ảnh emoji
return `https://fastly.jsdelivr.net/npm/emoji-datasource-apple/img/${style}/64/${unified}.png`;
}
@@ -45,78 +26,109 @@ export function AvatarPicker(props: {
theme={EmojiTheme.AUTO}
getEmojiUrl={getEmojiUrl}
onEmojiClick={(e) => {
// Gọi hàm onEmojiClick khi người dùng click vào emoji
// Truyền giá trị unified của emoji đã chọn
props.onEmojiClick(e.unified);
}}
/>
);
}
export function Avatar(props: { model?: ModelType; avatar?: string }) {
let LlmIcon = BotIconDefault;
if (props.model) {
const modelName = props.model.toLowerCase();
if (
modelName.startsWith("gpt") ||
modelName.startsWith("chatgpt") ||
modelName.startsWith("dall-e") ||
modelName.startsWith("dalle") ||
modelName.startsWith("o1") ||
modelName.startsWith("o3")
) {
LlmIcon = BotIconOpenAI;
} else if (modelName.startsWith("gemini")) {
LlmIcon = BotIconGemini;
} else if (modelName.startsWith("gemma")) {
LlmIcon = BotIconGemma;
} else if (modelName.startsWith("claude")) {
LlmIcon = BotIconClaude;
} else if (modelName.includes("llama")) {
LlmIcon = BotIconMeta;
} else if (
modelName.startsWith("mixtral") ||
modelName.startsWith("codestral")
) {
LlmIcon = BotIconMistral;
} else if (modelName.includes("deepseek")) {
LlmIcon = BotIconDeepseek;
} else if (modelName.startsWith("moonshot")) {
LlmIcon = BotIconMoonshot;
} else if (modelName.startsWith("qwen")) {
LlmIcon = BotIconQwen;
} else if (modelName.startsWith("ernie")) {
LlmIcon = BotIconWenxin;
} else if (modelName.startsWith("grok")) {
LlmIcon = BotIconGrok;
} else if (modelName.startsWith("hunyuan")) {
LlmIcon = BotIconHunyuan;
} else if (modelName.startsWith("doubao") || modelName.startsWith("ep-")) {
LlmIcon = BotIconDoubao;
} else if (
modelName.includes("glm") ||
modelName.startsWith("cogview-") ||
modelName.startsWith("cogvideox-")
) {
LlmIcon = BotIconChatglm;
}
return (
<div className="user-avatar">
<LlmIcon className="user-avatar" size={48} width={48} height={48} />
</div>
);
}
// Function to render chebichat PNG avatar
function chebichatAvatar() {
return (
<div className="user-avatar">
{props.avatar && <EmojiAvatar avatar={props.avatar} size={48} />}
<img
src="/chebichat.png"
alt="chebichat avatar"
width={48}
height={48}
style={{ borderRadius: "50%" }}
/>
</div>
);
}
//xu ly avatar cho Chebichat
// nếu không có avatar thì trả về avatar mặc định của Chebichat
// nếu có avatar thì trả về avatar tương ứng với tên avatar
export function Avatar(props: { model?: ModelType; avatar?: string }) {
// console.log("Avatar props", props);
if (props.avatar === "chebi-user") {
//sau thay the bang avatar tu Chebichat Platform (Avatar Google,...)
// Nếu avatar là "chebi-user", trả về avatar mặc định của Chebichat
return null;
}
return chebichatAvatar();
// let LlmIcon = BotIconDefault;
//phan biệt các loại model và gán icon tương ứng
// if (props.model) {
// const modelName = props.model.toLowerCase();
// // Xác định icon phù hợp dựa trên tên model
// if (
// modelName.startsWith("gpt") ||
// modelName.startsWith("chatgpt") ||
// modelName.startsWith("dall-e") ||
// modelName.startsWith("dalle") ||
// modelName.startsWith("o1") ||
// modelName.startsWith("o3")
// ) {
// LlmIcon = BotIconOpenAI;
// } else if (modelName.startsWith("gemini")) {
// LlmIcon = BotIconGemini;
// } else if (modelName.startsWith("gemma")) {
// LlmIcon = BotIconGemma;
// } else if (modelName.startsWith("claude")) {
// LlmIcon = BotIconClaude;
// } else if (modelName.includes("llama")) {
// LlmIcon = BotIconMeta;
// } else if (
// modelName.startsWith("mixtral") ||
// modelName.startsWith("codestral")
// ) {
// LlmIcon = BotIconMistral;
// } else if (modelName.includes("deepseek")) {
// LlmIcon = BotIconDeepseek;
// } else if (modelName.startsWith("moonshot")) {
// LlmIcon = BotIconMoonshot;
// } else if (modelName.startsWith("qwen")) {
// LlmIcon = BotIconQwen;
// } else if (modelName.startsWith("ernie")) {
// LlmIcon = BotIconWenxin;
// } else if (modelName.startsWith("grok")) {
// LlmIcon = BotIconGrok;
// } else if (modelName.startsWith("hunyuan")) {
// LlmIcon = BotIconHunyuan;
// } else if (modelName.startsWith("doubao") || modelName.startsWith("ep-")) {
// LlmIcon = BotIconDoubao;
// } else if (
// modelName.includes("glm") ||
// modelName.startsWith("cogview-") ||
// modelName.startsWith("cogvideox-")
// ) {
// LlmIcon = BotIconChatglm;
// }
// return chebichatAvatar();
// }
// return (
// console.log("Avatar", props.avatar),
// <div className="user-avatar">
// {props.avatar && <EmojiAvatar avatar={props.avatar} size={48} />}
// </div>
// );
}
export function EmojiAvatar(props: { avatar: string; size?: number }) {
return (
// Hiển thị emoji dựa trên giá trị avatar được truyền vào
<Emoji
unified={props.avatar}
size={props.size ?? 18}

View File

@@ -518,8 +518,8 @@ export function ImagePreviewer(props: {
<NextImage
src={ChatGptIcon.src}
alt="logo"
width={50}
height={50}
width={30}
height={30}
/>
</div>

View File

@@ -45,7 +45,6 @@ import {
readFromFile,
} from "../utils";
import { Updater } from "../typing";
import { ModelConfigList } from "./model-config";
import { FileName, Path } from "../constant";
import { BUILTIN_MASK_STORE } from "../masks";
import {
@@ -246,13 +245,14 @@ export function MaskConfig(props: {
) : null}
</List>
<List>
{/* CAU HINH MODEL */}
{/* <List>
<ModelConfigList
modelConfig={{ ...props.mask.modelConfig }}
updateConfig={updateConfig}
/>
{props.extraListItems}
</List>
</List> */}
</>
);
}

View File

@@ -31,7 +31,6 @@ import {
showConfirm,
showToast,
} from "./ui-lib";
import { ModelConfigList } from "./model-config";
import { IconButton } from "./button";
import {
@@ -1873,7 +1872,8 @@ export function Settings() {
</ListItem>
</List>
<List>
{/* CAU HINH MODEL CUSTOM */}
{/* <List>
<ModelConfigList
modelConfig={config.modelConfig}
updateConfig={(updater) => {
@@ -1882,7 +1882,7 @@ export function Settings() {
config.update((config) => (config.modelConfig = modelConfig));
}}
/>
</List>
</List> */}
{shouldShowPromptModal && (
<UserPromptModal onClose={() => setShowPromptModal(false)} />

View File

@@ -4,7 +4,6 @@ import styles from "./home.module.scss";
import { IconButton } from "./button";
import SettingsIcon from "../icons/settings.svg";
import GithubIcon from "../icons/github.svg";
import ChatGptIcon from "../icons/chebichat.svg";
@@ -25,7 +24,6 @@ import {
MIN_SIDEBAR_WIDTH,
NARROW_SIDEBAR_WIDTH,
Path,
REPO_URL,
} from "../constant";
import { Link, useNavigate } from "react-router-dom";
@@ -36,8 +34,8 @@ import clsx from "clsx";
import { isMcpEnabled } from "../mcp/actions";
const DISCOVERY = [
{ name: Locale.Plugin.Name, path: Path.Plugins },
{ name: "Stable Diffusion", path: Path.Sd },
// { name: Locale.Plugin.Name, path: Path.Plugins },
// { name: "Stable Diffusion", path: Path.Sd },
{ name: Locale.SearchChat.Page.Title, path: Path.SearchChat },
];
@@ -252,17 +250,20 @@ export function SideBar(props: { className?: string }) {
{...props}
>
<SideBarHeader
title="Chebi Chat"
subTitle="Trợ lý AI học tiếng Trung"
logo={<ChatGptIcon />}
shouldNarrow={shouldNarrow}
title="Chebi Chat" // Tiêu đề sidebar
subTitle="Trợ lý AI học tiếng Trung" // Phụ đề sidebar
logo={<ChatGptIcon />} // Logo hiển thị
shouldNarrow={shouldNarrow} // Trạng thái thu nhỏ sidebar
>
{/* Thanh công cụ phía trên của sidebar */}
<div className={styles["sidebar-header-bar"]}>
{/* Nút chuyển sang giao diện tạo chat mới hoặc danh sách mask */}
<IconButton
icon={<MaskIcon />}
text={shouldNarrow ? undefined : Locale.Mask.Name}
className={styles["sidebar-bar-button"]}
onClick={() => {
// Nếu chưa tắt splash screen mask thì chuyển sang tạo chat mới, ngược lại chuyển sang danh sách mask
if (config.dontShowMaskSplashScreen !== true) {
navigate(Path.NewChat, { state: { fromHome: true } });
} else {
@@ -271,17 +272,20 @@ export function SideBar(props: { className?: string }) {
}}
shadow
/>
{/* Nếu tính năng MCP được bật thì hiển thị nút MCP */}
{mcpEnabled && (
<IconButton
icon={<McpIcon />}
text={shouldNarrow ? undefined : Locale.Mcp.Name}
className={styles["sidebar-bar-button"]}
onClick={() => {
// Chuyển sang giao diện MCP Market
navigate(Path.McpMarket, { state: { fromHome: true } });
}}
shadow
/>
)}
{/* Nút chuyển sang giao diện Discovery */}
<IconButton
icon={<DiscoveryIcon />}
text={shouldNarrow ? undefined : Locale.Discovery.Name}
@@ -290,6 +294,7 @@ export function SideBar(props: { className?: string }) {
shadow
/>
</div>
{/* Hiển thị selector khi người dùng bấm vào Discovery */}
{showDiscoverySelector && (
<Selector
items={[
@@ -302,6 +307,7 @@ export function SideBar(props: { className?: string }) {
]}
onClose={() => setshowDiscoverySelector(false)}
onSelection={(s) => {
// Điều hướng đến trang được chọn
navigate(s[0], { state: { fromHome: true } });
}}
/>
@@ -338,7 +344,8 @@ export function SideBar(props: { className?: string }) {
/>
</Link>
</div>
<div className={styles["sidebar-action"]}>
{/* <div className={styles["sidebar-action"]}>
<a href={REPO_URL} target="_blank" rel="noopener noreferrer">
<IconButton
aria={Locale.Export.MessageFromChatGPT}
@@ -346,7 +353,7 @@ export function SideBar(props: { className?: string }) {
shadow
/>
</a>
</div>
</div> */}
</>
}
secondaryAction={