Update package version and add new chat button

This commit is contained in:
n4ze3m 2024-02-14 00:43:07 +05:30
parent e4011b7af6
commit 31cac3b5b7
3 changed files with 111 additions and 78 deletions

View File

@ -1,7 +1,7 @@
{ {
"name": "pageassist", "name": "pageassist",
"displayName": "Page Assist - A Web UI for Local AI Models", "displayName": "Page Assist - A Web UI for Local AI Models",
"version": "1.0.0", "version": "1.0.1",
"description": "Use your locally running AI models to assist you in your web browsing.", "description": "Use your locally running AI models to assist you in your web browsing.",
"author": "n4ze3m", "author": "n4ze3m",
"scripts": { "scripts": {

View File

@ -19,7 +19,7 @@ import { Drawer, Layout, Modal, Select } from "antd"
import { useQuery } from "@tanstack/react-query" import { useQuery } from "@tanstack/react-query"
import { fetchModels } from "~services/ollama" import { fetchModels } from "~services/ollama"
import { useMessageOption } from "~hooks/useMessageOption" import { useMessageOption } from "~hooks/useMessageOption"
import { PanelLeftIcon, Settings2 } from "lucide-react" import { GithubIcon, PanelLeftIcon, Settings2, SquarePen } from "lucide-react"
import { Settings } from "./Settings" import { Settings } from "./Settings"
import { useDarkMode } from "~hooks/useDarkmode" import { useDarkMode } from "~hooks/useDarkmode"
@ -67,7 +67,6 @@ export default function OptionLayout({
const { selectedModel, setSelectedModel } = useMessageOption() const { selectedModel, setSelectedModel } = useMessageOption()
return ( return (
<Layout className="bg-white dark:bg-[#171717] md:flex"> <Layout className="bg-white dark:bg-[#171717] md:flex">
<div className="flex items-center p-3 fixed flex-row justify-between border-b border-gray-200 dark:border-gray-600 bg-white dark:bg-[#171717] w-full z-10"> <div className="flex items-center p-3 fixed flex-row justify-between border-b border-gray-200 dark:border-gray-600 bg-white dark:bg-[#171717] w-full z-10">
@ -79,6 +78,12 @@ export default function OptionLayout({
<PanelLeftIcon className="w-6 h-6" /> <PanelLeftIcon className="w-6 h-6" />
</button> </button>
</div> </div>
<div>
<button className="inline-flex items-center rounded-md border border-transparent bg-black px-2 py-2 text-sm font-medium leading-4 text-white shadow-sm hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 dark:bg-white dark:text-gray-800 dark:hover:bg-gray-100 dark:focus:ring-gray-500 dark:focus:ring-offset-gray-100 disabled:opacity-50 ">
<SquarePen className="h-4 w-4 mr-3" />
New Chat
</button>
</div>
<div> <div>
<Select <Select
value={selectedModel} value={selectedModel}
@ -94,15 +99,20 @@ export default function OptionLayout({
/> />
</div> </div>
</div> </div>
<button> <div className="flex gap-3 items-center">
<a
</button> href="https://github.com/n4ze3m/page-assist"
target="_blank"
className="text-gray-500 dark:text-gray-400">
<GithubIcon className="w-6 h-6" />
</a>
<button <button
onClick={() => setOpen(true)} onClick={() => setOpen(true)}
className="text-gray-500 dark:text-gray-400"> className="text-gray-500 dark:text-gray-400">
<CogIcon className="w-6 h-6" /> <CogIcon className="w-6 h-6" />
</button> </button>
</div> </div>
</div>
<Layout.Content>{children}</Layout.Content> <Layout.Content>{children}</Layout.Content>

View File

@ -6,8 +6,9 @@ import PhotoIcon from "@heroicons/react/24/outline/PhotoIcon"
import XMarkIcon from "@heroicons/react/24/outline/XMarkIcon" import XMarkIcon from "@heroicons/react/24/outline/XMarkIcon"
import { toBase64 } from "~libs/to-base64" import { toBase64 } from "~libs/to-base64"
import { useMessageOption } from "~hooks/useMessageOption" import { useMessageOption } from "~hooks/useMessageOption"
import { ArrowPathIcon } from "@heroicons/react/24/outline"
import { Tooltip } from "antd" import { Tooltip } from "antd"
import { MicIcon } from "lucide-react"
import { Image } from "antd"
type Props = { type Props = {
dropedFile: File | undefined dropedFile: File | undefined
@ -30,6 +31,12 @@ export const PlaygroundForm = ({ dropedFile }: Props) => {
} }
}) })
React.useEffect(() => {
if (textareaRef.current) {
textareaRef.current.focus()
}
}, [])
const onInputChange = async ( const onInputChange = async (
e: React.ChangeEvent<HTMLInputElement> | File e: React.ChangeEvent<HTMLInputElement> | File
) => { ) => {
@ -66,28 +73,29 @@ export const PlaygroundForm = ({ dropedFile }: Props) => {
}) })
return ( return (
<div className="p-3 md:p-6 md:bg-white dark:bg-[#262626] border rounded-t-xl border-black/10 dark:border-gray-600"> <div className="px-3 pt-3 md:px-6 md:pt-6 md:bg-white dark:bg-[#262626] border rounded-t-xl border-black/10 dark:border-gray-600">
<div className="flex-grow space-y-6 ">
<div <div
className={`h-full rounded-md shadow relative ${ className={`h-full rounded-md shadow relative ${
form.values.image.length === 0 ? "hidden" : "block" form.values.image.length === 0 ? "hidden" : "block"
}`}> }`}>
<div> <div className="relative">
<img <Image
src={form.values.image} src={form.values.image}
alt="Uploaded" alt="Uploaded Image"
className="h-full w-auto object-cover rounded-md min-w-[50px]" width={180}
preview={false}
className="rounded-md"
/> />
<button <button
onClick={() => { onClick={() => {
form.setFieldValue("image", "") form.setFieldValue("image", "")
}} }}
className="absolute top-2 right-2 bg-white dark:bg-[#262626] p-1 rounded-full hover:bg-gray-100 dark:hover:bg-gray-600 text-black dark:text-gray-100"> className="flex items-center justify-center absolute top-0 m-2 bg-white dark:bg-[#262626] p-1 rounded-full hover:bg-gray-100 dark:hover:bg-gray-600 text-black dark:text-gray-100">
<XMarkIcon className="h-5 w-5" /> <XMarkIcon className="h-5 w-5" />
</button> </button>
</div> </div>
</div> </div>
<div className="flex"> {/* <div className="flex gap-3 justify-end">
<Tooltip title="New Chat"> <Tooltip title="New Chat">
<button <button
onClick={clearChat} onClick={clearChat}
@ -95,6 +103,9 @@ export const PlaygroundForm = ({ dropedFile }: Props) => {
<ArrowPathIcon className="h-5 w-5" /> <ArrowPathIcon className="h-5 w-5" />
</button> </button>
</Tooltip> </Tooltip>
</div> */}
<div>
<div className="flex">
<form <form
onSubmit={form.onSubmit(async (value) => { onSubmit={form.onSubmit(async (value) => {
if (!selectedModel || selectedModel.length === 0) { if (!selectedModel || selectedModel.length === 0) {
@ -108,18 +119,7 @@ export const PlaygroundForm = ({ dropedFile }: Props) => {
message: value.message.trim() message: value.message.trim()
}) })
})} })}
className="shrink-0 flex-grow flex items-center "> className="shrink-0 flex-grow flex flex-col items-center ">
<div className="flex items-center p-2 rounded-2xl border bg-gray-100 w-full dark:bg-[#262626] dark:border-gray-600">
<button
type="button"
onClick={() => {
inputRef.current?.click()
}}
className={`flex ml-3 items-center justify-center dark:text-gray-100 ${
chatMode === "rag" ? "hidden" : "block"
}`}>
<PhotoIcon className="h-5 w-5" />
</button>
<input <input
id="file-upload" id="file-upload"
name="file-upload" name="file-upload"
@ -130,7 +130,7 @@ export const PlaygroundForm = ({ dropedFile }: Props) => {
multiple={false} multiple={false}
onChange={onInputChange} onChange={onInputChange}
/> />
<div className="w-full border-x border-t flex flex-col dark:border-gray-600 rounded-t-xl p-2">
<textarea <textarea
onKeyDown={(e) => { onKeyDown={(e) => {
if (e.key === "Enter" && !e.shiftKey && !isSending) { if (e.key === "Enter" && !e.shiftKey && !isSending) {
@ -156,13 +156,34 @@ export const PlaygroundForm = ({ dropedFile }: Props) => {
className="px-2 py-2 w-full resize-none bg-transparent focus-within:outline-none sm:text-sm focus:ring-0 focus-visible:ring-0 ring-0 dark:ring-0 border-0 dark:text-gray-100" className="px-2 py-2 w-full resize-none bg-transparent focus-within:outline-none sm:text-sm focus:ring-0 focus-visible:ring-0 ring-0 dark:ring-0 border-0 dark:text-gray-100"
required required
rows={1} rows={1}
style={{ minHeight: "60px" }}
tabIndex={0} tabIndex={0}
placeholder="Type a message..." placeholder="Type a message..."
{...form.getInputProps("message")} {...form.getInputProps("message")}
/> />
<div className="flex mt-4 justify-end gap-3">
<Tooltip title="Voice Message">
<button
type="button"
className={`flex items-center justify-center dark:text-gray-300`}>
<MicIcon className="h-5 w-5" />
</button>
</Tooltip>
<Tooltip title="Upload Image">
<button
type="button"
onClick={() => {
inputRef.current?.click()
}}
className={`flex items-center justify-center dark:text-gray-300 ${
chatMode === "rag" ? "hidden" : "block"
}`}>
<PhotoIcon className="h-5 w-5" />
</button>
</Tooltip>
<button <button
disabled={isSending || form.values.message.length === 0} disabled={isSending || form.values.message.length === 0}
className="ml-2 flex items-center justify-center w-10 h-10 text-white bg-[#262626] rounded-xl disabled:opacity-50"> className="inline-flex items-center rounded-md border border-transparent bg-black px-2 py-2 text-sm font-medium leading-4 text-white shadow-sm hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 dark:bg-white dark:text-gray-800 dark:hover:bg-gray-100 dark:focus:ring-gray-500 dark:focus:ring-offset-gray-100 disabled:opacity-50 ">
<svg <svg
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
fill="none" fill="none"
@ -170,13 +191,15 @@ export const PlaygroundForm = ({ dropedFile }: Props) => {
strokeLinecap="round" strokeLinecap="round"
strokeLinejoin="round" strokeLinejoin="round"
strokeWidth="2" strokeWidth="2"
className="h-6 w-6" className="h-4 w-4 mr-2"
viewBox="0 0 24 24"> viewBox="0 0 24 24">
<path d="M9 10L4 15 9 20"></path> <path d="M9 10L4 15 9 20"></path>
<path d="M20 4v7a4 4 0 01-4 4H4"></path> <path d="M20 4v7a4 4 0 01-4 4H4"></path>
</svg> </svg>
Send
</button> </button>
</div> </div>
</div>
</form> </form>
</div> </div>
{form.errors.message && ( {form.errors.message && (