Add RAG
This commit is contained in:
parent
23e488770d
commit
28361c47e6
@ -20,6 +20,7 @@
|
|||||||
"@tanstack/react-query": "^5.17.19",
|
"@tanstack/react-query": "^5.17.19",
|
||||||
"antd": "^5.13.3",
|
"antd": "^5.13.3",
|
||||||
"axios": "^1.6.7",
|
"axios": "^1.6.7",
|
||||||
|
"html-to-text": "^9.0.5",
|
||||||
"langchain": "^0.1.9",
|
"langchain": "^0.1.9",
|
||||||
"plasmo": "0.84.1",
|
"plasmo": "0.84.1",
|
||||||
"property-information": "^6.4.1",
|
"property-information": "^6.4.1",
|
||||||
@ -38,6 +39,7 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@plasmohq/prettier-plugin-sort-imports": "4.0.1",
|
"@plasmohq/prettier-plugin-sort-imports": "4.0.1",
|
||||||
"@types/chrome": "0.0.259",
|
"@types/chrome": "0.0.259",
|
||||||
|
"@types/html-to-text": "^9.0.4",
|
||||||
"@types/node": "20.11.9",
|
"@types/node": "20.11.9",
|
||||||
"@types/react": "18.2.48",
|
"@types/react": "18.2.48",
|
||||||
"@types/react-dom": "18.2.18",
|
"@types/react-dom": "18.2.18",
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
export {}
|
export {}
|
||||||
|
|
||||||
|
|
||||||
chrome.runtime.onMessage.addListener(async (message) => {
|
chrome.runtime.onMessage.addListener(async (message) => {
|
||||||
chrome.tabs.query({ active: true, currentWindow: true }, async (tabs) => {
|
if (message.type === "sidepanel") {
|
||||||
const tab = tabs[0]
|
chrome.tabs.query({ active: true, currentWindow: true }, async (tabs) => {
|
||||||
await chrome.sidePanel.open({
|
const tab = tabs[0]
|
||||||
tabId: tab.id,
|
await chrome.sidePanel.open({
|
||||||
|
tabId: tab.id
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
}
|
||||||
})
|
})
|
||||||
|
170
src/chain/chat-with-website.ts
Normal file
170
src/chain/chat-with-website.ts
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
import { BaseLanguageModel } from "langchain/base_language";
|
||||||
|
import { Document } from "langchain/document";
|
||||||
|
import {
|
||||||
|
ChatPromptTemplate,
|
||||||
|
MessagesPlaceholder,
|
||||||
|
PromptTemplate,
|
||||||
|
} from "langchain/prompts";
|
||||||
|
import { AIMessage, BaseMessage, HumanMessage } from "langchain/schema";
|
||||||
|
import { StringOutputParser } from "langchain/schema/output_parser";
|
||||||
|
import {
|
||||||
|
Runnable,
|
||||||
|
RunnableBranch,
|
||||||
|
RunnableLambda,
|
||||||
|
RunnableMap,
|
||||||
|
RunnableSequence,
|
||||||
|
} from "langchain/schema/runnable";
|
||||||
|
type RetrievalChainInput = {
|
||||||
|
chat_history: string;
|
||||||
|
question: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function groupMessagesByConversation(messages: any[]) {
|
||||||
|
if (messages.length % 2 !== 0) {
|
||||||
|
messages.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
const groupedMessages = [];
|
||||||
|
for (let i = 0; i < messages.length; i += 2) {
|
||||||
|
groupedMessages.push({
|
||||||
|
human: messages[i].content,
|
||||||
|
ai: messages[i + 1].content,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return groupedMessages;
|
||||||
|
}
|
||||||
|
|
||||||
|
const formatChatHistoryAsString = (history: BaseMessage[]) => {
|
||||||
|
return history
|
||||||
|
.map((message) => `${message._getType()}: ${message.content}`)
|
||||||
|
.join("\n");
|
||||||
|
};
|
||||||
|
|
||||||
|
const formatDocs = (docs: Document[]) => {
|
||||||
|
return docs
|
||||||
|
.map((doc, i) => `<doc id='${i}'>${doc.pageContent}</doc>`)
|
||||||
|
.join("\n");
|
||||||
|
};
|
||||||
|
|
||||||
|
const serializeHistory = (input: any) => {
|
||||||
|
const chatHistory = input.chat_history || [];
|
||||||
|
const convertedChatHistory = [];
|
||||||
|
for (const message of chatHistory) {
|
||||||
|
if (message.human !== undefined) {
|
||||||
|
convertedChatHistory.push(new HumanMessage({ content: message.human }));
|
||||||
|
}
|
||||||
|
if (message["ai"] !== undefined) {
|
||||||
|
convertedChatHistory.push(new AIMessage({ content: message.ai }));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return convertedChatHistory;
|
||||||
|
};
|
||||||
|
|
||||||
|
const createRetrieverChain = (
|
||||||
|
llm: BaseLanguageModel,
|
||||||
|
retriever: Runnable,
|
||||||
|
question_template: string
|
||||||
|
) => {
|
||||||
|
const CONDENSE_QUESTION_PROMPT =
|
||||||
|
PromptTemplate.fromTemplate(question_template);
|
||||||
|
const condenseQuestionChain = RunnableSequence.from([
|
||||||
|
CONDENSE_QUESTION_PROMPT,
|
||||||
|
llm,
|
||||||
|
new StringOutputParser(),
|
||||||
|
]).withConfig({
|
||||||
|
runName: "CondenseQuestion",
|
||||||
|
});
|
||||||
|
const hasHistoryCheckFn = RunnableLambda.from(
|
||||||
|
(input: RetrievalChainInput) => input.chat_history.length > 0
|
||||||
|
).withConfig({ runName: "HasChatHistoryCheck" });
|
||||||
|
const conversationChain = condenseQuestionChain.pipe(retriever).withConfig({
|
||||||
|
runName: "RetrievalChainWithHistory",
|
||||||
|
});
|
||||||
|
const basicRetrievalChain = RunnableLambda.from(
|
||||||
|
(input: RetrievalChainInput) => input.question
|
||||||
|
)
|
||||||
|
.withConfig({
|
||||||
|
runName: "Itemgetter:question",
|
||||||
|
})
|
||||||
|
.pipe(retriever)
|
||||||
|
.withConfig({ runName: "RetrievalChainWithNoHistory" });
|
||||||
|
|
||||||
|
return RunnableBranch.from([
|
||||||
|
[hasHistoryCheckFn, conversationChain],
|
||||||
|
basicRetrievalChain,
|
||||||
|
]).withConfig({
|
||||||
|
runName: "FindDocs",
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const createChatWithWebsiteChain = ({
|
||||||
|
llm,
|
||||||
|
question_template,
|
||||||
|
question_llm,
|
||||||
|
retriever,
|
||||||
|
response_template,
|
||||||
|
}: {
|
||||||
|
llm: BaseLanguageModel;
|
||||||
|
question_llm: BaseLanguageModel;
|
||||||
|
retriever: Runnable;
|
||||||
|
question_template: string;
|
||||||
|
response_template: string;
|
||||||
|
}) => {
|
||||||
|
const retrieverChain = createRetrieverChain(
|
||||||
|
question_llm,
|
||||||
|
retriever,
|
||||||
|
question_template
|
||||||
|
);
|
||||||
|
const context = RunnableMap.from({
|
||||||
|
context: RunnableSequence.from([
|
||||||
|
({ question, chat_history }) => {
|
||||||
|
return {
|
||||||
|
question: question,
|
||||||
|
chat_history: formatChatHistoryAsString(chat_history),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
retrieverChain,
|
||||||
|
RunnableLambda.from(formatDocs).withConfig({
|
||||||
|
runName: "FormatDocumentChunks",
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
question: RunnableLambda.from(
|
||||||
|
(input: RetrievalChainInput) => input.question
|
||||||
|
).withConfig({
|
||||||
|
runName: "Itemgetter:question",
|
||||||
|
}),
|
||||||
|
chat_history: RunnableLambda.from(
|
||||||
|
(input: RetrievalChainInput) => input.chat_history
|
||||||
|
).withConfig({
|
||||||
|
runName: "Itemgetter:chat_history",
|
||||||
|
}),
|
||||||
|
}).withConfig({ tags: ["RetrieveDocs"] });
|
||||||
|
const prompt = ChatPromptTemplate.fromMessages([
|
||||||
|
["system", response_template],
|
||||||
|
new MessagesPlaceholder("chat_history"),
|
||||||
|
["human", "{question}"],
|
||||||
|
]);
|
||||||
|
|
||||||
|
const responseSynthesizerChain = RunnableSequence.from([
|
||||||
|
prompt,
|
||||||
|
llm,
|
||||||
|
new StringOutputParser(),
|
||||||
|
]).withConfig({
|
||||||
|
tags: ["GenerateResponse"],
|
||||||
|
});
|
||||||
|
return RunnableSequence.from([
|
||||||
|
{
|
||||||
|
question: RunnableLambda.from(
|
||||||
|
(input: RetrievalChainInput) => input.question
|
||||||
|
).withConfig({
|
||||||
|
runName: "Itemgetter:question",
|
||||||
|
}),
|
||||||
|
chat_history: RunnableLambda.from(serializeHistory).withConfig({
|
||||||
|
runName: "SerializeHistory",
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
context,
|
||||||
|
responseSynthesizerChain,
|
||||||
|
]);
|
||||||
|
};
|
@ -98,9 +98,13 @@ export const EmptySidePanel = () => {
|
|||||||
}}
|
}}
|
||||||
value={selectedModel}
|
value={selectedModel}
|
||||||
className="bg-gray-100 truncate w-full dark:bg-black dark:text-gray-100 rounded-md px-4 py-2 mt-2">
|
className="bg-gray-100 truncate w-full dark:bg-black dark:text-gray-100 rounded-md px-4 py-2 mt-2">
|
||||||
<option value={""}>Select a model</option>
|
<option key="0x" value={""}>
|
||||||
{ollamaInfo.models.map((model) => (
|
Select a model
|
||||||
<option value={model.name}>{model.name}</option>
|
</option>
|
||||||
|
{ollamaInfo.models.map((model, index) => (
|
||||||
|
<option key={index} value={model.name}>
|
||||||
|
{model.name}
|
||||||
|
</option>
|
||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
@ -23,6 +23,7 @@ const sidePanelController = async () => {
|
|||||||
chrome.runtime.sendMessage({ type: "sidepanel" })
|
chrome.runtime.sendMessage({ type: "sidepanel" })
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sidePanelController()
|
sidePanelController()
|
||||||
|
@ -4,6 +4,13 @@ import { getOllamaURL, systemPromptForNonRag } from "~services/ollama"
|
|||||||
import { useStoreMessage, type ChatHistory, type Message } from "~store"
|
import { useStoreMessage, type ChatHistory, type Message } from "~store"
|
||||||
import { ChatOllama } from "@langchain/community/chat_models/ollama"
|
import { ChatOllama } from "@langchain/community/chat_models/ollama"
|
||||||
import { HumanMessage, AIMessage } from "@langchain/core/messages"
|
import { HumanMessage, AIMessage } from "@langchain/core/messages"
|
||||||
|
import { getHtmlOfCurrentTab } from "~libs/get-html"
|
||||||
|
import { PageAssistHtmlLoader } from "~loader/html"
|
||||||
|
import { RecursiveCharacterTextSplitter } from "langchain/text_splitter"
|
||||||
|
import { OllamaEmbeddings } from "langchain/embeddings/ollama"
|
||||||
|
import { Voy as VoyClient } from "voy-search"
|
||||||
|
import { createChatWithWebsiteChain } from "~chain/chat-with-website"
|
||||||
|
import { MemoryVectorStore } from "langchain/vectorstores/memory"
|
||||||
|
|
||||||
export type BotResponse = {
|
export type BotResponse = {
|
||||||
bot: {
|
bot: {
|
||||||
@ -70,6 +77,10 @@ export const useMessage = () => {
|
|||||||
|
|
||||||
const abortControllerRef = React.useRef<AbortController | null>(null)
|
const abortControllerRef = React.useRef<AbortController | null>(null)
|
||||||
|
|
||||||
|
const [keepTrackOfEmbedding, setKeepTrackOfEmbedding] = React.useState<{
|
||||||
|
[key: string]: MemoryVectorStore
|
||||||
|
}>({})
|
||||||
|
|
||||||
const clearChat = () => {
|
const clearChat = () => {
|
||||||
stopStreamingRequest()
|
stopStreamingRequest()
|
||||||
setMessages([])
|
setMessages([])
|
||||||
@ -78,6 +89,149 @@ export const useMessage = () => {
|
|||||||
setIsFirstMessage(true)
|
setIsFirstMessage(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const voyEmbedding = async (
|
||||||
|
url: string,
|
||||||
|
html: string,
|
||||||
|
ollamaEmbedding: OllamaEmbeddings
|
||||||
|
) => {
|
||||||
|
const loader = new PageAssistHtmlLoader({
|
||||||
|
html,
|
||||||
|
url
|
||||||
|
})
|
||||||
|
const docs = await loader.load()
|
||||||
|
const textSplitter = new RecursiveCharacterTextSplitter({
|
||||||
|
chunkSize: 1000,
|
||||||
|
chunkOverlap: 200
|
||||||
|
})
|
||||||
|
|
||||||
|
const chunks = await textSplitter.splitDocuments(docs)
|
||||||
|
|
||||||
|
const store = new MemoryVectorStore(ollamaEmbedding)
|
||||||
|
|
||||||
|
await store.addDocuments(chunks)
|
||||||
|
|
||||||
|
setKeepTrackOfEmbedding({
|
||||||
|
...keepTrackOfEmbedding,
|
||||||
|
[url]: store
|
||||||
|
})
|
||||||
|
|
||||||
|
return store
|
||||||
|
}
|
||||||
|
|
||||||
|
const chatWithWebsiteMode = async (message: string) => {
|
||||||
|
const ollamaUrl = await getOllamaURL()
|
||||||
|
const { html, url } = await getHtmlOfCurrentTab()
|
||||||
|
const isAlreadyExistEmbedding = keepTrackOfEmbedding[url]
|
||||||
|
let newMessage: Message[] = [
|
||||||
|
...messages,
|
||||||
|
{
|
||||||
|
isBot: false,
|
||||||
|
name: "You",
|
||||||
|
message,
|
||||||
|
sources: []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
isBot: true,
|
||||||
|
name: selectedModel,
|
||||||
|
message: "▋",
|
||||||
|
sources: []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const appendingIndex = newMessage.length - 1
|
||||||
|
setMessages(newMessage)
|
||||||
|
const ollamaEmbedding = new OllamaEmbeddings({
|
||||||
|
model: selectedModel,
|
||||||
|
baseUrl: cleanUrl(ollamaUrl)
|
||||||
|
})
|
||||||
|
|
||||||
|
const ollamaChat = new ChatOllama({
|
||||||
|
model: selectedModel,
|
||||||
|
baseUrl: cleanUrl(ollamaUrl)
|
||||||
|
})
|
||||||
|
|
||||||
|
let vectorstore: MemoryVectorStore
|
||||||
|
|
||||||
|
if (isAlreadyExistEmbedding) {
|
||||||
|
vectorstore = isAlreadyExistEmbedding
|
||||||
|
} else {
|
||||||
|
vectorstore = await voyEmbedding(url, html, ollamaEmbedding)
|
||||||
|
}
|
||||||
|
|
||||||
|
const questionPrompt =
|
||||||
|
"Given the following conversation and a follow up question, rephrase the follow up question to be a standalone question. Chat History: {chat_history} Follow Up Input: {question} Standalone question:"
|
||||||
|
|
||||||
|
const systemPrompt = `You are a helpful AI assistant. Use the following pieces of context to answer the question at the end. If you don't know the answer, just say you don't know. DO NOT try to make up an answer. If the question is not related to the context, politely respond that you are tuned to only answer questions that are related to the context. {context} Question: {question} Helpful answer in markdown:`
|
||||||
|
|
||||||
|
const sanitizedQuestion = message.trim().replaceAll("\n", " ")
|
||||||
|
|
||||||
|
const chain = createChatWithWebsiteChain({
|
||||||
|
llm: ollamaChat,
|
||||||
|
question_llm: ollamaChat,
|
||||||
|
question_template: questionPrompt,
|
||||||
|
response_template: systemPrompt,
|
||||||
|
retriever: vectorstore.asRetriever()
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
const chunks = await chain.stream({
|
||||||
|
question: sanitizedQuestion
|
||||||
|
})
|
||||||
|
let count = 0
|
||||||
|
for await (const chunk of chunks) {
|
||||||
|
if (count === 0) {
|
||||||
|
setIsProcessing(true)
|
||||||
|
newMessage[appendingIndex].message = chunk + "▋"
|
||||||
|
setMessages(newMessage)
|
||||||
|
} else {
|
||||||
|
newMessage[appendingIndex].message =
|
||||||
|
newMessage[appendingIndex].message.slice(0, -1) + chunk + "▋"
|
||||||
|
setMessages(newMessage)
|
||||||
|
}
|
||||||
|
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
|
||||||
|
newMessage[appendingIndex].message = newMessage[
|
||||||
|
appendingIndex
|
||||||
|
].message.slice(0, -1)
|
||||||
|
|
||||||
|
setHistory([
|
||||||
|
...history,
|
||||||
|
{
|
||||||
|
role: "user",
|
||||||
|
content: message
|
||||||
|
},
|
||||||
|
{
|
||||||
|
role: "assistant",
|
||||||
|
content: newMessage[appendingIndex].message
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
setIsProcessing(false)
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e)
|
||||||
|
setIsProcessing(false)
|
||||||
|
setStreaming(false)
|
||||||
|
|
||||||
|
setMessages([
|
||||||
|
...messages,
|
||||||
|
{
|
||||||
|
isBot: true,
|
||||||
|
name: selectedModel,
|
||||||
|
message: `Something went wrong. Check out the following logs:
|
||||||
|
\`\`\`
|
||||||
|
${e?.message}
|
||||||
|
\`\`\`
|
||||||
|
`,
|
||||||
|
sources: []
|
||||||
|
}
|
||||||
|
])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const normalChatMode = async (message: string) => {
|
const normalChatMode = async (message: string) => {
|
||||||
const url = await getOllamaURL()
|
const url = await getOllamaURL()
|
||||||
|
|
||||||
@ -110,13 +264,8 @@ export const useMessage = () => {
|
|||||||
try {
|
try {
|
||||||
const prompt = await systemPromptForNonRag()
|
const prompt = await systemPromptForNonRag()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const chunks = await ollama.stream(
|
const chunks = await ollama.stream(
|
||||||
[
|
[
|
||||||
|
|
||||||
...generateHistory(history),
|
...generateHistory(history),
|
||||||
new HumanMessage({
|
new HumanMessage({
|
||||||
content: [
|
content: [
|
||||||
@ -187,7 +336,7 @@ export const useMessage = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const onSubmit = async (message: string) => {
|
const onSubmit = async (message: string) => {
|
||||||
await normalChatMode(message)
|
await chatWithWebsiteMode(message)
|
||||||
}
|
}
|
||||||
|
|
||||||
const stopStreamingRequest = () => {
|
const stopStreamingRequest = () => {
|
||||||
|
26
src/libs/get-html.ts
Normal file
26
src/libs/get-html.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
const _getHtml = () => {
|
||||||
|
const url = window.location.href
|
||||||
|
const html = document.documentElement.outerHTML
|
||||||
|
return { url, html }
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getHtmlOfCurrentTab = async () => {
|
||||||
|
const result = new Promise((resolve) => {
|
||||||
|
chrome.tabs.query({ active: true, currentWindow: true }, async (tabs) => {
|
||||||
|
const tab = tabs[0]
|
||||||
|
const data = await chrome.scripting.executeScript({
|
||||||
|
target: { tabId: tab.id },
|
||||||
|
func: _getHtml
|
||||||
|
})
|
||||||
|
|
||||||
|
if (data.length > 0) {
|
||||||
|
resolve(data[0].result)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}) as Promise<{
|
||||||
|
url: string
|
||||||
|
html: string
|
||||||
|
}>
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
31
src/loader/html.ts
Normal file
31
src/loader/html.ts
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import { BaseDocumentLoader } from "langchain/document_loaders/base"
|
||||||
|
import { Document } from "langchain/document"
|
||||||
|
import { compile } from "html-to-text"
|
||||||
|
|
||||||
|
export interface WebLoaderParams {
|
||||||
|
html: string
|
||||||
|
url: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export class PageAssistHtmlLoader
|
||||||
|
extends BaseDocumentLoader
|
||||||
|
implements WebLoaderParams
|
||||||
|
{
|
||||||
|
html: string
|
||||||
|
url: string
|
||||||
|
|
||||||
|
constructor({ html, url }: WebLoaderParams) {
|
||||||
|
super()
|
||||||
|
this.html = html
|
||||||
|
this.url = url
|
||||||
|
}
|
||||||
|
|
||||||
|
async load(): Promise<Document<Record<string, any>>[]> {
|
||||||
|
const htmlCompiler = compile({
|
||||||
|
wordwrap: false
|
||||||
|
})
|
||||||
|
const text = htmlCompiler(this.html)
|
||||||
|
const metadata = { source: this.url }
|
||||||
|
return [new Document({ pageContent: text, metadata })]
|
||||||
|
}
|
||||||
|
}
|
90
yarn.lock
90
yarn.lock
@ -2002,6 +2002,14 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@remix-run/router/-/router-1.5.0.tgz#57618e57942a5f0131374a9fdb0167e25a117fdc"
|
resolved "https://registry.yarnpkg.com/@remix-run/router/-/router-1.5.0.tgz#57618e57942a5f0131374a9fdb0167e25a117fdc"
|
||||||
integrity sha512-bkUDCp8o1MvFO+qxkODcbhSqRa6P2GXgrGZVpt0dCXNW2HCSCqYI0ZoAqEOSAjRWmmlKcYgFvN4B4S+zo/f8kg==
|
integrity sha512-bkUDCp8o1MvFO+qxkODcbhSqRa6P2GXgrGZVpt0dCXNW2HCSCqYI0ZoAqEOSAjRWmmlKcYgFvN4B4S+zo/f8kg==
|
||||||
|
|
||||||
|
"@selderee/plugin-htmlparser2@^0.11.0":
|
||||||
|
version "0.11.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@selderee/plugin-htmlparser2/-/plugin-htmlparser2-0.11.0.tgz#d5b5e29a7ba6d3958a1972c7be16f4b2c188c517"
|
||||||
|
integrity sha512-P33hHGdldxGabLFjPPpaTxVolMrzrcegejx+0GxjrIb9Zv48D8yAIA/QTDR2dFl7Uz7urX8aX6+5bCZslr+gWQ==
|
||||||
|
dependencies:
|
||||||
|
domhandler "^5.0.3"
|
||||||
|
selderee "^0.11.0"
|
||||||
|
|
||||||
"@sindresorhus/is@^5.2.0":
|
"@sindresorhus/is@^5.2.0":
|
||||||
version "5.6.0"
|
version "5.6.0"
|
||||||
resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-5.6.0.tgz#41dd6093d34652cddb5d5bdeee04eafc33826668"
|
resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-5.6.0.tgz#41dd6093d34652cddb5d5bdeee04eafc33826668"
|
||||||
@ -2355,6 +2363,11 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@types/unist" "^2"
|
"@types/unist" "^2"
|
||||||
|
|
||||||
|
"@types/html-to-text@^9.0.4":
|
||||||
|
version "9.0.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/html-to-text/-/html-to-text-9.0.4.tgz#4a83dd8ae8bfa91457d0b1ffc26f4d0537eff58c"
|
||||||
|
integrity sha512-pUY3cKH/Nm2yYrEmDlPR1mR7yszjGx4DrwPjQ702C4/D5CwHuZTgZdIdwPkRbcuhs7BAh2L5rg3CL5cbRiGTCQ==
|
||||||
|
|
||||||
"@types/http-cache-semantics@^4.0.2":
|
"@types/http-cache-semantics@^4.0.2":
|
||||||
version "4.0.4"
|
version "4.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz#b979ebad3919799c979b17c72621c0bc0a31c6c4"
|
resolved "https://registry.yarnpkg.com/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz#b979ebad3919799c979b17c72621c0bc0a31c6c4"
|
||||||
@ -3381,7 +3394,7 @@ deep-extend@^0.6.0:
|
|||||||
resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac"
|
resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac"
|
||||||
integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==
|
integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==
|
||||||
|
|
||||||
deepmerge@^4.2.2:
|
deepmerge@^4.2.2, deepmerge@^4.3.1:
|
||||||
version "4.3.1"
|
version "4.3.1"
|
||||||
resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a"
|
resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a"
|
||||||
integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==
|
integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==
|
||||||
@ -3466,7 +3479,16 @@ dom-serializer@^1.0.1:
|
|||||||
domhandler "^4.2.0"
|
domhandler "^4.2.0"
|
||||||
entities "^2.0.0"
|
entities "^2.0.0"
|
||||||
|
|
||||||
domelementtype@^2.0.1, domelementtype@^2.2.0:
|
dom-serializer@^2.0.0:
|
||||||
|
version "2.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-2.0.0.tgz#e41b802e1eedf9f6cae183ce5e622d789d7d8e53"
|
||||||
|
integrity sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==
|
||||||
|
dependencies:
|
||||||
|
domelementtype "^2.3.0"
|
||||||
|
domhandler "^5.0.2"
|
||||||
|
entities "^4.2.0"
|
||||||
|
|
||||||
|
domelementtype@^2.0.1, domelementtype@^2.2.0, domelementtype@^2.3.0:
|
||||||
version "2.3.0"
|
version "2.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.3.0.tgz#5c45e8e869952626331d7aab326d01daf65d589d"
|
resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.3.0.tgz#5c45e8e869952626331d7aab326d01daf65d589d"
|
||||||
integrity sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==
|
integrity sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==
|
||||||
@ -3485,6 +3507,13 @@ domhandler@^4.2.0, domhandler@^4.2.2, domhandler@^4.3.1:
|
|||||||
dependencies:
|
dependencies:
|
||||||
domelementtype "^2.2.0"
|
domelementtype "^2.2.0"
|
||||||
|
|
||||||
|
domhandler@^5.0.2, domhandler@^5.0.3:
|
||||||
|
version "5.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-5.0.3.tgz#cc385f7f751f1d1fc650c21374804254538c7d31"
|
||||||
|
integrity sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==
|
||||||
|
dependencies:
|
||||||
|
domelementtype "^2.3.0"
|
||||||
|
|
||||||
domutils@^2.8.0:
|
domutils@^2.8.0:
|
||||||
version "2.8.0"
|
version "2.8.0"
|
||||||
resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.8.0.tgz#4437def5db6e2d1f5d6ee859bd95ca7d02048135"
|
resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.8.0.tgz#4437def5db6e2d1f5d6ee859bd95ca7d02048135"
|
||||||
@ -3494,6 +3523,15 @@ domutils@^2.8.0:
|
|||||||
domelementtype "^2.2.0"
|
domelementtype "^2.2.0"
|
||||||
domhandler "^4.2.0"
|
domhandler "^4.2.0"
|
||||||
|
|
||||||
|
domutils@^3.0.1:
|
||||||
|
version "3.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/domutils/-/domutils-3.1.0.tgz#c47f551278d3dc4b0b1ab8cbb42d751a6f0d824e"
|
||||||
|
integrity sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==
|
||||||
|
dependencies:
|
||||||
|
dom-serializer "^2.0.0"
|
||||||
|
domelementtype "^2.3.0"
|
||||||
|
domhandler "^5.0.3"
|
||||||
|
|
||||||
dotenv-expand@10.0.0:
|
dotenv-expand@10.0.0:
|
||||||
version "10.0.0"
|
version "10.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/dotenv-expand/-/dotenv-expand-10.0.0.tgz#12605d00fb0af6d0a592e6558585784032e4ef37"
|
resolved "https://registry.yarnpkg.com/dotenv-expand/-/dotenv-expand-10.0.0.tgz#12605d00fb0af6d0a592e6558585784032e4ef37"
|
||||||
@ -3551,7 +3589,7 @@ entities@^3.0.1:
|
|||||||
resolved "https://registry.yarnpkg.com/entities/-/entities-3.0.1.tgz#2b887ca62585e96db3903482d336c1006c3001d4"
|
resolved "https://registry.yarnpkg.com/entities/-/entities-3.0.1.tgz#2b887ca62585e96db3903482d336c1006c3001d4"
|
||||||
integrity sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==
|
integrity sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==
|
||||||
|
|
||||||
entities@^4.4.0:
|
entities@^4.2.0, entities@^4.4.0:
|
||||||
version "4.5.0"
|
version "4.5.0"
|
||||||
resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48"
|
resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48"
|
||||||
integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==
|
integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==
|
||||||
@ -4108,6 +4146,17 @@ html-encoding-sniffer@^3.0.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
whatwg-encoding "^2.0.0"
|
whatwg-encoding "^2.0.0"
|
||||||
|
|
||||||
|
html-to-text@^9.0.5:
|
||||||
|
version "9.0.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/html-to-text/-/html-to-text-9.0.5.tgz#6149a0f618ae7a0db8085dca9bbf96d32bb8368d"
|
||||||
|
integrity sha512-qY60FjREgVZL03vJU6IfMV4GDjGBIoOyvuFdpBDIX9yTlDw0TjxVBQp+P8NvpdIXNJvfWBTNul7fsAQJq2FNpg==
|
||||||
|
dependencies:
|
||||||
|
"@selderee/plugin-htmlparser2" "^0.11.0"
|
||||||
|
deepmerge "^4.3.1"
|
||||||
|
dom-serializer "^2.0.0"
|
||||||
|
htmlparser2 "^8.0.2"
|
||||||
|
selderee "^0.11.0"
|
||||||
|
|
||||||
htmlnano@^2.0.0:
|
htmlnano@^2.0.0:
|
||||||
version "2.1.0"
|
version "2.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/htmlnano/-/htmlnano-2.1.0.tgz#67b31b3cd3fad23f0b610ca628fdb48382209c3c"
|
resolved "https://registry.yarnpkg.com/htmlnano/-/htmlnano-2.1.0.tgz#67b31b3cd3fad23f0b610ca628fdb48382209c3c"
|
||||||
@ -4127,6 +4176,16 @@ htmlparser2@^7.1.1:
|
|||||||
domutils "^2.8.0"
|
domutils "^2.8.0"
|
||||||
entities "^3.0.1"
|
entities "^3.0.1"
|
||||||
|
|
||||||
|
htmlparser2@^8.0.2:
|
||||||
|
version "8.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-8.0.2.tgz#f002151705b383e62433b5cf466f5b716edaec21"
|
||||||
|
integrity sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==
|
||||||
|
dependencies:
|
||||||
|
domelementtype "^2.3.0"
|
||||||
|
domhandler "^5.0.3"
|
||||||
|
domutils "^3.0.1"
|
||||||
|
entities "^4.4.0"
|
||||||
|
|
||||||
http-cache-semantics@^4.1.1:
|
http-cache-semantics@^4.1.1:
|
||||||
version "4.1.1"
|
version "4.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a"
|
resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a"
|
||||||
@ -4592,6 +4651,11 @@ langsmith@~0.0.48, langsmith@~0.0.59:
|
|||||||
p-retry "4"
|
p-retry "4"
|
||||||
uuid "^9.0.0"
|
uuid "^9.0.0"
|
||||||
|
|
||||||
|
leac@^0.6.0:
|
||||||
|
version "0.6.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/leac/-/leac-0.6.0.tgz#dcf136e382e666bd2475f44a1096061b70dc0912"
|
||||||
|
integrity sha512-y+SqErxb8h7nE/fiEX07jsbuhrpO9lL8eca7/Y1nuWV2moNlXhyd59iDGcRf6moVyDMbmTNzL40SUyrFU/yDpg==
|
||||||
|
|
||||||
less@^4.1.1:
|
less@^4.1.1:
|
||||||
version "4.2.0"
|
version "4.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/less/-/less-4.2.0.tgz#cbefbfaa14a4cd388e2099b2b51f956e1465c450"
|
resolved "https://registry.yarnpkg.com/less/-/less-4.2.0.tgz#cbefbfaa14a4cd388e2099b2b51f956e1465c450"
|
||||||
@ -5827,6 +5891,14 @@ parse5@^7.1.1:
|
|||||||
dependencies:
|
dependencies:
|
||||||
entities "^4.4.0"
|
entities "^4.4.0"
|
||||||
|
|
||||||
|
parseley@^0.12.0:
|
||||||
|
version "0.12.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/parseley/-/parseley-0.12.1.tgz#4afd561d50215ebe259e3e7a853e62f600683aef"
|
||||||
|
integrity sha512-e6qHKe3a9HWr0oMRVDTRhKce+bRO8VGQR3NyVwcjwrbhMmFCX9KszEV35+rn4AdilFAq9VPxP/Fe1wC9Qjd2lw==
|
||||||
|
dependencies:
|
||||||
|
leac "^0.6.0"
|
||||||
|
peberminta "^0.9.0"
|
||||||
|
|
||||||
path-key@^3.0.0, path-key@^3.1.0:
|
path-key@^3.0.0, path-key@^3.1.0:
|
||||||
version "3.1.1"
|
version "3.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375"
|
resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375"
|
||||||
@ -5850,6 +5922,11 @@ path-type@^4.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b"
|
resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b"
|
||||||
integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==
|
integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==
|
||||||
|
|
||||||
|
peberminta@^0.9.0:
|
||||||
|
version "0.9.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/peberminta/-/peberminta-0.9.0.tgz#8ec9bc0eb84b7d368126e71ce9033501dca2a352"
|
||||||
|
integrity sha512-XIxfHpEuSJbITd1H3EeQwpcZbTLHc+VVr8ANI9t5sit565tsI4/xK3KWTUFE2e6QiangUkh3B0jihzmGnNrRsQ==
|
||||||
|
|
||||||
periscopic@^3.1.0:
|
periscopic@^3.1.0:
|
||||||
version "3.1.0"
|
version "3.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/periscopic/-/periscopic-3.1.0.tgz#7e9037bf51c5855bd33b48928828db4afa79d97a"
|
resolved "https://registry.yarnpkg.com/periscopic/-/periscopic-3.1.0.tgz#7e9037bf51c5855bd33b48928828db4afa79d97a"
|
||||||
@ -6835,6 +6912,13 @@ scroll-into-view-if-needed@^3.1.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
compute-scroll-into-view "^3.0.2"
|
compute-scroll-into-view "^3.0.2"
|
||||||
|
|
||||||
|
selderee@^0.11.0:
|
||||||
|
version "0.11.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/selderee/-/selderee-0.11.0.tgz#6af0c7983e073ad3e35787ffe20cefd9daf0ec8a"
|
||||||
|
integrity sha512-5TF+l7p4+OsnP8BCCvSyZiSPc4x4//p5uPwK8TCnVPJYRmU2aYKMpOXvw8zM5a5JvuuCGN1jmsMwuU2W02ukfA==
|
||||||
|
dependencies:
|
||||||
|
parseley "^0.12.0"
|
||||||
|
|
||||||
semver@7.5.4, semver@^7.3.5, semver@^7.3.7, semver@^7.5.2, semver@^7.5.4:
|
semver@7.5.4, semver@^7.3.5, semver@^7.3.7, semver@^7.5.2, semver@^7.5.4:
|
||||||
version "7.5.4"
|
version "7.5.4"
|
||||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e"
|
resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user