refactor(layout): 重构布局组件并添加新功能
- 更新 Header 组件,增加项目标题和历史记录切换按钮 - 新增 DataNavigation 组件用于数据导航 - 添加 Playground 相关新组件,包括数据、场景、团队等信息展示 - 重构 Layout 组件,使用 Context 管理历史记录状态 - 更新 zh/option.json 文件,添加新的项目标题和对话相关翻译
This commit is contained in:
@@ -1,130 +1,113 @@
|
||||
import { cleanUrl } from "@/libs/clean-url"
|
||||
import { useStorage } from "@plasmohq/storage/hook"
|
||||
import { useQuery } from "@tanstack/react-query"
|
||||
import { RotateCcw } from "lucide-react"
|
||||
import { useEffect, useState } from "react"
|
||||
import { Trans, useTranslation } from "react-i18next"
|
||||
import {
|
||||
getOllamaURL,
|
||||
isOllamaRunning,
|
||||
setOllamaURL as saveOllamaURL
|
||||
} from "~/services/ollama"
|
||||
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"
|
||||
|
||||
|
||||
export const PlaygroundEmpty = () => {
|
||||
const [ollamaURL, setOllamaURL] = useState<string>("")
|
||||
const { t } = useTranslation(["playground", "common"])
|
||||
|
||||
const [checkOllamaStatus] = useStorage("checkOllamaStatus", true)
|
||||
|
||||
const {
|
||||
data: ollamaInfo,
|
||||
status: ollamaStatus,
|
||||
refetch,
|
||||
isRefetching
|
||||
} = useQuery({
|
||||
queryKey: ["ollamaStatus"],
|
||||
queryFn: async () => {
|
||||
const ollamaURL = await getOllamaURL()
|
||||
const isOk = await isOllamaRunning()
|
||||
onSubmit,
|
||||
setMessages,
|
||||
setHistory,
|
||||
setHistoryId,
|
||||
historyId,
|
||||
clearChat,
|
||||
setSelectedModel,
|
||||
temporaryChat,
|
||||
setSelectedSystemPrompt
|
||||
} = useMessageOption()
|
||||
|
||||
if (ollamaURL) {
|
||||
saveOllamaURL(ollamaURL)
|
||||
}
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
return {
|
||||
isOk,
|
||||
ollamaURL
|
||||
}
|
||||
|
||||
const questions = [
|
||||
{
|
||||
title: "最近一年大型语言模型的技术进展有哪些?",
|
||||
icon: <img src={RocketSvg} alt="Rocket" className="w-10 my-0" />,
|
||||
},
|
||||
enabled: checkOllamaStatus
|
||||
{
|
||||
title: "生成式AI在企业中有哪些具体应用场景?",
|
||||
icon: <img src={BulbSvg} alt="Rocket" className="w-10 my-0" />,
|
||||
},
|
||||
{
|
||||
title: "多模态学习技术的最新研究方向是什么?",
|
||||
icon: <img src={EyeSvg} alt="Rocket" className="w-10 my-0" />,
|
||||
},
|
||||
{
|
||||
title: "当前AI芯片市场格局和未来三年发展趋势如何?",
|
||||
icon: <img src={ASvg} alt="Rocket" className="w-10 my-0" />,
|
||||
},
|
||||
{
|
||||
title: "主流深度学习框架性能与易用性对比分析?",
|
||||
icon: <img src={BSvg} alt="Rocket" className="w-10 my-0" />,
|
||||
},
|
||||
{
|
||||
title: "国内外AI伦理治理框架有哪些最佳实践?",
|
||||
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: "量子计算对AI算法的影响与应用前景?",
|
||||
icon: <img src={FSvg} alt="Rocket" className="w-10 my-0" />,
|
||||
},
|
||||
]
|
||||
|
||||
const { mutateAsync: sendMessage } = useMutation({
|
||||
mutationFn: onSubmit,
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: ["fetchChatHistory"]
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
if (ollamaInfo?.ollamaURL) {
|
||||
setOllamaURL(ollamaInfo.ollamaURL)
|
||||
}
|
||||
}, [ollamaInfo])
|
||||
|
||||
|
||||
if (!checkOllamaStatus) {
|
||||
return (
|
||||
<div className="mx-auto sm:max-w-xl px-4 mt-10">
|
||||
<div className="rounded-lg justify-center items-center flex flex-col border p-8 bg-gray-50 dark:bg-[#262626] dark:border-gray-600">
|
||||
<h1 className="text-sm font-medium text-center text-gray-500 dark:text-gray-400 flex gap-3 items-center justify-center">
|
||||
<span >👋</span>
|
||||
<span className="text-gray-700 dark:text-gray-300">
|
||||
{t("welcome")}
|
||||
</span>
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
function handleQuestion(message: string) {
|
||||
void sendMessage({message, image: ''})
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="mx-auto sm:max-w-xl px-4 mt-10">
|
||||
<div className="rounded-lg justify-center items-center flex flex-col border p-8 bg-gray-50 dark:bg-[#262626] dark:border-gray-600">
|
||||
{(ollamaStatus === "pending" || isRefetching) && (
|
||||
<div className="inline-flex items-center space-x-2">
|
||||
<div className="w-3 h-3 bg-blue-500 rounded-full animate-pulse"></div>
|
||||
<p className="dark:text-gray-400 text-gray-900">
|
||||
{t("ollamaState.searching")}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
{!isRefetching && ollamaStatus === "success" ? (
|
||||
ollamaInfo.isOk ? (
|
||||
<div className="inline-flex items-center space-x-2">
|
||||
<div className="w-3 h-3 bg-green-500 rounded-full animate-pulse"></div>
|
||||
<p className="dark:text-gray-400 text-gray-900">
|
||||
{t("ollamaState.running")}
|
||||
</p>
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex flex-col space-y-2 justify-center items-center">
|
||||
<div className="inline-flex space-x-2">
|
||||
<div className="w-3 h-3 bg-red-500 rounded-full animate-pulse"></div>
|
||||
<p className="dark:text-gray-400 text-gray-900">
|
||||
{t("ollamaState.notRunning")}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<input
|
||||
className="bg-gray-100 dark:bg-[#262626] dark:text-gray-100 rounded-md px-4 py-2 mt-2 w-full"
|
||||
type="url"
|
||||
value={ollamaURL}
|
||||
onChange={(e) => setOllamaURL(e.target.value)}
|
||||
/>
|
||||
|
||||
<button
|
||||
onClick={() => {
|
||||
saveOllamaURL(ollamaURL)
|
||||
refetch()
|
||||
}}
|
||||
className="inline-flex mt-4 items-center rounded-md border border-transparent bg-black px-2 py-2 text-sm font-medium leading-4 text-white shadow-sm hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 dark:bg-white dark:text-gray-800 dark:hover:bg-gray-100 dark:focus:ring-gray-500 dark:focus:ring-offset-gray-100 disabled:opacity-50 ">
|
||||
<RotateCcw className="h-4 w-4 mr-3" />
|
||||
{t("common:retry")}
|
||||
</button>
|
||||
|
||||
{ollamaURL &&
|
||||
cleanUrl(ollamaURL) !== "http://127.0.0.1:11434" && (
|
||||
<p className="text-xs text-gray-500 dark:text-gray-400 mb-4 text-center">
|
||||
<Trans
|
||||
i18nKey="playground:ollamaState.connectionError"
|
||||
components={{
|
||||
anchor: (
|
||||
<a
|
||||
href="https://github.com/n4ze3m/page-assist/blob/main/docs/connection-issue.md"
|
||||
target="__blank"
|
||||
className="text-blue-600 dark:text-blue-400"></a>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
) : null}
|
||||
<div className="w-full p-4">
|
||||
{/* 标题区域 */}
|
||||
<div className="mb-4">
|
||||
<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) => (
|
||||
<Col key={index} xs={24} sm={12} md={8}>
|
||||
<Card
|
||||
hoverable
|
||||
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)}
|
||||
>
|
||||
<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>
|
||||
</Card>
|
||||
</Col>
|
||||
))}
|
||||
</Row>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user