adding new stat panel
This commit is contained in:
136
src/chatbox.tsx
136
src/chatbox.tsx
@@ -14,6 +14,7 @@ import {
|
|||||||
TemplateAPI,
|
TemplateAPI,
|
||||||
TemplateTools,
|
TemplateTools,
|
||||||
addTotalCost,
|
addTotalCost,
|
||||||
|
getTotalCost,
|
||||||
} from "./app";
|
} from "./app";
|
||||||
import ChatGPT, {
|
import ChatGPT, {
|
||||||
calculate_token_length,
|
calculate_token_length,
|
||||||
@@ -34,7 +35,15 @@ import { ListToolsTempaltes } from "./listToolsTemplates";
|
|||||||
import { autoHeight } from "./textarea";
|
import { autoHeight } from "./textarea";
|
||||||
import Search from "./search";
|
import Search from "./search";
|
||||||
import { IDBPDatabase } from "idb";
|
import { IDBPDatabase } from "idb";
|
||||||
import { MagnifyingGlassIcon } from "@heroicons/react/24/outline";
|
import {
|
||||||
|
MagnifyingGlassIcon,
|
||||||
|
CubeIcon,
|
||||||
|
BanknotesIcon,
|
||||||
|
DocumentTextIcon,
|
||||||
|
ChatBubbleLeftEllipsisIcon,
|
||||||
|
ScissorsIcon,
|
||||||
|
SwatchIcon,
|
||||||
|
} from "@heroicons/react/24/outline";
|
||||||
|
|
||||||
export interface TemplateChatStore extends ChatStore {
|
export interface TemplateChatStore extends ChatStore {
|
||||||
name: string;
|
name: string;
|
||||||
@@ -465,7 +474,7 @@ export default function ChatBOX(props: {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<div
|
<div
|
||||||
className="relative cursor-pointer rounded p-2 bg-base-200"
|
className="relative cursor-pointer rounded p-2"
|
||||||
onClick={() => setShowSettings(true)}
|
onClick={() => setShowSettings(true)}
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
@@ -479,38 +488,97 @@ export default function ChatBOX(props: {
|
|||||||
>
|
>
|
||||||
<MagnifyingGlassIcon class="w-5 h-5" />
|
<MagnifyingGlassIcon class="w-5 h-5" />
|
||||||
</button>
|
</button>
|
||||||
<div>
|
<div class="stats shadow hidden lg:inline-grid">
|
||||||
<button className="underline">
|
<div class="stat">
|
||||||
{chatStore.systemMessageContent.length > 16
|
<div class="stat-figure text-secondary">
|
||||||
? chatStore.systemMessageContent.slice(0, 16) + ".."
|
<CubeIcon class="h-10 w-10" />
|
||||||
: chatStore.systemMessageContent}
|
</div>
|
||||||
</button>{" "}
|
<div class="stat-title">Model</div>
|
||||||
<button className="underline">
|
<div class="stat-value">{chatStore.model}</div>
|
||||||
{chatStore.streamMode ? Tr("STREAM") : Tr("FETCH")}
|
<div class="stat-desc">
|
||||||
</button>{" "}
|
Prompt:{" "}
|
||||||
{chatStore.toolsString.trim() && (
|
{chatStore.systemMessageContent.length > 30
|
||||||
<button className="underline">TOOL</button>
|
? chatStore.systemMessageContent.slice(0, 30) + ".."
|
||||||
)}
|
: chatStore.systemMessageContent}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="stat">
|
||||||
|
<div class="stat-figure text-secondary">
|
||||||
|
<SwatchIcon class="h-10 w-10" />
|
||||||
|
</div>
|
||||||
|
<div class="stat-title">Mode</div>
|
||||||
|
<div class="stat-value">
|
||||||
|
{chatStore.streamMode ? Tr("STREAM") : Tr("FETCH")}
|
||||||
|
</div>
|
||||||
|
<div class="stat-desc">STREAM/FETCH</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="stat">
|
||||||
|
<div class="stat-figure text-secondary">
|
||||||
|
<ChatBubbleLeftEllipsisIcon class="h-10 w-10" />
|
||||||
|
</div>
|
||||||
|
<div class="stat-title">Tokens</div>
|
||||||
|
<div class="stat-value">{chatStore.totalTokens}</div>
|
||||||
|
<div class="stat-desc">Max: {chatStore.maxTokens}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="stat">
|
||||||
|
<div class="stat-figure text-secondary">
|
||||||
|
<ScissorsIcon class="h-10 w-10" />
|
||||||
|
</div>
|
||||||
|
<div class="stat-title">Cut</div>
|
||||||
|
<div class="stat-value">{chatStore.postBeginIndex}</div>
|
||||||
|
<div class="stat-desc">
|
||||||
|
Max: {chatStore.history.filter(({ hide }) => !hide).length}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="stat">
|
||||||
|
<div class="stat-figure text-secondary">
|
||||||
|
<BanknotesIcon class="h-10 w-10" />
|
||||||
|
</div>
|
||||||
|
<div class="stat-title">Cost</div>
|
||||||
|
<div class="stat-value">${chatStore.cost.toFixed(4)}</div>
|
||||||
|
<div class="stat-desc">
|
||||||
|
Accumulated: ${getTotalCost().toFixed(2)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="text-xs">
|
<div class="lg:hidden">
|
||||||
<span className="underline">{chatStore.model}</span>{" "}
|
<div>
|
||||||
<span>
|
<button className="underline">
|
||||||
Tokens:{" "}
|
{chatStore.systemMessageContent.length > 16
|
||||||
<span className="underline">
|
? chatStore.systemMessageContent.slice(0, 16) + ".."
|
||||||
{chatStore.totalTokens}/{chatStore.maxTokens}
|
: chatStore.systemMessageContent}
|
||||||
</span>
|
</button>{" "}
|
||||||
</span>{" "}
|
<button className="underline">
|
||||||
<span>
|
{chatStore.streamMode ? Tr("STREAM") : Tr("FETCH")}
|
||||||
{Tr("Cut")}:{" "}
|
</button>{" "}
|
||||||
<span className="underline">
|
{chatStore.toolsString.trim() && (
|
||||||
{chatStore.postBeginIndex}/
|
<button className="underline">TOOL</button>
|
||||||
{chatStore.history.filter(({ hide }) => !hide).length}
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="text-xs">
|
||||||
|
<span class="underline">{chatStore.model}</span>{" "}
|
||||||
|
<span>
|
||||||
|
Tokens:{" "}
|
||||||
|
<span class="underline">
|
||||||
|
{chatStore.totalTokens}/{chatStore.maxTokens}
|
||||||
|
</span>
|
||||||
</span>{" "}
|
</span>{" "}
|
||||||
</span>{" "}
|
<span>
|
||||||
<span>
|
{Tr("Cut")}:{" "}
|
||||||
{Tr("Cost")}:{" "}
|
<span class="underline">
|
||||||
<span className="underline">${chatStore.cost.toFixed(4)}</span>
|
{chatStore.postBeginIndex}/
|
||||||
</span>
|
{chatStore.history.filter(({ hide }) => !hide).length}
|
||||||
|
</span>{" "}
|
||||||
|
</span>{" "}
|
||||||
|
<span>
|
||||||
|
{Tr("Cost")}:{" "}
|
||||||
|
<span className="underline">${chatStore.cost.toFixed(4)}</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="grow overflow-scroll">
|
<div className="grow overflow-scroll">
|
||||||
@@ -730,7 +798,7 @@ export default function ChatBOX(props: {
|
|||||||
<p className="text-center">
|
<p className="text-center">
|
||||||
{chatStore.history.length > 0 && (
|
{chatStore.history.length > 0 && (
|
||||||
<button
|
<button
|
||||||
className="btn btn-warning disabled:line-through disabled:btn-neutral disabled:text-white m-2 p-2"
|
className="btn btn-outline btn-sm btn-warning disabled:line-through disabled:btn-neutral disabled:text-white m-2 p-2"
|
||||||
disabled={showGenerating}
|
disabled={showGenerating}
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
const messageIndex = chatStore.history.length - 1;
|
const messageIndex = chatStore.history.length - 1;
|
||||||
@@ -1110,7 +1178,7 @@ export default function ChatBOX(props: {
|
|||||||
</span>
|
</span>
|
||||||
<span className={`flex justify-between p-2`}>
|
<span className={`flex justify-between p-2`}>
|
||||||
<button
|
<button
|
||||||
className="rounded m-1 p-1 border-2 bg-red-400 hover:bg-red-600"
|
className="btn btn-info m-1 p-1"
|
||||||
onClick={() => setShowAddToolMsg(false)}
|
onClick={() => setShowAddToolMsg(false)}
|
||||||
>
|
>
|
||||||
{Tr("Cancle")}
|
{Tr("Cancle")}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ export function ListAPIs({
|
|||||||
keyField,
|
keyField,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
return (
|
return (
|
||||||
<div className="break-all opacity-80 p-3 rounded bg-white my-3 text-left dark:text-black">
|
<div className="break-all opacity-80 p-3 rounded base-200 my-3 text-left">
|
||||||
<h2>{Tr(`Saved ${label} templates`)}</h2>
|
<h2>{Tr(`Saved ${label} templates`)}</h2>
|
||||||
<hr className="my-2" />
|
<hr className="my-2" />
|
||||||
<div className="flex flex-wrap">
|
<div className="flex flex-wrap">
|
||||||
@@ -31,8 +31,8 @@ export function ListAPIs({
|
|||||||
chatStore[apiField] === t.endpoint &&
|
chatStore[apiField] === t.endpoint &&
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
chatStore[keyField] === t.key
|
chatStore[keyField] === t.key
|
||||||
? "bg-red-600"
|
? "bg-info"
|
||||||
: "bg-red-400"
|
: "bg-base-300"
|
||||||
} w-fit p-2 m-1 flex flex-col`}
|
} w-fit p-2 m-1 flex flex-col`}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
@@ -43,9 +43,9 @@ export function ListAPIs({
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span className="w-full text-center">{t.name}</span>
|
<span className="w-full text-center">{t.name}</span>
|
||||||
<hr className="mt-2" />
|
<span className="flex justify-between gap-x-2">
|
||||||
<span className="flex justify-between">
|
|
||||||
<button
|
<button
|
||||||
|
class="link"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
const name = prompt(`Give **${label}** template a name`);
|
const name = prompt(`Give **${label}** template a name`);
|
||||||
if (!name) {
|
if (!name) {
|
||||||
@@ -55,9 +55,10 @@ export function ListAPIs({
|
|||||||
setTmps(structuredClone(tmps));
|
setTmps(structuredClone(tmps));
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
🖋
|
Edit
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
|
class="link"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (
|
if (
|
||||||
!confirm(
|
!confirm(
|
||||||
@@ -70,7 +71,7 @@ export function ListAPIs({
|
|||||||
setTmps(structuredClone(tmps));
|
setTmps(structuredClone(tmps));
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
❌
|
Delete
|
||||||
</button>
|
</button>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -33,8 +33,8 @@ export function ListToolsTempaltes({
|
|||||||
<div
|
<div
|
||||||
className={`cursor-pointer rounded ${
|
className={`cursor-pointer rounded ${
|
||||||
chatStore.toolsString === t.toolsString
|
chatStore.toolsString === t.toolsString
|
||||||
? "bg-red-600"
|
? "bg-info"
|
||||||
: "bg-red-400"
|
: "bg-base-300"
|
||||||
} w-fit p-2 m-1 flex flex-col`}
|
} w-fit p-2 m-1 flex flex-col`}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
chatStore.toolsString = t.toolsString;
|
chatStore.toolsString = t.toolsString;
|
||||||
@@ -42,9 +42,9 @@ export function ListToolsTempaltes({
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span className="w-full text-center">{t.name}</span>
|
<span className="w-full text-center">{t.name}</span>
|
||||||
<hr className="mt-2" />
|
<span className="flex justify-between gap-x-2">
|
||||||
<span className="flex justify-between">
|
|
||||||
<button
|
<button
|
||||||
|
class="link"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
const name = prompt(`Give **tools** template a name`);
|
const name = prompt(`Give **tools** template a name`);
|
||||||
if (!name) {
|
if (!name) {
|
||||||
@@ -54,9 +54,10 @@ export function ListToolsTempaltes({
|
|||||||
setTemplateTools(structuredClone(templateTools));
|
setTemplateTools(structuredClone(templateTools));
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
🖋
|
Edit
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
|
class="link"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (
|
if (
|
||||||
!confirm(`Are you sure to delete this **tools** template?`)
|
!confirm(`Are you sure to delete this **tools** template?`)
|
||||||
@@ -67,7 +68,7 @@ export function ListToolsTempaltes({
|
|||||||
setTemplateTools(structuredClone(templateTools));
|
setTemplateTools(structuredClone(templateTools));
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
❌
|
Delete
|
||||||
</button>
|
</button>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -121,7 +121,9 @@ export default function Message(props: Props) {
|
|||||||
<div
|
<div
|
||||||
className={`chat-bubble ${
|
className={`chat-bubble ${
|
||||||
chat.role === "assistant"
|
chat.role === "assistant"
|
||||||
? "chat-bubble-secondary"
|
? renderColor
|
||||||
|
? "chat-bubble-neutral"
|
||||||
|
: "chat-bubble-secondary"
|
||||||
: "chat-bubble-primary"
|
: "chat-bubble-primary"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
|
|||||||
Reference in New Issue
Block a user