feat/playground: 重构 playground组件

- 更新 Data 和 History组件的样式和布局
- 添加新的功能和交互,如热门搜索和智能体选择
- 优化组件性能和可维护性
This commit is contained in:
zhaoweijie
2025-08-21 14:08:07 +08:00
parent df0bf51bdf
commit efbf2a3eff
19 changed files with 1009 additions and 709 deletions

View File

@@ -20,10 +20,8 @@ import { useStoreChatModelSettings } from "@/store/model"
import { useSmartScroll } from "@/hooks/useSmartScroll"
import { ChevronDown } from "lucide-react"
import { PlaygroundTeam } from "@/components/Common/Playground/Team.tsx"
import { PlaygroundTokenStatistics } from "@/components/Common/Playground/TokenStatistics.tsx"
import { PlaygroundHistory } from "@/components/Common/Playground/History.tsx"
import { PlaygroundIodRelevant } from "@/components/Common/Playground/IodRelevant.tsx"
import { HistoryContext } from "@/components/Layouts/Layout.tsx"
export const Playground = () => {
@@ -148,13 +146,13 @@ export const Playground = () => {
dropState === "dragging" ? "bg-gray-100 dark:bg-gray-800" : ""
} bg-white dark:bg-[#171717]`}>
<PlaygroundHistory />
<div className="relative h-full flex-1 prose-lg flex justify-center [&>*]:max-w-[848px]">
<div className="relative h-full flex-1 prose-lg flex flex-col items-center [&>*]:max-w-[848px] pt-[60px]">
<div
ref={containerRef}
className="custom-scrollbar bg-bottom-mask-light dark:bg-bottom-mask-dark mask-bottom-fade will-change-mask flex h-full w-full flex-col items-center overflow-x-hidden overflow-y-auto px-5">
className="custom-scrollbar flex h-auto w-full flex-col items-center overflow-x-hidden overflow-y-auto px-5">
<PlaygroundChat />
</div>
<div className="absolute bottom-0 w-full">
<div className="relative bottom-0 w-full">
{!isAtBottom && (
<div className="absolute bottom-36 z-20 left-0 right-0 flex justify-center">
<button
@@ -170,16 +168,16 @@ export const Playground = () => {
{/*auto_530px_165px*/}
{messages.length && (
<div
className="w-1/4 h-full grid grid-rows-[1fr_2fr_175px] pt-16 pr-5 pb-0 border-l border-gray-200"
className="w-4/12 h-full grid grid-rows-10 gap-3 pt-16 pr-5 pb-0"
style={{ paddingTop: "4rem" }}>
<div className="w-full overflow-y-auto border-gray-200 border-b p-3">
<div className="w-full row-span-4">
<PlaygroundIodRelevant />
</div>
<div className="w-full grid grid-cols-2 gap-3 custom-scrollbar border-gray-200 border-b p-3">
<div className="w-full row-span-4 grid grid-cols-2 gap-3 custom-scrollbar">
<PlaygroundData />
<PlaygroundScene />
</div>
<div className="w-full p-3">
<div className="w-full row-span-2 pb-3">
<PlaygroundTeam />
</div>
</div>

View File

@@ -18,7 +18,7 @@ export const PlaygroundChat = () => {
return (
<>
<div className="relative flex w-full flex-col items-center pt-16 pb-4">
<div className="relative flex w-full flex-col items-center pb-4">
{messages.length === 0 && (
<div className="mt-3 w-full">
<PlaygroundEmpty />
@@ -52,8 +52,7 @@ export const PlaygroundChat = () => {
/>
))}
</div>
<div className="w-full pb-[157px]"></div>
{/*<div className="w-full pb-[0px]"></div>*/}
<MessageSourcePopup
open={isSourceOpen}
setOpen={setIsSourceOpen}

View File

@@ -1,73 +1,14 @@
import { Card, Col, Row } from "antd"
import RocketSvg from '@/assets/icons/rocket.svg'
import BulbSvg from '@/assets/icons/bulb.svg'
import EyeSvg from '@/assets/icons/eye.svg'
import ASvg from '@/assets/icons/a.svg'
import BSvg from '@/assets/icons/b.svg'
import CSvg from '@/assets/icons/c.svg'
import DSvg from '@/assets/icons/d.svg'
import ESvg from '@/assets/icons/e.svg'
import FSvg from '@/assets/icons/f.svg'
import { useMessageOption } from "@/hooks/useMessageOption.tsx"
import { useMutation, useQueryClient } from "@tanstack/react-query"
import { qaPrompt } from "@/libs/playground.tsx"
export const PlaygroundEmpty = () => {
const {
onSubmit,
setMessages,
setHistory,
setHistoryId,
historyId,
clearChat,
setSelectedModel,
temporaryChat,
setSelectedSystemPrompt
} = useMessageOption()
const { onSubmit } = useMessageOption()
const queryClient = useQueryClient()
const questions = [
{
title: "如何开发一个适合超大型城市的碳普惠方法学?",
icon: <img src={RocketSvg} alt="Rocket" className="w-10 my-0" />,
},
{
title: "如何开发一个零碳园区的数字化评价系统?",
icon: <img src={BulbSvg} alt="Rocket" className="w-10 my-0" />,
},
{
title: "如何开发一个碳定价预测系统?",
icon: <img src={EyeSvg} alt="Rocket" className="w-10 my-0" />,
},
{
title: "新药临床研究如何提升实验安全性?",
icon: <img src={ASvg} alt="Rocket" className="w-10 my-0" />,
},
{
title: "如何加速新药申报和审批?",
icon: <img src={BSvg} alt="Rocket" className="w-10 my-0" />,
},
{
title: "如何研制与司美格鲁肽相似的新药?",
icon: <img src={CSvg} alt="Rocket" className="w-10 my-0" />,
},
{
title: "如何解决固态电池的成本和寿命难题?",
icon: <img src={DSvg} alt="Rocket" className="w-10 my-0" />,
},
{
title: "如何解决船舶制造中的材料腐蚀难题?",
icon: <img src={ESvg} alt="Rocket" className="w-10 my-0" />,
},
{
title: "如何解决船舶制造中流体模拟和建模优化难题?",
icon: <img src={FSvg} alt="Rocket" className="w-10 my-0" />,
},
]
const { mutateAsync: sendMessage } = useMutation({
mutationFn: onSubmit,
onSuccess: () => {
@@ -77,32 +18,36 @@ export const PlaygroundEmpty = () => {
}
})
function handleQuestion(message: string) {
void sendMessage({message, image: ''})
void sendMessage({ message, image: "" })
}
return (
<div className="w-full p-4">
{/* 标题区域 */}
<div className="mb-4">
<h2 className="text-xl font-bold text-gray-800" style={{lineHeight: '0'}}></h2>
<h2
className="text-xl font-bold text-gray-800"
style={{ lineHeight: "0" }}>
</h2>
<p className="text-sm text-gray-500"></p>
</div>
{/* 卡片网格布局 */}
<Row gutter={[16, 16]} className="w-full">
{questions.map((item, index) => (
{qaPrompt.map((item, index) => (
<Col key={index} xs={24} sm={12} md={8}>
<Card
hoverable
style={{backgroundColor: "#f3f4f6"}}
style={{ backgroundColor: "#f3f4f6" }}
className="border border-gray-200 rounded-lg shadow-sm hover:shadow-md transition-shadow duration-200 cursor-pointer"
onClick={() => handleQuestion(item.title)}
>
onClick={() => handleQuestion(item.title)}>
<div className="flex items-center">
<div className="text-blue-500 mr-2">{item.icon}</div>
<div className="font-medium text-sm text-gray-800">{item.title}</div>
<div className="text-blue-500 mr-2 w-10">{item.icon}</div>
<div className="font-medium text-sm text-gray-800">
{item.title}
</div>
</div>
</Card>
</Col>

View File

@@ -357,6 +357,7 @@ export const PlaygroundForm = ({ dropedFile }: Props) => {
if (isListening) {
stopSpeechRecognition()
} else {
console.log("开始语音识别,语言:", speechToTextLanguage);
resetTranscript()
startListening({
continuous: true,