mirror of
https://github.com/coaidev/coai.git
synced 2025-05-19 13:00:14 +09:00
update sharing using feature
This commit is contained in:
parent
0f345fbfa4
commit
9eb021a52e
@ -115,6 +115,9 @@ func (c *ChatInstance) Test() bool {
|
|||||||
Message: []globals.Message{{Role: "user", Content: "hi"}},
|
Message: []globals.Message{{Role: "user", Content: "hi"}},
|
||||||
Token: 1,
|
Token: 1,
|
||||||
})
|
})
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(fmt.Sprintf("%s: test failed (%s)", c.GetApiKey(), err.Error()))
|
||||||
|
}
|
||||||
|
|
||||||
return err == nil && len(result) > 0
|
return err == nil && len(result) > 0
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { toggleConversation } from "../../conversation/history.ts";
|
import { toggleConversation } from "../../conversation/history.ts";
|
||||||
import { filterMessage, mobile } from "../../utils.ts";
|
import { filterMessage, mobile } from "../../utils.ts";
|
||||||
import { setMenu } from "../../store/menu.ts";
|
import { setMenu } from "../../store/menu.ts";
|
||||||
import {MessageSquare, MoreHorizontal, Share2, Trash2} from "lucide-react";
|
import { MessageSquare, MoreHorizontal, Share2, Trash2 } from "lucide-react";
|
||||||
import {
|
import {
|
||||||
DropdownMenu,
|
DropdownMenu,
|
||||||
DropdownMenuContent,
|
DropdownMenuContent,
|
||||||
@ -16,7 +16,10 @@ import { useState } from "react";
|
|||||||
type ConversationSegmentProps = {
|
type ConversationSegmentProps = {
|
||||||
conversation: ConversationInstance;
|
conversation: ConversationInstance;
|
||||||
current: number;
|
current: number;
|
||||||
operate: (conversation: { target: ConversationInstance, type: string }) => void;
|
operate: (conversation: {
|
||||||
|
target: ConversationInstance;
|
||||||
|
type: string;
|
||||||
|
}) => void;
|
||||||
};
|
};
|
||||||
function ConversationSegment({
|
function ConversationSegment({
|
||||||
conversation,
|
conversation,
|
||||||
@ -45,10 +48,13 @@ function ConversationSegment({
|
|||||||
<MessageSquare className={`h-4 w-4 mr-1`} />
|
<MessageSquare className={`h-4 w-4 mr-1`} />
|
||||||
<div className={`title`}>{filterMessage(conversation.name)}</div>
|
<div className={`title`}>{filterMessage(conversation.name)}</div>
|
||||||
<div className={`id`}>{conversation.id}</div>
|
<div className={`id`}>{conversation.id}</div>
|
||||||
<DropdownMenu open={open} onOpenChange={(state: boolean) => {
|
<DropdownMenu
|
||||||
setOpen(state);
|
open={open}
|
||||||
if (state) setOffset(new Date().getTime());
|
onOpenChange={(state: boolean) => {
|
||||||
}}>
|
setOpen(state);
|
||||||
|
if (state) setOffset(new Date().getTime());
|
||||||
|
}}
|
||||||
|
>
|
||||||
<DropdownMenuTrigger>
|
<DropdownMenuTrigger>
|
||||||
<MoreHorizontal className={`more h-5 w-5 p-0.5`} />
|
<MoreHorizontal className={`more h-5 w-5 p-0.5`} />
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
|
|
||||||
export const version = "3.4.2";
|
export const version = "3.4.3";
|
||||||
export const deploy: boolean = false;
|
export const deploy: boolean = true;
|
||||||
export let rest_api: string = "http://localhost:8094";
|
export let rest_api: string = "http://localhost:8094";
|
||||||
export let ws_api: string = "ws://localhost:8094";
|
export let ws_api: string = "ws://localhost:8094";
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { ChatProps, Connection, StreamMessage } from "./connection.ts";
|
import { ChatProps, Connection, StreamMessage } from "./connection.ts";
|
||||||
import { Message } from "./types.ts";
|
import { Message } from "./types.ts";
|
||||||
|
import { event } from "../events/sharing.ts";
|
||||||
|
|
||||||
type ConversationCallback = (idx: number, message: Message[]) => void;
|
type ConversationCallback = (idx: number, message: Message[]) => void;
|
||||||
|
|
||||||
@ -18,6 +19,15 @@ export class Conversation {
|
|||||||
this.id = id;
|
this.id = id;
|
||||||
this.end = true;
|
this.end = true;
|
||||||
this.connection = new Connection(this.id);
|
this.connection = new Connection(this.id);
|
||||||
|
|
||||||
|
if (id === -1 && this.idx === -1) {
|
||||||
|
event.bind(({ refer, data }) => {
|
||||||
|
console.log(
|
||||||
|
`[conversation] load from sharing event (ref: ${refer}, length: ${data.length})`,
|
||||||
|
);
|
||||||
|
this.load(data);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public setId(id: number): void {
|
public setId(id: number): void {
|
||||||
|
@ -11,6 +11,7 @@ import { useShared } from "../utils.ts";
|
|||||||
import { ChatProps } from "./connection.ts";
|
import { ChatProps } from "./connection.ts";
|
||||||
import { supportModelConvertor } from "../conf.ts";
|
import { supportModelConvertor } from "../conf.ts";
|
||||||
import { AppDispatch } from "../store";
|
import { AppDispatch } from "../store";
|
||||||
|
import { event } from "../events/sharing.ts";
|
||||||
|
|
||||||
export class Manager {
|
export class Manager {
|
||||||
conversations: Record<number, Conversation>;
|
conversations: Record<number, Conversation>;
|
||||||
@ -21,6 +22,17 @@ export class Manager {
|
|||||||
this.conversations = {};
|
this.conversations = {};
|
||||||
this.conversations[-1] = this.createConversation(-1);
|
this.conversations[-1] = this.createConversation(-1);
|
||||||
this.current = -1;
|
this.current = -1;
|
||||||
|
|
||||||
|
event.addEventListener(async (data) => {
|
||||||
|
console.debug(`[manager] accept sharing event (refer: ${data.refer})`);
|
||||||
|
|
||||||
|
const interval = setInterval(() => {
|
||||||
|
if (this.dispatch) {
|
||||||
|
this.toggle(this.dispatch, -1);
|
||||||
|
clearInterval(interval);
|
||||||
|
}
|
||||||
|
}, 100);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public setDispatch(dispatch: AppDispatch): void {
|
public setDispatch(dispatch: AppDispatch): void {
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import {Message} from "./types.ts";
|
import { Message } from "./types.ts";
|
||||||
|
|
||||||
export type SharingForm = {
|
export type SharingForm = {
|
||||||
status: boolean;
|
status: boolean;
|
||||||
message: string;
|
message: string;
|
||||||
data: string;
|
data: string;
|
||||||
}
|
};
|
||||||
|
|
||||||
export type ViewData = {
|
export type ViewData = {
|
||||||
name: string;
|
name: string;
|
||||||
@ -18,10 +18,11 @@ export type ViewForm = {
|
|||||||
status: boolean;
|
status: boolean;
|
||||||
message: string;
|
message: string;
|
||||||
data: ViewData | null;
|
data: ViewData | null;
|
||||||
}
|
};
|
||||||
|
|
||||||
export async function shareConversation(
|
export async function shareConversation(
|
||||||
id: number, refs: number[] = [-1],
|
id: number,
|
||||||
|
refs: number[] = [-1],
|
||||||
): Promise<SharingForm> {
|
): Promise<SharingForm> {
|
||||||
try {
|
try {
|
||||||
const resp = await axios.post("/conversation/share", { id, refs });
|
const resp = await axios.post("/conversation/share", { id, refs });
|
||||||
@ -31,9 +32,7 @@ export async function shareConversation(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function viewConversation(
|
export async function viewConversation(hash: string): Promise<ViewForm> {
|
||||||
hash: string,
|
|
||||||
): Promise<ViewForm> {
|
|
||||||
try {
|
try {
|
||||||
const resp = await axios.get(`/conversation/view?hash=${hash}`);
|
const resp = await axios.get(`/conversation/view?hash=${hash}`);
|
||||||
return resp.data as ViewForm;
|
return resp.data as ViewForm;
|
||||||
@ -42,6 +41,6 @@ export async function viewConversation(
|
|||||||
status: false,
|
status: false,
|
||||||
message: (e as Error).message,
|
message: (e as Error).message,
|
||||||
data: null,
|
data: null,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
12
app/src/events/sharing.ts
Normal file
12
app/src/events/sharing.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import { EventCommitter } from "./struct.ts";
|
||||||
|
import { Message } from "../conversation/types.ts";
|
||||||
|
|
||||||
|
export type SharingEvent = {
|
||||||
|
refer: string;
|
||||||
|
data: Message[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export const event = new EventCommitter<SharingEvent>({
|
||||||
|
name: "sharing",
|
||||||
|
destroyedAfterTrigger: true,
|
||||||
|
});
|
51
app/src/events/struct.ts
Normal file
51
app/src/events/struct.ts
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
export type EventCommitterProps = {
|
||||||
|
name: string;
|
||||||
|
destroyedAfterTrigger?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export class EventCommitter<T> {
|
||||||
|
name: string;
|
||||||
|
trigger: ((data: T) => void) | undefined;
|
||||||
|
listeners: ((data: T) => void)[] = [];
|
||||||
|
destroyedAfterTrigger: boolean;
|
||||||
|
|
||||||
|
constructor({ name, destroyedAfterTrigger = false }: EventCommitterProps) {
|
||||||
|
this.name = name;
|
||||||
|
this.destroyedAfterTrigger = destroyedAfterTrigger;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected setTrigger(trigger: (data: T) => void) {
|
||||||
|
this.trigger = trigger;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected clearTrigger() {
|
||||||
|
this.trigger = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected triggerEvent(data: T) {
|
||||||
|
this.trigger && this.trigger(data);
|
||||||
|
if (this.destroyedAfterTrigger) this.clearTrigger();
|
||||||
|
|
||||||
|
this.listeners.forEach((listener) => listener(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
public emit(data: T) {
|
||||||
|
this.triggerEvent(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bind(trigger: (data: T) => void) {
|
||||||
|
this.setTrigger(trigger);
|
||||||
|
}
|
||||||
|
|
||||||
|
public addEventListener(listener: (data: T) => void) {
|
||||||
|
this.listeners.push(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
public removeEventListener(listener: (data: T) => void) {
|
||||||
|
this.listeners = this.listeners.filter((item) => item !== listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
public clearEventListener() {
|
||||||
|
this.listeners = [];
|
||||||
|
}
|
||||||
|
}
|
@ -178,14 +178,15 @@ const resources = {
|
|||||||
"share-conversation": "Share Conversation",
|
"share-conversation": "Share Conversation",
|
||||||
description: "Share this conversation with others: ",
|
description: "Share this conversation with others: ",
|
||||||
"copy-link": "Copy Link",
|
"copy-link": "Copy Link",
|
||||||
"view": "View",
|
view: "View",
|
||||||
success: "Share success",
|
success: "Share success",
|
||||||
failed: "Share failed",
|
failed: "Share failed",
|
||||||
copied: "Copied",
|
copied: "Copied",
|
||||||
"copied-description": "Link has been copied to clipboard",
|
"copied-description": "Link has been copied to clipboard",
|
||||||
"not-found": "Conversation not found",
|
"not-found": "Conversation not found",
|
||||||
"not-found-description": "Conversation not found, please check if the link is correct or the conversation has been deleted",
|
"not-found-description":
|
||||||
}
|
"Conversation not found, please check if the link is correct or the conversation has been deleted",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
cn: {
|
cn: {
|
||||||
@ -350,14 +351,15 @@ const resources = {
|
|||||||
"share-conversation": "分享对话",
|
"share-conversation": "分享对话",
|
||||||
description: "将此对话与他人分享:",
|
description: "将此对话与他人分享:",
|
||||||
"copy-link": "复制链接",
|
"copy-link": "复制链接",
|
||||||
"view": "查看",
|
view: "查看",
|
||||||
success: "分享成功",
|
success: "分享成功",
|
||||||
failed: "分享失败",
|
failed: "分享失败",
|
||||||
copied: "复制成功",
|
copied: "复制成功",
|
||||||
"copied-description": "链接已复制到剪贴板",
|
"copied-description": "链接已复制到剪贴板",
|
||||||
"not-found": "对话未找到",
|
"not-found": "对话未找到",
|
||||||
"not-found-description": "对话未找到,请检查链接是否正确或对话是否已被删除",
|
"not-found-description":
|
||||||
}
|
"对话未找到,请检查链接是否正确或对话是否已被删除",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ru: {
|
ru: {
|
||||||
@ -533,14 +535,15 @@ const resources = {
|
|||||||
"share-conversation": "Поделиться разговором",
|
"share-conversation": "Поделиться разговором",
|
||||||
description: "Поделитесь этим разговором с другими: ",
|
description: "Поделитесь этим разговором с другими: ",
|
||||||
"copy-link": "Скопировать ссылку",
|
"copy-link": "Скопировать ссылку",
|
||||||
"view": "Посмотреть",
|
view: "Посмотреть",
|
||||||
success: "Поделиться успешно",
|
success: "Поделиться успешно",
|
||||||
failed: "Поделиться не удалось",
|
failed: "Поделиться не удалось",
|
||||||
copied: "Скопировано",
|
copied: "Скопировано",
|
||||||
"copied-description": "Ссылка скопирована в буфер обмена",
|
"copied-description": "Ссылка скопирована в буфер обмена",
|
||||||
"not-found": "Разговор не найден",
|
"not-found": "Разговор не найден",
|
||||||
"not-found-description": "Разговор не найден, пожалуйста, проверьте, правильная ли ссылка или разговор был удален",
|
"not-found-description":
|
||||||
}
|
"Разговор не найден, пожалуйста, проверьте, правильная ли ссылка или разговор был удален",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -27,7 +27,7 @@ const router = createBrowserRouter([
|
|||||||
id: "share",
|
id: "share",
|
||||||
path: "/share/:hash",
|
path: "/share/:hash",
|
||||||
Component: Sharing,
|
Component: Sharing,
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
export default router;
|
export default router;
|
||||||
|
@ -4,7 +4,8 @@ import { Input } from "../components/ui/input.tsx";
|
|||||||
import { Toggle } from "../components/ui/toggle.tsx";
|
import { Toggle } from "../components/ui/toggle.tsx";
|
||||||
import {
|
import {
|
||||||
ChevronDown,
|
ChevronDown,
|
||||||
ChevronRight, Copy,
|
ChevronRight,
|
||||||
|
Copy,
|
||||||
FolderKanban,
|
FolderKanban,
|
||||||
Globe,
|
Globe,
|
||||||
LogIn,
|
LogIn,
|
||||||
@ -35,7 +36,8 @@ import {
|
|||||||
formatMessage,
|
formatMessage,
|
||||||
mobile,
|
mobile,
|
||||||
useAnimation,
|
useAnimation,
|
||||||
useEffectAsync, copyClipboard,
|
useEffectAsync,
|
||||||
|
copyClipboard,
|
||||||
} from "../utils.ts";
|
} from "../utils.ts";
|
||||||
import { toast, useToast } from "../components/ui/use-toast.ts";
|
import { toast, useToast } from "../components/ui/use-toast.ts";
|
||||||
import { ConversationInstance, Message } from "../conversation/types.ts";
|
import { ConversationInstance, Message } from "../conversation/types.ts";
|
||||||
@ -74,11 +76,10 @@ function SideBar() {
|
|||||||
const open = useSelector((state: RootState) => state.menu.open);
|
const open = useSelector((state: RootState) => state.menu.open);
|
||||||
const auth = useSelector(selectAuthenticated);
|
const auth = useSelector(selectAuthenticated);
|
||||||
const current = useSelector(selectCurrent);
|
const current = useSelector(selectCurrent);
|
||||||
const [operateConversation, setOperateConversation] =
|
const [operateConversation, setOperateConversation] = useState<{
|
||||||
useState<{
|
target: ConversationInstance | null;
|
||||||
target: ConversationInstance | null;
|
type: string;
|
||||||
type: string;
|
}>({ target: null, type: "" });
|
||||||
}>({ target: null, type: "" });
|
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
const history: ConversationInstance[] = useSelector(selectHistory);
|
const history: ConversationInstance[] = useSelector(selectHistory);
|
||||||
const refresh = useRef(null);
|
const refresh = useRef(null);
|
||||||
@ -140,7 +141,10 @@ function SideBar() {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<AlertDialog
|
<AlertDialog
|
||||||
open={operateConversation.type === "delete" && !!operateConversation.target}
|
open={
|
||||||
|
operateConversation.type === "delete" &&
|
||||||
|
!!operateConversation.target
|
||||||
|
}
|
||||||
onOpenChange={(open) => {
|
onOpenChange={(open) => {
|
||||||
if (!open) setOperateConversation({ target: null, type: "" });
|
if (!open) setOperateConversation({ target: null, type: "" });
|
||||||
}}
|
}}
|
||||||
@ -194,16 +198,17 @@ function SideBar() {
|
|||||||
</AlertDialog>
|
</AlertDialog>
|
||||||
|
|
||||||
<AlertDialog
|
<AlertDialog
|
||||||
open={operateConversation.type === "share" && !!operateConversation.target}
|
open={
|
||||||
|
operateConversation.type === "share" &&
|
||||||
|
!!operateConversation.target
|
||||||
|
}
|
||||||
onOpenChange={(open) => {
|
onOpenChange={(open) => {
|
||||||
if (!open) setOperateConversation({ target: null, type: "" });
|
if (!open) setOperateConversation({ target: null, type: "" });
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<AlertDialogContent>
|
<AlertDialogContent>
|
||||||
<AlertDialogHeader>
|
<AlertDialogHeader>
|
||||||
<AlertDialogTitle>
|
<AlertDialogTitle>{t("share.title")}</AlertDialogTitle>
|
||||||
{t("share.title")}
|
|
||||||
</AlertDialogTitle>
|
|
||||||
<AlertDialogDescription>
|
<AlertDialogDescription>
|
||||||
{t("share.description")}
|
{t("share.description")}
|
||||||
<strong className={`conversation-name`}>
|
<strong className={`conversation-name`}>
|
||||||
@ -223,9 +228,13 @@ function SideBar() {
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
|
||||||
const resp = await shareConversation(operateConversation?.target?.id || -1);
|
const resp = await shareConversation(
|
||||||
if (resp.status) setShared(`${location.origin}/share/${resp.data}`);
|
operateConversation?.target?.id || -1,
|
||||||
else toast({
|
);
|
||||||
|
if (resp.status)
|
||||||
|
setShared(`${location.origin}/share/${resp.data}`);
|
||||||
|
else
|
||||||
|
toast({
|
||||||
title: t("share.failed"),
|
title: t("share.failed"),
|
||||||
description: resp.message,
|
description: resp.message,
|
||||||
});
|
});
|
||||||
@ -250,19 +259,21 @@ function SideBar() {
|
|||||||
>
|
>
|
||||||
<AlertDialogContent>
|
<AlertDialogContent>
|
||||||
<AlertDialogHeader>
|
<AlertDialogHeader>
|
||||||
<AlertDialogTitle>
|
<AlertDialogTitle>{t("share.success")}</AlertDialogTitle>
|
||||||
{t("share.success")}
|
|
||||||
</AlertDialogTitle>
|
|
||||||
<AlertDialogDescription>
|
<AlertDialogDescription>
|
||||||
<div className={`share-wrapper mt-4 mb-2`}>
|
<div className={`share-wrapper mt-4 mb-2`}>
|
||||||
<Input value={shared} />
|
<Input value={shared} />
|
||||||
<Button variant={`default`} size={`icon`} onClick={async () => {
|
<Button
|
||||||
await copyClipboard(shared);
|
variant={`default`}
|
||||||
toast({
|
size={`icon`}
|
||||||
title: t("share.copied"),
|
onClick={async () => {
|
||||||
description: t("share.copied-description"),
|
await copyClipboard(shared);
|
||||||
});
|
toast({
|
||||||
}}>
|
title: t("share.copied"),
|
||||||
|
description: t("share.copied-description"),
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
<Copy className={`h-4 w-4`} />
|
<Copy className={`h-4 w-4`} />
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,25 +1,33 @@
|
|||||||
import "../assets/sharing.less";
|
import "../assets/sharing.less";
|
||||||
import {useParams} from "react-router-dom";
|
import { useParams } from "react-router-dom";
|
||||||
import {viewConversation, ViewData, ViewForm} from "../conversation/sharing.ts";
|
import {
|
||||||
import {copyClipboard, saveAsFile, useEffectAsync} from "../utils.ts";
|
viewConversation,
|
||||||
import {useState} from "react";
|
ViewData,
|
||||||
import {Copy, File, HelpCircle, Loader2, MessagesSquare} from "lucide-react";
|
ViewForm,
|
||||||
import {useTranslation} from "react-i18next";
|
} from "../conversation/sharing.ts";
|
||||||
|
import { copyClipboard, saveAsFile, useEffectAsync } from "../utils.ts";
|
||||||
|
import { useState } from "react";
|
||||||
|
import { Copy, File, HelpCircle, Loader2, MessagesSquare } from "lucide-react";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
import MessageSegment from "../components/Message.tsx";
|
import MessageSegment from "../components/Message.tsx";
|
||||||
import {Button} from "../components/ui/button.tsx";
|
import { Button } from "../components/ui/button.tsx";
|
||||||
import router from "../router.ts";
|
import router from "../router.ts";
|
||||||
import {useToast} from "../components/ui/use-toast.ts";
|
import { useToast } from "../components/ui/use-toast.ts";
|
||||||
|
import { event } from "../events/sharing.ts";
|
||||||
|
import { Message } from "../conversation/types.ts";
|
||||||
|
|
||||||
type SharingFormProps = {
|
type SharingFormProps = {
|
||||||
refer?: string;
|
refer?: string;
|
||||||
data: ViewData | null;
|
data: ViewData | null;
|
||||||
}
|
};
|
||||||
|
|
||||||
function SharingForm({ refer, data }: SharingFormProps) {
|
function SharingForm({ refer, data }: SharingFormProps) {
|
||||||
if (data === null) return null;
|
if (data === null) return null;
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const date = new Date(data.time);
|
const date = new Date(data.time);
|
||||||
const time = `${date.getMonth() + 1}-${date.getDate()} ${date.getHours()}:${date.getMinutes()}`;
|
const time = `${
|
||||||
|
date.getMonth() + 1
|
||||||
|
}-${date.getDate()} ${date.getHours()}:${date.getMinutes()}`;
|
||||||
const value = JSON.stringify(data, null, 2);
|
const value = JSON.stringify(data, null, 2);
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
|
|
||||||
@ -27,43 +35,56 @@ function SharingForm({ refer, data }: SharingFormProps) {
|
|||||||
<div className={`sharing-container`}>
|
<div className={`sharing-container`}>
|
||||||
<div className={`header`}>
|
<div className={`header`}>
|
||||||
<div className={`user`}>
|
<div className={`user`}>
|
||||||
<img src={`https://api.deeptrain.net/avatar/${data.username}`} alt="" />
|
<img
|
||||||
|
src={`https://api.deeptrain.net/avatar/${data.username}`}
|
||||||
|
alt=""
|
||||||
|
/>
|
||||||
<span>{data.username}</span>
|
<span>{data.username}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className={`name`}>{data.name}</div>
|
<div className={`name`}>{data.name}</div>
|
||||||
<div className={`time`}>{time}</div>
|
<div className={`time`}>{time}</div>
|
||||||
</div>
|
</div>
|
||||||
<div className={`body`}>
|
<div className={`body`}>
|
||||||
{
|
{data.messages.map((message, i) => (
|
||||||
data.messages.map((message, i) => (
|
<MessageSegment message={message} key={i} />
|
||||||
<MessageSegment message={message} key={i} />
|
))}
|
||||||
))
|
|
||||||
}
|
|
||||||
</div>
|
</div>
|
||||||
<div className={`action`}>
|
<div className={`action`}>
|
||||||
<Button variant={`outline`} onClick={async () => {
|
<Button
|
||||||
await copyClipboard(value);
|
variant={`outline`}
|
||||||
toast({
|
onClick={async () => {
|
||||||
title: t('share.copied'),
|
await copyClipboard(value);
|
||||||
});
|
toast({
|
||||||
}}>
|
title: t("share.copied"),
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
<Copy className={`h-4 w-4 mr-2`} />
|
<Copy className={`h-4 w-4 mr-2`} />
|
||||||
{t('message.copy')}
|
{t("message.copy")}
|
||||||
</Button>
|
</Button>
|
||||||
<Button variant={`outline`} onClick={() => saveAsFile("conversation.json", value)}>
|
<Button
|
||||||
|
variant={`outline`}
|
||||||
|
onClick={() => saveAsFile("conversation.json", value)}
|
||||||
|
>
|
||||||
<File className={`h-4 w-4 mr-2`} />
|
<File className={`h-4 w-4 mr-2`} />
|
||||||
{t('message.save')}
|
{t("message.save")}
|
||||||
</Button>
|
</Button>
|
||||||
<Button variant={`outline`} onClick={async () => {
|
<Button
|
||||||
refer && sessionStorage.setItem('refer', refer);
|
variant={`outline`}
|
||||||
await router.navigate('/');
|
onClick={async () => {
|
||||||
}}>
|
event.emit({
|
||||||
|
refer: refer as string,
|
||||||
|
data: data?.messages as Message[],
|
||||||
|
});
|
||||||
|
await router.navigate("/");
|
||||||
|
}}
|
||||||
|
>
|
||||||
<MessagesSquare className={`h-4 w-4 mr-2`} />
|
<MessagesSquare className={`h-4 w-4 mr-2`} />
|
||||||
{t('message.use')}
|
{t("message.use")}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function Sharing() {
|
function Sharing() {
|
||||||
@ -84,25 +105,21 @@ function Sharing() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`sharing-page`}>
|
<div className={`sharing-page`}>
|
||||||
{
|
{data === null ? (
|
||||||
data === null ? (
|
<div className={`loading`}>
|
||||||
<div className={`loading`}>
|
<Loader2 className={`loader w-12 h-12`} />
|
||||||
<Loader2 className={`loader w-12 h-12`} />
|
</div>
|
||||||
</div>
|
) : data.status ? (
|
||||||
) : (
|
<SharingForm refer={hash} data={data.data} />
|
||||||
data.status ? (
|
) : (
|
||||||
<SharingForm refer={hash} data={data.data} />
|
<div className={`error-container`}>
|
||||||
) : (
|
<HelpCircle className={`w-12 h-12 mb-2.5`} />
|
||||||
<div className={`error-container`}>
|
<p className={`title`}>{t("share.not-found")}</p>
|
||||||
<HelpCircle className={`w-12 h-12 mb-2.5`} />
|
<p className={`description`}>{t("share.not-found-description")}</p>
|
||||||
<p className={`title`}>{t('share.not-found')}</p>
|
</div>
|
||||||
<p className={`description`}>{t('share.not-found-description')}</p>
|
)}
|
||||||
</div>
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Sharing;
|
export default Sharing;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { createSlice } from "@reduxjs/toolkit";
|
import { createSlice } from "@reduxjs/toolkit";
|
||||||
import { getKey } from "../conversation/addition.ts";
|
import { getKey } from "../conversation/addition.ts";
|
||||||
import { AppDispatch } from "./index.ts";
|
import { AppDispatch, RootState } from "./index.ts";
|
||||||
|
|
||||||
export const apiSlice = createSlice({
|
export const apiSlice = createSlice({
|
||||||
name: "api",
|
name: "api",
|
||||||
@ -31,8 +31,8 @@ export const { toggleDialog, setDialog, openDialog, closeDialog, setKey } =
|
|||||||
apiSlice.actions;
|
apiSlice.actions;
|
||||||
export default apiSlice.reducer;
|
export default apiSlice.reducer;
|
||||||
|
|
||||||
export const dialogSelector = (state: any): boolean => state.api.dialog;
|
export const dialogSelector = (state: RootState): boolean => state.api.dialog;
|
||||||
export const keySelector = (state: any): string => state.api.key;
|
export const keySelector = (state: RootState): string => state.api.key;
|
||||||
|
|
||||||
export const getApiKey = async (dispatch: AppDispatch) => {
|
export const getApiKey = async (dispatch: AppDispatch) => {
|
||||||
const response = await getKey();
|
const response = await getKey();
|
||||||
|
3
main.go
3
main.go
@ -1,7 +1,6 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"chat/adapter/chatgpt"
|
|
||||||
"chat/addition"
|
"chat/addition"
|
||||||
"chat/auth"
|
"chat/auth"
|
||||||
"chat/manager"
|
"chat/manager"
|
||||||
@ -22,8 +21,6 @@ func main() {
|
|||||||
app := gin.Default()
|
app := gin.Default()
|
||||||
middleware.RegisterMiddleware(app)
|
middleware.RegisterMiddleware(app)
|
||||||
|
|
||||||
fmt.Println(chatgpt.FilterKeys("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|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|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|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|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|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|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|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|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|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|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"))
|
|
||||||
return
|
|
||||||
{
|
{
|
||||||
auth.Register(app)
|
auth.Register(app)
|
||||||
manager.Register(app)
|
manager.Register(app)
|
||||||
|
Loading…
Reference in New Issue
Block a user