From 23cfca6ea40e300ffe7a023521ab8a3ed70e419b Mon Sep 17 00:00:00 2001 From: situ Date: Sun, 28 May 2023 22:02:22 +0800 Subject: [PATCH] Add chatgpt chat person set magisk --- .gitignore | 1 + src/app/bots/chatgpt-api/index.ts | 11 +- src/app/components/Chat/ChatMessageInput.tsx | 17 +- src/app/components/PromptLibrary/Dialog.tsx | 23 +- src/app/components/PromptLibrary/Library.tsx | 225 ++++++++++++++++++- src/app/i18n.ts | 4 + src/services/magisk.ts | 60 +++++ 7 files changed, 332 insertions(+), 9 deletions(-) create mode 100644 src/services/magisk.ts diff --git a/.gitignore b/.gitignore index 50c8dda2..7f3a8b42 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,4 @@ dist-ssr *.sw? .env +.lh* diff --git a/src/app/bots/chatgpt-api/index.ts b/src/app/bots/chatgpt-api/index.ts index 030c3516..43bff4c3 100644 --- a/src/app/bots/chatgpt-api/index.ts +++ b/src/app/bots/chatgpt-api/index.ts @@ -4,19 +4,26 @@ import { parseSSEResponse } from '~utils/sse' import { AbstractBot, SendMessageParams } from '../abstract-bot' import { CHATGPT_SYSTEM_MESSAGE, ChatMessage } from './consts' import { updateTokenUsage } from './usage' +import { loadUsedMagisk } from '~services/magisk' + interface ConversationContext { messages: ChatMessage[] } -const SYSTEM_MESSAGE: ChatMessage = { role: 'system', content: CHATGPT_SYSTEM_MESSAGE } +const getChatGptSystemMessage = () => { + const magiskInfo = loadUsedMagisk() + const magisk = magiskInfo.magisk ?? CHATGPT_SYSTEM_MESSAGE + return magisk +} const CONTEXT_SIZE = 10 export class ChatGPTApiBot extends AbstractBot { private conversationContext?: ConversationContext buildMessages(): ChatMessage[] { - return [SYSTEM_MESSAGE, ...this.conversationContext!.messages.slice(-(CONTEXT_SIZE + 1))] + const systemMessage: ChatMessage = { role: 'system', content: getChatGptSystemMessage() } + return [systemMessage, ...this.conversationContext!.messages.slice(-(CONTEXT_SIZE + 1))] } async fetchAzureCompletionApi(userConfig: UserConfig, signal?: AbortSignal) { diff --git a/src/app/components/Chat/ChatMessageInput.tsx b/src/app/components/Chat/ChatMessageInput.tsx index 5773fc3a..a9f46dea 100644 --- a/src/app/components/Chat/ChatMessageInput.tsx +++ b/src/app/components/Chat/ChatMessageInput.tsx @@ -15,11 +15,12 @@ import cx from 'classnames' import { FC, memo, ReactNode, useCallback, useEffect, useMemo, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' import { GoBook } from 'react-icons/go' +import { SiMagisk } from 'react-icons/si' import { trackEvent } from '~app/plausible' import { Prompt } from '~services/prompts' import Button from '../Button' import PromptCombobox, { ComboboxContext } from '../PromptCombobox' -import PromptLibraryDialog from '../PromptLibrary/Dialog' +import { PromptLibraryDialog, MagiskLibraryDialog} from '../PromptLibrary/Dialog' import TextInput from './TextInput' interface Props { @@ -40,6 +41,7 @@ const ChatMessageInput: FC = (props) => { const formRef = useRef(null) const inputRef = useRef(null) const [isPromptLibraryDialogOpen, setIsPromptLibraryDialogOpen] = useState(false) + const [isMagiskLibraryDialogOpen, setIsMagiskLibraryDialogOpen] = useState(false) const [activeIndex, setActiveIndex] = useState(null) const [isComboboxOpen, setIsComboboxOpen] = useState(false) @@ -136,6 +138,11 @@ const ChatMessageInput: FC = (props) => { trackEvent('open_prompt_library') }, []) + const openMagiskLibrary = useCallback(() => { + setIsMagiskLibraryDialogOpen(true) + trackEvent('open_magisk_library') + }, []) + return (
{props.mode === 'full' && ( @@ -148,6 +155,14 @@ const ChatMessageInput: FC = (props) => { insertPrompt={insertTextAtCursor} /> )} + + {isMagiskLibraryDialogOpen && ( + setIsMagiskLibraryDialogOpen(false)} + insertMagisk={insertTextAtCursor} + /> + )} {isComboboxOpen && ( diff --git a/src/app/components/PromptLibrary/Dialog.tsx b/src/app/components/PromptLibrary/Dialog.tsx index 7b488423..a389494a 100644 --- a/src/app/components/PromptLibrary/Dialog.tsx +++ b/src/app/components/PromptLibrary/Dialog.tsx @@ -1,13 +1,17 @@ -import PromptLibrary from './Library' +import PromptLibrary, { MagiskLibrary } from './Library' import Dialog from '../Dialog' -interface Props { +interface PromptProps { isOpen: boolean onClose: () => void insertPrompt: (text: string) => void } - -const PromptLibraryDialog = (props: Props) => { +interface MagiskProps { + isOpen: boolean + onClose: () => void + insertMagisk: (text: string) => void +} +export const PromptLibraryDialog = (props: PromptProps) => { return (
@@ -17,4 +21,13 @@ const PromptLibraryDialog = (props: Props) => { ) } -export default PromptLibraryDialog +export const MagiskLibraryDialog = (props: MagiskProps) => { + return ( + +
+ +
+
+ ) +} + diff --git a/src/app/components/PromptLibrary/Library.tsx b/src/app/components/PromptLibrary/Library.tsx index ced85803..fae55d2b 100644 --- a/src/app/components/PromptLibrary/Library.tsx +++ b/src/app/components/PromptLibrary/Library.tsx @@ -5,6 +5,7 @@ import useSWR from 'swr' import closeIcon from '~/assets/icons/close.svg' import { trackEvent } from '~app/plausible' import { Prompt, loadLocalPrompts, loadRemotePrompts, removeLocalPrompt, saveLocalPrompt } from '~services/prompts' +import { Magisk, loadUsedMagisk, useMagisk, loadLocalMagiskList, loadRemoteMagiskList, removeLocalMagisk, saveLocalMagisk } from '~services/magisk' import { uuid } from '~utils' import Button from '../Button' import { Input, Textarea } from '../Input' @@ -231,4 +232,226 @@ const PromptLibrary = (props: { insertPrompt: (text: string) => void }) => { ) } -export default PromptLibrary +const MagiskItem = (props: { + id: string + title: string + magisk: string + edit?: () => void + remove?: () => void + copyToLocal?: () => void + setUseMagisk: (magisk: Magisk) => void +}) => { + const { t } = useTranslation() + const [saved, setSaved] = useState(false) + const usedMagiskQuery = useSWR('used-magisk', () => loadUsedMagisk(), { suspense: true }) + const copyToLocal = useCallback(() => { + props.copyToLocal?.() + setSaved(true) + }, [props]) + const emptyMagisk = { + id: '', + title: '', + magisk: '' + } + return ( +
+
+

{props.title}

+
+
+ {props.edit && } + {props.copyToLocal && } + {!props.copyToLocal && !(usedMagiskQuery.data.id === props.id) && {props.setUseMagisk(props)}} />} + {!props.copyToLocal && (usedMagiskQuery.data.id === props.id) && {props.setUseMagisk(emptyMagisk)}} />} +
+ {props.remove && ( + + )} +
+ ) +} + +function MagiskForm(props: { initialData: Magisk; onSubmit: (data: Magisk) => void }) { + const { t } = useTranslation() + const onSubmit = useCallback( + (e: React.FormEvent) => { + e.preventDefault() + e.stopPropagation() + const formdata = new FormData(e.currentTarget) + + const json = Object.fromEntries(formdata.entries()) + + if (json.title && json.magisk) { + props.onSubmit({ + id: props.initialData.id, + title: json.title as string, + magisk: json.magisk as string, + }) + } + }, + [props], + ) + return ( + +
+ Magisk {t('Title')} + +
+
+ Magisk {t('Content')} +