2024-03-09 18:43:39 +05:30
|
|
|
import { Form, Image, Input, Modal, Tooltip, message } from "antd"
|
|
|
|
|
import { Share } from "lucide-react"
|
|
|
|
|
import { useState } from "react"
|
2024-03-23 14:44:05 +05:30
|
|
|
import type { Message } from "~/store/option"
|
2024-03-09 18:43:39 +05:30
|
|
|
import Markdown from "./Markdown"
|
|
|
|
|
import React from "react"
|
|
|
|
|
import { useMutation } from "@tanstack/react-query"
|
2024-03-23 14:44:05 +05:30
|
|
|
import { getPageShareUrl } from "~/services/ollama"
|
|
|
|
|
import { cleanUrl } from "~/libs/clean-url"
|
2024-04-05 20:28:29 +05:30
|
|
|
import { getUserId, saveWebshare } from "@/db"
|
2024-03-24 14:38:37 +05:30
|
|
|
import { useTranslation } from "react-i18next"
|
2024-08-22 10:12:03 +02:00
|
|
|
import fetcher from "@/libs/fetcher"
|
2024-03-09 18:43:39 +05:30
|
|
|
|
|
|
|
|
type Props = {
|
|
|
|
|
messages: Message[]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const reformatMessages = (messages: Message[], username: string) => {
|
|
|
|
|
return messages.map((message, idx) => {
|
|
|
|
|
return {
|
|
|
|
|
id: idx,
|
|
|
|
|
name: message.isBot ? message.name : username,
|
|
|
|
|
isBot: message.isBot,
|
|
|
|
|
message: message.message,
|
|
|
|
|
images: message.images
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export const PlaygroundMessage = (
|
|
|
|
|
props: Message & {
|
|
|
|
|
username: string
|
|
|
|
|
}
|
|
|
|
|
) => {
|
|
|
|
|
return (
|
|
|
|
|
<div className="group w-full text-gray-800 dark:text-gray-100">
|
|
|
|
|
<div className="text-base gap-4 md:gap-6 md:max-w-2xl lg:max-w-xl xl:max-w-3xl flex lg:px-0 m-auto w-full">
|
|
|
|
|
<div className="flex flex-row gap-4 md:gap-6 md:max-w-2xl lg:max-w-xl xl:max-w-3xl m-auto w-full">
|
|
|
|
|
<div className="w-8 flex flex-col relative items-end">
|
|
|
|
|
<div className="relative h-7 w-7 p-1 rounded-sm text-white flex items-center justify-center text-opacity-100r">
|
|
|
|
|
{props.isBot ? (
|
|
|
|
|
<div className="absolute h-8 w-8 rounded-full bg-gradient-to-r from-green-300 to-purple-400"></div>
|
|
|
|
|
) : (
|
|
|
|
|
<div className="absolute h-8 w-8 rounded-full from-blue-400 to-blue-600 bg-gradient-to-r"></div>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="flex w-[calc(100%-50px)] flex-col gap-3 lg:w-[calc(100%-115px)]">
|
|
|
|
|
<span className="text-xs font-bold text-gray-800 dark:text-white">
|
|
|
|
|
{props.isBot ? props.name : props.username}
|
|
|
|
|
</span>
|
|
|
|
|
|
|
|
|
|
<div className="flex flex-grow flex-col">
|
|
|
|
|
<Markdown message={props.message} />
|
|
|
|
|
</div>
|
|
|
|
|
{/* source if aviable */}
|
|
|
|
|
{props.images && props.images.length > 0 && (
|
|
|
|
|
<div className="flex md:max-w-2xl lg:max-w-xl xl:max-w-3xl mt-4 m-auto w-full">
|
|
|
|
|
{props.images
|
|
|
|
|
.filter((image) => image.length > 0)
|
|
|
|
|
.map((image, index) => (
|
|
|
|
|
<Image
|
|
|
|
|
key={index}
|
|
|
|
|
src={image}
|
|
|
|
|
alt="Uploaded Image"
|
|
|
|
|
width={180}
|
|
|
|
|
className="rounded-md relative"
|
|
|
|
|
/>
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export const ShareBtn: React.FC<Props> = ({ messages }) => {
|
2024-03-24 14:38:37 +05:30
|
|
|
const { t } = useTranslation("common")
|
2024-03-09 18:43:39 +05:30
|
|
|
const [open, setOpen] = useState(false)
|
|
|
|
|
const [form] = Form.useForm()
|
|
|
|
|
const name = Form.useWatch("name", form)
|
|
|
|
|
|
|
|
|
|
React.useEffect(() => {
|
|
|
|
|
if (messages.length > 0) {
|
|
|
|
|
form.setFieldsValue({
|
|
|
|
|
title: messages[0].message
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}, [messages])
|
|
|
|
|
|
|
|
|
|
const onSubmit = async (values: { title: string; name: string }) => {
|
|
|
|
|
const owner_id = await getUserId()
|
|
|
|
|
const chat = reformatMessages(messages, values.name)
|
|
|
|
|
const title = values.title
|
|
|
|
|
const url = await getPageShareUrl()
|
2024-08-22 10:12:03 +02:00
|
|
|
const res = await fetcher(`${cleanUrl(url)}/api/v1/share/create`, {
|
2024-03-09 18:43:39 +05:30
|
|
|
method: "POST",
|
|
|
|
|
headers: {
|
|
|
|
|
"Content-Type": "application/json"
|
|
|
|
|
},
|
|
|
|
|
body: JSON.stringify({
|
|
|
|
|
owner_id,
|
|
|
|
|
messages: chat,
|
|
|
|
|
title
|
|
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
|
2024-03-24 14:38:37 +05:30
|
|
|
if (!res.ok) throw new Error(t("share.notification.failGenerate"))
|
2024-03-09 18:43:39 +05:30
|
|
|
|
|
|
|
|
const data = await res.json()
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
...data,
|
|
|
|
|
url: `${cleanUrl(url)}/share/${data.chat_id}`,
|
|
|
|
|
api_url: cleanUrl(url),
|
|
|
|
|
share_id: data.chat_id
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const { mutate: createShareLink, isPending } = useMutation({
|
|
|
|
|
mutationFn: onSubmit,
|
|
|
|
|
onSuccess: async (data) => {
|
|
|
|
|
const url = data.url
|
|
|
|
|
navigator.clipboard.writeText(url)
|
2024-03-24 14:38:37 +05:30
|
|
|
message.success(t("share.notification.successGenerate"))
|
|
|
|
|
await saveWebshare({
|
|
|
|
|
title: data.title,
|
|
|
|
|
url,
|
|
|
|
|
api_url: data.api_url,
|
|
|
|
|
share_id: data.share_id
|
|
|
|
|
})
|
2024-03-09 18:43:39 +05:30
|
|
|
setOpen(false)
|
|
|
|
|
},
|
|
|
|
|
onError: (error) => {
|
2024-03-24 14:38:37 +05:30
|
|
|
message.error(error?.message || t("share.notification.failGenerate"))
|
2024-03-09 18:43:39 +05:30
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<>
|
2024-03-24 14:38:37 +05:30
|
|
|
<Tooltip title={t("share.tooltip.share")}>
|
2024-03-09 18:43:39 +05:30
|
|
|
<button
|
|
|
|
|
onClick={() => setOpen(true)}
|
|
|
|
|
className="!text-gray-500 dark:text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 transition-colors">
|
|
|
|
|
<Share className="w-6 h-6" />
|
|
|
|
|
</button>
|
|
|
|
|
</Tooltip>
|
|
|
|
|
|
|
|
|
|
<Modal
|
2024-03-24 14:38:37 +05:30
|
|
|
title={t("share.modal.title")}
|
2024-03-09 18:43:39 +05:30
|
|
|
open={open}
|
|
|
|
|
footer={null}
|
|
|
|
|
width={600}
|
|
|
|
|
onCancel={() => setOpen(false)}>
|
|
|
|
|
<Form
|
|
|
|
|
form={form}
|
|
|
|
|
layout="vertical"
|
|
|
|
|
onFinish={createShareLink}
|
|
|
|
|
initialValues={{
|
2024-03-24 14:38:37 +05:30
|
|
|
title: t("share.form.defaultValue.title"),
|
|
|
|
|
name: t("share.form.defaultValue.name")
|
2024-03-09 18:43:39 +05:30
|
|
|
}}>
|
|
|
|
|
<Form.Item
|
|
|
|
|
name="title"
|
2024-03-24 14:38:37 +05:30
|
|
|
label={t("share.form.title.label")}
|
|
|
|
|
rules={[
|
|
|
|
|
{ required: true, message: t("share.form.title.required") }
|
|
|
|
|
]}>
|
|
|
|
|
<Input
|
|
|
|
|
size="large"
|
|
|
|
|
placeholder={t("share.form.title.placeholder")}
|
|
|
|
|
/>
|
2024-03-09 18:43:39 +05:30
|
|
|
</Form.Item>
|
|
|
|
|
<Form.Item
|
|
|
|
|
name="name"
|
2024-03-24 14:38:37 +05:30
|
|
|
label={t("share.form.name.label")}
|
|
|
|
|
rules={[
|
|
|
|
|
{ required: true, message: t("share.form.name.required") }
|
|
|
|
|
]}>
|
|
|
|
|
<Input
|
|
|
|
|
size="large"
|
|
|
|
|
placeholder={t("share.form.name.placeholder")}
|
|
|
|
|
/>
|
2024-03-09 18:43:39 +05:30
|
|
|
</Form.Item>
|
|
|
|
|
|
|
|
|
|
<Form.Item>
|
|
|
|
|
<div className="max-h-[180px] overflow-x-auto border dark:border-gray-700 rounded-md p-2">
|
|
|
|
|
<div className="flex flex-col p-3">
|
|
|
|
|
{messages.map((message, index) => (
|
|
|
|
|
<PlaygroundMessage key={index} {...message} username={name} />
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</Form.Item>
|
|
|
|
|
|
|
|
|
|
<Form.Item>
|
|
|
|
|
<div className="flex justify-end">
|
|
|
|
|
<button
|
|
|
|
|
type="submit"
|
|
|
|
|
className="inline-flex items-center rounded-md border border-transparent bg-black px-2 py-2.5 text-md font-medium leading-4 text-white shadow-sm dark:bg-white dark:text-gray-800 disabled:opacity-50 ">
|
2024-03-24 14:38:37 +05:30
|
|
|
{isPending
|
|
|
|
|
? t("share.form.btn.saving")
|
|
|
|
|
: t("share.form.btn.save")}
|
2024-03-09 18:43:39 +05:30
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
</Form.Item>
|
|
|
|
|
</Form>
|
|
|
|
|
</Modal>
|
|
|
|
|
</>
|
|
|
|
|
)
|
|
|
|
|
}
|