Add @mantine/hooks dependency and update PlaygroundChat component

This commit is contained in:
n4ze3m 2024-02-25 21:17:27 +05:30
parent 86d4d53693
commit 094615498c
13 changed files with 99 additions and 40 deletions

View File

@ -16,6 +16,7 @@
"@langchain/community": "^0.0.21", "@langchain/community": "^0.0.21",
"@langchain/core": "^0.1.22", "@langchain/core": "^0.1.22",
"@mantine/form": "^7.5.0", "@mantine/form": "^7.5.0",
"@mantine/hooks": "^7.5.3",
"@plasmohq/storage": "^1.9.0", "@plasmohq/storage": "^1.9.0",
"@tailwindcss/forms": "^0.5.7", "@tailwindcss/forms": "^0.5.7",
"@tailwindcss/typography": "^0.5.10", "@tailwindcss/typography": "^0.5.10",

View File

@ -7,8 +7,7 @@ import ReactMarkdown from "react-markdown"
import "property-information" import "property-information"
import React from "react" import React from "react"
import { Tooltip } from "antd" import { Tooltip } from "antd"
import { ClipboardIcon } from "~icons/ClipboardIcon" import { CheckIcon, ClipboardIcon } from "lucide-react"
import { CheckIcon } from "~icons/CheckIcon"
export default function Markdown({ message }: { message: string }) { export default function Markdown({ message }: { message: string }) {
const [isBtnPressed, setIsBtnPressed] = React.useState(false) const [isBtnPressed, setIsBtnPressed] = React.useState(false)

View File

@ -18,6 +18,7 @@ type Props = {
isProcessing: boolean isProcessing: boolean
webSearch?: {} webSearch?: {}
isSearchingInternet?: boolean isSearchingInternet?: boolean
sources?: any[]
} }
export const PlaygroundMessage = (props: Props) => { export const PlaygroundMessage = (props: Props) => {
@ -72,6 +73,20 @@ export const PlaygroundMessage = (props: Props) => {
))} ))}
</div> </div>
)} )}
{props.isBot && (
<div className="mb-3 flex flex-wrap gap-2">
{props?.sources?.map((source, index) => (
<a
key={index}
href={source?.url}
target="_blank"
className="inline-flex cursor-pointer transition-shadow duration-300 ease-in-out hover:shadow-lg items-center rounded-md bg-gray-100 p-1 text-xs text-gray-800 border border-gray-300 dark:bg-gray-800 dark:border-gray-700 dark:text-gray-100 opacity-80 hover:opacity-100">
<span className="text-xs">{source.name}</span>
</a>
))}
</div>
)}
{props.isBot && !props.isProcessing && ( {props.isBot && !props.isProcessing && (
<div className="flex space-x-2 gap-2"> <div className="flex space-x-2 gap-2">
{!props.hideCopy && ( {!props.hideCopy && (

View File

@ -1,19 +1,12 @@
import { useWebSearch } from "~store/web" import { Globe } from "lucide-react"
import {
Globe,
MousePointer,
Boxes
} from "lucide-react"
export const WebSearch = () => { export const WebSearch = () => {
const { state, text } = useWebSearch()
return ( return (
<div className="gradient-border mt-4 flex w-56 items-center gap-4 rounded-lg bg-neutral-100 p-1ccc text-slate-900 dark:bg-neutral-800 dark:text-slate-50"> <div className="gradient-border mt-4 flex w-56 items-center gap-4 rounded-lg bg-neutral-100 p-1ccc text-slate-900 dark:bg-neutral-800 dark:text-slate-50">
<div className="rounded p-1"> <div className="rounded p-1">
<Globe className="w-6 h-6" />
</div> </div>
<div className="text-sm font-semibold">{text}</div> <div className="text-sm font-semibold">Searching the web</div>
</div> </div>
) )
} }

View File

@ -5,6 +5,7 @@ import { PlaygroundChat } from "./PlaygroundChat"
export const Playground = () => { export const Playground = () => {
const drop = React.useRef<HTMLDivElement>(null) const drop = React.useRef<HTMLDivElement>(null)
const [dropedFile, setDropedFile] = React.useState<File | undefined>() const [dropedFile, setDropedFile] = React.useState<File | undefined>()
const [dropState, setDropState] = React.useState< const [dropState, setDropState] = React.useState<
"idle" | "dragging" | "error" "idle" | "dragging" | "error"
>("idle") >("idle")
@ -77,7 +78,9 @@ export const Playground = () => {
<div className="bottom-0 w-full bg-transparent border-0 fixed pt-2"> <div className="bottom-0 w-full bg-transparent border-0 fixed pt-2">
<div className="stretch mx-2 flex flex-row gap-3 md:mx-4 lg:mx-auto lg:max-w-2xl xl:max-w-3xl justify-center items-center"> <div className="stretch mx-2 flex flex-row gap-3 md:mx-4 lg:mx-auto lg:max-w-2xl xl:max-w-3xl justify-center items-center">
<div className="relative h-full flex-1 items-center justify-center md:flex-col"> <div className="relative h-full flex-1 items-center justify-center md:flex-col">
<PlaygroundForm dropedFile={dropedFile} /> <PlaygroundForm
dropedFile={dropedFile}
/>
</div> </div>
</div> </div>
</div> </div>

View File

@ -31,6 +31,7 @@ export const PlaygroundChat = () => {
onRengerate={regenerateLastMessage} onRengerate={regenerateLastMessage}
isProcessing={streaming} isProcessing={streaming}
isSearchingInternet={isSearchingInternet} isSearchingInternet={isSearchingInternet}
sources={message.sources}
/> />
))} ))}
{messages.length > 0 && ( {messages.length > 0 && (

View File

@ -1,6 +1,10 @@
import React from "react" import React from "react"
import { cleanUrl } from "~libs/clean-url" import { cleanUrl } from "~libs/clean-url"
import { getOllamaURL, systemPromptForNonRagOption } from "~services/ollama" import {
geWebSearchFollowUpPrompt,
getOllamaURL,
systemPromptForNonRagOption
} from "~services/ollama"
import { type ChatHistory, type Message } from "~store/option" import { type ChatHistory, type Message } from "~store/option"
import { ChatOllama } from "@langchain/community/chat_models/ollama" import { ChatOllama } from "@langchain/community/chat_models/ollama"
import { import {
@ -101,7 +105,6 @@ export const useMessageOption = () => {
setIsSearchingInternet setIsSearchingInternet
} = useStoreMessageOption() } = useStoreMessageOption()
const navigate = useNavigate() const navigate = useNavigate()
const abortControllerRef = React.useRef<AbortController | null>(null) const abortControllerRef = React.useRef<AbortController | null>(null)
@ -158,7 +161,30 @@ export const useMessageOption = () => {
try { try {
setIsSearchingInternet(true) setIsSearchingInternet(true)
const prompt = await getSystemPromptForWeb(message)
let query = message
if (newMessage.length > 2) {
let questionPrompt = await geWebSearchFollowUpPrompt()
const lastTenMessages = newMessage.slice(-10)
lastTenMessages.pop()
const chat_history = lastTenMessages
.map((message) => {
return `${message.isBot ? "Assistant: " : "Human: "}${message.message}`
})
.join("\n")
const promptForQuestion = questionPrompt
.replaceAll("{chat_history}", chat_history)
.replaceAll("{question}", message)
const questionOllama = new ChatOllama({
model: selectedModel,
baseUrl: cleanUrl(url)
})
const response = await questionOllama.invoke(promptForQuestion)
query = response.content.toString()
}
const { prompt, source } = await getSystemPromptForWeb(query)
setIsSearchingInternet(false) setIsSearchingInternet(false)
message = message.trim().replaceAll("\n", " ") message = message.trim().replaceAll("\n", " ")
@ -228,6 +254,8 @@ export const useMessageOption = () => {
appendingIndex appendingIndex
].message.slice(0, -1) ].message.slice(0, -1)
newMessage[appendingIndex].sources = source
if (!isRegenerate) { if (!isRegenerate) {
setHistory([ setHistory([
...history, ...history,
@ -260,7 +288,8 @@ export const useMessageOption = () => {
selectedModel, selectedModel,
"assistant", "assistant",
newMessage[appendingIndex].message, newMessage[appendingIndex].message,
[] [],
source
) )
} else { } else {
const newHistoryId = await saveHistory(message) const newHistoryId = await saveHistory(message)
@ -272,7 +301,8 @@ export const useMessageOption = () => {
selectedModel, selectedModel,
"assistant", "assistant",
newMessage[appendingIndex].message, newMessage[appendingIndex].message,
[] [],
source
) )
setHistoryId(newHistoryId.id) setHistoryId(newHistoryId.id)
} }
@ -615,6 +645,6 @@ export const useMessageOption = () => {
regenerateLastMessage, regenerateLastMessage,
webSearch, webSearch,
setWebSearch, setWebSearch,
isSearchingInternet, isSearchingInternet
} }
} }

View File

@ -125,11 +125,12 @@ export const saveMessage = async (
name: string, name: string,
role: string, role: string,
content: string, content: string,
images: string[] images: string[],
source?: any[]
) => { ) => {
const id = generateID() const id = generateID()
const createdAt = Date.now() const createdAt = Date.now()
const message = { id, history_id, name, role, content, images, createdAt } const message = { id, history_id, name, role, content, images, createdAt, sources: source }
const db = new PageAssitDatabase() const db = new PageAssitDatabase()
await db.addMessage(message) await db.addMessage(message)
return message return message

View File

@ -41,7 +41,7 @@ export class PageAssistHtmlLoader
] ]
}) })
const text = htmlCompiler(html) const text = htmlCompiler(html)
const metadata = { source: this.url } const metadata = { url: this.url }
return [new Document({ pageContent: text, metadata })] return [new Document({ pageContent: text, metadata })]
} }
} }

View File

@ -267,3 +267,16 @@ export const getWebSearchPrompt = async () => {
export const setWebSearchPrompt = async (prompt: string) => { export const setWebSearchPrompt = async (prompt: string) => {
await storage.set("webSearchPrompt", prompt) await storage.set("webSearchPrompt", prompt)
} }
export const geWebSearchFollowUpPrompt = async () => {
const prompt = await storage.get("webSearchFollowUpPrompt")
if (!prompt || prompt.length === 0) {
return DEFAULT_RAG_QUESTION_PROMPT;
}
return prompt
}
export const setWebSearchFollowUpPrompt = async (prompt: string) => {
await storage.set("webSearchFollowUpPrompt", prompt)
}

View File

@ -1,15 +0,0 @@
import { create } from "zustand"
type State = {
state: "searching" | "clicked" | "embeddings" | "done"
text: string
setText: (text: string) => void
setState: (state: "searching" | "clicked" | "embeddings" | "done") => void
}
export const useWebSearch = create<State>((set) => ({
state: "searching",
text: "Searching Google",
setText: (text) => set({ text }),
setState: (state) => set({ state })
}))

View File

@ -13,8 +13,21 @@ export const getSystemPromptForWeb = async (query: string) => {
const prompt = system.replace("{current_date_time}", current_date_time).replace("{search_results}", search_results) const prompt = system.replace("{current_date_time}", current_date_time).replace("{search_results}", search_results)
return prompt return {
prompt,
source: search.map((result) => {
return {
url: result.url,
name: new URL(result.url).hostname,
type: "url",
}
})
}
} catch (e) { } catch (e) {
return '' console.error(e)
return {
prompt: "",
source: [],
}
} }
} }

View File

@ -681,6 +681,11 @@
fast-deep-equal "^3.1.3" fast-deep-equal "^3.1.3"
klona "^2.0.6" klona "^2.0.6"
"@mantine/hooks@^7.5.3":
version "7.5.3"
resolved "https://registry.yarnpkg.com/@mantine/hooks/-/hooks-7.5.3.tgz#34168712075ee40ff7353c840420d4568b0dd54e"
integrity sha512-mFI448mAs12v8FrgSVhytqlhTVrEjIfd/PqPEfwJu5YcZIq4YZdqpzJIUbANnRrFSvmoQpDb1PssdKx7Ds35hw==
"@mischnic/json-sourcemap@0.1.0": "@mischnic/json-sourcemap@0.1.0":
version "0.1.0" version "0.1.0"
resolved "https://registry.yarnpkg.com/@mischnic/json-sourcemap/-/json-sourcemap-0.1.0.tgz#38af657be4108140a548638267d02a2ea3336507" resolved "https://registry.yarnpkg.com/@mischnic/json-sourcemap/-/json-sourcemap-0.1.0.tgz#38af657be4108140a548638267d02a2ea3336507"