From 3170bc4be6c1ef5ba00bc6f93d0cac8b10dbea75 Mon Sep 17 00:00:00 2001 From: n4ze3m Date: Tue, 14 May 2024 12:44:37 +0530 Subject: [PATCH 01/12] chore: Update shareMode default value to false --- README.md | 8 +++++++- src/components/Layouts/Layout.tsx | 2 +- src/components/Option/Share/index.tsx | 13 ++++++++++--- wxt.config.ts | 2 +- 4 files changed, 19 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index c1fdc5a..3b0e408 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,6 @@ want more features? Create an issue and let me know. You can install the extension from the [Chrome Web Store](https://chromewebstore.google.com/detail/page-assist-a-web-ui-for/jfgfiigpkhlkbnfnbobbkinehhfdhndo) -Note: You can install the extension on any Chromium-based browser. It is not limited to Chrome. ### Manual Installation @@ -126,6 +125,13 @@ This will start a development server and watch for changes in the source files. - [ ] More Customization Options - [ ] Better UI/UX + +## Privacy + +Page Assist does not collect any personal data. The only time the extension communicates with the server is when you are using the share feature, which can be disabled from the settings. + +All the data is stored locally in the browser storage. You can view the source code and verify it yourself. + ## Contributing Contributions are welcome. If you have any feature requests, bug reports, or questions, feel free to create an issue. diff --git a/src/components/Layouts/Layout.tsx b/src/components/Layouts/Layout.tsx index 03916be..0c3673a 100644 --- a/src/components/Layouts/Layout.tsx +++ b/src/components/Layouts/Layout.tsx @@ -29,7 +29,7 @@ export default function OptionLayout({ }) { const [sidebarOpen, setSidebarOpen] = useState(false) const { t } = useTranslation(["option", "common"]) - const [shareModeEnabled] = useStorage("shareMode", true) + const [shareModeEnabled] = useStorage("shareMode", false) const { selectedModel, diff --git a/src/components/Option/Share/index.tsx b/src/components/Option/Share/index.tsx index 9ab128a..cd46f72 100644 --- a/src/components/Option/Share/index.tsx +++ b/src/components/Option/Share/index.tsx @@ -11,7 +11,10 @@ import { useStorage } from "@plasmohq/storage/hook" export const OptionShareBody = () => { const queryClient = useQueryClient() const { t } = useTranslation(["settings"]) - const [shareModeEnabled, setShareModelEnabled] = useStorage("shareMode", true) + const [shareModeEnabled, setShareModelEnabled] = useStorage( + "shareMode", + false + ) const { status, data } = useQuery({ queryKey: ["fetchShareInfo"], @@ -25,8 +28,12 @@ export const OptionShareBody = () => { }) const onSubmit = async (values: { url: string }) => { - const isOk = await verifyPageShareURL(values.url) - if (isOk) { + if (shareModeEnabled) { + const isOk = await verifyPageShareURL(values.url) + if (isOk) { + await setPageShareUrl(values.url) + } + } else { await setPageShareUrl(values.url) } } diff --git a/wxt.config.ts b/wxt.config.ts index 0f5aeba..9e49dc8 100644 --- a/wxt.config.ts +++ b/wxt.config.ts @@ -48,7 +48,7 @@ export default defineConfig({ outDir: "build", manifest: { - version: "1.1.7", + version: "1.1.8", name: process.env.TARGET === "firefox" ? "Page Assist - A Web UI for Local AI Models" From a4ee6b3d7b8bf55ec6a4de75a326755b06c987d9 Mon Sep 17 00:00:00 2001 From: n4ze3m Date: Tue, 14 May 2024 12:52:39 +0530 Subject: [PATCH 02/12] chore: Update page share feature description --- src/assets/locale/en/settings.json | 2 +- src/assets/locale/ja-JP/settings.json | 2 +- src/assets/locale/ml/settings.json | 2 +- src/assets/locale/ru/settings.json | 2 +- src/assets/locale/zh/settings.json | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/assets/locale/en/settings.json b/src/assets/locale/en/settings.json index acfcfa5..de86d3d 100644 --- a/src/assets/locale/en/settings.json +++ b/src/assets/locale/en/settings.json @@ -195,7 +195,7 @@ "delete": "Are you sure you want to delete this share? This action cannot be undone." }, "label": "Manage Page Share", - "description": "Enable or disable the page share feature. By default, the page share feature is enabled." + "description": "Enable or disable the page share feature" }, "notification": { "pageShareSuccess": "Page Share URL updated successfully", diff --git a/src/assets/locale/ja-JP/settings.json b/src/assets/locale/ja-JP/settings.json index 8fd2860..c519a71 100644 --- a/src/assets/locale/ja-JP/settings.json +++ b/src/assets/locale/ja-JP/settings.json @@ -198,7 +198,7 @@ "delete": "本当にこの共有を削除しますか?この操作は元に戻せません。" }, "label": "ページ共有を管理する", - "description": "ページ共有機能を有効または無効にします。デフォルトでは、ページ共有機能は有効になっています。" + "description": "ページ共有機能を有効または無効にする" }, "notification": { "pageShareSuccess": "ページ共有URLが正常に更新されました", diff --git a/src/assets/locale/ml/settings.json b/src/assets/locale/ml/settings.json index b3384c7..937b1e3 100644 --- a/src/assets/locale/ml/settings.json +++ b/src/assets/locale/ml/settings.json @@ -198,7 +198,7 @@ "delete": "ഈ പങ്കിടല്‍ ഇല്ലാതാക്കണമെന്ന് തീർച്ചയാണോ? ഈ പ്രവർത്തനം പിന്നീട് പിൻവലിക്കാനാകില്ല." }, "label": "പേജ് ഷെയർ നിയന്ത്രിക്കുക", - "description": "പേജ് ഷെയർ സവിശേഷത സജീവമാക്കുകയോ അക്ഷമമാക്കുകയോ ചെയ്യുക. സ്ഥിരംമായി, പേജ് ഷെയർ സവിശേഷത സജീവമാക്കപ്പെടുന്നു." + "description": "പേജ് ഷെയർ സാങ്കേതികത സജ്ജീകരിക്കുക അല്ലെങ്കിൽ നിലവിളിക്കുക ." }, "notification": { "pageShareSuccess": "പേജ് പങ്കിടാനുള്ള URL വിജയകരമായി അപ്ഡേറ്റ് ചെയ്തു", diff --git a/src/assets/locale/ru/settings.json b/src/assets/locale/ru/settings.json index 51fa44e..913025f 100644 --- a/src/assets/locale/ru/settings.json +++ b/src/assets/locale/ru/settings.json @@ -195,7 +195,7 @@ "delete": "Вы уверены, что хотите удалить этот обмен? Это действие нельзя отменить." }, "label": "Управление общим доступом к странице", - "description": "Включите или отключите функцию общего доступа к странице. По умолчанию функция общего доступа к странице включена." + "description": "Включить или отключить функцию обмена страницей" }, "notification": { "pageShareSuccess": "URL обмена страницей успешно обновлен", diff --git a/src/assets/locale/zh/settings.json b/src/assets/locale/zh/settings.json index 883ae22..2cf06de 100644 --- a/src/assets/locale/zh/settings.json +++ b/src/assets/locale/zh/settings.json @@ -199,7 +199,7 @@ "delete": "您确定要删除此对话共享吗?这个操作不能撤销。" }, "label": "管理页面分享", - "description": "启用或禁用页面分享功能。默认情况下,页面分享功能已启用。" + "description": "启用或禁用页面分享功能 " }, "notification": { "pageShareSuccess": "对话共享服务 URL 已成功更新", From 0ce06752c3c027ee68e1964f5f75876b8444f805 Mon Sep 17 00:00:00 2001 From: n4ze3m Date: Tue, 14 May 2024 16:16:09 +0530 Subject: [PATCH 03/12] chore: Add description for executing action in Web UI --- wxt.config.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/wxt.config.ts b/wxt.config.ts index 9e49dc8..aa890c4 100644 --- a/wxt.config.ts +++ b/wxt.config.ts @@ -71,6 +71,7 @@ export default defineConfig({ : undefined, commands: { _execute_action: { + description: "Open the Web UI", suggested_key: { default: "Ctrl+Shift+L" } From 128bf57171404ba4e75f587bc4cfdeab5275528a Mon Sep 17 00:00:00 2001 From: vcapp Date: Tue, 14 May 2024 23:55:21 +0200 Subject: [PATCH 04/12] Fix Incorrect Method Call and Potential Race Condition in src/db/index.ts - Corrected deleteChatHistory method call to include id parameter. - Addressed potential race condition in addMessage method to handle simultaneous message additions. --- src/db/index.ts | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/db/index.ts b/src/db/index.ts index f709905..088038a 100644 --- a/src/db/index.ts +++ b/src/db/index.ts @@ -89,7 +89,7 @@ export class PageAssitDatabase { const history_id = message.history_id const chatHistory = await this.getChatHistory(history_id) const newChatHistory = [message, ...chatHistory] - this.db.set({ [history_id]: newChatHistory }) + await this.db.set({ [history_id]: newChatHistory }) } async removeChatHistory(id: string) { @@ -112,12 +112,13 @@ export class PageAssitDatabase { this.db.clear() } - async deleteChatHistory() { + async deleteChatHistory(id: string) { const chatHistories = await this.getChatHistories() - for (const history of chatHistories) { - this.db.remove(history.id) - } - this.db.remove("chatHistories") + const newChatHistories = chatHistories.filter( + (history) => history.id !== id + ) + this.db.set({ chatHistories: newChatHistories }) + this.db.remove(id) } async deleteMessage(history_id: string) { From 182f9142750d4686023395b30e28b3417281c76c Mon Sep 17 00:00:00 2001 From: n4ze3m Date: Wed, 15 May 2024 10:21:32 +0530 Subject: [PATCH 05/12] chore: Update README with blogs and videos about Page Assist --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index 95b8cb4..a3d0a3a 100644 --- a/README.md +++ b/README.md @@ -153,6 +153,15 @@ If you like the project and want to support it, you can buy me a coffee. It will or you can sponsor me on GitHub. + +## Blogs and Videos About Page Assist + +This are some of the blogs and videos about Page Assist. If you have written a blog or made a video about Page Assist, feel free to create a PR and add it here. + +- [OllamaをChromeAddonのPage Assistで簡単操作](https://note.com/lucas_san/n/nf00d01a02c3a) by [LucasChatGPT](https://twitter.com/LucasChatGPT) + +- [This Chrome Extension Surprised Me](https://www.youtube.com/watch?v=IvLTlDy9G8c) by [Matt Williams](https://www.youtube.com/@technovangelist) + ## License MIT From d6fff4bfa131c67c2cfa0531834fa01737ae15b5 Mon Sep 17 00:00:00 2001 From: n4ze3m Date: Wed, 15 May 2024 10:30:11 +0530 Subject: [PATCH 06/12] chore: Refactor deleteChatHistory method to deleteAllChatHistory --- src/components/Option/Settings/other.tsx | 2 +- src/db/index.ts | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/components/Option/Settings/other.tsx b/src/components/Option/Settings/other.tsx index e33b389..edb4349 100644 --- a/src/components/Option/Settings/other.tsx +++ b/src/components/Option/Settings/other.tsx @@ -116,7 +116,7 @@ export const SettingOther = () => { if (confirm) { const db = new PageAssitDatabase() - await db.deleteChatHistory() + await db.deleteAllChatHistory() queryClient.invalidateQueries({ queryKey: ["fetchChatHistory"] }) diff --git a/src/db/index.ts b/src/db/index.ts index 088038a..1b85d11 100644 --- a/src/db/index.ts +++ b/src/db/index.ts @@ -121,6 +121,14 @@ export class PageAssitDatabase { this.db.remove(id) } + async deleteAllChatHistory() { + const chatHistories = await this.getChatHistories() + chatHistories.forEach((history) => { + this.db.remove(history.id) + }) + this.db.set({ chatHistories: [] }) + } + async deleteMessage(history_id: string) { await this.db.remove(history_id) } @@ -456,4 +464,4 @@ export const importPrompts = async (prompts: Prompts) => { for (const prompt of prompts) { await db.addPrompt(prompt) } -} \ No newline at end of file +} From d28525ad02c41f685a6bd2e5aba90c33749c0880 Mon Sep 17 00:00:00 2001 From: n4ze3m Date: Thu, 16 May 2024 11:32:31 +0530 Subject: [PATCH 07/12] chore: Update Sidepanel UI styling and manifest configuration --- src/components/Sidepanel/Chat/body.tsx | 4 +++- src/components/Sidepanel/Chat/form.tsx | 2 +- src/entries/sidepanel/index.html | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/components/Sidepanel/Chat/body.tsx b/src/components/Sidepanel/Chat/body.tsx index d6e3684..5617970 100644 --- a/src/components/Sidepanel/Chat/body.tsx +++ b/src/components/Sidepanel/Chat/body.tsx @@ -32,7 +32,9 @@ export const SidePanelBody = () => { isTTSEnabled={ttsEnabled} /> ))} -
+ { + import.meta.env.BROWSER === "chrome" ?
:
+ }
) diff --git a/src/components/Sidepanel/Chat/form.tsx b/src/components/Sidepanel/Chat/form.tsx index 45ec340..41afbcb 100644 --- a/src/components/Sidepanel/Chat/form.tsx +++ b/src/components/Sidepanel/Chat/form.tsx @@ -117,7 +117,7 @@ export const SidepanelForm = ({ dropedFile }: Props) => { } return ( -
+
+ From 160927a5a65a861bcc1548cc04351d04a5e06732 Mon Sep 17 00:00:00 2001 From: n4ze3m Date: Sat, 18 May 2024 16:25:06 +0530 Subject: [PATCH 08/12] chore: Refactor Sidepanel Chat body and form components --- src/components/Sidepanel/Chat/body.tsx | 18 ++-- src/components/Sidepanel/Chat/form.tsx | 76 +++++++-------- src/hooks/useMessage.tsx | 130 ++++++++++++++++++++++--- 3 files changed, 163 insertions(+), 61 deletions(-) diff --git a/src/components/Sidepanel/Chat/body.tsx b/src/components/Sidepanel/Chat/body.tsx index 5617970..46daeb5 100644 --- a/src/components/Sidepanel/Chat/body.tsx +++ b/src/components/Sidepanel/Chat/body.tsx @@ -5,7 +5,8 @@ import { EmptySidePanel } from "../Chat/empty" import { useWebUI } from "@/store/webui" export const SidePanelBody = () => { - const { messages, streaming } = useMessage() + const { messages, streaming, regenerateLastMessage, editMessage } = + useMessage() const divRef = React.useRef(null) const { ttsEnabled } = useWebUI() React.useEffect(() => { @@ -18,7 +19,6 @@ export const SidePanelBody = () => { {messages.length === 0 && } {messages.map((message, index) => ( {}} key={index} isBot={message.isBot} message={message.message} @@ -26,15 +26,19 @@ export const SidePanelBody = () => { images={message.images || []} currentMessageIndex={index} totalMessages={messages.length} - onRengerate={() => {}} + onRengerate={regenerateLastMessage} + onEditFormSubmit={(value) => { + editMessage(index, value, !message.isBot) + }} isProcessing={streaming} - hideEditAndRegenerate isTTSEnabled={ttsEnabled} /> ))} - { - import.meta.env.BROWSER === "chrome" ?
:
- } + {import.meta.env.BROWSER === "chrome" ? ( +
+ ) : ( +
+ )}
) diff --git a/src/components/Sidepanel/Chat/form.tsx b/src/components/Sidepanel/Chat/form.tsx index 41afbcb..a5a0a2e 100644 --- a/src/components/Sidepanel/Chat/form.tsx +++ b/src/components/Sidepanel/Chat/form.tsx @@ -23,11 +23,6 @@ export const SidepanelForm = ({ dropedFile }: Props) => { const [typing, setTyping] = React.useState(false) const { t } = useTranslation(["playground", "common"]) - const textAreaFocus = () => { - if (textareaRef.current) { - textareaRef.current.focus() - } - } const form = useForm({ initialValues: { message: "", @@ -48,39 +43,11 @@ export const SidepanelForm = ({ dropedFile }: Props) => { } } } - - React.useEffect(() => { - if (dropedFile) { - onInputChange(dropedFile) + const textAreaFocus = () => { + if (textareaRef.current) { + textareaRef.current.focus() } - }, [dropedFile]) - - useDynamicTextareaSize(textareaRef, form.values.message, 120) - - const { - onSubmit, - selectedModel, - chatMode, - speechToTextLanguage, - stopStreamingRequest - } = useMessage() - const { isListening, start, stop, transcript } = useSpeechRecognition() - - React.useEffect(() => { - if (isListening) { - form.setFieldValue("message", transcript) - } - }, [transcript]) - const { mutateAsync: sendMessage, isPending: isSending } = useMutation({ - mutationFn: onSubmit, - onSuccess: () => { - textAreaFocus() - }, - onError: (error) => { - textAreaFocus() - } - }) - + } const handleKeyDown = (e: React.KeyboardEvent) => { if (e.key === "Process" || e.key === "229") return if ( @@ -116,6 +83,39 @@ export const SidepanelForm = ({ dropedFile }: Props) => { } } + const { + onSubmit, + selectedModel, + chatMode, + speechToTextLanguage, + stopStreamingRequest, + streaming + } = useMessage() + const { isListening, start, stop, transcript } = useSpeechRecognition() + + React.useEffect(() => { + if (dropedFile) { + onInputChange(dropedFile) + } + }, [dropedFile]) + + useDynamicTextareaSize(textareaRef, form.values.message, 120) + + React.useEffect(() => { + if (isListening) { + form.setFieldValue("message", transcript) + } + }, [transcript]) + const { mutateAsync: sendMessage, isPending: isSending } = useMutation({ + mutationFn: onSubmit, + onSuccess: () => { + textAreaFocus() + }, + onError: (error) => { + textAreaFocus() + } + }) + return (
{ - {!isSending ? ( + {!streaming ? ( { setCurrentURL(url) isAlreadyExistEmbedding = keepTrackOfEmbedding[currentURL] } else { - isAlreadyExistEmbedding = keepTrackOfEmbedding[currentURL] - embedURL = currentURL + const { content: html, url, type, pdf } = await getDataFromCurrentTab() + if (currentURL !== url) { + embedHTML = html + embedURL = url + embedType = type + embedPDF = pdf + setCurrentURL(url) + } else { + embedHTML = html + embedURL = currentURL + embedType = type + embedPDF = pdf + } + isAlreadyExistEmbedding = keepTrackOfEmbedding[url] } setMessages(newMessage) @@ -157,6 +173,7 @@ export const useMessage = () => { try { if (isAlreadyExistEmbedding) { vectorstore = isAlreadyExistEmbedding + console.log("Embedding already exist") } else { vectorstore = await memoryEmbedding({ html: embedHTML, @@ -168,6 +185,8 @@ export const useMessage = () => { type: embedType, url: embedURL }) + + console.log("Embedding created") } let query = message const { ragPrompt: systemPrompt, ragQuestionPrompt: questionPrompt } = @@ -202,7 +221,7 @@ export const useMessage = () => { url: "" } }) - // message = message.trim().replaceAll("\n", " ") + // message = message.trim().replaceAll("\n", " ") let humanMessage = new HumanMessage({ content: [ @@ -478,8 +497,6 @@ export const useMessage = () => { setIsProcessing(false) setStreaming(false) - setIsProcessing(false) - setStreaming(false) } catch (e) { const errorSave = await saveMessageOnError({ e, @@ -509,17 +526,38 @@ export const useMessage = () => { const onSubmit = async ({ message, - image + image, + isRegenerate, + controller, + memory, + messages: chatHistory }: { message: string image: string + isRegenerate?: boolean + messages?: Message[] + memory?: ChatHistory + controller?: AbortController }) => { - const newController = new AbortController() - let signal = newController.signal - setAbortController(newController) + let signal: AbortSignal + if (!controller) { + const newController = new AbortController() + signal = newController.signal + setAbortController(newController) + } else { + setAbortController(controller) + signal = controller.signal + } if (chatMode === "normal") { - await normalChatMode(message, image, false, messages, history, signal) + await normalChatMode( + message, + image, + isRegenerate, + chatHistory || messages, + memory || history, + signal + ) } else { const newEmbeddingController = new AbortController() let embeddingSignal = newEmbeddingController.signal @@ -527,9 +565,9 @@ export const useMessage = () => { await chatWithWebsiteMode( message, image, - false, - messages, - history, + isRegenerate, + chatHistory || messages, + memory || history, signal, embeddingSignal ) @@ -548,9 +586,68 @@ export const useMessage = () => { setAbortController(null) } } + + const editMessage = async ( + index: number, + message: string, + isHuman: boolean + ) => { + let newMessages = messages + let newHistory = history + + if (isHuman) { + const currentHumanMessage = newMessages[index] + newMessages[index].message = message + const previousMessages = newMessages.slice(0, index + 1) + setMessages(previousMessages) + const previousHistory = newHistory.slice(0, index) + setHistory(previousHistory) + await updateMessageByIndex(historyId, index, message) + await deleteChatForEdit(historyId, index) + const abortController = new AbortController() + await onSubmit({ + message: message, + image: currentHumanMessage.images[0] || "", + isRegenerate: true, + messages: previousMessages, + memory: previousHistory, + controller: abortController + }) + } else { + newMessages[index].message = message + setMessages(newMessages) + newHistory[index].content = message + setHistory(newHistory) + await updateMessageByIndex(historyId, index, message) + } + } + + const regenerateLastMessage = async () => { + if (history.length > 0) { + const lastMessage = history[history.length - 2] + let newHistory = history.slice(0, -2) + let mewMessages = messages + mewMessages.pop() + setHistory(newHistory) + setMessages(mewMessages) + await removeMessageUsingHistoryId(historyId) + if (lastMessage.role === "user") { + const newController = new AbortController() + await onSubmit({ + message: lastMessage.content, + image: lastMessage.image || "", + isRegenerate: true, + memory: newHistory, + controller: newController + }) + } + } + } + return { messages, setMessages, + editMessage, onSubmit, setStreaming, streaming, @@ -569,6 +666,7 @@ export const useMessage = () => { setChatMode, isEmbedding, speechToTextLanguage, - setSpeechToTextLanguage + setSpeechToTextLanguage, + regenerateLastMessage } } From e623cc5ead847672fd28d6f6b6d346d0580f416d Mon Sep 17 00:00:00 2001 From: n4ze3m Date: Sat, 18 May 2024 17:36:50 +0530 Subject: [PATCH 09/12] Update form components to handle pasted files --- src/components/Option/Playground/PlaygroundForm.tsx | 7 ++++++- src/components/Sidepanel/Chat/form.tsx | 7 +++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/components/Option/Playground/PlaygroundForm.tsx b/src/components/Option/Playground/PlaygroundForm.tsx index 64c3683..a694149 100644 --- a/src/components/Option/Playground/PlaygroundForm.tsx +++ b/src/components/Option/Playground/PlaygroundForm.tsx @@ -71,7 +71,11 @@ export const PlaygroundForm = ({ dropedFile }: Props) => { } } } - + const handlePaste = (e: React.ClipboardEvent) => { + if (e.clipboardData.files.length > 0) { + onInputChange(e.clipboardData.files[0]) + } + } React.useEffect(() => { if (dropedFile) { onInputChange(dropedFile) @@ -219,6 +223,7 @@ export const PlaygroundForm = ({ dropedFile }: Props) => { ref={textareaRef} className="px-2 py-2 w-full resize-none bg-transparent focus-within:outline-none focus:ring-0 focus-visible:ring-0 ring-0 dark:ring-0 border-0 dark:text-gray-100" required + onPaste={handlePaste} rows={1} style={{ minHeight: "60px" }} tabIndex={0} diff --git a/src/components/Sidepanel/Chat/form.tsx b/src/components/Sidepanel/Chat/form.tsx index a5a0a2e..08c0659 100644 --- a/src/components/Sidepanel/Chat/form.tsx +++ b/src/components/Sidepanel/Chat/form.tsx @@ -83,6 +83,12 @@ export const SidepanelForm = ({ dropedFile }: Props) => { } } + const handlePaste = (e: React.ClipboardEvent) => { + if (e.clipboardData.files.length > 0) { + onInputChange(e.clipboardData.files[0]) + } + } + const { onSubmit, selectedModel, @@ -178,6 +184,7 @@ export const SidepanelForm = ({ dropedFile }: Props) => { ref={textareaRef} className="px-2 py-2 w-full resize-none bg-transparent focus-within:outline-none focus:ring-0 focus-visible:ring-0 ring-0 dark:ring-0 border-0 dark:text-gray-100" required + onPaste={handlePaste} rows={1} style={{ minHeight: "60px" }} tabIndex={0} From 8662fd069384b841f9b2e69dc7f5b023c95531eb Mon Sep 17 00:00:00 2001 From: n4ze3m Date: Sat, 18 May 2024 20:54:43 +0530 Subject: [PATCH 10/12] chore: Update form components to handle pasted files --- src/components/Common/PromptSelect.tsx | 90 +++++++++++++++++++ src/components/Layouts/Layout.tsx | 25 ++++-- .../Option/Knowledge/SelectedKnwledge.tsx | 15 ++-- src/components/Option/Models/index.tsx | 6 +- 4 files changed, 123 insertions(+), 13 deletions(-) create mode 100644 src/components/Common/PromptSelect.tsx diff --git a/src/components/Common/PromptSelect.tsx b/src/components/Common/PromptSelect.tsx new file mode 100644 index 0000000..fadd8c0 --- /dev/null +++ b/src/components/Common/PromptSelect.tsx @@ -0,0 +1,90 @@ +import { useQuery } from "@tanstack/react-query" +import { Dropdown, Empty, Tooltip } from "antd" +import { BookIcon, ComputerIcon, ZapIcon } from "lucide-react" +import React from "react" +import { useTranslation } from "react-i18next" +import { getAllPrompts } from "@/db" +import { useMessageOption } from "@/hooks/useMessageOption" + +export const PromptSelect: React.FC = () => { + const { t } = useTranslation("option") + const { + selectedSystemPrompt, + setSelectedQuickPrompt, + setSelectedSystemPrompt + } = useMessageOption() + + const { data } = useQuery({ + queryKey: ["getAllPromptsForSelect"], + queryFn: getAllPrompts + }) + const handlePromptChange = (value?: string) => { + if (!value) { + setSelectedSystemPrompt(undefined) + setSelectedQuickPrompt(undefined) + return + } + const prompt = data?.find((prompt) => prompt.id === value) + if (prompt?.is_system) { + setSelectedSystemPrompt(prompt.id) + } else { + setSelectedSystemPrompt(undefined) + setSelectedQuickPrompt(prompt!.content) + } + } + return ( + <> + {data && ( + 0 + ? data?.map((prompt) => ({ + key: prompt.id, + label: ( +
+ + {prompt.is_system ? ( + + ) : ( + + )} + {prompt.title} + +
+ ), + onClick: () => { + if (selectedSystemPrompt === prompt.id) { + setSelectedSystemPrompt(undefined) + } else { + handlePromptChange(prompt.id) + } + } + })) + : [ + { + key: "empty", + label: + } + ], + style: { + maxHeight: 500, + overflowY: "scroll" + }, + className: "no-scrollbar", + activeKey: selectedSystemPrompt + }} + placement={"topLeft"} + trigger={["click"]}> + + + +
+ )} + + ) +} diff --git a/src/components/Layouts/Layout.tsx b/src/components/Layouts/Layout.tsx index 0c3673a..2156710 100644 --- a/src/components/Layouts/Layout.tsx +++ b/src/components/Layouts/Layout.tsx @@ -12,6 +12,7 @@ import { ComputerIcon, GithubIcon, PanelLeftIcon, + SlashIcon, SquarePen, ZapIcon } from "lucide-react" @@ -21,6 +22,8 @@ import { useTranslation } from "react-i18next" import { OllamaIcon } from "../Icons/Ollama" import { SelectedKnowledge } from "../Option/Knowledge/SelectedKnwledge" import { useStorage } from "@plasmohq/storage/hook" +import { ModelSelect } from "../Common/ModelSelect" +import { PromptSelect } from "../Common/PromptSelect" export default function OptionLayout({ children @@ -89,7 +92,7 @@ export default function OptionLayout({ - +
)} @@ -103,15 +106,17 @@ export default function OptionLayout({
{"/"} -
+
+
+ +
@@ -190,7 +201,7 @@ export default function OptionLayout({ + className="!text-gray-500 hidden lg:block dark:text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 transition-colors"> diff --git a/src/components/Option/Knowledge/SelectedKnwledge.tsx b/src/components/Option/Knowledge/SelectedKnwledge.tsx index b7eaa2d..066c91f 100644 --- a/src/components/Option/Knowledge/SelectedKnwledge.tsx +++ b/src/components/Option/Knowledge/SelectedKnwledge.tsx @@ -1,5 +1,6 @@ import { Blocks, XIcon } from "lucide-react" import { useMessageOption } from "@/hooks/useMessageOption" +import { Tooltip } from "antd" export const SelectedKnowledge = () => { const { selectedKnowledge: knowledge, setSelectedKnowledge } = @@ -8,17 +9,21 @@ export const SelectedKnowledge = () => { if (!knowledge) return <> return ( -
+
{"/"} -
-
- - +
+ +
+ + {knowledge.title}
+