Update package version and add new chat button
This commit is contained in:
parent
e4011b7af6
commit
31cac3b5b7
@ -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": {
|
||||||
|
@ -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,14 +99,19 @@ 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"
|
||||||
<button
|
target="_blank"
|
||||||
onClick={() => setOpen(true)}
|
className="text-gray-500 dark:text-gray-400">
|
||||||
className="text-gray-500 dark:text-gray-400">
|
<GithubIcon className="w-6 h-6" />
|
||||||
<CogIcon className="w-6 h-6" />
|
</a>
|
||||||
</button>
|
<button
|
||||||
|
onClick={() => setOpen(true)}
|
||||||
|
className="text-gray-500 dark:text-gray-400">
|
||||||
|
<CogIcon className="w-6 h-6" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Layout.Content>{children}</Layout.Content>
|
<Layout.Content>{children}</Layout.Content>
|
||||||
|
@ -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,35 +73,39 @@ 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 className="relative">
|
||||||
<div>
|
<Image
|
||||||
<img
|
src={form.values.image}
|
||||||
src={form.values.image}
|
alt="Uploaded Image"
|
||||||
alt="Uploaded"
|
width={180}
|
||||||
className="h-full w-auto object-cover rounded-md min-w-[50px]"
|
preview={false}
|
||||||
/>
|
className="rounded-md"
|
||||||
<button
|
/>
|
||||||
onClick={() => {
|
<button
|
||||||
form.setFieldValue("image", "")
|
onClick={() => {
|
||||||
}}
|
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">
|
}}
|
||||||
<XMarkIcon className="h-5 w-5" />
|
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">
|
||||||
</button>
|
<XMarkIcon className="h-5 w-5" />
|
||||||
</div>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
{/* <div className="flex gap-3 justify-end">
|
||||||
|
<Tooltip title="New Chat">
|
||||||
|
<button
|
||||||
|
onClick={clearChat}
|
||||||
|
className="text-gray-500 dark:text-gray-100 mr-3">
|
||||||
|
<ArrowPathIcon className="h-5 w-5" />
|
||||||
|
</button>
|
||||||
|
</Tooltip>
|
||||||
|
</div> */}
|
||||||
|
<div>
|
||||||
<div className="flex">
|
<div className="flex">
|
||||||
<Tooltip title="New Chat">
|
|
||||||
<button
|
|
||||||
onClick={clearChat}
|
|
||||||
className="text-gray-500 dark:text-gray-100 mr-3">
|
|
||||||
<ArrowPathIcon className="h-5 w-5" />
|
|
||||||
</button>
|
|
||||||
</Tooltip>
|
|
||||||
<form
|
<form
|
||||||
onSubmit={form.onSubmit(async (value) => {
|
onSubmit={form.onSubmit(async (value) => {
|
||||||
if (!selectedModel || selectedModel.length === 0) {
|
if (!selectedModel || selectedModel.length === 0) {
|
||||||
@ -108,29 +119,18 @@ 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">
|
<input
|
||||||
<button
|
id="file-upload"
|
||||||
type="button"
|
name="file-upload"
|
||||||
onClick={() => {
|
type="file"
|
||||||
inputRef.current?.click()
|
className="sr-only"
|
||||||
}}
|
ref={inputRef}
|
||||||
className={`flex ml-3 items-center justify-center dark:text-gray-100 ${
|
accept="image/*"
|
||||||
chatMode === "rag" ? "hidden" : "block"
|
multiple={false}
|
||||||
}`}>
|
onChange={onInputChange}
|
||||||
<PhotoIcon className="h-5 w-5" />
|
/>
|
||||||
</button>
|
<div className="w-full border-x border-t flex flex-col dark:border-gray-600 rounded-t-xl p-2">
|
||||||
<input
|
|
||||||
id="file-upload"
|
|
||||||
name="file-upload"
|
|
||||||
type="file"
|
|
||||||
className="sr-only"
|
|
||||||
ref={inputRef}
|
|
||||||
accept="image/*"
|
|
||||||
multiple={false}
|
|
||||||
onChange={onInputChange}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<textarea
|
<textarea
|
||||||
onKeyDown={(e) => {
|
onKeyDown={(e) => {
|
||||||
if (e.key === "Enter" && !e.shiftKey && !isSending) {
|
if (e.key === "Enter" && !e.shiftKey && !isSending) {
|
||||||
@ -156,26 +156,49 @@ 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")}
|
||||||
/>
|
/>
|
||||||
<button
|
<div className="flex mt-4 justify-end gap-3">
|
||||||
disabled={isSending || form.values.message.length === 0}
|
<Tooltip title="Voice Message">
|
||||||
className="ml-2 flex items-center justify-center w-10 h-10 text-white bg-[#262626] rounded-xl disabled:opacity-50">
|
<button
|
||||||
<svg
|
type="button"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
className={`flex items-center justify-center dark:text-gray-300`}>
|
||||||
fill="none"
|
<MicIcon className="h-5 w-5" />
|
||||||
stroke="currentColor"
|
</button>
|
||||||
strokeLinecap="round"
|
</Tooltip>
|
||||||
strokeLinejoin="round"
|
<Tooltip title="Upload Image">
|
||||||
strokeWidth="2"
|
<button
|
||||||
className="h-6 w-6"
|
type="button"
|
||||||
viewBox="0 0 24 24">
|
onClick={() => {
|
||||||
<path d="M9 10L4 15 9 20"></path>
|
inputRef.current?.click()
|
||||||
<path d="M20 4v7a4 4 0 01-4 4H4"></path>
|
}}
|
||||||
</svg>
|
className={`flex items-center justify-center dark:text-gray-300 ${
|
||||||
</button>
|
chatMode === "rag" ? "hidden" : "block"
|
||||||
|
}`}>
|
||||||
|
<PhotoIcon className="h-5 w-5" />
|
||||||
|
</button>
|
||||||
|
</Tooltip>
|
||||||
|
<button
|
||||||
|
disabled={isSending || form.values.message.length === 0}
|
||||||
|
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
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
strokeWidth="2"
|
||||||
|
className="h-4 w-4 mr-2"
|
||||||
|
viewBox="0 0 24 24">
|
||||||
|
<path d="M9 10L4 15 9 20"></path>
|
||||||
|
<path d="M20 4v7a4 4 0 01-4 4H4"></path>
|
||||||
|
</svg>
|
||||||
|
Send
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user