From e7df154f843cde2447f9b55b0b77794fc7350593 Mon Sep 17 00:00:00 2001 From: an-lee Date: Mon, 8 Apr 2024 16:42:41 +0800 Subject: [PATCH] Feat: share GPT (#502) * may share GPT * add ai assistant from shared gpt --- enjoy/src/i18n/en.json | 4 + enjoy/src/i18n/zh-CN.json | 4 + .../conversations/conversation-form.tsx | 589 ++++++++++-------- .../components/posts/post-actions.tsx | 42 ++ .../renderer/components/posts/post-card.tsx | 21 +- enjoy/src/renderer/pages/conversation.tsx | 4 +- enjoy/src/renderer/pages/conversations.tsx | 20 +- enjoy/src/types/post.d.ts | 2 +- 8 files changed, 426 insertions(+), 260 deletions(-) diff --git a/enjoy/src/i18n/en.json b/enjoy/src/i18n/en.json index b46c7331..4e315ede 100644 --- a/enjoy/src/i18n/en.json +++ b/enjoy/src/i18n/en.json @@ -454,6 +454,10 @@ "shareStory": "Share story", "sharedStory": "Shared a story", "areYouSureToShareThisStoryToCommunity": "Are you sure to share this story to community?", + "shareGpt": "Share GPT", + "sharedGpt": "Shared a GPT", + "areYouSureToShareThisGptToCommunity": "Are you sure to share this GPT to community?", + "saveAiAssistant": "Save this AI assistant", "addToLibary": "Add to library", "areYouSureToAddThisVideoToYourLibrary": "Are you sure to add this video to library?", "areYouSureToAddThisAudioToYourLibrary": "Are you sure to add this audio to library?", diff --git a/enjoy/src/i18n/zh-CN.json b/enjoy/src/i18n/zh-CN.json index e6cf0699..45d5c7f7 100644 --- a/enjoy/src/i18n/zh-CN.json +++ b/enjoy/src/i18n/zh-CN.json @@ -453,6 +453,10 @@ "shareStory": "分享文章", "sharedStory": "分享了一篇文章", "areYouSureToShareThisStoryToCommunity": "您确定要分享此文章到社区吗?", + "shareGpt": "分享智能助手", + "sharedGpt": "分享了一个智能助手", + "areYouSureToShareThisGptToCommunity": "您确定要将这个智能助手分享到社区吗?", + "saveAiAssistant": "保存智能助手", "addToLibary": "添加到资源库", "areYouSureToAddThisVideoToYourLibrary": "您确定要添加此视频到资料库吗?", "areYouSureToAddThisAudioToYourLibrary": "您确定要添加此音频到资料库吗?", diff --git a/enjoy/src/renderer/components/conversations/conversation-form.tsx b/enjoy/src/renderer/components/conversations/conversation-form.tsx index 0c00bfac..3d46dc68 100644 --- a/enjoy/src/renderer/components/conversations/conversation-form.tsx +++ b/enjoy/src/renderer/components/conversations/conversation-form.tsx @@ -28,13 +28,14 @@ import { SelectContent, SelectItem, Textarea, + toast, } from "@renderer/components/ui"; import { useState, useEffect, useContext } from "react"; import { AppSettingsProviderContext, AISettingsProviderContext, } from "@renderer/context"; -import { LoaderIcon } from "lucide-react"; +import { LoaderIcon, Share2Icon } from "lucide-react"; import { useNavigate } from "react-router-dom"; const conversationFormSchema = z.object({ @@ -125,20 +126,20 @@ export const ConversationForm = (props: { // @ts-ignore values: conversation?.id ? { - name: conversation.name, - engine: conversation.engine, - configuration: { - type: conversation.configuration.type || "gpt", - ...conversation.configuration, - }, - } - : { - name: defaultConfig.name, - engine: defaultConfig.engine, - configuration: { - ...defaultConfig.configuration, - }, + name: conversation.name, + engine: conversation.engine, + configuration: { + type: conversation.configuration.type || "gpt", + ...conversation.configuration, }, + } + : { + name: defaultConfig.name, + engine: defaultConfig.engine, + configuration: { + ...defaultConfig.configuration, + }, + }, }); const onSubmit = async (data: z.infer) => { @@ -203,8 +204,11 @@ export const ConversationForm = (props: { className="h-full flex flex-col pt-6" data-testid="conversation-form" > -
- {conversation.id ? t("editConversation") : t("startConversation")} +
+
+ {conversation.id ? t("editConversation") : t("startConversation")} +
+
@@ -342,160 +346,160 @@ export const ConversationForm = (props: { {LLM_PROVIDERS[form.watch("engine")]?.configurable.includes( "temperature" ) && ( - ( - - - {t("models.conversation.temperature")} - - { - field.onChange( - event.target.value - ? parseFloat(event.target.value) - : 0.0 - ); - }} - /> - - {t("models.conversation.temperatureDescription")} - - - - )} - /> - )} + ( + + + {t("models.conversation.temperature")} + + { + field.onChange( + event.target.value + ? parseFloat(event.target.value) + : 0.0 + ); + }} + /> + + {t("models.conversation.temperatureDescription")} + + + + )} + /> + )} {LLM_PROVIDERS[form.watch("engine")]?.configurable.includes( "maxTokens" ) && ( - ( - - - {t("models.conversation.maxTokens")} - - { - if (!event.target.value) return; - field.onChange(parseInt(event.target.value)); - }} - /> - - {t("models.conversation.maxTokensDescription")} - - - - )} - /> - )} + ( + + + {t("models.conversation.maxTokens")} + + { + if (!event.target.value) return; + field.onChange(parseInt(event.target.value)); + }} + /> + + {t("models.conversation.maxTokensDescription")} + + + + )} + /> + )} {LLM_PROVIDERS[form.watch("engine")]?.configurable.includes( "presencePenalty" ) && ( - ( - - - {t("models.conversation.presencePenalty")} - - { - if (!event.target.value) return; - field.onChange(parseInt(event.target.value)); - }} - /> - - {t("models.conversation.presencePenaltyDescription")} - - - - )} - /> - )} + ( + + + {t("models.conversation.presencePenalty")} + + { + if (!event.target.value) return; + field.onChange(parseInt(event.target.value)); + }} + /> + + {t("models.conversation.presencePenaltyDescription")} + + + + )} + /> + )} {LLM_PROVIDERS[form.watch("engine")]?.configurable.includes( "frequencyPenalty" ) && ( - ( - - - {t("models.conversation.frequencyPenalty")} - - { - if (!event.target.value) return; - field.onChange(parseInt(event.target.value)); - }} - /> - - {t("models.conversation.frequencyPenaltyDescription")} - - - - )} - /> - )} + ( + + + {t("models.conversation.frequencyPenalty")} + + { + if (!event.target.value) return; + field.onChange(parseInt(event.target.value)); + }} + /> + + {t("models.conversation.frequencyPenaltyDescription")} + + + + )} + /> + )} {LLM_PROVIDERS[form.watch("engine")]?.configurable.includes( "numberOfChoices" ) && ( - ( - - - {t("models.conversation.numberOfChoices")} - - { - field.onChange( - event.target.value - ? parseInt(event.target.value) - : 1.0 - ); - }} - /> - - {t("models.conversation.numberOfChoicesDescription")} - - - - )} - /> - )} + ( + + + {t("models.conversation.numberOfChoices")} + + { + field.onChange( + event.target.value + ? parseInt(event.target.value) + : 1.0 + ); + }} + /> + + {t("models.conversation.numberOfChoicesDescription")} + + + + )} + /> + )} ( - - - {t("models.conversation.baseUrl")} - - - - - )} - /> - )} + ( + + + {t("models.conversation.baseUrl")} + + + + + )} + /> + )} )} @@ -584,95 +588,95 @@ export const ConversationForm = (props: { {TTS_PROVIDERS[ form.watch("configuration.tts.engine") ]?.configurable.includes("model") && ( - ( - - {t("models.conversation.ttsModel")} - - - - )} - /> - )} + ( + + {t("models.conversation.ttsModel")} + + + + )} + /> + )} {TTS_PROVIDERS[ form.watch("configuration.tts.engine") ]?.configurable.includes("voice") && ( - ( - - {t("models.conversation.ttsVoice")} - - - - )} - /> - )} + ( + + {t("models.conversation.ttsVoice")} + + + + )} + /> + )} {TTS_PROVIDERS[ form.watch("configuration.tts.engine") ]?.configurable.includes("baseUrl") && ( - ( - - {t("models.conversation.ttsBaseUrl")} - - - - )} - /> - )} + ( + + {t("models.conversation.ttsBaseUrl")} + + + + )} + /> + )}
@@ -838,3 +842,80 @@ export const TTS_PROVIDERS: { [key: string]: any } = { configurable: ["model", "voice", "baseUrl"], }, }; + +const GPTShareButton = (props: { + conversation: Partial; +}) => { + const { conversation } = props; + const { webApi } = useContext(AppSettingsProviderContext); + const navigate = useNavigate(); + + const handleShare = () => { + const { configuration } = conversation; + delete configuration.baseUrl + delete configuration?.tts?.baseUrl + + if (!configuration.roleDefinition) { + toast.error('shareFailed'); + return; + } + + webApi + .createPost({ + metadata: { + type: "gpt", + content: { + name: conversation.name, + engine: conversation.engine, + configuration, + }, + }, + }) + .then(() => { + toast.success(t("sharedSuccessfully"), { + description: t("sharedGpt"), + action: { + label: t("view"), + onClick: () => { + navigate("/community"); + }, + }, + actionButtonStyle: { + backgroundColor: "var(--primary)", + }, + }); + }) + .catch((err) => { + toast.error(t("shareFailed"), { description: err.message }); + }); + } + + if (!conversation.id) return null; + if (conversation.type !== "gpt") return null; + + return ( + + + + + + + {t("shareGpt")} + + {t("areYouSureToShareThisGptToCommunity")} + + + + {t("cancel")} + + + + + + + ); +} \ No newline at end of file diff --git a/enjoy/src/renderer/components/posts/post-actions.tsx b/enjoy/src/renderer/components/posts/post-actions.tsx index 07069127..61ab7184 100644 --- a/enjoy/src/renderer/components/posts/post-actions.tsx +++ b/enjoy/src/renderer/components/posts/post-actions.tsx @@ -143,6 +143,7 @@ export const PostActions = (props: { post: PostType }) => { )} )} + {post.metadata?.type === "prompt" && ( { } /> )} + + {post.metadata?.type === "gpt" && ( + <> + + + + + + + )}
{aiReplies.length > 0 && } diff --git a/enjoy/src/renderer/components/posts/post-card.tsx b/enjoy/src/renderer/components/posts/post-card.tsx index 2eb499e6..493be3fb 100644 --- a/enjoy/src/renderer/components/posts/post-card.tsx +++ b/enjoy/src/renderer/components/posts/post-card.tsx @@ -12,6 +12,7 @@ import { formatDateTime } from "@renderer/lib/utils"; import { t } from "i18next"; import Markdown from "react-markdown"; import { Link } from "react-router-dom"; +import { BotIcon } from "lucide-react"; export const PostCard = (props: { post: PostType; @@ -50,12 +51,30 @@ export const PostCard = (props: {
{t("sharedPrompt")}
- + {"```prompt\n" + post.metadata.content + "\n```"} )} + {post.metadata?.type === "gpt" && ( + <> +
+ {t("sharedGpt")} +
+
+ {t('models.conversation.roleDefinition')}: +
+
+
+ + {(post.metadata.content as { [key: string]: any }).configuration?.roleDefinition} + +
+
+ + )} + {post.targetType == "Medium" && ( )} diff --git a/enjoy/src/renderer/pages/conversation.tsx b/enjoy/src/renderer/pages/conversation.tsx index efb88824..bdef866d 100644 --- a/enjoy/src/renderer/pages/conversation.tsx +++ b/enjoy/src/renderer/pages/conversation.tsx @@ -213,7 +213,7 @@ export default () => { inputRef.current.focus(); return () => { - inputRef.current?.removeEventListener("keypress", () => {}); + inputRef.current?.removeEventListener("keypress", () => { }); autosize.destroy(inputRef.current); }; }, [id, inputRef.current]); @@ -319,7 +319,7 @@ export default () => { onChange={(e) => setContent(e.target.value)} placeholder={t("pressEnterToSend")} data-testid="conversation-page-input" - className="text-base px-4 py-0 shadow-none border-none focus-visible:outline-0 focus-visible:ring-0 border-none bg-muted focus:bg-background min-h-[1rem] max-h-[70vh] scrollbar-thin scrollbar-thumb-sky-500 !overflow-x-hidden" + className="text-base px-4 py-0 shadow-none focus-visible:outline-0 focus-visible:ring-0 border-none bg-muted focus:bg-background min-h-[1rem] max-h-[70vh] scrollbar-thin scrollbar-thumb-sky-500 !overflow-x-hidden" />