Merge branch 'feat/metering' of gitea.internetapi.cn:iod/page-assist into feat/page
This commit is contained in:
commit
970ffdac15
@ -1,29 +1,30 @@
|
|||||||
{
|
{
|
||||||
"newChat": "New Chat",
|
"newChat": "New Chat",
|
||||||
"selectAPrompt": "Select a Prompt",
|
"selectAPrompt": "Select a Prompt",
|
||||||
"githubRepository": "GitHub Repository",
|
"githubRepository": "GitHub Repository",
|
||||||
"settings": "Settings",
|
"settings": "Settings",
|
||||||
"sidebarTitle": "Chat History",
|
"metering": "Metering",
|
||||||
"error": "Error",
|
"sidebarTitle": "Chat History",
|
||||||
"somethingWentWrong": "Something went wrong",
|
"error": "Error",
|
||||||
"validationSelectModel": "Please select a model to continue",
|
"somethingWentWrong": "Something went wrong",
|
||||||
"deleteHistoryConfirmation": "Are you sure you want to delete this history?",
|
"validationSelectModel": "Please select a model to continue",
|
||||||
"editHistoryTitle": "Enter a new title",
|
"deleteHistoryConfirmation": "Are you sure you want to delete this history?",
|
||||||
"temporaryChat": "Temporary Chat",
|
"editHistoryTitle": "Enter a new title",
|
||||||
"more": {
|
"temporaryChat": "Temporary Chat",
|
||||||
"copy": {
|
"more": {
|
||||||
"group": "Copy",
|
"copy": {
|
||||||
"asText": "Copy as Text",
|
"group": "Copy",
|
||||||
"asMarkdown": "Copy as Markdown",
|
"asText": "Copy as Text",
|
||||||
"success": "Copied to clipboard!"
|
"asMarkdown": "Copy as Markdown",
|
||||||
},
|
"success": "Copied to clipboard!"
|
||||||
"download": {
|
},
|
||||||
"group": "Download",
|
"download": {
|
||||||
"text": "Text File (.txt)",
|
"group": "Download",
|
||||||
"markdown": "Markdown (.md)",
|
"text": "Text File (.txt)",
|
||||||
"json": "JSON File (.json)",
|
"markdown": "Markdown (.md)",
|
||||||
"image": "Image (.png)"
|
"json": "JSON File (.json)",
|
||||||
},
|
"image": "Image (.png)"
|
||||||
"share": "Share"
|
},
|
||||||
}
|
"share": "Share"
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,28 +1,29 @@
|
|||||||
{
|
{
|
||||||
"newChat": "新聊天",
|
"newChat": "新聊天",
|
||||||
"selectAPrompt": "选择一个提示词",
|
"selectAPrompt": "选择一个提示词",
|
||||||
"githubRepository": "GitHub 仓库",
|
"githubRepository": "GitHub 仓库",
|
||||||
"settings": "设置",
|
"settings": "设置",
|
||||||
"sidebarTitle": "聊天历史",
|
"metering": "计量",
|
||||||
"error": "错误",
|
"sidebarTitle": "聊天历史",
|
||||||
"somethingWentWrong": "出现了错误",
|
"error": "错误",
|
||||||
"validationSelectModel": "请选择一个模型以继续",
|
"somethingWentWrong": "出现了错误",
|
||||||
"deleteHistoryConfirmation": "你确定要删除这个历史记录吗?",
|
"validationSelectModel": "请选择一个模型以继续",
|
||||||
"editHistoryTitle": "输入一个新的标题",
|
"deleteHistoryConfirmation": "你确定要删除这个历史记录吗?",
|
||||||
"temporaryChat": "临时聊天",
|
"editHistoryTitle": "输入一个新的标题",
|
||||||
"more": {
|
"temporaryChat": "临时聊天",
|
||||||
"copy": {
|
"more": {
|
||||||
"group": "复制",
|
"copy": {
|
||||||
"asText": "复制为文本",
|
"group": "复制",
|
||||||
"asMarkdown": "复制为 Markdown",
|
"asText": "复制为文本",
|
||||||
"success": "已复制到剪贴板!"
|
"asMarkdown": "复制为 Markdown",
|
||||||
},
|
"success": "已复制到剪贴板!"
|
||||||
"download": {
|
},
|
||||||
"group": "下载",
|
"download": {
|
||||||
"text": "文本文件 (.txt)",
|
"group": "下载",
|
||||||
"markdown": "Markdown 文件 (.md)",
|
"text": "文本文件 (.txt)",
|
||||||
"json": "JSON 文件 (.json)"
|
"markdown": "Markdown 文件 (.md)",
|
||||||
},
|
"json": "JSON 文件 (.json)"
|
||||||
"share": "分享"
|
},
|
||||||
}
|
"share": "分享"
|
||||||
|
}
|
||||||
}
|
}
|
@ -5,6 +5,7 @@ import {
|
|||||||
ChevronRight,
|
ChevronRight,
|
||||||
CogIcon,
|
CogIcon,
|
||||||
ComputerIcon,
|
ComputerIcon,
|
||||||
|
Slice,
|
||||||
GithubIcon,
|
GithubIcon,
|
||||||
PanelLeftIcon,
|
PanelLeftIcon,
|
||||||
ZapIcon
|
ZapIcon
|
||||||
@ -240,7 +241,14 @@ export const Header: React.FC<Props> = ({
|
|||||||
<CogIcon className="w-6 h-6" />
|
<CogIcon className="w-6 h-6" />
|
||||||
</NavLink>
|
</NavLink>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</div>
|
<Tooltip title={t("metering")}>
|
||||||
|
<NavLink
|
||||||
|
to="/metering"
|
||||||
|
className="!text-gray-500 dark:text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 transition-colors">
|
||||||
|
<Slice className="w-6 h-6" />
|
||||||
|
</NavLink>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
168
src/components/Option/Metering/ListDetail.tsx
Normal file
168
src/components/Option/Metering/ListDetail.tsx
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
import {
|
||||||
|
Card,
|
||||||
|
List,
|
||||||
|
Table,
|
||||||
|
Tag,
|
||||||
|
Space,
|
||||||
|
TableProps,
|
||||||
|
Divider,
|
||||||
|
Typography
|
||||||
|
} from "antd"
|
||||||
|
import { NavLink } from "react-router-dom"
|
||||||
|
|
||||||
|
const data = [
|
||||||
|
{
|
||||||
|
key: "输出token数",
|
||||||
|
value: 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "输入token数",
|
||||||
|
value: 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "模型",
|
||||||
|
value: "xxx"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const outputTokenData = [
|
||||||
|
{
|
||||||
|
key: "关键词提示",
|
||||||
|
value: "xxx"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "问题",
|
||||||
|
value: "xxx"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "数联网引用数据",
|
||||||
|
value: "xxx"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "提供方",
|
||||||
|
value: "xxx"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "token数量",
|
||||||
|
value: 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "内容",
|
||||||
|
value: "xxx"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
interface DataType {
|
||||||
|
key: string
|
||||||
|
name: string
|
||||||
|
age: number
|
||||||
|
address: string
|
||||||
|
tags: string[]
|
||||||
|
}
|
||||||
|
|
||||||
|
const columns: TableProps<DataType>["columns"] = [
|
||||||
|
{
|
||||||
|
title: "Name",
|
||||||
|
dataIndex: "name",
|
||||||
|
key: "name",
|
||||||
|
render: (text) => <a>{text}</a>
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Age",
|
||||||
|
dataIndex: "age",
|
||||||
|
key: "age"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Address",
|
||||||
|
dataIndex: "address",
|
||||||
|
key: "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Tags",
|
||||||
|
key: "tags",
|
||||||
|
dataIndex: "tags",
|
||||||
|
render: (_, { tags }) => (
|
||||||
|
<>
|
||||||
|
{tags.map((tag) => {
|
||||||
|
let color = tag.length > 5 ? "geekblue" : "green"
|
||||||
|
if (tag === "loser") {
|
||||||
|
color = "volcano"
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<Tag color={color} key={tag}>
|
||||||
|
{tag.toUpperCase()}
|
||||||
|
</Tag>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Action",
|
||||||
|
key: "action",
|
||||||
|
render: (_, record) => (
|
||||||
|
<Space size="middle">
|
||||||
|
{/* <a>Invite {record.name}</a> */}
|
||||||
|
|
||||||
|
<NavLink to="/metering/list/123">
|
||||||
|
<a>Detail</a>
|
||||||
|
</NavLink>
|
||||||
|
</Space>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const data1: DataType[] = [
|
||||||
|
{
|
||||||
|
key: "1",
|
||||||
|
name: "John Brown",
|
||||||
|
age: 32,
|
||||||
|
address: "New York No. 1 Lake Park",
|
||||||
|
tags: ["nice", "developer"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "2",
|
||||||
|
name: "Jim Green",
|
||||||
|
age: 42,
|
||||||
|
address: "London No. 1 Lake Park",
|
||||||
|
tags: ["loser"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "3",
|
||||||
|
name: "Joe Black",
|
||||||
|
age: 32,
|
||||||
|
address: "Sydney No. 1 Lake Park",
|
||||||
|
tags: ["cool", "teacher"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
export const ListDetail = () => {
|
||||||
|
return (
|
||||||
|
<div className="p-[1rem] pt-[4rem]">
|
||||||
|
<List
|
||||||
|
grid={{ gutter: 16, column: 3 }}
|
||||||
|
dataSource={data}
|
||||||
|
renderItem={(item) => (
|
||||||
|
<List.Item>
|
||||||
|
<Card title={item.key}>{item.value}</Card>
|
||||||
|
</List.Item>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div className="mb-[50px]">
|
||||||
|
<Divider orientation="left">输出token详情</Divider>
|
||||||
|
<List
|
||||||
|
bordered
|
||||||
|
dataSource={outputTokenData}
|
||||||
|
renderItem={(item) => (
|
||||||
|
<List.Item>
|
||||||
|
<Typography.Text mark>{item.key}</Typography.Text> {item.value}
|
||||||
|
</List.Item>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Table<DataType> columns={columns} dataSource={data1} />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
137
src/components/Option/Metering/detail.tsx
Normal file
137
src/components/Option/Metering/detail.tsx
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
import React from "react"
|
||||||
|
import { ChatMessage, useStoreMessageOption } from "@/store/option"
|
||||||
|
import { Card, List, Table, Tag, Space, TableProps, Tooltip } from "antd"
|
||||||
|
import { NavLink } from "react-router-dom"
|
||||||
|
import { formatDate } from "@/utils/date"
|
||||||
|
|
||||||
|
const data = [
|
||||||
|
{
|
||||||
|
key: "对话数量",
|
||||||
|
value: 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "输出token数",
|
||||||
|
value: 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "输入token数",
|
||||||
|
value: 2
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const columns: TableProps<ChatMessage>["columns"] = [
|
||||||
|
{
|
||||||
|
title: "id",
|
||||||
|
dataIndex: "id",
|
||||||
|
key: "id",
|
||||||
|
width: "13%"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "问题",
|
||||||
|
dataIndex: "query",
|
||||||
|
key: "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "提示词全文",
|
||||||
|
dataIndex: "prompt",
|
||||||
|
key: "prompt",
|
||||||
|
ellipsis: {
|
||||||
|
showTitle: false
|
||||||
|
},
|
||||||
|
render: (prompt) => (
|
||||||
|
<Tooltip placement="topLeft" title={prompt}>
|
||||||
|
{prompt}
|
||||||
|
</Tooltip>
|
||||||
|
),
|
||||||
|
width: "10%"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "思维链",
|
||||||
|
key: "thinkingChain",
|
||||||
|
dataIndex: "thinkingChain",
|
||||||
|
width: "10%"
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
title: "回答",
|
||||||
|
dataIndex: "answer",
|
||||||
|
key: "answer",
|
||||||
|
ellipsis: {
|
||||||
|
showTitle: false
|
||||||
|
},
|
||||||
|
render: (answer) => (
|
||||||
|
<Tooltip placement="topLeft" title={answer}>
|
||||||
|
{answer}
|
||||||
|
</Tooltip>
|
||||||
|
),
|
||||||
|
width: "10%"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "关联数据个数",
|
||||||
|
dataIndex: "relatedDataCount",
|
||||||
|
key: "relatedDataCount"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "数联网token",
|
||||||
|
dataIndex: "iodOutputToken",
|
||||||
|
key: "iodOutputToken",
|
||||||
|
render: (iodOutputToken) => <div>{iodOutputToken.length}</div>
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "大模型token",
|
||||||
|
key: "largeModelToken",
|
||||||
|
dataIndex: "largeModelToken",
|
||||||
|
render: (_, record) => {
|
||||||
|
return (
|
||||||
|
<div>{record.iodInputToken.length + record.iodOutputToken.length}</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "日期",
|
||||||
|
dataIndex: "date",
|
||||||
|
key: "date",
|
||||||
|
render: (date) => {
|
||||||
|
return <div>{formatDate(date)}</div>
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "耗时",
|
||||||
|
key: "timeTaken",
|
||||||
|
dataIndex: "timeTaken"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "操作",
|
||||||
|
key: "action",
|
||||||
|
render: (_, record) => (
|
||||||
|
<Space size="middle">
|
||||||
|
{/* <a>Invite {record.name}</a> */}
|
||||||
|
|
||||||
|
<NavLink to={`/metering/list/${record.id}`}>
|
||||||
|
<a>Detail</a>
|
||||||
|
</NavLink>
|
||||||
|
</Space>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
export const MeteringDetail = () => {
|
||||||
|
const { chatMessages } = useStoreMessageOption()
|
||||||
|
console.log(chatMessages, "opppp")
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="pt-[4rem]">
|
||||||
|
<List
|
||||||
|
grid={{ gutter: 16, column: 3 }}
|
||||||
|
dataSource={data}
|
||||||
|
renderItem={(item) => (
|
||||||
|
<List.Item>
|
||||||
|
<Card title={item.key}>{item.value}</Card>
|
||||||
|
</List.Item>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Table<ChatMessage> columns={columns} dataSource={chatMessages} />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
@ -8,7 +8,7 @@ import {
|
|||||||
promptForRag,
|
promptForRag,
|
||||||
systemPromptForNonRagOption
|
systemPromptForNonRagOption
|
||||||
} from "~/services/ollama"
|
} from "~/services/ollama"
|
||||||
import { type ChatHistory, type Message } from "~/store/option"
|
import { type ChatHistory, ChatMessage, type Message } from "~/store/option"
|
||||||
import { SystemMessage } from "@langchain/core/messages"
|
import { SystemMessage } from "@langchain/core/messages"
|
||||||
import { useStoreMessageOption } from "~/store/option"
|
import { useStoreMessageOption } from "~/store/option"
|
||||||
import {
|
import {
|
||||||
@ -114,6 +114,26 @@ export const useMessageOption = () => {
|
|||||||
setWebSearch(true)
|
setWebSearch(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 从最后的结果中解析出 思维链 和 结果
|
||||||
|
const responseResolver = (msg: string) => {
|
||||||
|
const thinkStart = msg.indexOf("<think>")
|
||||||
|
const thinkEnd = msg.indexOf("</think>")
|
||||||
|
let think = ""
|
||||||
|
let content = ""
|
||||||
|
if (thinkStart > -1 && thinkEnd > -1) {
|
||||||
|
think = msg.substring(thinkStart + 7, thinkEnd)
|
||||||
|
content = msg.substring(thinkEnd + 8)
|
||||||
|
} else {
|
||||||
|
content = msg
|
||||||
|
}
|
||||||
|
// 去掉换行符
|
||||||
|
think = think.replace(/\n/g, "")
|
||||||
|
content = content.replace(/\n/g, "")
|
||||||
|
return {
|
||||||
|
think,
|
||||||
|
content
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const searchChatMode = async (
|
const searchChatMode = async (
|
||||||
webSearch: boolean,
|
webSearch: boolean,
|
||||||
@ -170,6 +190,10 @@ export const useMessageOption = () => {
|
|||||||
})
|
})
|
||||||
let newMessage: Message[] = []
|
let newMessage: Message[] = []
|
||||||
let generateMessageId = generateID()
|
let generateMessageId = generateID()
|
||||||
|
const chatMessage: ChatMessage = {
|
||||||
|
id: generateMessageId,
|
||||||
|
queryContent: message
|
||||||
|
} as ChatMessage
|
||||||
|
|
||||||
if (!isRegenerate) {
|
if (!isRegenerate) {
|
||||||
newMessage = [
|
newMessage = [
|
||||||
@ -300,6 +324,7 @@ export const useMessageOption = () => {
|
|||||||
)
|
)
|
||||||
console.log("prompt:\n" + prompt)
|
console.log("prompt:\n" + prompt)
|
||||||
setIsSearchingInternet(false)
|
setIsSearchingInternet(false)
|
||||||
|
chatMessage.prompt = prompt
|
||||||
|
|
||||||
// message = message.trim().replaceAll("\n", " ")
|
// message = message.trim().replaceAll("\n", " ")
|
||||||
|
|
||||||
@ -460,23 +485,13 @@ export const useMessageOption = () => {
|
|||||||
setIsProcessing(false)
|
setIsProcessing(false)
|
||||||
setStreaming(false)
|
setStreaming(false)
|
||||||
|
|
||||||
setChatMessages([
|
chatMessage.relatedDataCount = keywords.length
|
||||||
...chatMessages,
|
chatMessage.timeTaken = timetaken
|
||||||
{
|
chatMessage.date = reasoningStartTime
|
||||||
id: generateMessageId,
|
const { think, content } = responseResolver(fullText)
|
||||||
query: message,
|
chatMessage.thinkingChain = think
|
||||||
prompt: prompt,
|
chatMessage.responseContent = content
|
||||||
thinkingChain: "",
|
setChatMessages([...chatMessages, chatMessage])
|
||||||
answer: fullText,
|
|
||||||
relatedDataCount: count,
|
|
||||||
iodInputToken: "",
|
|
||||||
iodOutputToken: "",
|
|
||||||
modelInputToken: "",
|
|
||||||
modelOutputToken: "",
|
|
||||||
date: reasoningStartTime,
|
|
||||||
timeTaken: timetaken
|
|
||||||
}
|
|
||||||
])
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const errorSave = await saveMessageOnError({
|
const errorSave = await saveMessageOnError({
|
||||||
e,
|
e,
|
||||||
|
@ -12,6 +12,8 @@ import SidepanelSettings from "./sidepanel-settings"
|
|||||||
import OptionRagSettings from "./option-rag"
|
import OptionRagSettings from "./option-rag"
|
||||||
import OptionChrome from "./option-settings-chrome"
|
import OptionChrome from "./option-settings-chrome"
|
||||||
import OptionOpenAI from "./option-settings-openai"
|
import OptionOpenAI from "./option-settings-openai"
|
||||||
|
import OptionMetering from "./option-metering"
|
||||||
|
import MeteringListDetail from "./metering-list-detail"
|
||||||
|
|
||||||
export const OptionRoutingChrome = () => {
|
export const OptionRoutingChrome = () => {
|
||||||
return (
|
return (
|
||||||
@ -27,6 +29,8 @@ export const OptionRoutingChrome = () => {
|
|||||||
<Route path="/settings/knowledge" element={<OptionKnowledgeBase />} />
|
<Route path="/settings/knowledge" element={<OptionKnowledgeBase />} />
|
||||||
<Route path="/settings/rag" element={<OptionRagSettings />} />
|
<Route path="/settings/rag" element={<OptionRagSettings />} />
|
||||||
<Route path="/settings/about" element={<OptionAbout />} />
|
<Route path="/settings/about" element={<OptionAbout />} />
|
||||||
|
<Route path="/metering" element={<OptionMetering />} />
|
||||||
|
<Route path="/metering/list/:id" element={<MeteringListDetail />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,8 @@ const OptionModal = lazy(() => import("./option-settings-model"))
|
|||||||
const OptionPrompt = lazy(() => import("./option-settings-prompt"))
|
const OptionPrompt = lazy(() => import("./option-settings-prompt"))
|
||||||
const OptionOllamaSettings = lazy(() => import("./options-settings-ollama"))
|
const OptionOllamaSettings = lazy(() => import("./options-settings-ollama"))
|
||||||
const OptionSettings = lazy(() => import("./option-settings"))
|
const OptionSettings = lazy(() => import("./option-settings"))
|
||||||
|
const OptionMetering = lazy(() => import("./option-metering"))
|
||||||
|
const MeteringListDetail = lazy(() => import("./metering-list-detail"))
|
||||||
const OptionShare = lazy(() => import("./option-settings-share"))
|
const OptionShare = lazy(() => import("./option-settings-share"))
|
||||||
const OptionKnowledgeBase = lazy(() => import("./option-settings-knowledge"))
|
const OptionKnowledgeBase = lazy(() => import("./option-settings-knowledge"))
|
||||||
const OptionAbout = lazy(() => import("./option-settings-about"))
|
const OptionAbout = lazy(() => import("./option-settings-about"))
|
||||||
@ -29,6 +31,8 @@ export const OptionRoutingFirefox = () => {
|
|||||||
<Route path="/settings/knowledge" element={<OptionKnowledgeBase />} />
|
<Route path="/settings/knowledge" element={<OptionKnowledgeBase />} />
|
||||||
<Route path="/settings/about" element={<OptionAbout />} />
|
<Route path="/settings/about" element={<OptionAbout />} />
|
||||||
<Route path="/settings/rag" element={<OptionRagSettings />} />
|
<Route path="/settings/rag" element={<OptionRagSettings />} />
|
||||||
|
<Route path="/metering" element={<OptionMetering />} />
|
||||||
|
<Route path="/metering/list/:id" element={<MeteringListDetail />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
12
src/routes/metering-list-detail.tsx
Normal file
12
src/routes/metering-list-detail.tsx
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import OptionLayout from "~/components/Layouts/Layout"
|
||||||
|
import { ListDetail } from "~/components/Option/Metering/listDetail"
|
||||||
|
|
||||||
|
const OptionSettings = () => {
|
||||||
|
return (
|
||||||
|
<OptionLayout>
|
||||||
|
<ListDetail />
|
||||||
|
</OptionLayout>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default OptionSettings
|
12
src/routes/option-metering.tsx
Normal file
12
src/routes/option-metering.tsx
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import OptionLayout from "~/components/Layouts/Layout"
|
||||||
|
import { MeteringDetail } from "~/components/Option/Metering/detail"
|
||||||
|
|
||||||
|
const OptionSettings = () => {
|
||||||
|
return (
|
||||||
|
<OptionLayout>
|
||||||
|
<MeteringDetail />
|
||||||
|
</OptionLayout>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default OptionSettings
|
@ -33,13 +33,13 @@ export type ChatHistory = {
|
|||||||
export type ChatMessage = {
|
export type ChatMessage = {
|
||||||
id: string
|
id: string
|
||||||
// 问题
|
// 问题
|
||||||
query: string
|
queryContent: string
|
||||||
// 提示词全文
|
// 提示词全文
|
||||||
prompt: string
|
prompt: string
|
||||||
// 思维链(只有深度思考时有)
|
// 思维链(只有深度思考时有)
|
||||||
thinkingChain?: string
|
thinkingChain?: string
|
||||||
// 回答
|
// 回答
|
||||||
answer: string
|
responseContent: string
|
||||||
// 关联数据个数
|
// 关联数据个数
|
||||||
relatedDataCount: number
|
relatedDataCount: number
|
||||||
// 数联网输入token
|
// 数联网输入token
|
||||||
@ -54,15 +54,15 @@ export type ChatMessage = {
|
|||||||
date: Date
|
date: Date
|
||||||
// 耗时
|
// 耗时
|
||||||
timeTaken: number
|
timeTaken: number
|
||||||
}[]
|
}
|
||||||
|
|
||||||
type State = {
|
type State = {
|
||||||
messages: Message[]
|
messages: Message[]
|
||||||
setMessages: (messages: Message[]) => void
|
setMessages: (messages: Message[]) => void
|
||||||
history: ChatHistory
|
history: ChatHistory
|
||||||
setHistory: (history: ChatHistory) => void
|
setHistory: (history: ChatHistory) => void
|
||||||
chatMessages: ChatMessage
|
chatMessages: ChatMessage[]
|
||||||
setChatMessages: (chatMessages: ChatMessage) => void
|
setChatMessages: (chatMessages: ChatMessage[]) => void
|
||||||
streaming: boolean
|
streaming: boolean
|
||||||
setStreaming: (streaming: boolean) => void
|
setStreaming: (streaming: boolean) => void
|
||||||
isFirstMessage: boolean
|
isFirstMessage: boolean
|
||||||
|
22
src/utils/date.ts
Normal file
22
src/utils/date.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
export function formatDate(date) {
|
||||||
|
// 获取年份
|
||||||
|
const year = date.getFullYear()
|
||||||
|
|
||||||
|
// 获取月份,注意月份是从0开始计数的,所以需要加1,并且确保月份是两位数
|
||||||
|
const month = String(date.getMonth() + 1).padStart(2, "0")
|
||||||
|
|
||||||
|
// 获取日期,确保日期是两位数
|
||||||
|
const day = String(date.getDate()).padStart(2, "0")
|
||||||
|
|
||||||
|
// 获取小时,24小时制,并确保小时是两位数
|
||||||
|
const hours = String(date.getHours()).padStart(2, "0")
|
||||||
|
|
||||||
|
// 获取分钟,并确保分钟是两位数
|
||||||
|
const minutes = String(date.getMinutes()).padStart(2, "0")
|
||||||
|
|
||||||
|
// 组合成所需的格式
|
||||||
|
return `${year}-${month}-${day} ${hours}:${minutes}`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 示例使用
|
||||||
|
const now = new Date()
|
Loading…
x
Reference in New Issue
Block a user