Compare commits
9 Commits
feat/page
...
feat/meter
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c5fa739a95 | ||
|
|
70d1f40333 | ||
|
|
2866bcc7af | ||
|
|
2a57034c9d | ||
|
|
79a03ab6fc | ||
|
|
50f9e4354f | ||
|
|
8f27ca2e4e | ||
|
|
ce333714b7 | ||
|
|
7b8879a7a8 |
@@ -1,30 +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",
|
||||||
"metering": "Metering",
|
"metering": "Metering",
|
||||||
"sidebarTitle": "Chat History",
|
"sidebarTitle": "Chat History",
|
||||||
"error": "Error",
|
"error": "Error",
|
||||||
"somethingWentWrong": "Something went wrong",
|
"somethingWentWrong": "Something went wrong",
|
||||||
"validationSelectModel": "Please select a model to continue",
|
"validationSelectModel": "Please select a model to continue",
|
||||||
"deleteHistoryConfirmation": "Are you sure you want to delete this history?",
|
"deleteHistoryConfirmation": "Are you sure you want to delete this history?",
|
||||||
"editHistoryTitle": "Enter a new title",
|
"editHistoryTitle": "Enter a new title",
|
||||||
"temporaryChat": "Temporary Chat",
|
"temporaryChat": "Temporary Chat",
|
||||||
"more": {
|
"more": {
|
||||||
"copy": {
|
"copy": {
|
||||||
"group": "Copy",
|
"group": "Copy",
|
||||||
"asText": "Copy as Text",
|
"asText": "Copy as Text",
|
||||||
"asMarkdown": "Copy as Markdown",
|
"asMarkdown": "Copy as Markdown",
|
||||||
"success": "Copied to clipboard!"
|
"success": "Copied to clipboard!"
|
||||||
},
|
},
|
||||||
"download": {
|
"download": {
|
||||||
"group": "Download",
|
"group": "Download",
|
||||||
"text": "Text File (.txt)",
|
"text": "Text File (.txt)",
|
||||||
"markdown": "Markdown (.md)",
|
"markdown": "Markdown (.md)",
|
||||||
"json": "JSON File (.json)",
|
"json": "JSON File (.json)",
|
||||||
"image": "Image (.png)"
|
"image": "Image (.png)"
|
||||||
},
|
},
|
||||||
"share": "Share"
|
"share": "Share"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,29 +1,29 @@
|
|||||||
{
|
{
|
||||||
"newChat": "新聊天",
|
"newChat": "新聊天",
|
||||||
"selectAPrompt": "选择一个提示词",
|
"selectAPrompt": "选择一个提示词",
|
||||||
"githubRepository": "GitHub 仓库",
|
"githubRepository": "GitHub 仓库",
|
||||||
"settings": "设置",
|
"settings": "设置",
|
||||||
"metering": "计量",
|
"metering": "计量",
|
||||||
"sidebarTitle": "聊天历史",
|
"sidebarTitle": "聊天历史",
|
||||||
"error": "错误",
|
"error": "错误",
|
||||||
"somethingWentWrong": "出现了错误",
|
"somethingWentWrong": "出现了错误",
|
||||||
"validationSelectModel": "请选择一个模型以继续",
|
"validationSelectModel": "请选择一个模型以继续",
|
||||||
"deleteHistoryConfirmation": "你确定要删除这个历史记录吗?",
|
"deleteHistoryConfirmation": "你确定要删除这个历史记录吗?",
|
||||||
"editHistoryTitle": "输入一个新的标题",
|
"editHistoryTitle": "输入一个新的标题",
|
||||||
"temporaryChat": "临时聊天",
|
"temporaryChat": "临时聊天",
|
||||||
"more": {
|
"more": {
|
||||||
"copy": {
|
"copy": {
|
||||||
"group": "复制",
|
"group": "复制",
|
||||||
"asText": "复制为文本",
|
"asText": "复制为文本",
|
||||||
"asMarkdown": "复制为 Markdown",
|
"asMarkdown": "复制为 Markdown",
|
||||||
"success": "已复制到剪贴板!"
|
"success": "已复制到剪贴板!"
|
||||||
},
|
},
|
||||||
"download": {
|
"download": {
|
||||||
"group": "下载",
|
"group": "下载",
|
||||||
"text": "文本文件 (.txt)",
|
"text": "文本文件 (.txt)",
|
||||||
"markdown": "Markdown 文件 (.md)",
|
"markdown": "Markdown 文件 (.md)",
|
||||||
"json": "JSON 文件 (.json)"
|
"json": "JSON 文件 (.json)"
|
||||||
},
|
},
|
||||||
"share": "分享"
|
"share": "分享"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -9,7 +9,12 @@ import {
|
|||||||
Pen,
|
Pen,
|
||||||
PlayIcon,
|
PlayIcon,
|
||||||
RotateCcw,
|
RotateCcw,
|
||||||
Square
|
Square,
|
||||||
|
Star,
|
||||||
|
ThumbsUp,
|
||||||
|
ThumbsDown,
|
||||||
|
MessageSquareShare,
|
||||||
|
ArrowUpSquare
|
||||||
} from "lucide-react"
|
} from "lucide-react"
|
||||||
import { EditMessageForm } from "./EditMessageForm"
|
import { EditMessageForm } from "./EditMessageForm"
|
||||||
import { useTranslation } from "react-i18next"
|
import { useTranslation } from "react-i18next"
|
||||||
@@ -316,6 +321,51 @@ export const PlaygroundMessage = (props: Props) => {
|
|||||||
</button>
|
</button>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
)}
|
)}
|
||||||
|
{ (
|
||||||
|
<Tooltip title="收藏">
|
||||||
|
<button
|
||||||
|
aria-label="收藏"
|
||||||
|
className="flex items-center justify-center w-6 h-6 rounded-full bg-gray-100 dark:bg-gray-800 hover:bg-gray-200 dark:hover:bg-gray-700 transition-colors duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-500">
|
||||||
|
<Star className="w-3 h-3 text-gray-400 group-hover:text-gray-500" />
|
||||||
|
</button>
|
||||||
|
</Tooltip>
|
||||||
|
)}
|
||||||
|
{ (
|
||||||
|
<Tooltip title="发布语用">
|
||||||
|
<button
|
||||||
|
aria-label="发布语用"
|
||||||
|
className="flex items-center justify-center w-6 h-6 rounded-full bg-gray-100 dark:bg-gray-800 hover:bg-gray-200 dark:hover:bg-gray-700 transition-colors duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-500">
|
||||||
|
<ArrowUpSquare className="w-3 h-3 text-gray-400 group-hover:text-gray-500" />
|
||||||
|
</button>
|
||||||
|
</Tooltip>
|
||||||
|
)}
|
||||||
|
{ (
|
||||||
|
<Tooltip title="发布对话">
|
||||||
|
<button
|
||||||
|
aria-label="发布对话"
|
||||||
|
className="flex items-center justify-center w-6 h-6 rounded-full bg-gray-100 dark:bg-gray-800 hover:bg-gray-200 dark:hover:bg-gray-700 transition-colors duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-500">
|
||||||
|
<MessageSquareShare className="w-3 h-3 text-gray-400 group-hover:text-gray-500" />
|
||||||
|
</button>
|
||||||
|
</Tooltip>
|
||||||
|
)}
|
||||||
|
{ (
|
||||||
|
<Tooltip title="点赞">
|
||||||
|
<button
|
||||||
|
aria-label="点赞"
|
||||||
|
className="flex items-center justify-center w-6 h-6 rounded-full bg-gray-100 dark:bg-gray-800 hover:bg-gray-200 dark:hover:bg-gray-700 transition-colors duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-500">
|
||||||
|
<ThumbsUp className="w-3 h-3 text-gray-400 group-hover:text-gray-500" />
|
||||||
|
</button>
|
||||||
|
</Tooltip>
|
||||||
|
)}
|
||||||
|
{ (
|
||||||
|
<Tooltip title="点踩">
|
||||||
|
<button
|
||||||
|
aria-label="点踩"
|
||||||
|
className="flex items-center justify-center w-6 h-6 rounded-full bg-gray-100 dark:bg-gray-800 hover:bg-gray-200 dark:hover:bg-gray-700 transition-colors duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-500">
|
||||||
|
<ThumbsDown className="w-3 h-3 text-gray-400 group-hover:text-gray-500" />
|
||||||
|
</button>
|
||||||
|
</Tooltip>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
// add invisible div to prevent layout shift
|
// add invisible div to prevent layout shift
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import {
|
|||||||
ChevronRight,
|
ChevronRight,
|
||||||
CogIcon,
|
CogIcon,
|
||||||
ComputerIcon,
|
ComputerIcon,
|
||||||
Slice,
|
GaugeCircle,
|
||||||
GithubIcon,
|
GithubIcon,
|
||||||
PanelLeftIcon,
|
PanelLeftIcon,
|
||||||
ZapIcon
|
ZapIcon
|
||||||
@@ -245,7 +245,7 @@ export const Header: React.FC<Props> = ({
|
|||||||
<NavLink
|
<NavLink
|
||||||
to="/metering"
|
to="/metering"
|
||||||
className="!text-gray-500 dark:text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 transition-colors">
|
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" />
|
<GaugeCircle className="w-6 h-6" />
|
||||||
</NavLink>
|
</NavLink>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,192 +0,0 @@
|
|||||||
import {
|
|
||||||
Card,
|
|
||||||
List,
|
|
||||||
Table,
|
|
||||||
Tag,
|
|
||||||
Space,
|
|
||||||
TableProps,
|
|
||||||
Divider,
|
|
||||||
Typography,
|
|
||||||
Tooltip
|
|
||||||
} from "antd"
|
|
||||||
import { NavLink } from "react-router-dom"
|
|
||||||
|
|
||||||
const data = [
|
|
||||||
{
|
|
||||||
key: "输出token数",
|
|
||||||
value: 2
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "输入token数",
|
|
||||||
value: 2
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "模型",
|
|
||||||
value: "xxx"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
const inputTokenData = [
|
|
||||||
{
|
|
||||||
key: "关键词提示",
|
|
||||||
value: "xxx"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "问题",
|
|
||||||
value: "xxx"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "数联网引用数据",
|
|
||||||
value: "xxx"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "提供方",
|
|
||||||
value: "xxx"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "token数量",
|
|
||||||
value: 2
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "内容",
|
|
||||||
value: "xxx"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
const outputTokenData = [
|
|
||||||
{
|
|
||||||
key: "类型",
|
|
||||||
value: "xxx"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "来源",
|
|
||||||
value: "xxx"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "token数量",
|
|
||||||
value: 2
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "内容",
|
|
||||||
value: "xxx"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
interface DataType {
|
|
||||||
key: string
|
|
||||||
name: string
|
|
||||||
age: number
|
|
||||||
address: string
|
|
||||||
tags: number
|
|
||||||
content: string
|
|
||||||
}
|
|
||||||
|
|
||||||
const columns: TableProps<DataType>["columns"] = [
|
|
||||||
{
|
|
||||||
title: "序号",
|
|
||||||
dataIndex: "key",
|
|
||||||
key: "name",
|
|
||||||
render: (text) => <a>{text}</a>
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "标识",
|
|
||||||
dataIndex: "age",
|
|
||||||
key: "age"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "提供方",
|
|
||||||
dataIndex: "address",
|
|
||||||
key: "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "token数量",
|
|
||||||
key: "tags",
|
|
||||||
dataIndex: "tags"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "内容",
|
|
||||||
key: "content",
|
|
||||||
dataIndex: "content"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
const data1: DataType[] = [
|
|
||||||
{
|
|
||||||
key: "1",
|
|
||||||
name: "John Brown",
|
|
||||||
age: 32,
|
|
||||||
address: "New York No. 1 Lake Park",
|
|
||||||
tags: 2,
|
|
||||||
content: "内容"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "2",
|
|
||||||
name: "Jim Green",
|
|
||||||
age: 42,
|
|
||||||
address: "London No. 1 Lake Park",
|
|
||||||
tags: 3,
|
|
||||||
content: "内容"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "3",
|
|
||||||
name: "Joe Black",
|
|
||||||
age: 32,
|
|
||||||
address: "Sydney No. 1 Lake Park",
|
|
||||||
tags: 3,
|
|
||||||
content: "内容"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
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>
|
|
||||||
)}
|
|
||||||
style={{ marginBottom: "2rem" }}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<Divider orientation="left">输入token详情</Divider>
|
|
||||||
<List
|
|
||||||
bordered
|
|
||||||
dataSource={inputTokenData}
|
|
||||||
renderItem={(item) => (
|
|
||||||
<List.Item style={{ justifyContent: "flex-start" }}>
|
|
||||||
<Typography.Text mark className="mr-1">
|
|
||||||
{item.key}
|
|
||||||
</Typography.Text>
|
|
||||||
<Tooltip placement="topLeft" title={item.value}>
|
|
||||||
{item.value}
|
|
||||||
</Tooltip>
|
|
||||||
</List.Item>
|
|
||||||
)}
|
|
||||||
style={{ marginBottom: "1rem" }}
|
|
||||||
/>
|
|
||||||
<Table<DataType> columns={columns} dataSource={data1} />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<Divider orientation="left">输出token详情</Divider>
|
|
||||||
<List
|
|
||||||
bordered
|
|
||||||
dataSource={outputTokenData}
|
|
||||||
renderItem={(item) => (
|
|
||||||
<List.Item style={{ justifyContent: "flex-start" }}>
|
|
||||||
<Typography.Text mark className="mr-1">
|
|
||||||
{item.key}
|
|
||||||
</Typography.Text>
|
|
||||||
<Tooltip placement="topLeft" title={item.value}>
|
|
||||||
{item.value}
|
|
||||||
</Tooltip>
|
|
||||||
</List.Item>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,30 +1,15 @@
|
|||||||
import React from "react"
|
import React, { useMemo } from "react"
|
||||||
import { ChatMessage, useStoreMessageOption } from "@/store/option"
|
import { MeteringEntry, useStoreMessageOption } from "@/store/option"
|
||||||
import { Card, List, Table, Tag, Space, TableProps, Tooltip } from "antd"
|
import { Card, List, Table, Tag, Space, TableProps, Tooltip } from "antd"
|
||||||
import { NavLink } from "react-router-dom"
|
import { NavLink } from "react-router-dom"
|
||||||
import { formatDate } from "@/utils/date"
|
import { formatDate } from "@/utils/date"
|
||||||
|
|
||||||
const data = [
|
const columns: TableProps<MeteringEntry>["columns"] = [
|
||||||
{
|
{
|
||||||
key: "对话数量",
|
title: '序号',
|
||||||
value: 2
|
key: 'index',
|
||||||
},
|
width: 100,
|
||||||
{
|
render: (_text, _record, index) => index + 1, // 索引从0开始,+1后从1显示
|
||||||
key: "输出token数",
|
|
||||||
value: 2
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "输入token数",
|
|
||||||
value: 2
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
const columns: TableProps<ChatMessage>["columns"] = [
|
|
||||||
{
|
|
||||||
title: "id",
|
|
||||||
dataIndex: "id",
|
|
||||||
key: "id",
|
|
||||||
width: "13%"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "问题",
|
title: "问题",
|
||||||
@@ -47,8 +32,16 @@ const columns: TableProps<ChatMessage>["columns"] = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "思维链",
|
title: "思维链",
|
||||||
key: "thinkingChain",
|
key: "cot",
|
||||||
dataIndex: "thinkingChain",
|
dataIndex: "cot",
|
||||||
|
ellipsis: {
|
||||||
|
showTitle: false
|
||||||
|
},
|
||||||
|
render: (responseContent) => (
|
||||||
|
<Tooltip placement="topLeft" title={responseContent}>
|
||||||
|
{responseContent}
|
||||||
|
</Tooltip>
|
||||||
|
),
|
||||||
width: "10%"
|
width: "10%"
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -73,9 +66,8 @@ const columns: TableProps<ChatMessage>["columns"] = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "数联网token",
|
title: "数联网token",
|
||||||
dataIndex: "iodOutputToken",
|
dataIndex: "iodTokenCount",
|
||||||
key: "iodOutputToken",
|
key: "iodTokenCount"
|
||||||
render: (iodOutputToken) => <div>{iodOutputToken?.length}</div>
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "大模型token",
|
title: "大模型token",
|
||||||
@@ -83,9 +75,7 @@ const columns: TableProps<ChatMessage>["columns"] = [
|
|||||||
dataIndex: "largeModelToken",
|
dataIndex: "largeModelToken",
|
||||||
render: (_, record) => {
|
render: (_, record) => {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>{record.modelInputTokenCount + record.modelOutputTokenCount}</div>
|
||||||
{record.iodInputToken?.length + record.iodOutputToken?.length}
|
|
||||||
</div>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -94,7 +84,7 @@ const columns: TableProps<ChatMessage>["columns"] = [
|
|||||||
dataIndex: "date",
|
dataIndex: "date",
|
||||||
key: "date",
|
key: "date",
|
||||||
render: (date) => {
|
render: (date) => {
|
||||||
return <div>{formatDate(date)}</div>
|
return <div>{formatDate(date ?? new Date())}</div>
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -118,14 +108,50 @@ const columns: TableProps<ChatMessage>["columns"] = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
export const MeteringDetail = () => {
|
export const MeteringDetail = () => {
|
||||||
const { chatMessages } = useStoreMessageOption()
|
const { meteringEntries } = useStoreMessageOption()
|
||||||
console.log(chatMessages, "opppp")
|
|
||||||
|
|
||||||
|
const data = useMemo(
|
||||||
|
() => [
|
||||||
|
{
|
||||||
|
key: "对话数量",
|
||||||
|
value: meteringEntries.length
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "数联网输入token数",
|
||||||
|
value: meteringEntries.reduce((acc, cur) => {
|
||||||
|
for (const item of cur.iodKeywords) {
|
||||||
|
acc += item.length
|
||||||
|
}
|
||||||
|
return acc
|
||||||
|
}, 0)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "数联网输出token数",
|
||||||
|
value: meteringEntries.reduce((acc, cur) => acc + cur.iodTokenCount, 0)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "大模型输入token数",
|
||||||
|
value: meteringEntries.reduce(
|
||||||
|
(acc, cur) => acc + cur.modelInputTokenCount,
|
||||||
|
0
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "大模型输出token数",
|
||||||
|
value: meteringEntries.reduce(
|
||||||
|
(acc, cur) => acc + cur.modelOutputTokenCount,
|
||||||
|
0
|
||||||
|
)
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[meteringEntries]
|
||||||
|
)
|
||||||
return (
|
return (
|
||||||
<div className="pt-[4rem]">
|
<div className="p-4 pt-[4rem]">
|
||||||
<List
|
<List
|
||||||
grid={{ gutter: 16, column: 3 }}
|
grid={{ gutter: 16, column: 5 }}
|
||||||
dataSource={data}
|
dataSource={data}
|
||||||
|
split={false}
|
||||||
renderItem={(item) => (
|
renderItem={(item) => (
|
||||||
<List.Item>
|
<List.Item>
|
||||||
<Card title={item.key}>{item.value}</Card>
|
<Card title={item.key}>{item.value}</Card>
|
||||||
@@ -133,7 +159,7 @@ export const MeteringDetail = () => {
|
|||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Table<ChatMessage> columns={columns} dataSource={chatMessages} />
|
<Table<MeteringEntry> columns={columns} dataSource={meteringEntries} />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
203
src/components/Option/Metering/listDetail.tsx
Normal file
203
src/components/Option/Metering/listDetail.tsx
Normal file
@@ -0,0 +1,203 @@
|
|||||||
|
import {
|
||||||
|
Card,
|
||||||
|
List,
|
||||||
|
Table,
|
||||||
|
Tag,
|
||||||
|
Space,
|
||||||
|
TableProps,
|
||||||
|
Divider,
|
||||||
|
Typography,
|
||||||
|
Tooltip
|
||||||
|
} from "antd"
|
||||||
|
import { NavLink, useParams } from "react-router-dom"
|
||||||
|
import { useStoreMessageOption } from "@/store/option.tsx"
|
||||||
|
import { useMemo } from "react"
|
||||||
|
|
||||||
|
interface DataType {
|
||||||
|
key: string
|
||||||
|
name: string
|
||||||
|
doId: number
|
||||||
|
data_space: string
|
||||||
|
content: string
|
||||||
|
tokenCount: number
|
||||||
|
}
|
||||||
|
|
||||||
|
const columns: TableProps<DataType>["columns"] = [
|
||||||
|
{
|
||||||
|
title: '序号',
|
||||||
|
key: 'index',
|
||||||
|
width: 100,
|
||||||
|
render: (_text, _record, index) => index + 1, // 索引从0开始,+1后从1显示
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "标识",
|
||||||
|
dataIndex: "doId",
|
||||||
|
key: "doId"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "提供方",
|
||||||
|
dataIndex: "data_space",
|
||||||
|
key: "data_space"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "token数量",
|
||||||
|
key: "tokenCount",
|
||||||
|
dataIndex: "tokenCount",
|
||||||
|
width: 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "内容",
|
||||||
|
key: "content",
|
||||||
|
dataIndex: "content",
|
||||||
|
ellipsis: {
|
||||||
|
showTitle: false
|
||||||
|
},
|
||||||
|
render: (content) => (
|
||||||
|
<Tooltip placement="topLeft" title={content}>
|
||||||
|
{content}
|
||||||
|
</Tooltip>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
export const ListDetail = () => {
|
||||||
|
const { meteringEntries } = useStoreMessageOption()
|
||||||
|
const { id } = useParams()
|
||||||
|
const record = useMemo(
|
||||||
|
() => meteringEntries.find((item) => item.id === id),
|
||||||
|
[meteringEntries]
|
||||||
|
)
|
||||||
|
|
||||||
|
const modelData = useMemo(
|
||||||
|
() => [
|
||||||
|
{
|
||||||
|
key: "大模型输入token数",
|
||||||
|
value: record.modelInputTokenCount
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "大模型输出token数",
|
||||||
|
value: record.modelOutputTokenCount
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "模型",
|
||||||
|
value: record.model
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[record]
|
||||||
|
)
|
||||||
|
|
||||||
|
const inputTokenData = useMemo(
|
||||||
|
() => [
|
||||||
|
{
|
||||||
|
key: "内容:",
|
||||||
|
value: record.queryContent
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "token数量:",
|
||||||
|
value: record.queryContent.length
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[record]
|
||||||
|
)
|
||||||
|
const keywordsData = useMemo(
|
||||||
|
() => [
|
||||||
|
{
|
||||||
|
key: "token数量:",
|
||||||
|
value: record.iodKeywords.reduce((acc, cur) => acc + cur.length, 0)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "内容:",
|
||||||
|
value: record.iodKeywords.join(", ")
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[record]
|
||||||
|
)
|
||||||
|
const responseContent = useMemo(
|
||||||
|
() => [
|
||||||
|
{
|
||||||
|
key: "token数量:",
|
||||||
|
value: record.modelResponseContent.length
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "内容:",
|
||||||
|
value: record.modelResponseContent
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[record]
|
||||||
|
)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="p-[1rem] pt-[4rem]">
|
||||||
|
<List
|
||||||
|
grid={{ gutter: 16, column: 3 }}
|
||||||
|
dataSource={modelData}
|
||||||
|
renderItem={(item) => (
|
||||||
|
<List.Item>
|
||||||
|
<Card title={item.key}>{item.value}</Card>
|
||||||
|
</List.Item>
|
||||||
|
)}
|
||||||
|
style={{ marginBottom: "2rem" }}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Space direction="vertical" size={10}>
|
||||||
|
<Divider orientation="left">输入token详情</Divider>
|
||||||
|
<List
|
||||||
|
bordered
|
||||||
|
header={<div>问题</div>}
|
||||||
|
dataSource={inputTokenData}
|
||||||
|
renderItem={(item) => (
|
||||||
|
<List.Item style={{ justifyContent: "flex-start" }}>
|
||||||
|
<Typography.Paragraph style={{ marginBottom: 0 }} className="mr-1">
|
||||||
|
{item.key}
|
||||||
|
</Typography.Paragraph>
|
||||||
|
<Tooltip placement="topLeft" style={{ marginBottom: 0 }} title={item.value}>
|
||||||
|
{item.value}
|
||||||
|
</Tooltip>
|
||||||
|
</List.Item>
|
||||||
|
)}
|
||||||
|
style={{ marginBottom: "1rem" }}
|
||||||
|
/>
|
||||||
|
<Card title="数联网引用数据">
|
||||||
|
<Table<DataType> columns={columns} dataSource={record.iodData} />
|
||||||
|
</Card>
|
||||||
|
</Space>
|
||||||
|
|
||||||
|
<Space direction="vertical" size={10}>
|
||||||
|
<Divider orientation="left">输出token详情</Divider>
|
||||||
|
<List
|
||||||
|
bordered
|
||||||
|
dataSource={keywordsData}
|
||||||
|
header={<div>数联网搜索关键词</div>}
|
||||||
|
renderItem={(item) => (
|
||||||
|
<List.Item style={{ justifyContent: "flex-start" }}>
|
||||||
|
<Typography.Text className="mr-1" style={{ marginBottom: 0 }}>{item.key}</Typography.Text>
|
||||||
|
<Tooltip style={{ marginBottom: 0 }} placement="topLeft" title={item.value}>
|
||||||
|
{item.value}
|
||||||
|
</Tooltip>
|
||||||
|
</List.Item>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<List
|
||||||
|
bordered
|
||||||
|
dataSource={responseContent}
|
||||||
|
header={<div>回答</div>}
|
||||||
|
renderItem={(item) => (
|
||||||
|
<List.Item
|
||||||
|
style={{ justifyContent: "flex-start", alignItems: "center" }}>
|
||||||
|
<Typography.Text
|
||||||
|
className="mt-0 mr-1 w-20"
|
||||||
|
style={{ marginBottom: 0 }}>
|
||||||
|
{item.key}
|
||||||
|
</Typography.Text>
|
||||||
|
<Typography.Paragraph
|
||||||
|
style={{ marginBottom: 0 }}
|
||||||
|
ellipsis={{ tooltip: item.value, rows: 2, expandable: true }}>
|
||||||
|
{item.value}
|
||||||
|
</Typography.Paragraph>
|
||||||
|
</List.Item>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</Space>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -8,7 +8,7 @@ import {
|
|||||||
promptForRag,
|
promptForRag,
|
||||||
systemPromptForNonRagOption
|
systemPromptForNonRagOption
|
||||||
} from "~/services/ollama"
|
} from "~/services/ollama"
|
||||||
import { type ChatHistory, ChatMessage, type Message } from "~/store/option"
|
import type { ChatHistory, Message, MeteringEntry } 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 {
|
||||||
@@ -55,8 +55,8 @@ export const useMessageOption = () => {
|
|||||||
const {
|
const {
|
||||||
history,
|
history,
|
||||||
setHistory,
|
setHistory,
|
||||||
chatMessages,
|
meteringEntries,
|
||||||
setChatMessages,
|
setMeteringEntries,
|
||||||
setStreaming,
|
setStreaming,
|
||||||
streaming,
|
streaming,
|
||||||
setIsFirstMessage,
|
setIsFirstMessage,
|
||||||
@@ -114,23 +114,24 @@ export const useMessageOption = () => {
|
|||||||
setWebSearch(true)
|
setWebSearch(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 从最后的结果中解析出 思维链 和 结果
|
|
||||||
|
// 从最后的结果中解析出 思维链 (Chain-of-Thought) 和 结果
|
||||||
const responseResolver = (msg: string) => {
|
const responseResolver = (msg: string) => {
|
||||||
const thinkStart = msg.indexOf("<think>")
|
const cotStart = msg.indexOf("<think>")
|
||||||
const thinkEnd = msg.indexOf("</think>")
|
const cotEnd = msg.indexOf("</think>")
|
||||||
let think = ""
|
let cot = ""
|
||||||
let content = ""
|
let content = ""
|
||||||
if (thinkStart > -1 && thinkEnd > -1) {
|
if (cotStart > -1 && cotEnd > -1) {
|
||||||
think = msg.substring(thinkStart + 7, thinkEnd)
|
cot = msg.substring(cotStart + 7, cotEnd)
|
||||||
content = msg.substring(thinkEnd + 8)
|
content = msg.substring(cotEnd + 8)
|
||||||
} else {
|
} else {
|
||||||
content = msg
|
content = msg
|
||||||
}
|
}
|
||||||
// 去掉换行符
|
// 去掉换行符
|
||||||
think = think.replace(/\n/g, "")
|
cot = cot.replace(/\n/g, "")
|
||||||
content = content.replace(/\n/g, "")
|
content = content.replace(/\n/g, "")
|
||||||
return {
|
return {
|
||||||
think,
|
cot: cot,
|
||||||
content
|
content
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -190,10 +191,11 @@ export const useMessageOption = () => {
|
|||||||
})
|
})
|
||||||
let newMessage: Message[] = []
|
let newMessage: Message[] = []
|
||||||
let generateMessageId = generateID()
|
let generateMessageId = generateID()
|
||||||
const chatMessage: ChatMessage = {
|
const meter: MeteringEntry = {
|
||||||
id: generateMessageId,
|
id: generateMessageId,
|
||||||
queryContent: message
|
queryContent: message,
|
||||||
} as ChatMessage
|
date: new Date()
|
||||||
|
} as MeteringEntry
|
||||||
|
|
||||||
if (!isRegenerate) {
|
if (!isRegenerate) {
|
||||||
newMessage = [
|
newMessage = [
|
||||||
@@ -316,15 +318,14 @@ export const useMessageOption = () => {
|
|||||||
.map((k) => k.trim())
|
.map((k) => k.trim())
|
||||||
}
|
}
|
||||||
|
|
||||||
const { prompt, webSources, iodSources } = await getSystemPromptForWeb(
|
const { prompt, webSources, iodSources, iodSearchResults: iodData, iodTokenCount } =
|
||||||
query,
|
await getSystemPromptForWeb(query, keywords, webSearch, iodSearch)
|
||||||
keywords,
|
|
||||||
webSearch,
|
|
||||||
iodSearch
|
|
||||||
)
|
|
||||||
console.log("prompt:\n" + prompt)
|
console.log("prompt:\n" + prompt)
|
||||||
setIsSearchingInternet(false)
|
setIsSearchingInternet(false)
|
||||||
chatMessage.prompt = prompt
|
meter.prompt = prompt
|
||||||
|
meter.iodKeywords = keywords
|
||||||
|
meter.iodData = iodData
|
||||||
|
meter.iodTokenCount = iodTokenCount
|
||||||
|
|
||||||
// message = message.trim().replaceAll("\n", " ")
|
// message = message.trim().replaceAll("\n", " ")
|
||||||
|
|
||||||
@@ -385,6 +386,7 @@ export const useMessageOption = () => {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
let count = 0
|
let count = 0
|
||||||
|
const chatStartTime = new Date()
|
||||||
let reasoningStartTime: Date | undefined = undefined
|
let reasoningStartTime: Date | undefined = undefined
|
||||||
let reasoningEndTime: Date | undefined = undefined
|
let reasoningEndTime: Date | undefined = undefined
|
||||||
let apiReasoning = false
|
let apiReasoning = false
|
||||||
@@ -485,13 +487,22 @@ export const useMessageOption = () => {
|
|||||||
setIsProcessing(false)
|
setIsProcessing(false)
|
||||||
setStreaming(false)
|
setStreaming(false)
|
||||||
|
|
||||||
chatMessage.relatedDataCount = keywords.length
|
// Save metering entry
|
||||||
chatMessage.timeTaken = timetaken
|
const { cot, content } = responseResolver(fullText)
|
||||||
chatMessage.date = reasoningStartTime
|
setMeteringEntries([ {
|
||||||
const { think, content } = responseResolver(fullText)
|
...meter,
|
||||||
chatMessage.thinkingChain = think
|
modelInputTokenCount: prompt.length,
|
||||||
chatMessage.responseContent = content
|
modelOutputTokenCount: fullText.length,
|
||||||
setChatMessages([...chatMessages, chatMessage])
|
model: ollama.modelName,
|
||||||
|
relatedDataCount: iodData?.length ?? 0,
|
||||||
|
timeTaken: new Date().getTime() - meter.date.getTime(),
|
||||||
|
date: chatStartTime,
|
||||||
|
cot,
|
||||||
|
responseContent: content,
|
||||||
|
modelResponseContent: fullText,
|
||||||
|
},
|
||||||
|
...meteringEntries,
|
||||||
|
])
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const errorSave = await saveMessageOnError({
|
const errorSave = await saveMessageOnError({
|
||||||
e,
|
e,
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ export const pageAssistModel = async ({
|
|||||||
configuration: {
|
configuration: {
|
||||||
apiKey: providerInfo.apiKey || "temp",
|
apiKey: providerInfo.apiKey || "temp",
|
||||||
baseURL: providerInfo.baseUrl || ""
|
baseURL: providerInfo.baseUrl || ""
|
||||||
}
|
},
|
||||||
}) as any
|
}) as any
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,7 +85,7 @@ export const pageAssistModel = async ({
|
|||||||
configuration: {
|
configuration: {
|
||||||
apiKey: providerInfo.apiKey || "temp",
|
apiKey: providerInfo.apiKey || "temp",
|
||||||
baseURL: providerInfo.baseUrl || ""
|
baseURL: providerInfo.baseUrl || ""
|
||||||
}
|
},
|
||||||
}) as any
|
}) as any
|
||||||
}
|
}
|
||||||
return new ChatOllama({
|
return new ChatOllama({
|
||||||
|
|||||||
@@ -30,39 +30,13 @@ export type ChatHistory = {
|
|||||||
messageType?: string
|
messageType?: string
|
||||||
}[]
|
}[]
|
||||||
|
|
||||||
export type ChatMessage = {
|
|
||||||
id: string
|
|
||||||
// 问题
|
|
||||||
queryContent: string
|
|
||||||
// 提示词全文
|
|
||||||
prompt: string
|
|
||||||
// 思维链(只有深度思考时有)
|
|
||||||
thinkingChain?: string
|
|
||||||
// 回答
|
|
||||||
responseContent: string
|
|
||||||
// 关联数据个数
|
|
||||||
relatedDataCount: number
|
|
||||||
// 数联网输入token
|
|
||||||
iodInputToken: string
|
|
||||||
// 数联网输出token
|
|
||||||
iodOutputToken: string
|
|
||||||
// 大模型输入token
|
|
||||||
modelInputToken: string
|
|
||||||
// 大模型输出token
|
|
||||||
modelOutputToken: string
|
|
||||||
// 日期
|
|
||||||
date: Date
|
|
||||||
// 耗时
|
|
||||||
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[]
|
meteringEntries: MeteringEntry[]
|
||||||
setChatMessages: (chatMessages: ChatMessage[]) => void
|
setMeteringEntries: (meteringEntries: MeteringEntry[]) => void
|
||||||
streaming: boolean
|
streaming: boolean
|
||||||
setStreaming: (streaming: boolean) => void
|
setStreaming: (streaming: boolean) => void
|
||||||
isFirstMessage: boolean
|
isFirstMessage: boolean
|
||||||
@@ -105,13 +79,49 @@ type State = {
|
|||||||
setUseOCR: (useOCR: boolean) => void
|
setUseOCR: (useOCR: boolean) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type MeteringEntry = {
|
||||||
|
id: string
|
||||||
|
// 问题
|
||||||
|
queryContent: string
|
||||||
|
// 提示词全文
|
||||||
|
prompt: string
|
||||||
|
// 思维链(只有深度思考时有)
|
||||||
|
cot?: string
|
||||||
|
// 回答
|
||||||
|
responseContent: string
|
||||||
|
// 关联数据个数
|
||||||
|
relatedDataCount: number
|
||||||
|
// 数联网输入token
|
||||||
|
iodInputToken: string
|
||||||
|
// 数联网输出token
|
||||||
|
iodOutputToken: string
|
||||||
|
// 大模型输入token数量
|
||||||
|
modelInputTokenCount: number
|
||||||
|
// 大模型输出token数量
|
||||||
|
modelOutputTokenCount: number
|
||||||
|
// 日期
|
||||||
|
date: Date
|
||||||
|
// 耗时
|
||||||
|
timeTaken: number
|
||||||
|
// 大模型回答的全部内容
|
||||||
|
modelResponseContent: string
|
||||||
|
// iod的全部内容的token数量
|
||||||
|
iodTokenCount: number
|
||||||
|
// iod返回的数据
|
||||||
|
iodData: any[]
|
||||||
|
// iod keywords
|
||||||
|
iodKeywords: string[]
|
||||||
|
// 模型
|
||||||
|
model: string
|
||||||
|
}
|
||||||
|
|
||||||
export const useStoreMessageOption = create<State>((set) => ({
|
export const useStoreMessageOption = create<State>((set) => ({
|
||||||
messages: [],
|
messages: [],
|
||||||
setMessages: (messages) => set({ messages }),
|
setMessages: (messages) => set({ messages }),
|
||||||
history: [],
|
history: [],
|
||||||
setHistory: (history) => set({ history }),
|
setHistory: (history) => set({ history }),
|
||||||
chatMessages: [],
|
meteringEntries: [],
|
||||||
setChatMessages: (chatMessages) => set({ chatMessages }),
|
setMeteringEntries: (meteringEntries) => set({ meteringEntries }),
|
||||||
streaming: false,
|
streaming: false,
|
||||||
setStreaming: (streaming) => set({ streaming }),
|
setStreaming: (streaming) => set({ streaming }),
|
||||||
isFirstMessage: true,
|
isFirstMessage: true,
|
||||||
|
|||||||
@@ -5,4 +5,5 @@ export type IodRegistryEntry = {
|
|||||||
pdf_url?: string
|
pdf_url?: string
|
||||||
description: string
|
description: string
|
||||||
content?: string
|
content?: string
|
||||||
|
data_space?: string
|
||||||
}
|
}
|
||||||
|
|||||||
21
src/web/1.json
Normal file
21
src/web/1.json
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"action": "executeContract",
|
||||||
|
"contractID": "BDBrowser",
|
||||||
|
"operation": "sendRequestDirectly",
|
||||||
|
"arg": {
|
||||||
|
"id": "670E241C9937B3537047C87053E3AA36",
|
||||||
|
"doipUrl": "tcp://reg01.public.internetofdata.cn:21037",
|
||||||
|
"op": "Search",
|
||||||
|
"attributes": {
|
||||||
|
"offset": 2100,
|
||||||
|
"count": 5,
|
||||||
|
"bodyBase64Encoded": false,
|
||||||
|
"searchMode": [
|
||||||
|
{ "key": "data_type", "type": "MUST", "value": "paper" },
|
||||||
|
{ "key": "title", "type": "MUST", "value": "Number_1" },
|
||||||
|
{ "key": "description", "type": "MUST", "value": "Number_1" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"body": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
33
src/web/2.ts
Normal file
33
src/web/2.ts
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
const ollama = await pageAssistModel({
|
||||||
|
model: selectedModel!,
|
||||||
|
baseUrl: cleanUrl(url),
|
||||||
|
keepAlive:
|
||||||
|
currentChatModelSettings?.keepAlive ?? userDefaultModelSettings?.keepAlive,
|
||||||
|
temperature:
|
||||||
|
currentChatModelSettings?.temperature ??
|
||||||
|
userDefaultModelSettings?.temperature,
|
||||||
|
topK: currentChatModelSettings?.topK ?? userDefaultModelSettings?.topK,
|
||||||
|
topP: currentChatModelSettings?.topP ?? userDefaultModelSettings?.topP,
|
||||||
|
numCtx: currentChatModelSettings?.numCtx ?? userDefaultModelSettings?.numCtx,
|
||||||
|
seed: currentChatModelSettings?.seed,
|
||||||
|
numGpu: currentChatModelSettings?.numGpu ?? userDefaultModelSettings?.numGpu,
|
||||||
|
numPredict:
|
||||||
|
currentChatModelSettings?.numPredict ??
|
||||||
|
userDefaultModelSettings?.numPredict,
|
||||||
|
useMMap:
|
||||||
|
currentChatModelSettings?.useMMap ?? userDefaultModelSettings?.useMMap,
|
||||||
|
minP: currentChatModelSettings?.minP ?? userDefaultModelSettings?.minP,
|
||||||
|
repeatLastN:
|
||||||
|
currentChatModelSettings?.repeatLastN ??
|
||||||
|
userDefaultModelSettings?.repeatLastN,
|
||||||
|
repeatPenalty:
|
||||||
|
currentChatModelSettings?.repeatPenalty ??
|
||||||
|
userDefaultModelSettings?.repeatPenalty,
|
||||||
|
tfsZ: currentChatModelSettings?.tfsZ ?? userDefaultModelSettings?.tfsZ,
|
||||||
|
numKeep:
|
||||||
|
currentChatModelSettings?.numKeep ?? userDefaultModelSettings?.numKeep,
|
||||||
|
numThread:
|
||||||
|
currentChatModelSettings?.numThread ?? userDefaultModelSettings?.numThread,
|
||||||
|
useMlock:
|
||||||
|
currentChatModelSettings?.useMlock ?? userDefaultModelSettings?.useMlock
|
||||||
|
})
|
||||||
@@ -91,7 +91,13 @@ export async function localIodSearch(
|
|||||||
)
|
)
|
||||||
).flat()
|
).flat()
|
||||||
|
|
||||||
return results
|
// results 根据 doId 去重
|
||||||
|
const map = new Map<string, IodRegistryEntry>()
|
||||||
|
for (const r of results) {
|
||||||
|
map.set(r.doId, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
return Array.from(map.values())
|
||||||
}
|
}
|
||||||
|
|
||||||
const ARXIV_URL_PATTERN = /^https?:\/\/arxiv\.org\//
|
const ARXIV_URL_PATTERN = /^https?:\/\/arxiv\.org\//
|
||||||
|
|||||||
@@ -95,13 +95,17 @@ export const getSystemPromptForWeb = async (
|
|||||||
// )
|
// )
|
||||||
// .join("\n")
|
// .join("\n")
|
||||||
}
|
}
|
||||||
const iod_search_results = iodSearchResults
|
const _iodSearchResults = iodSearchResults
|
||||||
.map((res) => ({
|
.map((res) => ({
|
||||||
doId: res.doId,
|
doId: res.doId,
|
||||||
name: res.name,
|
name: res.name,
|
||||||
url: res.url,
|
url: res.url,
|
||||||
content: res.content || res.description
|
data_space: res.data_space,
|
||||||
}))
|
content: res.content || res.description,
|
||||||
|
tokenCount: (res.content || res.description)?.length ?? 0,
|
||||||
|
}))
|
||||||
|
|
||||||
|
const iod_search_results = _iodSearchResults
|
||||||
.map(
|
.map(
|
||||||
(result, idx) =>
|
(result, idx) =>
|
||||||
`<result doId="${result.doId}" name="${result.name}" source="${result.url}" id="${idx + 1}">${result.content}</result>`
|
`<result doId="${result.doId}" name="${result.name}" source="${result.url}" id="${idx + 1}">${result.content}</result>`
|
||||||
@@ -135,14 +139,18 @@ export const getSystemPromptForWeb = async (
|
|||||||
type: "url"
|
type: "url"
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
iodSources: iodSearchResults
|
iodSources: iodSearchResults,
|
||||||
|
iodSearchResults: _iodSearchResults,
|
||||||
|
iodTokenCount: _iodSearchResults.reduce((acc, cur) => (acc + cur.content.length), 0)
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e)
|
console.error(e)
|
||||||
return {
|
return {
|
||||||
prompt: "",
|
prompt: "",
|
||||||
webSources: [],
|
webSources: [],
|
||||||
iodSources: []
|
iodSources: [],
|
||||||
|
iodSearchResults: [],
|
||||||
|
iodTokenCount: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user