feat(components): 新增图标组件并优化历史记录功能

- 新增 Bell、Collect 和 NotCollect 图标组件
- 优化 History 组件,添加隐藏 logo 功能
- 调整 Message 组件样式,移除不必要的代码
- 更新 Scene 组件 Header 颜色
- 注释掉 tailwind.css 中的 arimo 字体权重
This commit is contained in:
zhaoweijie
2025-08-23 20:11:11 +08:00
parent e640b1254d
commit e0e41d7e21
24 changed files with 331 additions and 183 deletions

View File

@@ -1,12 +1,11 @@
import { Sidebar } from "@/components/Option/Sidebar.tsx"
import React, { useContext, useMemo, useState } from "react"
import React, { useContext, useMemo } from "react"
import { useMessageOption } from "@/hooks/useMessageOption.tsx"
import { useStoreChatModelSettings } from "@/store/model.tsx"
import {
Button,
Card,
Divider,
List,
Menu,
MenuProps,
Popover,
@@ -22,8 +21,7 @@ import { PlusOutlined, RightOutlined } from "@ant-design/icons"
import { qaPrompt } from "@/libs/playground.tsx"
import { ProviderIcons } from "@/components/Common/ProviderIcon.tsx"
import { fetchChatModels } from "@/services/ollama.ts"
import logo from '@/assets/logo.png'
import logo from "@/assets/logo.png"
const ModelIcon = () => {
return (
@@ -74,10 +72,14 @@ export const PlaygroundHistory = () => {
children: qaPrompt.map((item) => {
return {
key: item.id,
label: <div className="flex items-center gap-2">
<p className="w-5 h-5 [&_.ant-avatar]:!w-full [&_.ant-avatar]:!h-full [&_.ant-avatar]:relative [&_.ant-avatar]:-top-3">{item.icon}</p>
<span title={item.title}>{item.title}</span>
</div>,
label: (
<div className="flex items-center gap-2">
<p className="w-5 h-5 [&_.ant-avatar]:!w-full [&_.ant-avatar]:!h-full [&_.ant-avatar]:relative [&_.ant-avatar]:-top-3">
{item.icon}
</p>
<span title={item.title}>{item.title}</span>
</div>
)
}
})
}
@@ -101,25 +103,26 @@ export const PlaygroundHistory = () => {
}
// 大模型
const {
data: models,
isLoading: isModelsLoading,
refetch
} = useQuery({
const { data: models, isLoading: isModelsLoading } = useQuery({
queryKey: ["fetchModel"],
queryFn: () => fetchChatModels({ returnEmpty: true }),
refetchIntervalInBackground: false,
placeholderData: (prev) => prev
})
// 是否隐藏logo
const hideLogo = useMemo(() => {
return localStorage.getItem("hideLogo") === "true"
}, [])
return (
<Card
className={`flex flex-col [&_.ant-card-body]:h-full w-[300px] overflow-hidden h-full pb-5 transition-all duration-300 ease-in-out !bg-[#f3f4f6]`}
className={`flex flex-col [&_.ant-card-body]:h-full w-[300px] overflow-hidden h-full pb-5 transition-all duration-300 ease-in-out backdrop-blur-lg !bg-[#f3f4f6]`}
style={{ width: show ? "300px" : "0" }}>
{/*Header*/}
<div className="flex flex-col overflow-y-hidden h-full">
<div className="flex items-center justify-between transition-all duration-300 ease-in-out w-[250px]">
<img src={logo} alt="logo" className="w-8" />
{!hideLogo && <img src={logo} alt="logo" className="w-8" />}
<h2 className="text-xl font-bold text-zinc-700 dark:text-zinc-300 mr-3">
<span className="text-[#d30100]"></span>
</h2>

View File

@@ -350,7 +350,7 @@ export const PlaygroundIodRelevant: React.FC<Props> = ({ className }) => {
<Card
hoverable
variant="outlined"
className={`${className} translate-y-[-2px] !bg-[#d0e6ff] shadow-[#d0e6ff]/30`}>
className={`${className} translate-y-[-2px] !bg-[#d0e6ff] !shadow-md`}>
<div className="h-full flex flex-col relative">
{/* 花瓣效果 */}
<div

View File

@@ -63,22 +63,7 @@ export const PlaygroundMessage = (props: Props) => {
{/* <div className="text-base md:max-w-2xl lg:max-w-xl xl:max-w-3xl flex lg:px-0 m-auto w-full"> */}
<div
className={`flex flex-row gap-1 md:gap-1 my-2 m-auto w-full ${props.isBot ? "" : "flex-row-reverse"}`}>
<div className="w-8 flex flex-col relative items-center justify-center bottom-[8px]">
<div className="relative h-7 w-7 p-1 rounded-sm text-white flex items-center justify-center text-opacity-100r">
{props.isBot ? (
!props.botAvatar ? (
<div className="absolute h-8 w-8 rounded-full bg-gradient-to-r from-green-300 to-purple-400 hidden"></div>
) : (
props.botAvatar
)
) : !props.userAvatar ? (
<div className="absolute h-8 w-8 rounded-full from-blue-400 to-blue-600 bg-gradient-to-r"></div>
) : (
props.userAvatar
)}
</div>
</div>
<div className="flex w-[calc(100%-50px)] flex-col gap-2 lg:w-[calc(100%-115px)]">
<div className="flex flex-col gap-2">
<span className="text-xs font-bold text-gray-800 dark:text-white"></span>
{props.isBot &&
@@ -102,7 +87,7 @@ export const PlaygroundMessage = (props: Props) => {
return (
<Collapse
key={i}
defaultActiveKey={['reasoning']}
defaultActiveKey={["reasoning"]}
className="border-none !mb-3"
items={[
{
@@ -132,12 +117,18 @@ export const PlaygroundMessage = (props: Props) => {
})}
</>
) : (
// <p
// className={`bg-[#f1f3f4] font-normal text-[#000000d9] px-4 py-2.5 rounded-2xl prose-lg dark:prose-invert whitespace-pre-line prose-p:leading-relaxed prose-pre:p-0 dark:prose-dark ${
// props.message_type && "italic dark:text-gray-400"
// } flex flex-row-reverse`}>
// {props.message}
// </p>
<p
className={`prose-lg dark:prose-invert whitespace-pre-line prose-p:leading-relaxed prose-pre:p-0 dark:prose-dark ${
props.message_type && "italic dark:text-gray-400"
} flex flex-row-reverse`}>
className={`bg-[#2563eb] font-normal rounded-tr-none
text-white px-4 py-2.5 rounded-2xl prose-lg dark:prose-invert whitespace-pre-line prose-p:leading-relaxed prose-pre:p-0 dark:prose-dark ${
props.message_type && "italic dark:text-gray-400"
} flex flex-row-reverse`}>
{props.message}
{/*<span className="bg-[#0000000a] inline-block py-[9px] text-[#000000d9] rounded-xl px-4 font-light text-sm">{props.message}</span>*/}
</p>
)
) : (
@@ -196,35 +187,42 @@ export const PlaygroundMessage = (props: Props) => {
]}
/>
)}
{props.isBot && props?.iodSources && Object.values(props?.iodSources).map(item => item.data).flat().length > 0 && (
<Collapse
className="mt-6"
ghost
// defaultActiveKey={['iod']}
items={[
{
key: "iod",
label: (
<div className="italic text-gray-500 dark:text-gray-400">
{t("iodCitations")}
</div>
),
children: (
<div className="mb-3 flex flex-wrap gap-2">
{Object.values(props?.iodSources).map(item => item.data).flat()?.map((source, index) => (
<MessageSource
onSourceClick={props.onSourceClick}
key={index}
index={index}
source={source}
/>
))}
</div>
)
}
]}
/>
)}
{props.isBot &&
props?.iodSources &&
Object.values(props?.iodSources)
.map((item) => item.data)
.flat().length > 0 && (
<Collapse
className="mt-6"
ghost
// defaultActiveKey={['iod']}
items={[
{
key: "iod",
label: (
<div className="italic text-gray-500 dark:text-gray-400">
{t("iodCitations")}
</div>
),
children: (
<div className="mb-3 flex flex-wrap gap-2">
{Object.values(props?.iodSources)
.map((item) => item.data)
.flat()
?.map((source, index) => (
<MessageSource
onSourceClick={props.onSourceClick}
key={index}
index={index}
source={source}
/>
))}
</div>
)
}
]}
/>
)}
{!props.isProcessing && !editMode ? (
<div
className={`space-x-2 gap-2 flex ${

View File

@@ -36,7 +36,7 @@ type HeaderProps = {
const Header: React.FC<HeaderProps> = ({ title, showButton = true, onClick }) => (
<DataNavigation
Header={
<div className="flex items-center text-[#54c41d] gap-1">
<div className="flex items-center text-[#4ab01a] gap-1">
<svg
className="icon"
viewBox="0 0 1025 1024"
@@ -47,7 +47,7 @@ const Header: React.FC<HeaderProps> = ({ title, showButton = true, onClick }) =>
height="18">
<path
d="M980.34571 1.143792c-4.850903 0-9.824354 0.888481-14.797806 2.930966L229.773215 299.724504H20.428686c-11.233669 0-20.424853 9.446494-20.424853 21.180572V702.584302c0 11.74429 9.191184 21.180572 20.424853 21.180573h129.820365c-4.728353 14.808018-7.271248 30.51473-7.271248 46.46654 0 84.119757 68.678568 152.543014 153.176184 152.543014 70.721053 0 130.330986-47.998404 147.93721-112.847312l521.569043 209.59984c4.983664 1.919936 9.957116 2.930966 14.808019 2.930967 21.568645 0 40.839493-18.127057 40.839493-42.371358V43.525362C1021.195415 19.270849 1002.047116 1.143792 980.34571 1.143792zM296.153987 831.250663c-33.833769 0-61.274559-27.308028-61.274558-61.009035 0-14.297397 4.983664-27.951411 14.042086-38.807221l108.374269 43.525362c-2.553107 31.403211-28.972654 56.290895-61.141797 56.290894z m633.12959 74.550713L263.984844 638.501326l-16.462431-6.638077H91.915671V391.626129h155.606742l16.462431-6.638077 665.298733-267.30005v788.113374z m0 0"
fill="#54c41d"
fill="#4ab01a"
p-id="6236"></path>
</svg>
{title}

View File

@@ -0,0 +1,26 @@
import React from "react"
export const BellIcon = React.forwardRef<
SVGSVGElement,
React.SVGProps<SVGSVGElement>
>((props, ref) => {
return (
<svg
className="icon"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="76534"
fill="currentColor"
fillRule="evenodd"
ref={ref}
{...props}>
<path
d="M593.861938 788.582269 424.670537 788.582269c-9.444093 0-18.437931 3.931542-24.695448 10.902304-6.313799 6.970762-9.441023 16.32378-8.547677 25.675776 2.860141 29.191856 16.32378 56.238862 38.009685 76.018348 21.772886 20.016893 50.161447 31.0379 79.889515 31.0379 29.696346 0 58.084906-11.022031 79.830163-30.977525 21.714558-19.839861 35.178197-46.885843 38.068014-76.255755 0.595564-9.473769-2.534729-18.707061-8.638751-25.498744C612.299869 792.513812 603.306031 788.582269 593.861938 788.582269zM555.020304 863.825974c-25.082258 22.877033-66.604954 22.817682-91.567485 0.060375-7.596002-6.970762-13.404288-15.429411-17.157775-24.723078l125.82266 0C568.394916 848.51629 562.643935 856.914564 555.020304 863.825974z"
p-id="76535"></path>
<path
d="M818.608631 648.343271l-62.763462-82.927711 0-36.22197 0-13.046131L755.845169 410.432767c0-70.745251-24.215518-136.337131-68.182892-184.682209-26.003234-28.625968-57.310264-49.715285-93.055372-62.821791-3.306302-18.944468-12.720719-36.251645-26.926256-49.207725-32.050973-29.251208-85.104283-29.251208-117.095905 0-14.356986 13.046131-23.77038 30.382984-26.986631 49.2681-35.71441 13.046131-67.022463 34.135448-93.025697 62.791092-43.937698 48.434106-68.183915 114.025986-68.183915 184.652534l0.179079 154.686035-62.315254 82.45085c-8.757454 9.353019-13.582343 21.506826-13.582343 34.256198l0 40.331567c0 27.643594 22.460548 50.042743 50.042743 50.042743l544.812313 0c27.610848 0 50.011021-22.400173 50.011021-50.042743l0-40.331567C831.535035 669.075455 826.739822 656.921647 818.608631 648.343271zM535.776008 149.881612c-7.387247-0.655939-19.301602-1.906419-26.569122-1.906419-7.29822 0-19.689435 1.251503-27.048029 1.906419C494.578724 129.627313 526.542716 133.379777 535.776008 149.881612zM237.426992 722.156394l-0.119727-40.034808 62.315254-82.449827c8.698103-9.354042 13.524015-21.447475 13.524015-34.256198L313.146535 410.432767c0-58.056254 19.540032-111.553679 54.986335-150.634766 17.574261-19.361977 38.307468-34.374902 61.540611-44.681642 48.851615-21.745257 110.302175-21.745257 159.096485 0 23.321148 10.425444 43.99398 25.438369 61.538565 44.681642 35.449373 39.081087 54.958706 92.578512 54.958706 150.634766l0 105.715717 0 13.046131 0 36.22197c0 12.867052 4.825912 25.081235 12.95608 33.539884l62.791092 82.868359 0.508583 39.795355L237.426992 722.156394z"
p-id="76536"></path>
</svg>
)
})

View File

@@ -0,0 +1,24 @@
import React from "react"
export const CollectIcon = React.forwardRef<
SVGSVGElement,
React.SVGProps<SVGSVGElement>
>((props, ref) => {
return (
<svg
className="icon"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="73631"
fill="currentColor"
fillRule="evenodd"
ref={ref}
{...props}
>
<path
d="M536.934 860.314c-26.828-14.797-70.502-14.695-97.177 0L251.238 964.096c-53.606 29.542-88.78 2.56-78.54-59.802l35.993-219.801c5.12-31.335-8.448-74.752-30.054-96.768L26.163 431.975c-43.417-44.289-29.696-87.655 30.003-96.769l210.74-32c30.003-4.608 65.28-31.539 78.643-59.852l94.259-199.936c26.829-56.884 70.451-56.679 97.126 0l94.208 199.987c13.466 28.467 48.896 55.296 78.695 59.853l210.739 32.05c60.006 9.114 73.216 52.583 30.054 96.718L798.106 587.674c-21.71 22.17-35.124 65.69-30.055 96.819l35.994 219.801c10.24 62.567-25.14 89.19-78.541 59.802l-188.57-103.782z"
p-id="73632"></path>
</svg>
)
})

View File

@@ -0,0 +1,23 @@
import React from "react"
export const NotCollectIcon = React.forwardRef<
SVGSVGElement,
React.SVGProps<SVGSVGElement>
>((props, ref) => {
return (
<svg
className="icon"
viewBox="0 0 1059 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="73488"
fill="currentColor"
fillRule="evenodd"
ref={ref}
{...props}>
<path
d="M253.488042 1024c-16.9 0-33.2875-5.1125-47.6125-15.3625-26.625-18.425-39.425-49.6625-34.3125-81.925l40.9625-251.9c1.5375-10.2375-1.5375-20.475-8.7-27.65L28.213042 466.4375c-22.0125-22.525-29.1875-55.3-19.45-84.9875 9.725-29.7 35.325-51.2 66.05-55.8125l237.575-36.35c10.75-1.5375 19.4625-8.1875 24.0625-17.925L441.388042 48.125c13.825-29.7 42.5-48.125 75.2625-48.125s61.4375 18.4375 75.2625 48.125l104.45 223.2375c4.6125 9.725 13.825 16.375 24.0625 17.925L958.000542 325.625a82.355 82.355 0 0 1 66.05 55.8125c10.2375 29.7 2.5625 62.4625-19.45 84.9875l-175.625 180.7375c-7.1625 7.175-10.2375 17.925-8.7 27.65l40.9625 251.9c5.125 31.75-8.1875 63.4875-34.3 81.925-26.1125 18.4375-59.9 20.4875-88.0625 4.6125l-206.85-114.6875c-9.725-5.1125-20.9875-5.1125-30.7125 0l-207.3625 115.2c-12.8125 6.65-26.6375 10.2375-40.4625 10.2375zM516.650542 51.2c-12.8 0-23.55 7.1625-29.1875 18.4375L383.525542 292.875c-11.775 25.0875-35.325 43.0125-62.975 47.1l-237.575 36.35c-12.2875 2.05-21.5 9.7375-25.6 21.5-4.1 11.775-1.025 24.0625 7.675 32.775L240.688042 611.325c18.4375 18.95 26.625 45.5625 22.525 71.675L222.250542 934.9125c-2.05 12.8 3.075 24.575 13.3125 31.7375 10.2375 7.175 23.0375 7.6875 33.7875 1.5375l207.3625-115.2c25.0875-13.825 55.3-13.825 80.3875 0l207.3625 115.2c10.75 6.1375 23.55 5.625 33.8-1.5375 10.2375-7.1625 15.3625-18.95 13.3125-31.7375L770.625542 683.0125c-4.1-26.1125 4.1-52.7375 22.525-71.675l175.625-180.7375c8.7-8.7 11.2625-20.9875 7.675-32.775-4.0875-11.775-13.3125-19.9625-25.6-21.5l-237.5625-36.35c-27.65-4.0875-51.2-22.0125-62.975-47.1L545.838042 69.6375c-5.625-11.2625-16.375-18.4375-29.1875-18.4375z m0 0"
p-id="73489"></path>
</svg>
)
})

View File

@@ -0,0 +1,22 @@
import React from "react"
export const SettingIcon = React.forwardRef<
SVGSVGElement,
React.SVGProps<SVGSVGElement>
>((props, ref) => {
return (
<svg
className="icon"
viewBox="0 0 1084 1024"
version="1.1"
p-id="10420"
fill="currentColor"
fillRule="evenodd"
ref={ref}
{...props}>
<path
d="M1072.147851 406.226367c-6.331285-33.456782-26.762037-55.073399-52.047135-55.073399-0.323417 0-0.651455 0.003081-0.830105 0.009241l-4.655674 0c-73.124722 0-132.618162-59.491899-132.618162-132.618162 0-23.731152 11.447443-50.336101 11.546009-50.565574 13.104573-29.498767 3.023185-65.672257-23.427755-84.127081l-1.601687-1.127342-134.400039-74.661726-1.700252-0.745401c-8.753836-3.805547-18.334698-5.735272-28.479231-5.735272-20.789593 0-41.235746 8.344174-54.683758 22.306575-14.741683 15.216028-65.622973 58.649474-104.721083 58.649474-39.450789 0-90.633935-44.286652-105.438762-59.784516-13.518857-14.247316-34.128258-22.753199-55.127302-22.753199-9.945862 0-19.354234 1.861961-27.958682 5.531982l-1.746455 0.74078-139.141957 76.431283-1.643269 1.139662c-26.537186 18.437884-36.675557 54.579032-23.584845 84.062398 0.115506 0.264895 11.579891 26.725075 11.579891 50.634877 0 73.126262-59.491899 132.618162-132.618162 132.618162l-4.581749 0c-0.318797-0.00616-0.636055-0.01078-0.951772-0.01078-25.260456 0-45.672728 21.618157-52.002472 55.0811-0.462025 2.453354-11.313456 60.622322-11.313456 106.117939 0 45.494078 10.85143 103.659965 11.314996 106.119479 6.334365 33.458322 26.758957 55.076479 52.036353 55.076479 0.320337 0 0.651455-0.00616 0.842426-0.012321l4.655674 0c73.126262 0 132.618162 59.491899 132.618162 132.616622 0 23.760413-11.444363 50.333021-11.546009 50.565574-13.093793 29.474125-3.041666 65.646075 23.395414 84.151722l1.569346 1.093459 131.838879 73.726895 1.675611 0.7377c8.750757 3.84251 18.305437 5.790715 28.397607 5.790715 21.082208 0 41.676209-8.706094 55.0888-23.290689 18.724339-20.347588 69.527086-62.362616 107.04815-62.362616 40.625872 0 92.72537 47.100385 107.759669 63.583903 13.441852 14.831008 34.176001 23.689571 55.470741 23.695731l0.00616 0c9.895039 0 19.27877-1.883523 27.893999-5.598205l1.711034-0.73924 136.659342-75.531873 1.617088-1.128882c26.492523-18.456365 36.601633-54.600594 23.538642-84.016195-0.115506-0.267974-11.595291-27.082374-11.595291-50.67646 0-73.124722 59.49344-132.616622 132.618162-132.616622l4.517066-0.00154c0.300316 0.00616 0.599092 0.009241 0.899409 0.009241 25.331299-0.00154 45.785153-21.619697 52.107197-55.054918 0.112426-0.589852 11.325776-59.507301 11.325776-106.14104C1083.464388 466.640776 1072.609877 408.67356 1072.147851 406.226367zM377.486862 945.656142l-115.32764-64.487932c5.082277-13.052211 15.437801-43.51815 15.437801-75.017486 0-109.382917-84.176364-199.816642-192.587488-208.134635-2.647404-15.427021-8.873963-54.967133-8.873963-85.667166 0-30.65691 6.223479-70.232445 8.869343-85.671786 108.415744-8.311832 192.592108-98.745557 192.592108-208.134635 0-31.416171-10.300081-61.797405-15.371577-74.854236l122.721583-67.40331c0.003081 0 0.00462 0.00154 0.007701 0.00154 4.423121 4.518606 22.121764 22.080182 46.558275 39.493911 39.929754 28.46229 77.952885 42.894416 113.014434 42.894416 34.716571 0 72.437845-14.151831 112.115025-42.06431 24.282503-17.07953 41.896442-34.302288 46.308782-38.74543 0.009241-0.00154 0.018481-0.00462 0.026182-0.00616l118.301542 65.726159c-5.077657 13.055291-15.416239 43.499669-15.416239 74.958962 0 109.389077 84.174824 199.822802 192.590568 208.134635 2.645865 15.462442 8.872423 55.107281 8.872423 85.671786 0 30.687711-6.223479 70.241685-8.869343 85.673326C890.042174 606.334084 805.86427 696.767809 805.86427 806.158426c0 31.450053 10.317022 61.851309 15.393138 74.903519l-119.783103 66.198965c-5.168521-5.490399-22.603811-23.363073-46.740005-41.288109-40.701336-30.224145-79.662378-45.549521-115.800446-45.549521-35.79155 0-74.458435 15.038919-114.927219 44.694774C400.22004 922.554885 382.666163 940.255068 377.486862 945.656142zM731.271848 511.646647c0-105.803762-86.081448-191.88059-191.888289-191.88059-105.803762 0-191.88059 86.076827-191.88059 191.88059 0 105.803762 86.076827 191.882129 191.88059 191.882129C645.19194 703.528777 731.271848 617.450409 731.271848 511.646647zM539.383558 395.903184c63.825696 0 115.751164 51.922387 115.751164 115.743463 0 63.825696-51.925468 115.751164-115.751164 115.751164-63.821076 0-115.743463-51.925468-115.743463-115.751164C423.640095 447.824031 475.562482 395.903184 539.383558 395.903184z"
p-id="10421"></path>
</svg>
)
})

View File

@@ -0,0 +1,23 @@
import React from "react"
export const ShareIcon = React.forwardRef<
SVGSVGElement,
React.SVGProps<SVGSVGElement>
>((props, ref) => {
return (
<svg
className="icon"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="75461"
fill="currentColor"
fillRule="evenodd"
ref={ref}
{...props}>
<path
d="M1009.777778 503.466667l-443.733334-455.111111c-5.688889-5.688889-11.377778 0-11.377777 5.688888v267.377778C8.533333 409.6 2.844444 918.755556 17.066667 932.977778c0 0 45.511111-48.355556 164.977777-113.777778 85.333333-48.355556 224.711111-85.333333 369.777778-102.4v261.688889c0 8.533333 11.377778 11.377778 14.222222 5.688889l443.733334-480.711111z m-398.222222 358.4v-199.111111l-36.977778-2.844445c-221.866667 8.533333-378.311111 73.955556-497.777778 156.444445 76.8-275.911111 267.377778-403.911111 466.488889-438.044445l68.266667-2.844444v-199.111111l312.888888 312.888888s8.533333 5.688889 8.533334 14.222223-8.533333 14.222222-8.533334 14.222222l-312.888888 344.177778z"
p-id="75462"></path>
</svg>
)
})

View File

@@ -1,4 +1,4 @@
import React, { useContext, useMemo } from "react"
import React, { useContext, useMemo, useState } from "react"
import { HistoryContext } from "@/components/Layouts/Layout.tsx"
import { PanelLeftIcon } from "lucide-react"
import { Button, Tooltip } from "antd"
@@ -7,27 +7,11 @@ import { useMessageOption } from "@/hooks/useMessageOption.tsx"
import { useTranslation } from "react-i18next"
import { NavLink, useLocation } from "react-router-dom"
import logo from "@/assets/logo.png"
interface SettingIconProps {}
const SettingIcon: React.FC<SettingIconProps> = () => {
return (
<svg
// @ts-ignore
t="1755767517454"
className="icon"
viewBox="0 0 1084 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="10420"
width="20"
height="20">
<path
d="M1072.147851 406.226367c-6.331285-33.456782-26.762037-55.073399-52.047135-55.073399-0.323417 0-0.651455 0.003081-0.830105 0.009241l-4.655674 0c-73.124722 0-132.618162-59.491899-132.618162-132.618162 0-23.731152 11.447443-50.336101 11.546009-50.565574 13.104573-29.498767 3.023185-65.672257-23.427755-84.127081l-1.601687-1.127342-134.400039-74.661726-1.700252-0.745401c-8.753836-3.805547-18.334698-5.735272-28.479231-5.735272-20.789593 0-41.235746 8.344174-54.683758 22.306575-14.741683 15.216028-65.622973 58.649474-104.721083 58.649474-39.450789 0-90.633935-44.286652-105.438762-59.784516-13.518857-14.247316-34.128258-22.753199-55.127302-22.753199-9.945862 0-19.354234 1.861961-27.958682 5.531982l-1.746455 0.74078-139.141957 76.431283-1.643269 1.139662c-26.537186 18.437884-36.675557 54.579032-23.584845 84.062398 0.115506 0.264895 11.579891 26.725075 11.579891 50.634877 0 73.126262-59.491899 132.618162-132.618162 132.618162l-4.581749 0c-0.318797-0.00616-0.636055-0.01078-0.951772-0.01078-25.260456 0-45.672728 21.618157-52.002472 55.0811-0.462025 2.453354-11.313456 60.622322-11.313456 106.117939 0 45.494078 10.85143 103.659965 11.314996 106.119479 6.334365 33.458322 26.758957 55.076479 52.036353 55.076479 0.320337 0 0.651455-0.00616 0.842426-0.012321l4.655674 0c73.126262 0 132.618162 59.491899 132.618162 132.616622 0 23.760413-11.444363 50.333021-11.546009 50.565574-13.093793 29.474125-3.041666 65.646075 23.395414 84.151722l1.569346 1.093459 131.838879 73.726895 1.675611 0.7377c8.750757 3.84251 18.305437 5.790715 28.397607 5.790715 21.082208 0 41.676209-8.706094 55.0888-23.290689 18.724339-20.347588 69.527086-62.362616 107.04815-62.362616 40.625872 0 92.72537 47.100385 107.759669 63.583903 13.441852 14.831008 34.176001 23.689571 55.470741 23.695731l0.00616 0c9.895039 0 19.27877-1.883523 27.893999-5.598205l1.711034-0.73924 136.659342-75.531873 1.617088-1.128882c26.492523-18.456365 36.601633-54.600594 23.538642-84.016195-0.115506-0.267974-11.595291-27.082374-11.595291-50.67646 0-73.124722 59.49344-132.616622 132.618162-132.616622l4.517066-0.00154c0.300316 0.00616 0.599092 0.009241 0.899409 0.009241 25.331299-0.00154 45.785153-21.619697 52.107197-55.054918 0.112426-0.589852 11.325776-59.507301 11.325776-106.14104C1083.464388 466.640776 1072.609877 408.67356 1072.147851 406.226367zM377.486862 945.656142l-115.32764-64.487932c5.082277-13.052211 15.437801-43.51815 15.437801-75.017486 0-109.382917-84.176364-199.816642-192.587488-208.134635-2.647404-15.427021-8.873963-54.967133-8.873963-85.667166 0-30.65691 6.223479-70.232445 8.869343-85.671786 108.415744-8.311832 192.592108-98.745557 192.592108-208.134635 0-31.416171-10.300081-61.797405-15.371577-74.854236l122.721583-67.40331c0.003081 0 0.00462 0.00154 0.007701 0.00154 4.423121 4.518606 22.121764 22.080182 46.558275 39.493911 39.929754 28.46229 77.952885 42.894416 113.014434 42.894416 34.716571 0 72.437845-14.151831 112.115025-42.06431 24.282503-17.07953 41.896442-34.302288 46.308782-38.74543 0.009241-0.00154 0.018481-0.00462 0.026182-0.00616l118.301542 65.726159c-5.077657 13.055291-15.416239 43.499669-15.416239 74.958962 0 109.389077 84.174824 199.822802 192.590568 208.134635 2.645865 15.462442 8.872423 55.107281 8.872423 85.671786 0 30.687711-6.223479 70.241685-8.869343 85.673326C890.042174 606.334084 805.86427 696.767809 805.86427 806.158426c0 31.450053 10.317022 61.851309 15.393138 74.903519l-119.783103 66.198965c-5.168521-5.490399-22.603811-23.363073-46.740005-41.288109-40.701336-30.224145-79.662378-45.549521-115.800446-45.549521-35.79155 0-74.458435 15.038919-114.927219 44.694774C400.22004 922.554885 382.666163 940.255068 377.486862 945.656142zM731.271848 511.646647c0-105.803762-86.081448-191.88059-191.888289-191.88059-105.803762 0-191.88059 86.076827-191.88059 191.88059 0 105.803762 86.076827 191.882129 191.88059 191.882129C645.19194 703.528777 731.271848 617.450409 731.271848 511.646647zM539.383558 395.903184c63.825696 0 115.751164 51.922387 115.751164 115.743463 0 63.825696-51.925468 115.751164-115.751164 115.751164-63.821076 0-115.743463-51.925468-115.743463-115.751164C423.640095 447.824031 475.562482 395.903184 539.383558 395.903184z"
fill="#272636"
p-id="10421"></path>
</svg>
)
}
import { BellIcon } from "@/components/Icons/Bell.tsx"
import { ShareIcon } from "@/components/Icons/Share.tsx"
import { NotCollectIcon } from "@/components/Icons/NotCollect.tsx"
import { CollectIcon } from "@/components/Icons/Collect.tsx"
import { SettingIcon } from "@/components/Icons/Setting.tsx"
type Props = {
setOpenModelSettings: (open: boolean) => void
@@ -49,6 +33,13 @@ export const Header: React.FC<Props> = ({ setOpenModelSettings }) => {
const { t } = useTranslation(["option", "common", "settings"])
const { clearChat } = useMessageOption()
// 是否隐藏logo
const hideLogo = useMemo(() => {
return localStorage.getItem("hideLogo") === "true"
}, [])
const [collect, setCollect] = useState<boolean>(false)
return (
<div
className={`h-[60px] absolute inset-0 pl-5 z-10 flex items-center transition-all duration-300 ease-in-out ${show && !location.pathname.includes("/settings") ? "left-[300px]" : ""}`}>
@@ -88,8 +79,11 @@ export const Header: React.FC<Props> = ({ setOpenModelSettings }) => {
<h2 className="text-xl font-bold text-zinc-700 dark:text-zinc-300 mr-3">
<NavLink
to="/"
className="!text-gray-500 dark:text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 transition-colors">
<span className="text-[#d30100]"></span>
className="!text-gray-500 dark:text-gray-400 flex items-center gap-2 hover:text-gray-600 dark:hover:text-gray-300 transition-colors">
{!hideLogo && <img src={logo} alt="logo" className="w-8" />}
<p>
<span className="text-[#d30100]"></span>
</p>
</NavLink>
</h2>
)}
@@ -103,14 +97,11 @@ export const Header: React.FC<Props> = ({ setOpenModelSettings }) => {
${show ? "-top-[60px]" : "-top-[2px] delay-200"}
`}>
<svg
// @ts-ignore
t="1755653236428"
className="icon"
viewBox="0 0 8960 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="9634"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="100%"
height="55">
<path
@@ -119,17 +110,40 @@ export const Header: React.FC<Props> = ({ setOpenModelSettings }) => {
p-id="9635"></path>
</svg>
<h2 className="flex items-center gap-3 text-xl font-bold text-zinc-700 dark:text-zinc-300 mr-3 absolute left-1/2 transform -translate-x-1/2">
<img src={logo} alt="logo" className="w-8" />
<p><span className="text-[#d30100]"></span></p>
{!hideLogo && <img src={logo} alt="logo" className="w-8" />}
<p>
<span className="text-[#d30100]"></span>
</p>
</h2>
</div>
{/*设置框*/}
<div className="flex items-center ml-auto pr-5">
<div className="flex items-center gap-1 ml-auto pr-5">
{collect ? (
<Button color="default" variant="text" className="!px-[5px]" onClick={() => setCollect(false)}>
<CollectIcon
className="!text-gray-500 dark:text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 transition-colors w-5 h-5 cursor-pointer"
/>
</Button>
) : (
<Button color="default" variant="text" className="!px-[5px]" onClick={() => setCollect(true)}>
<NotCollectIcon
className="!text-gray-500 dark:text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 transition-colors w-5 h-5 cursor-pointer"
/>
</Button>
)}
<Button color="default" variant="text" className="!px-[5px]">
<ShareIcon className="!text-gray-500 dark:text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 transition-colors w-5 h-5 cursor-pointer" />
</Button>
<Button color="default" variant="text" className="!px-[5px]">
<BellIcon className="!text-gray-500 dark:text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 transition-colors w-5 h-5 cursor-pointer" />
</Button>
<Tooltip title={t("settings")}>
<NavLink
to="/settings"
className="!text-gray-500 dark:text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 transition-colors">
<SettingIcon />
<NavLink to="/settings">
<SettingIcon className="!text-gray-500 dark:text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 transition-colors w-5 h-5 cursor-pointer" />
</NavLink>
</Tooltip>
</div>

View File

@@ -24,11 +24,12 @@ export const PlaygroundEmpty = () => {
<div className="w-full pb-4 pt-[20%] grid grid-cols-3 gap-3">
{qaPrompt.map((item, index) => (
<div
key={item.id}
className="p-6 bg-gradient-to-br from-blue-50/90 via-indigo-50/90 to-purple-50/90 backdrop-blur-xl border border-white/60 shadow-xl rounded-2xl cursor-pointer hover:shadow-blue-200/40 hover:from-blue-100/90 hover:to-indigo-100/90 transition-all duration-500 hover:-translate-y-1"
onClick={() => handleQuestion(item.title)}>
<div className="flex items-center">
<div className="text-blue-500 mr-2 w-10">{item.icon}</div>
<div className="font-medium text-sm text-gray-800">
<div className="text-sm text-gray-800">
{item.title}
</div>
</div>

View File

@@ -18,7 +18,7 @@ import { defaultEmbeddingModelForRag } from "~/services/ollama"
import { ImageIcon, MicIcon, StopCircleIcon, X } from "lucide-react"
import { getVariable } from "@/utils/select-variable"
import { useTranslation } from "react-i18next"
import { KnowledgeSelect } from "../Knowledge/KnowledgeSelect"
// import { KnowledgeSelect } from "../Knowledge/KnowledgeSelect"
import { useSpeechRecognition } from "@/hooks/useSpeechRecognition"
import { PiGlobe, PiNetwork } from "react-icons/pi"
import { handleChatInputKeyDown } from "@/utils/key-down"
@@ -369,11 +369,15 @@ export const PlaygroundForm = ({ dropedFile }: Props) => {
variant="filled"
size="large"
className="w-full mt-4 hover:!bg-[#0057ff1a]"
style={iodSearch ? {
color: "#0057ff",
background: "#0057ff0f",
border: "1px solid #0066ff26"
} : {}}>
style={
iodSearch
? {
color: "#0057ff",
background: "#0057ff0f",
border: "1px solid #0066ff26"
}
: {}
}>
<PiNetwork className="h-5 w-5" />
{iodSearch ? ":开" : ""}
</Button>
@@ -381,34 +385,32 @@ export const PlaygroundForm = ({ dropedFile }: Props) => {
</div>
)}
</div>
<div className="flex !justify-end gap-3">
<div className="flex !justify-end gap-1">
{!selectedKnowledge && (
<Tooltip title={t("tooltip.uploadImage")}>
<button
type="button"
<Button
color="default"
variant="text"
onClick={() => {
inputRef.current?.click()
}}
className={`flex items-center justify-center dark:text-gray-300 ${
className={`!px-[5px] flex items-center justify-center dark:text-gray-300 ${
chatMode === "rag" ? "hidden" : "block"
}`}>
<ImageIcon className="h-5 w-5" />
</button>
<ImageIcon stroke-width={1} className="h-5 w-5" />
</Button>
</Tooltip>
)}
{browserSupportsSpeechRecognition && (
<Tooltip title={t("tooltip.speechToText")}>
<button
type="button"
<Button
color="default"
variant="text"
onClick={async () => {
if (isListening) {
stopSpeechRecognition()
} else {
console.log(
"开始语音识别,语言:",
speechToTextLanguage
)
resetTranscript()
startListening({
continuous: true,
@@ -416,40 +418,43 @@ export const PlaygroundForm = ({ dropedFile }: Props) => {
})
}
}}
className={`flex items-center justify-center dark:text-gray-300`}>
className={`flex items-center justify-center dark:text-gray-300 !px-[5px]`}>
{!isListening ? (
<MicIcon className="h-5 w-5" />
<MicIcon stroke-width={1} className="h-5 w-5" />
) : (
<div className="relative">
<span className="animate-ping absolute inline-flex h-3 w-3 rounded-full bg-red-400 opacity-75"></span>
<MicIcon className="h-5 w-5" />
<MicIcon
stroke-width={1}
className="h-5 w-5"
/>
</div>
)}
</button>
</Button>
</Tooltip>
)}
<KnowledgeSelect />
{/*<KnowledgeSelect />*/}
{!isSending ? (
<Dropdown.Button
type="default"
htmlType="submit"
disabled={isSending}
className="!justify-end !w-auto"
icon={
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
strokeWidth={1.5}
stroke="currentColor"
className="w-5 h-5">
<path
strokeLinecap="round"
strokeLinejoin="round"
d="m19.5 8.25-7.5 7.5-7.5-7.5"
/>
</svg>
}
// icon={
// <svg
// xmlns="http://www.w3.org/2000/svg"
// fill="none"
// viewBox="0 0 24 24"
// strokeWidth={1.5}
// stroke="currentColor"
// className="w-5 h-5">
// <path
// strokeLinecap="round"
// strokeLinejoin="round"
// d="m19.5 8.25-7.5 7.5-7.5-7.5"
// />
// </svg>
// }
menu={{
items: [
{
@@ -479,20 +484,6 @@ export const PlaygroundForm = ({ dropedFile }: Props) => {
]
}}>
<div className="inline-flex gap-2">
{sendWhenEnter ? (
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
className="h-5 w-5"
viewBox="0 0 24 24">
<path d="M9 10L4 15 9 20"></path>
<path d="M20 4v7a4 4 0 01-4 4H4"></path>
</svg>
) : null}
{t("common:submit")}
</div>
</Dropdown.Button>

View File

@@ -1,4 +1,4 @@
import React, { createContext, useContext, useState } from "react"
import React, { createContext, useContext, useMemo, useState } from "react"
import { AnimatePresence, motion } from "framer-motion"
@@ -8,6 +8,8 @@ import { PlaygroundScene } from "@/components/Common/Playground/Scene.tsx"
import { PlaygroundTeam } from "@/components/Common/Playground/Team.tsx"
import { Card } from "antd"
import { CloseOutlined } from "@ant-design/icons"
import { useMessageOption } from "@/hooks/useMessageOption.tsx"
import { Message } from "@/types/message.ts"
// 定义 Context 类型
interface IodPlaygroundContextType {
@@ -17,6 +19,7 @@ interface IodPlaygroundContextType {
setDetailHeader: React.Dispatch<React.SetStateAction<React.ReactNode>>
detailMain: React.ReactNode
setDetailMain: React.Dispatch<React.SetStateAction<React.ReactNode>>
currentMessage: Message | null
}
// 创建 Context
@@ -36,13 +39,41 @@ export const useIodPlaygroundContext = () => {
}
export const PlaygroundIod = () => {
const { messages, iodLoading, currentMessageId, iodSearch } =
useMessageOption()
const [showPlayground, setShowPlayground] = useState<boolean>(true)
const [detailHeader, setDetailHeader] = useState(<></>)
const [detailMain, setDetailMain] = useState(<></>)
const currentMessage = useMemo<Message | null>(() => {
if (iodLoading) {
return null
}
if (messages.length && iodSearch) {
// 如果不存在currentMessageId默认返回最后一个message
if (!currentMessageId) {
return messages.at(-1)
}
const currentMessage = messages?.find(
(message) => message.id === currentMessageId
)
if (currentMessage) {
return currentMessage
}
// 如果当前message不存在最后一个message
return messages.at(-1)
}
return null
}, [currentMessageId, messages, iodLoading, iodSearch])
return (
<PlaygroundContext.Provider
value={{
currentMessage,
showPlayground,
setShowPlayground,
detailMain,
@@ -65,7 +96,6 @@ const PlaygroundContent = () => {
const { showPlayground, detailMain, detailHeader, setShowPlayground } =
useIodPlaygroundContext()
return (
<AnimatePresence mode="popLayout">
{showPlayground ? (
@@ -80,7 +110,9 @@ const PlaygroundContent = () => {
}}
className="h-full grid grid-rows-12 gap-3">
<div className="w-full row-span-5">
<PlaygroundIodRelevant className={classNames.replace('!bg-[rgba(240,245,255,0.3)]', '')} />
<PlaygroundIodRelevant
className={classNames.replace("!bg-[rgba(240,245,255,0.3)]", "")}
/>
</div>
<div className="w-full row-span-4 grid grid-cols-2 gap-3 custom-scrollbar">
<PlaygroundData className={classNames} />

View File

@@ -1,21 +1,21 @@
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"
import {
PageAssitDatabase,
deleteByHistoryId,
formatToChatHistory,
formatToMessage,
deleteByHistoryId,
updateHistory,
getPromptById,
PageAssitDatabase,
pinHistory,
getPromptById
updateHistory
} from "@/db"
import { Empty, Skeleton, Dropdown, Menu, Tooltip } from "antd"
import { Dropdown, Empty, Menu, Skeleton, Tooltip } from "antd"
import {
PencilIcon,
Trash2,
BotIcon,
MoreVertical,
PencilIcon,
PinIcon,
PinOffIcon,
BotIcon
Trash2
} from "lucide-react"
import { useNavigate } from "react-router-dom"
import { useTranslation } from "react-i18next"
@@ -24,7 +24,6 @@ import {
getLastUsedChatSystemPrompt,
lastUsedChatModelEnabled
} from "@/services/model-settings"
import { useState } from "react"
type Props = {
onClose: () => void
@@ -171,10 +170,9 @@ export const Sidebar = ({
<div
key={index}
className={`
flex py-2 px-2 items-center gap-3 relative rounded-md truncate hover:pr-4 group transition-opacity duration-300 ease-in-out border
hover:text-[#000000d9] hover:bg-[#f3f2ff] dark:hover:bg-[#2d2d2d] dark:border-gray-800
hover:[&_.more-vertical]:text-[#000000d9]
${historyId === chat.id ? 'text-[#000000d9] bg-[#f3f2ff] border-[#000000d9]' : 'dark:text-gray-100 text-gray-800'}
flex py-2 px-2 items-center gap-3 relative rounded-md truncate group ease-in-out
dark:hover:bg-[#2d2d2d] transition-colors duration-300
${historyId === chat.id ? "text-white bg-[#2563eb] hover:bg-[#1d4ed8]" : "dark:text-gray-100 text-gray-800 hover:text-white hover:bg-[#2563eb]"}
`}>
{chat?.message_source === "copilot" && (
<Tooltip title={t("common:sidebarChat")} placement="top">
@@ -271,7 +269,9 @@ export const Sidebar = ({
trigger={["click"]}
placement="bottomRight">
<button className="text-gray-500 dark:text-gray-400 opacity-80 hover:opacity-100">
<MoreVertical className={`group-hover:text-[#000000d9] w-4 h-4 more-vertical ${historyId === chat.id ? 'text-[#000000d9]' : ''}`} />
<MoreVertical
className={`w-4 h-4 group-hover:text-white ${historyId === chat.id ? "text-white" : ""}`}
/>
</button>
</Dropdown>
</div>