feat: add metering data
This commit is contained in:
parent
c50bb49b37
commit
7b8879a7a8
@ -9,139 +9,128 @@ import {
|
||||
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"
|
||||
}
|
||||
]
|
||||
import { NavLink, useParams } from "react-router-dom"
|
||||
import { useStoreMessageOption } from "@/store/option.tsx"
|
||||
import { useMemo } from "react"
|
||||
|
||||
interface DataType {
|
||||
key: string
|
||||
name: string
|
||||
age: number
|
||||
address: string
|
||||
tags: number
|
||||
doId: number
|
||||
data_space: string
|
||||
content: string
|
||||
tokenCount: number
|
||||
}
|
||||
|
||||
const columns: TableProps<DataType>["columns"] = [
|
||||
{
|
||||
title: "序号",
|
||||
dataIndex: "key",
|
||||
key: "name",
|
||||
render: (text) => <a>{text}</a>
|
||||
title: '序号',
|
||||
key: 'index',
|
||||
width: 100,
|
||||
render: (_text, _record, index) => index + 1, // 索引从0开始,+1后从1显示
|
||||
},
|
||||
{
|
||||
title: "标识",
|
||||
dataIndex: "age",
|
||||
key: "age"
|
||||
dataIndex: "doId",
|
||||
key: "doId"
|
||||
},
|
||||
{
|
||||
title: "提供方",
|
||||
dataIndex: "address",
|
||||
key: "address"
|
||||
dataIndex: "data_space",
|
||||
key: "data_space"
|
||||
},
|
||||
{
|
||||
title: "token数量",
|
||||
key: "tags",
|
||||
dataIndex: "tags"
|
||||
key: "tokenCount",
|
||||
dataIndex: "tokenCount",
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
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: "内容"
|
||||
dataIndex: "content",
|
||||
ellipsis: {
|
||||
showTitle: false
|
||||
},
|
||||
{
|
||||
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: "内容"
|
||||
render: (content) => (
|
||||
<Tooltip placement="topLeft" title={content}>
|
||||
{content}
|
||||
</Tooltip>
|
||||
)
|
||||
}
|
||||
]
|
||||
|
||||
export const ListDetail = () => {
|
||||
const { chatMessages } = useStoreMessageOption()
|
||||
const { id } = useParams()
|
||||
const record = useMemo(
|
||||
() => chatMessages.find((item) => item.id === id),
|
||||
[chatMessages]
|
||||
)
|
||||
|
||||
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={data}
|
||||
dataSource={modelData}
|
||||
renderItem={(item) => (
|
||||
<List.Item>
|
||||
<Card title={item.key}>{item.value}</Card>
|
||||
@ -150,43 +139,65 @@ export const ListDetail = () => {
|
||||
style={{ marginBottom: "2rem" }}
|
||||
/>
|
||||
|
||||
<div>
|
||||
<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.Text mark className="mr-1">
|
||||
<Typography.Paragraph style={{ marginBottom: 0 }} className="mr-1">
|
||||
{item.key}
|
||||
</Typography.Text>
|
||||
<Tooltip placement="topLeft" title={item.value}>
|
||||
</Typography.Paragraph>
|
||||
<Tooltip placement="topLeft" style={{ marginBottom: 0 }} title={item.value}>
|
||||
{item.value}
|
||||
</Tooltip>
|
||||
</List.Item>
|
||||
)}
|
||||
style={{ marginBottom: "1rem" }}
|
||||
/>
|
||||
<Table<DataType> columns={columns} dataSource={data1} />
|
||||
</div>
|
||||
<Card title="数联网引用数据">
|
||||
<Table<DataType> columns={columns} dataSource={record.iodData} />
|
||||
</Card>
|
||||
</Space>
|
||||
|
||||
<div>
|
||||
<Space direction="vertical" size={10}>
|
||||
<Divider orientation="left">输出token详情</Divider>
|
||||
<List
|
||||
bordered
|
||||
dataSource={outputTokenData}
|
||||
dataSource={keywordsData}
|
||||
header={<div>数联网搜索关键词</div>}
|
||||
renderItem={(item) => (
|
||||
<List.Item style={{ justifyContent: "flex-start" }}>
|
||||
<Typography.Text mark className="mr-1">
|
||||
{item.key}
|
||||
</Typography.Text>
|
||||
<Tooltip placement="topLeft" title={item.value}>
|
||||
<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>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<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>
|
||||
)
|
||||
}
|
||||
|
@ -1,24 +1,9 @@
|
||||
import React from "react"
|
||||
import React, { useMemo } 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",
|
||||
@ -49,6 +34,14 @@ const columns: TableProps<ChatMessage>["columns"] = [
|
||||
title: "思维链",
|
||||
key: "thinkingChain",
|
||||
dataIndex: "thinkingChain",
|
||||
ellipsis: {
|
||||
showTitle: false
|
||||
},
|
||||
render: (responseContent) => (
|
||||
<Tooltip placement="topLeft" title={responseContent}>
|
||||
{responseContent}
|
||||
</Tooltip>
|
||||
),
|
||||
width: "10%"
|
||||
},
|
||||
|
||||
@ -73,9 +66,8 @@ const columns: TableProps<ChatMessage>["columns"] = [
|
||||
},
|
||||
{
|
||||
title: "数联网token",
|
||||
dataIndex: "iodOutputToken",
|
||||
key: "iodOutputToken",
|
||||
render: (iodOutputToken) => <div>{iodOutputToken?.length}</div>
|
||||
dataIndex: "iodDataTokenCount",
|
||||
key: "iodDataTokenCount"
|
||||
},
|
||||
{
|
||||
title: "大模型token",
|
||||
@ -83,9 +75,7 @@ const columns: TableProps<ChatMessage>["columns"] = [
|
||||
dataIndex: "largeModelToken",
|
||||
render: (_, record) => {
|
||||
return (
|
||||
<div>
|
||||
{record.iodInputToken?.length + record.iodOutputToken?.length}
|
||||
</div>
|
||||
<div>{record.modelInputTokenCount + record.modelOutputTokenCount}</div>
|
||||
)
|
||||
}
|
||||
},
|
||||
@ -119,13 +109,49 @@ const columns: TableProps<ChatMessage>["columns"] = [
|
||||
|
||||
export const MeteringDetail = () => {
|
||||
const { chatMessages } = useStoreMessageOption()
|
||||
console.log(chatMessages, "opppp")
|
||||
|
||||
const data = useMemo(
|
||||
() => [
|
||||
{
|
||||
key: "对话数量",
|
||||
value: chatMessages.length
|
||||
},
|
||||
{
|
||||
key: "数联网输入token数",
|
||||
value: chatMessages.reduce((acc, cur) => {
|
||||
for (const item of cur.iodKeywords) {
|
||||
acc += item.length
|
||||
}
|
||||
return acc
|
||||
}, 0)
|
||||
},
|
||||
{
|
||||
key: "数联网输出token数",
|
||||
value: chatMessages.reduce((acc, cur) => acc + cur.iodDataTokenCount, 0)
|
||||
},
|
||||
{
|
||||
key: "大模型输入token数",
|
||||
value: chatMessages.reduce(
|
||||
(acc, cur) => acc + cur.modelInputTokenCount,
|
||||
0
|
||||
)
|
||||
},
|
||||
{
|
||||
key: "大模型输出token数",
|
||||
value: chatMessages.reduce(
|
||||
(acc, cur) => acc + cur.modelOutputTokenCount,
|
||||
0
|
||||
)
|
||||
}
|
||||
],
|
||||
[chatMessages]
|
||||
)
|
||||
return (
|
||||
<div className="pt-[4rem]">
|
||||
<div className="p-4 pt-[4rem]">
|
||||
<List
|
||||
grid={{ gutter: 16, column: 3 }}
|
||||
grid={{ gutter: 16, column: 5 }}
|
||||
dataSource={data}
|
||||
split={false}
|
||||
renderItem={(item) => (
|
||||
<List.Item>
|
||||
<Card title={item.key}>{item.value}</Card>
|
||||
|
@ -316,15 +316,14 @@ export const useMessageOption = () => {
|
||||
.map((k) => k.trim())
|
||||
}
|
||||
|
||||
const { prompt, webSources, iodSources } = await getSystemPromptForWeb(
|
||||
query,
|
||||
keywords,
|
||||
webSearch,
|
||||
iodSearch
|
||||
)
|
||||
const { prompt, webSources, iodSources, iodData, iodDataTokenCount } =
|
||||
await getSystemPromptForWeb(query, keywords, webSearch, iodSearch)
|
||||
console.log("prompt:\n" + prompt)
|
||||
setIsSearchingInternet(false)
|
||||
chatMessage.prompt = prompt
|
||||
chatMessage.iodKeywords = keywords
|
||||
chatMessage.iodData = iodData
|
||||
chatMessage.iodDataTokenCount = iodDataTokenCount
|
||||
|
||||
// message = message.trim().replaceAll("\n", " ")
|
||||
|
||||
@ -485,12 +484,16 @@ export const useMessageOption = () => {
|
||||
setIsProcessing(false)
|
||||
setStreaming(false)
|
||||
|
||||
chatMessage.relatedDataCount = keywords.length
|
||||
chatMessage.modelInputTokenCount = generationInfo?.prompt_eval_count ?? 0
|
||||
chatMessage.modelOutputTokenCount = generationInfo?.eval_count ?? 0
|
||||
chatMessage.model = generationInfo?.model ?? ""
|
||||
chatMessage.relatedDataCount = iodData?.length ?? 0
|
||||
chatMessage.timeTaken = timetaken
|
||||
chatMessage.date = reasoningStartTime
|
||||
const { think, content } = responseResolver(fullText)
|
||||
chatMessage.thinkingChain = think
|
||||
chatMessage.responseContent = content
|
||||
chatMessage.modelResponseContent = fullText
|
||||
setChatMessages([...chatMessages, chatMessage])
|
||||
} catch (e) {
|
||||
const errorSave = await saveMessageOnError({
|
||||
|
@ -46,14 +46,24 @@ export type ChatMessage = {
|
||||
iodInputToken: string
|
||||
// 数联网输出token
|
||||
iodOutputToken: string
|
||||
// 大模型输入token
|
||||
modelInputToken: string
|
||||
// 大模型输出token
|
||||
modelOutputToken: string
|
||||
// 大模型输入token数量
|
||||
modelInputTokenCount: number
|
||||
// 大模型输出token数量
|
||||
modelOutputTokenCount: number
|
||||
// 日期
|
||||
date: Date
|
||||
// 耗时
|
||||
timeTaken: number
|
||||
// 大模型回答的全部内容
|
||||
modelResponseContent: string
|
||||
// iod的全部内容的token数量
|
||||
iodDataTokenCount: number
|
||||
// iod返回的数据
|
||||
iodData: any[]
|
||||
// iod keywords
|
||||
iodKeywords: string[]
|
||||
// 模型
|
||||
model: string
|
||||
}
|
||||
|
||||
type State = {
|
||||
|
@ -5,4 +5,5 @@ export type IodRegistryEntry = {
|
||||
pdf_url?: string
|
||||
description: string
|
||||
content?: string
|
||||
data_space?: string
|
||||
}
|
||||
|
@ -91,7 +91,13 @@ export async function localIodSearch(
|
||||
)
|
||||
).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\//
|
||||
|
@ -95,13 +95,17 @@ export const getSystemPromptForWeb = async (
|
||||
// )
|
||||
// .join("\n")
|
||||
}
|
||||
const iod_search_results = iodSearchResults
|
||||
const _iodSearchResults = iodSearchResults
|
||||
.map((res) => ({
|
||||
doId: res.doId,
|
||||
name: res.name,
|
||||
url: res.url,
|
||||
data_space: res.data_space,
|
||||
tokenCount: (res.content || res.description)?.length ?? 0,
|
||||
content: res.content || res.description
|
||||
}))
|
||||
|
||||
const iod_search_results = _iodSearchResults
|
||||
.map(
|
||||
(result, idx) =>
|
||||
`<result doId="${result.doId}" name="${result.name}" source="${result.url}" id="${idx + 1}">${result.content}</result>`
|
||||
@ -135,7 +139,9 @@ export const getSystemPromptForWeb = async (
|
||||
type: "url"
|
||||
}
|
||||
}),
|
||||
iodSources: iodSearchResults
|
||||
iodSources: iodSearchResults,
|
||||
iodData: _iodSearchResults,
|
||||
iodDataTokenCount: _iodSearchResults.reduce((acc, cur) => (acc + cur.content.length), 0)
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
|
Loading…
x
Reference in New Issue
Block a user