mirror of
https://github.com/khoj-ai/khoj.git
synced 2024-11-23 15:38:55 +01:00
Add Vision Support (#889)
# Summary of Changes * New UI to show preview of image uploads * ChatML message changes to support gpt-4o vision based responses on images * AWS S3 image uploads for persistent image context in conversations * Database changes to have `vision_enabled` option in server admin panel while configuring models * Render previously uploaded images in the chat history, show uploaded images for pending msgs * Pass the uploaded_image_url through to subqueries * Allow image to render upon first message from the homepage * Add rendering support for images to shared chat as well * Fix some UI/functionality bugs in the share page * Convert user attached images for chat to webp format before upload * Use placeholder to attached image for data source, response mode actors * Update all clients to call /api/chat as a POST instead of GET request * Fix copying chat messages with images to clipboard TLDR; Add vision support for openai models on Khoj via the web UI! --------- Co-authored-by: sabaimran <narmiabas@gmail.com> Co-authored-by: Debanjum Singh Solanky <debanjum@gmail.com>
This commit is contained in:
parent
b553bba1d8
commit
549686a7a4
33 changed files with 740 additions and 417 deletions
|
@ -154,7 +154,7 @@
|
|||
? `®ion=${region}&city=${city}&country=${countryName}&timezone=${timezone}`
|
||||
: '';
|
||||
|
||||
const response = await fetch(chatApi, { headers });
|
||||
const response = await fetch(chatApi, { method: 'POST', headers });
|
||||
|
||||
try {
|
||||
if (!response.ok) throw new Error(response.statusText);
|
||||
|
|
|
@ -407,7 +407,7 @@
|
|||
? `®ion=${region}&city=${city}&country=${countryName}&timezone=${timezone}`
|
||||
: '';
|
||||
|
||||
const response = await fetch(chatApi, { headers });
|
||||
const response = await fetch(chatApi, { method: 'POST', headers });
|
||||
|
||||
try {
|
||||
if (!response.ok) throw new Error(response.statusText);
|
||||
|
|
|
@ -878,7 +878,7 @@ Call CALLBACK func with response and CBARGS."
|
|||
(let ((params `(("q" ,query) ("n" ,khoj-results-count))))
|
||||
(when session-id (push `("conversation_id" ,session-id) params))
|
||||
(khoj--call-api-async "/api/chat"
|
||||
"GET"
|
||||
"POST"
|
||||
params
|
||||
callback cbargs)))
|
||||
|
||||
|
|
|
@ -1074,9 +1074,9 @@ export class KhojChatView extends KhojPaneView {
|
|||
};
|
||||
|
||||
let response = await fetch(chatUrl, {
|
||||
method: "GET",
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "text/plain",
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": `Bearer ${this.setting.khojApiKey}`,
|
||||
},
|
||||
})
|
||||
|
|
|
@ -40,9 +40,9 @@ export default function RootLayout({
|
|||
content="default-src 'self' https://assets.khoj.dev;
|
||||
media-src * blob:;
|
||||
script-src 'self' https://assets.khoj.dev 'unsafe-inline' 'unsafe-eval';
|
||||
connect-src 'self' https://ipapi.co/json ws://localhost:42110;
|
||||
connect-src 'self' blob: https://ipapi.co/json ws://localhost:42110;
|
||||
style-src 'self' https://assets.khoj.dev 'unsafe-inline' https://fonts.googleapis.com;
|
||||
img-src 'self' data: https://*.khoj.dev https://*.googleusercontent.com https://*.google.com/ https://*.gstatic.com;
|
||||
img-src 'self' data: blob: https://*.khoj.dev https://*.googleusercontent.com https://*.google.com/ https://*.gstatic.com;
|
||||
font-src 'self' https://assets.khoj.dev https://fonts.gstatic.com;
|
||||
child-src 'none';
|
||||
object-src 'none';"
|
||||
|
|
|
@ -27,12 +27,14 @@ interface ChatBodyDataProps {
|
|||
setUploadedFiles: (files: string[]) => void;
|
||||
isMobileWidth?: boolean;
|
||||
isLoggedIn: boolean;
|
||||
setImage64: (image64: string) => void;
|
||||
}
|
||||
|
||||
function ChatBodyData(props: ChatBodyDataProps) {
|
||||
const searchParams = useSearchParams();
|
||||
const conversationId = searchParams.get("conversationId");
|
||||
const [message, setMessage] = useState("");
|
||||
const [image, setImage] = useState<string | null>(null);
|
||||
const [processingMessage, setProcessingMessage] = useState(false);
|
||||
const [agentMetadata, setAgentMetadata] = useState<AgentData | null>(null);
|
||||
|
||||
|
@ -40,6 +42,19 @@ function ChatBodyData(props: ChatBodyDataProps) {
|
|||
const onConversationIdChange = props.onConversationIdChange;
|
||||
|
||||
useEffect(() => {
|
||||
if (image) {
|
||||
props.setImage64(encodeURIComponent(image));
|
||||
}
|
||||
}, [image, props.setImage64]);
|
||||
|
||||
useEffect(() => {
|
||||
const storedImage = localStorage.getItem("image");
|
||||
if (storedImage) {
|
||||
setImage(storedImage);
|
||||
props.setImage64(encodeURIComponent(storedImage));
|
||||
localStorage.removeItem("image");
|
||||
}
|
||||
|
||||
const storedMessage = localStorage.getItem("message");
|
||||
if (storedMessage) {
|
||||
setProcessingMessage(true);
|
||||
|
@ -95,6 +110,7 @@ function ChatBodyData(props: ChatBodyDataProps) {
|
|||
agentColor={agentMetadata?.color}
|
||||
isLoggedIn={props.isLoggedIn}
|
||||
sendMessage={(message) => setMessage(message)}
|
||||
sendImage={(image) => setImage(image)}
|
||||
sendDisabled={processingMessage}
|
||||
chatOptionsData={props.chatOptionsData}
|
||||
conversationId={conversationId}
|
||||
|
@ -116,6 +132,7 @@ export default function Chat() {
|
|||
const [queryToProcess, setQueryToProcess] = useState<string>("");
|
||||
const [processQuerySignal, setProcessQuerySignal] = useState(false);
|
||||
const [uploadedFiles, setUploadedFiles] = useState<string[]>([]);
|
||||
const [image64, setImage64] = useState<string>("");
|
||||
const locationData = useIPLocationData();
|
||||
const authenticatedData = useAuthenticatedData();
|
||||
const isMobileWidth = useIsMobileWidth();
|
||||
|
@ -148,6 +165,7 @@ export default function Chat() {
|
|||
completed: false,
|
||||
timestamp: new Date().toISOString(),
|
||||
rawQuery: queryToProcess || "",
|
||||
uploadedImageData: decodeURIComponent(image64),
|
||||
};
|
||||
setMessages((prevMessages) => [...prevMessages, newStreamMessage]);
|
||||
setProcessQuerySignal(true);
|
||||
|
@ -178,6 +196,7 @@ export default function Chat() {
|
|||
if (done) {
|
||||
setQueryToProcess("");
|
||||
setProcessQuerySignal(false);
|
||||
setImage64("");
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -218,7 +237,14 @@ export default function Chat() {
|
|||
chatAPI += `®ion=${locationData.region}&country=${locationData.country}&city=${locationData.city}&timezone=${locationData.timezone}`;
|
||||
}
|
||||
|
||||
const response = await fetch(chatAPI);
|
||||
const response = await fetch(chatAPI, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: image64 ? JSON.stringify({ image: image64 }) : undefined,
|
||||
});
|
||||
|
||||
try {
|
||||
await readChatStream(response);
|
||||
} catch (err) {
|
||||
|
@ -282,6 +308,7 @@ export default function Chat() {
|
|||
setUploadedFiles={setUploadedFiles}
|
||||
isMobileWidth={isMobileWidth}
|
||||
onConversationIdChange={handleConversationIdChange}
|
||||
setImage64={setImage64}
|
||||
/>
|
||||
</Suspense>
|
||||
</div>
|
||||
|
|
|
@ -267,6 +267,7 @@ export default function ChatHistory(props: ChatHistoryProps) {
|
|||
created: message.timestamp,
|
||||
by: "you",
|
||||
automationId: "",
|
||||
uploadedImageData: message.uploadedImageData,
|
||||
}}
|
||||
customClassName="fullHistory"
|
||||
borderLeftColor={`${data?.agent.color}-500`}
|
||||
|
@ -309,6 +310,7 @@ export default function ChatHistory(props: ChatHistoryProps) {
|
|||
created: new Date().getTime().toString(),
|
||||
by: "you",
|
||||
automationId: "",
|
||||
uploadedImageData: props.pendingMessage,
|
||||
}}
|
||||
customClassName="fullHistory"
|
||||
borderLeftColor={`${data?.agent.color}-500`}
|
||||
|
|
|
@ -16,6 +16,7 @@ import {
|
|||
Microphone,
|
||||
Notebook,
|
||||
Paperclip,
|
||||
X,
|
||||
Question,
|
||||
Robot,
|
||||
Shapes,
|
||||
|
@ -55,6 +56,7 @@ export interface ChatOptions {
|
|||
|
||||
interface ChatInputProps {
|
||||
sendMessage: (message: string) => void;
|
||||
sendImage: (image: string) => void;
|
||||
sendDisabled: boolean;
|
||||
setUploadedFiles?: (files: string[]) => void;
|
||||
conversationId?: string | null;
|
||||
|
@ -75,6 +77,9 @@ export default function ChatInputArea(props: ChatInputProps) {
|
|||
const [showLoginPrompt, setShowLoginPrompt] = useState(false);
|
||||
|
||||
const [recording, setRecording] = useState(false);
|
||||
const [imageUploaded, setImageUploaded] = useState(false);
|
||||
const [imagePath, setImagePath] = useState<string | null>(null);
|
||||
const [imageData, setImageData] = useState<string | null>(null);
|
||||
const [mediaRecorder, setMediaRecorder] = useState<MediaRecorder | null>(null);
|
||||
|
||||
const [progressValue, setProgressValue] = useState(0);
|
||||
|
@ -97,7 +102,30 @@ export default function ChatInputArea(props: ChatInputProps) {
|
|||
}
|
||||
}, [uploading]);
|
||||
|
||||
useEffect(() => {
|
||||
async function fetchImageData() {
|
||||
if (imagePath) {
|
||||
const response = await fetch(imagePath);
|
||||
const blob = await response.blob();
|
||||
const reader = new FileReader();
|
||||
reader.onload = function () {
|
||||
const base64data = reader.result;
|
||||
setImageData(base64data as string);
|
||||
};
|
||||
reader.readAsDataURL(blob);
|
||||
}
|
||||
setUploading(false);
|
||||
}
|
||||
setUploading(true);
|
||||
fetchImageData();
|
||||
}, [imagePath]);
|
||||
|
||||
function onSendMessage() {
|
||||
if (imageUploaded) {
|
||||
setImageUploaded(false);
|
||||
setImagePath(null);
|
||||
props.sendImage(imageData || "");
|
||||
}
|
||||
if (!message.trim()) return;
|
||||
|
||||
if (!props.isLoggedIn) {
|
||||
|
@ -142,6 +170,17 @@ export default function ChatInputArea(props: ChatInputProps) {
|
|||
setShowLoginPrompt(true);
|
||||
return;
|
||||
}
|
||||
// check for image file
|
||||
const image_endings = ["jpg", "jpeg", "png"];
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
const file = files[i];
|
||||
const file_extension = file.name.split(".").pop();
|
||||
if (image_endings.includes(file_extension || "")) {
|
||||
setImageUploaded(true);
|
||||
setImagePath(URL.createObjectURL(file));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
uploadDataForIndexing(
|
||||
files,
|
||||
|
@ -287,6 +326,11 @@ export default function ChatInputArea(props: ChatInputProps) {
|
|||
setIsDragAndDropping(false);
|
||||
}
|
||||
|
||||
function removeImageUpload() {
|
||||
setImageUploaded(false);
|
||||
setImagePath(null);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{showLoginPrompt && loginRedirectMessage && (
|
||||
|
@ -397,11 +441,24 @@ export default function ChatInputArea(props: ChatInputProps) {
|
|||
</div>
|
||||
)}
|
||||
<div
|
||||
className={`${styles.actualInputArea} items-center justify-between dark:bg-neutral-700`}
|
||||
className={`${styles.actualInputArea} items-center justify-between dark:bg-neutral-700 relative`}
|
||||
onDragOver={handleDragOver}
|
||||
onDragLeave={handleDragLeave}
|
||||
onDrop={handleDragAndDropFiles}
|
||||
>
|
||||
{imageUploaded && (
|
||||
<div className="absolute bottom-[80px] left-0 right-0 dark:bg-neutral-700 bg-white pt-5 pb-5 w-full rounded-lg border dark:border-none grid grid-cols-2">
|
||||
<div className="pl-4 pr-4">
|
||||
<img src={imagePath || ""} alt="img" className="w-auto max-h-[100px]" />
|
||||
</div>
|
||||
<div className="pl-4 pr-4">
|
||||
<X
|
||||
className="w-6 h-6 float-right dark:hover:bg-[hsl(var(--background))] hover:bg-neutral-100 rounded-sm"
|
||||
onClick={removeImageUpload}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<input
|
||||
type="file"
|
||||
multiple={true}
|
||||
|
@ -427,6 +484,8 @@ export default function ChatInputArea(props: ChatInputProps) {
|
|||
value={message}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter" && !e.shiftKey) {
|
||||
setImageUploaded(false);
|
||||
setImagePath(null);
|
||||
e.preventDefault();
|
||||
onSendMessage();
|
||||
}
|
||||
|
|
|
@ -53,6 +53,11 @@ div.chatMessageContainer h3 img {
|
|||
width: 24px;
|
||||
}
|
||||
|
||||
div.you img {
|
||||
height: 16rem;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
div.you {
|
||||
color: hsla(var(--secondary-foreground));
|
||||
}
|
||||
|
|
|
@ -111,6 +111,7 @@ export interface SingleChatMessage {
|
|||
rawQuery?: string;
|
||||
intent?: Intent;
|
||||
agent?: AgentData;
|
||||
uploadedImageData?: string;
|
||||
}
|
||||
|
||||
export interface StreamMessage {
|
||||
|
@ -122,6 +123,7 @@ export interface StreamMessage {
|
|||
rawQuery: string;
|
||||
timestamp: string;
|
||||
agent?: AgentData;
|
||||
uploadedImageData?: string;
|
||||
}
|
||||
|
||||
export interface ChatHistoryData {
|
||||
|
@ -203,6 +205,7 @@ interface ChatMessageProps {
|
|||
borderLeftColor?: string;
|
||||
isLastMessage?: boolean;
|
||||
agent?: AgentData;
|
||||
uploadedImageData?: string;
|
||||
}
|
||||
|
||||
interface TrainOfThoughtProps {
|
||||
|
@ -273,6 +276,7 @@ export function TrainOfThought(props: TrainOfThoughtProps) {
|
|||
export default function ChatMessage(props: ChatMessageProps) {
|
||||
const [copySuccess, setCopySuccess] = useState<boolean>(false);
|
||||
const [isHovering, setIsHovering] = useState<boolean>(false);
|
||||
const [textRendered, setTextRendered] = useState<string>("");
|
||||
const [markdownRendered, setMarkdownRendered] = useState<string>("");
|
||||
const [isPlaying, setIsPlaying] = useState<boolean>(false);
|
||||
const [interrupted, setInterrupted] = useState<boolean>(false);
|
||||
|
@ -322,6 +326,10 @@ export default function ChatMessage(props: ChatMessageProps) {
|
|||
.replace(/\\\[/g, "LEFTBRACKET")
|
||||
.replace(/\\\]/g, "RIGHTBRACKET");
|
||||
|
||||
if (props.chatMessage.uploadedImageData) {
|
||||
message = `![uploaded image](${props.chatMessage.uploadedImageData})\n\n${message}`;
|
||||
}
|
||||
|
||||
if (props.chatMessage.intent && props.chatMessage.intent.type == "text-to-image") {
|
||||
message = `![generated image](data:image/png;base64,${message})`;
|
||||
} else if (props.chatMessage.intent && props.chatMessage.intent.type == "text-to-image2") {
|
||||
|
@ -340,6 +348,9 @@ export default function ChatMessage(props: ChatMessageProps) {
|
|||
message += `\n\n**Inferred Query**\n\n${props.chatMessage.intent["inferred-queries"][0]}`;
|
||||
}
|
||||
|
||||
setTextRendered(message);
|
||||
|
||||
// Render the markdown
|
||||
let markdownRendered = md.render(message);
|
||||
|
||||
// Replace placeholders with LaTeX delimiters
|
||||
|
@ -542,7 +553,6 @@ export default function ChatMessage(props: ChatMessageProps) {
|
|||
className={constructClasses(props.chatMessage)}
|
||||
onMouseLeave={(event) => setIsHovering(false)}
|
||||
onMouseEnter={(event) => setIsHovering(true)}
|
||||
onClick={props.chatMessage.by === "khoj" ? (event) => undefined : undefined}
|
||||
>
|
||||
<div className={chatMessageWrapperClasses(props.chatMessage)}>
|
||||
<div
|
||||
|
@ -595,7 +605,7 @@ export default function ChatMessage(props: ChatMessageProps) {
|
|||
title="Copy"
|
||||
className={`${styles.copyButton}`}
|
||||
onClick={() => {
|
||||
navigator.clipboard.writeText(props.chatMessage.message);
|
||||
navigator.clipboard.writeText(textRendered);
|
||||
setCopySuccess(true);
|
||||
}}
|
||||
>
|
||||
|
|
|
@ -79,7 +79,7 @@ async function verifyStatement(
|
|||
let verificationMessage = `${verificationPrecursor} ${message}`;
|
||||
const apiURL = `${chatURL}?q=${encodeURIComponent(verificationMessage)}&client=web&stream=true&conversation_id=${conversationId}`;
|
||||
try {
|
||||
const response = await fetch(apiURL);
|
||||
const response = await fetch(apiURL, { method: "POST" });
|
||||
if (!response.body) throw new Error("No response body found");
|
||||
|
||||
const reader = response.body?.getReader();
|
||||
|
|
|
@ -45,9 +45,9 @@ export default function RootLayout({
|
|||
content="default-src 'self' https://assets.khoj.dev;
|
||||
media-src * blob:;
|
||||
script-src 'self' https://assets.khoj.dev 'unsafe-inline' 'unsafe-eval';
|
||||
connect-src 'self' https://ipapi.co/json ws://localhost:42110;
|
||||
connect-src 'self' blob: https://ipapi.co/json ws://localhost:42110;
|
||||
style-src 'self' https://assets.khoj.dev 'unsafe-inline' https://fonts.googleapis.com;
|
||||
img-src 'self' data: https://*.khoj.dev https://*.googleusercontent.com https://*.google.com/ https://*.gstatic.com;
|
||||
img-src 'self' data: blob: https://*.khoj.dev https://*.googleusercontent.com https://*.google.com/ https://*.gstatic.com;
|
||||
font-src 'self' https://assets.khoj.dev https://fonts.gstatic.com;
|
||||
child-src 'none';
|
||||
object-src 'none';"
|
||||
|
|
|
@ -43,6 +43,7 @@ function FisherYatesShuffle(array: any[]) {
|
|||
|
||||
function ChatBodyData(props: ChatBodyDataProps) {
|
||||
const [message, setMessage] = useState("");
|
||||
const [image, setImage] = useState<string | null>(null);
|
||||
const [processingMessage, setProcessingMessage] = useState(false);
|
||||
const [greeting, setGreeting] = useState("");
|
||||
const [shuffledOptions, setShuffledOptions] = useState<Suggestion[]>([]);
|
||||
|
@ -141,6 +142,9 @@ function ChatBodyData(props: ChatBodyDataProps) {
|
|||
onConversationIdChange?.(newConversationId);
|
||||
window.location.href = `/chat?conversationId=${newConversationId}`;
|
||||
localStorage.setItem("message", message);
|
||||
if (image) {
|
||||
localStorage.setItem("image", image);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error creating new conversation:", error);
|
||||
setProcessingMessage(false);
|
||||
|
@ -230,6 +234,7 @@ function ChatBodyData(props: ChatBodyDataProps) {
|
|||
<ChatInputArea
|
||||
isLoggedIn={props.isLoggedIn}
|
||||
sendMessage={(message) => setMessage(message)}
|
||||
sendImage={(image) => setImage(image)}
|
||||
sendDisabled={processingMessage}
|
||||
chatOptionsData={props.chatOptionsData}
|
||||
conversationId={null}
|
||||
|
@ -310,6 +315,7 @@ function ChatBodyData(props: ChatBodyDataProps) {
|
|||
<ChatInputArea
|
||||
isLoggedIn={props.isLoggedIn}
|
||||
sendMessage={(message) => setMessage(message)}
|
||||
sendImage={(image) => setImage(image)}
|
||||
sendDisabled={processingMessage}
|
||||
chatOptionsData={props.chatOptionsData}
|
||||
conversationId={null}
|
||||
|
|
|
@ -20,9 +20,9 @@ export default function RootLayout({
|
|||
httpEquiv="Content-Security-Policy"
|
||||
content="default-src 'self' https://assets.khoj.dev;
|
||||
script-src 'self' https://assets.khoj.dev 'unsafe-inline' 'unsafe-eval';
|
||||
connect-src 'self' https://ipapi.co/json ws://localhost:42110;
|
||||
connect-src 'self' blob: https://ipapi.co/json ws://localhost:42110;
|
||||
style-src 'self' https://assets.khoj.dev 'unsafe-inline' https://fonts.googleapis.com;
|
||||
img-src 'self' data: https://*.khoj.dev https://*.googleusercontent.com https://*.google.com/ https://*.gstatic.com;
|
||||
img-src 'self' data: blob: https://*.khoj.dev https://*.googleusercontent.com https://*.google.com/ https://*.gstatic.com;
|
||||
font-src 'self' https://assets.khoj.dev https://fonts.gstatic.com;
|
||||
child-src 'none';
|
||||
object-src 'none';"
|
||||
|
|
|
@ -28,16 +28,23 @@ interface ChatBodyDataProps {
|
|||
isLoggedIn: boolean;
|
||||
conversationId?: string;
|
||||
setQueryToProcess: (query: string) => void;
|
||||
setImage64: (image64: string) => void;
|
||||
}
|
||||
|
||||
function ChatBodyData(props: ChatBodyDataProps) {
|
||||
const [message, setMessage] = useState("");
|
||||
const [image, setImage] = useState<string | null>(null);
|
||||
const [processingMessage, setProcessingMessage] = useState(false);
|
||||
const [agentMetadata, setAgentMetadata] = useState<AgentData | null>(null);
|
||||
|
||||
const setQueryToProcess = props.setQueryToProcess;
|
||||
const streamedMessages = props.streamedMessages;
|
||||
|
||||
useEffect(() => {
|
||||
if (image) {
|
||||
props.setImage64(encodeURIComponent(image));
|
||||
}
|
||||
}, [image, props.setImage64]);
|
||||
|
||||
useEffect(() => {
|
||||
if (message) {
|
||||
setProcessingMessage(true);
|
||||
|
@ -74,11 +81,12 @@ function ChatBodyData(props: ChatBodyDataProps) {
|
|||
/>
|
||||
</div>
|
||||
<div
|
||||
className={`${styles.inputBox} shadow-md bg-background align-middle items-center justify-center px-3`}
|
||||
className={`${styles.inputBox} p-1 md:px-2 shadow-md bg-background align-middle items-center justify-center dark:bg-neutral-700 dark:border-0 dark:shadow-sm rounded-t-2xl rounded-b-none md:rounded-xl`}
|
||||
>
|
||||
<ChatInputArea
|
||||
isLoggedIn={props.isLoggedIn}
|
||||
sendMessage={(message) => setMessage(message)}
|
||||
sendImage={(image) => setImage(image)}
|
||||
sendDisabled={processingMessage}
|
||||
chatOptionsData={props.chatOptionsData}
|
||||
conversationId={props.conversationId}
|
||||
|
@ -101,6 +109,7 @@ export default function SharedChat() {
|
|||
const [processQuerySignal, setProcessQuerySignal] = useState(false);
|
||||
const [uploadedFiles, setUploadedFiles] = useState<string[]>([]);
|
||||
const [paramSlug, setParamSlug] = useState<string | undefined>(undefined);
|
||||
const [image64, setImage64] = useState<string>("");
|
||||
|
||||
const locationData = useIPLocationData();
|
||||
const authenticatedData = useAuthenticatedData();
|
||||
|
@ -156,6 +165,7 @@ export default function SharedChat() {
|
|||
completed: false,
|
||||
timestamp: new Date().toISOString(),
|
||||
rawQuery: queryToProcess || "",
|
||||
uploadedImageData: decodeURIComponent(image64),
|
||||
};
|
||||
setMessages((prevMessages) => [...prevMessages, newStreamMessage]);
|
||||
setProcessQuerySignal(true);
|
||||
|
@ -182,6 +192,7 @@ export default function SharedChat() {
|
|||
if (done) {
|
||||
setQueryToProcess("");
|
||||
setProcessQuerySignal(false);
|
||||
setImage64("");
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -216,33 +227,21 @@ export default function SharedChat() {
|
|||
chatAPI += `®ion=${locationData.region}&country=${locationData.country}&city=${locationData.city}&timezone=${locationData.timezone}`;
|
||||
}
|
||||
|
||||
const response = await fetch(chatAPI);
|
||||
const response = await fetch(chatAPI, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: image64 ? JSON.stringify({ image: image64 }) : undefined,
|
||||
});
|
||||
|
||||
try {
|
||||
await readChatStream(response);
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
if (conversationId) {
|
||||
// Add a new object to the state
|
||||
const newStreamMessage: StreamMessage = {
|
||||
rawResponse: "",
|
||||
trainOfThought: [],
|
||||
context: [],
|
||||
onlineContext: {},
|
||||
completed: false,
|
||||
timestamp: new Date().toISOString(),
|
||||
rawQuery: queryToProcess || "",
|
||||
};
|
||||
setProcessQuerySignal(true);
|
||||
setMessages((prevMessages) => [...prevMessages, newStreamMessage]);
|
||||
}
|
||||
})();
|
||||
}, [conversationId, queryToProcess]);
|
||||
|
||||
if (isLoading) {
|
||||
return <Loading />;
|
||||
}
|
||||
|
@ -275,6 +274,7 @@ export default function SharedChat() {
|
|||
setTitle={setTitle}
|
||||
setUploadedFiles={setUploadedFiles}
|
||||
isMobileWidth={isMobileWidth}
|
||||
setImage64={setImage64}
|
||||
/>
|
||||
</Suspense>
|
||||
</div>
|
||||
|
|
|
@ -12,15 +12,11 @@ div.main {
|
|||
|
||||
div.inputBox {
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 16px;
|
||||
margin-bottom: 20px;
|
||||
gap: 12px;
|
||||
padding-left: 20px;
|
||||
padding-right: 20px;
|
||||
align-content: center;
|
||||
}
|
||||
|
||||
|
||||
input.inputBox {
|
||||
border: none;
|
||||
}
|
||||
|
@ -31,7 +27,7 @@ input.inputBox:focus {
|
|||
}
|
||||
|
||||
div.inputBox:focus {
|
||||
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
|
||||
box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
div.chatBodyFull {
|
||||
|
@ -94,7 +90,6 @@ div.agentIndicator {
|
|||
padding: 10px;
|
||||
}
|
||||
|
||||
|
||||
@media (max-width: 768px) {
|
||||
div.chatBody {
|
||||
grid-template-columns: 0fr 1fr;
|
||||
|
@ -124,5 +119,4 @@ div.agentIndicator {
|
|||
gap: 0;
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@
|
|||
"eslint": "^8",
|
||||
"eslint-config-next": "14.2.3",
|
||||
"input-otp": "^1.2.4",
|
||||
"intl-tel-input": "^23.8.0",
|
||||
"intl-tel-input": "^23.8.1",
|
||||
"katex": "^0.16.10",
|
||||
"libphonenumber-js": "^1.11.4",
|
||||
"lucide-react": "^0.397.0",
|
||||
|
|
|
@ -28,38 +28,38 @@
|
|||
"@babel/highlight" "^7.24.7"
|
||||
picocolors "^1.0.0"
|
||||
|
||||
"@babel/compat-data@^7.24.8":
|
||||
version "7.25.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.25.0.tgz#6b226a5da3a686db3c30519750e071dce292ad95"
|
||||
integrity sha512-P4fwKI2mjEb3ZU5cnMJzvRsRKGBUcs8jvxIoRmr6ufAY9Xk2Bz7JubRTTivkw55c7WQJfTECeqYVa+HZ0FzREg==
|
||||
"@babel/compat-data@^7.25.2":
|
||||
version "7.25.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.25.4.tgz#7d2a80ce229890edcf4cc259d4d696cb4dae2fcb"
|
||||
integrity sha512-+LGRog6RAsCJrrrg/IO6LGmpphNe5DiK30dGjCoxxeGv49B10/3XYGxPsAwrDlMFcFEvdAUavDT8r9k/hSyQqQ==
|
||||
|
||||
"@babel/core@^7.22.1":
|
||||
version "7.24.9"
|
||||
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.24.9.tgz#dc07c9d307162c97fa9484ea997ade65841c7c82"
|
||||
integrity sha512-5e3FI4Q3M3Pbr21+5xJwCv6ZT6KmGkI0vw3Tozy5ODAQFTIWe37iT8Cr7Ice2Ntb+M3iSKCEWMB1MBgKrW3whg==
|
||||
version "7.25.2"
|
||||
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.25.2.tgz#ed8eec275118d7613e77a352894cd12ded8eba77"
|
||||
integrity sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA==
|
||||
dependencies:
|
||||
"@ampproject/remapping" "^2.2.0"
|
||||
"@babel/code-frame" "^7.24.7"
|
||||
"@babel/generator" "^7.24.9"
|
||||
"@babel/helper-compilation-targets" "^7.24.8"
|
||||
"@babel/helper-module-transforms" "^7.24.9"
|
||||
"@babel/helpers" "^7.24.8"
|
||||
"@babel/parser" "^7.24.8"
|
||||
"@babel/template" "^7.24.7"
|
||||
"@babel/traverse" "^7.24.8"
|
||||
"@babel/types" "^7.24.9"
|
||||
"@babel/generator" "^7.25.0"
|
||||
"@babel/helper-compilation-targets" "^7.25.2"
|
||||
"@babel/helper-module-transforms" "^7.25.2"
|
||||
"@babel/helpers" "^7.25.0"
|
||||
"@babel/parser" "^7.25.0"
|
||||
"@babel/template" "^7.25.0"
|
||||
"@babel/traverse" "^7.25.2"
|
||||
"@babel/types" "^7.25.2"
|
||||
convert-source-map "^2.0.0"
|
||||
debug "^4.1.0"
|
||||
gensync "^1.0.0-beta.2"
|
||||
json5 "^2.2.3"
|
||||
semver "^6.3.1"
|
||||
|
||||
"@babel/generator@^7.24.9", "@babel/generator@^7.25.0":
|
||||
version "7.25.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.25.0.tgz#f858ddfa984350bc3d3b7f125073c9af6988f18e"
|
||||
integrity sha512-3LEEcj3PVW8pW2R1SR1M89g/qrYk/m/mB/tLqn7dn4sbBUQyTqnlod+II2U4dqiGtUmkcnAmkMDralTFZttRiw==
|
||||
"@babel/generator@^7.25.0", "@babel/generator@^7.25.6":
|
||||
version "7.25.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.25.6.tgz#0df1ad8cb32fe4d2b01d8bf437f153d19342a87c"
|
||||
integrity sha512-VPC82gr1seXOpkjAAKoLhP50vx4vGNlF4msF64dSFq1P8RfB+QAuJWGHPXXPc8QyfVWwwB/TNNU4+ayZmHNbZw==
|
||||
dependencies:
|
||||
"@babel/types" "^7.25.0"
|
||||
"@babel/types" "^7.25.6"
|
||||
"@jridgewell/gen-mapping" "^0.3.5"
|
||||
"@jridgewell/trace-mapping" "^0.3.25"
|
||||
jsesc "^2.5.1"
|
||||
|
@ -71,28 +71,28 @@
|
|||
dependencies:
|
||||
"@babel/types" "^7.24.7"
|
||||
|
||||
"@babel/helper-compilation-targets@^7.24.8":
|
||||
version "7.24.8"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.8.tgz#b607c3161cd9d1744977d4f97139572fe778c271"
|
||||
integrity sha512-oU+UoqCHdp+nWVDkpldqIQL/i/bvAv53tRqLG/s+cOXxe66zOYLU7ar/Xs3LdmBihrUMEUhwu6dMZwbNOYDwvw==
|
||||
"@babel/helper-compilation-targets@^7.25.2":
|
||||
version "7.25.2"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.2.tgz#e1d9410a90974a3a5a66e84ff55ef62e3c02d06c"
|
||||
integrity sha512-U2U5LsSaZ7TAt3cfaymQ8WHh0pxvdHoEk6HVpaexxixjyEquMh0L0YNJNM6CTGKMXV1iksi0iZkGw4AcFkPaaw==
|
||||
dependencies:
|
||||
"@babel/compat-data" "^7.24.8"
|
||||
"@babel/compat-data" "^7.25.2"
|
||||
"@babel/helper-validator-option" "^7.24.8"
|
||||
browserslist "^4.23.1"
|
||||
lru-cache "^5.1.1"
|
||||
semver "^6.3.1"
|
||||
|
||||
"@babel/helper-create-class-features-plugin@^7.25.0":
|
||||
version "7.25.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.0.tgz#a109bf9c3d58dfed83aaf42e85633c89f43a6253"
|
||||
integrity sha512-GYM6BxeQsETc9mnct+nIIpf63SAyzvyYN7UB/IlTyd+MBg06afFGp0mIeUqGyWgS2mxad6vqbMrHVlaL3m70sQ==
|
||||
version "7.25.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.4.tgz#57eaf1af38be4224a9d9dd01ddde05b741f50e14"
|
||||
integrity sha512-ro/bFs3/84MDgDmMwbcHgDa8/E6J3QKNTk4xJJnVeFtGE+tL0K26E3pNxhYz2b67fJpt7Aphw5XcploKXuCvCQ==
|
||||
dependencies:
|
||||
"@babel/helper-annotate-as-pure" "^7.24.7"
|
||||
"@babel/helper-member-expression-to-functions" "^7.24.8"
|
||||
"@babel/helper-optimise-call-expression" "^7.24.7"
|
||||
"@babel/helper-replace-supers" "^7.25.0"
|
||||
"@babel/helper-skip-transparent-expression-wrappers" "^7.24.7"
|
||||
"@babel/traverse" "^7.25.0"
|
||||
"@babel/traverse" "^7.25.4"
|
||||
semver "^6.3.1"
|
||||
|
||||
"@babel/helper-member-expression-to-functions@^7.24.8":
|
||||
|
@ -111,15 +111,15 @@
|
|||
"@babel/traverse" "^7.24.7"
|
||||
"@babel/types" "^7.24.7"
|
||||
|
||||
"@babel/helper-module-transforms@^7.24.9":
|
||||
version "7.25.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.25.0.tgz#3ffc23c473a2769a7e40d3274495bd559fdd2ecc"
|
||||
integrity sha512-bIkOa2ZJYn7FHnepzr5iX9Kmz8FjIz4UKzJ9zhX3dnYuVW0xul9RuR3skBfoLu+FPTQw90EHW9rJsSZhyLQ3fQ==
|
||||
"@babel/helper-module-transforms@^7.25.2":
|
||||
version "7.25.2"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.25.2.tgz#ee713c29768100f2776edf04d4eb23b8d27a66e6"
|
||||
integrity sha512-BjyRAbix6j/wv83ftcVJmBt72QtHI56C7JXZoG2xATiLpmoC7dpd8WnkikExHDVPpi/3qCmO6WY1EaXOluiecQ==
|
||||
dependencies:
|
||||
"@babel/helper-module-imports" "^7.24.7"
|
||||
"@babel/helper-simple-access" "^7.24.7"
|
||||
"@babel/helper-validator-identifier" "^7.24.7"
|
||||
"@babel/traverse" "^7.25.0"
|
||||
"@babel/traverse" "^7.25.2"
|
||||
|
||||
"@babel/helper-optimise-call-expression@^7.24.7":
|
||||
version "7.24.7"
|
||||
|
@ -128,7 +128,7 @@
|
|||
dependencies:
|
||||
"@babel/types" "^7.24.7"
|
||||
|
||||
"@babel/helper-plugin-utils@^7.24.7", "@babel/helper-plugin-utils@^7.24.8":
|
||||
"@babel/helper-plugin-utils@^7.24.8":
|
||||
version "7.24.8"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.8.tgz#94ee67e8ec0e5d44ea7baeb51e571bd26af07878"
|
||||
integrity sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg==
|
||||
|
@ -173,13 +173,13 @@
|
|||
resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz#3725cdeea8b480e86d34df15304806a06975e33d"
|
||||
integrity sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==
|
||||
|
||||
"@babel/helpers@^7.24.8":
|
||||
version "7.25.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.25.0.tgz#e69beb7841cb93a6505531ede34f34e6a073650a"
|
||||
integrity sha512-MjgLZ42aCm0oGjJj8CtSM3DB8NOOf8h2l7DCTePJs29u+v7yO/RBX9nShlKMgFnRks/Q4tBAe7Hxnov9VkGwLw==
|
||||
"@babel/helpers@^7.25.0":
|
||||
version "7.25.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.25.6.tgz#57ee60141829ba2e102f30711ffe3afab357cc60"
|
||||
integrity sha512-Xg0tn4HcfTijTwfDwYlvVCl43V6h4KyVVX2aEm4qdO/PC6L2YvzLHFdmxhoeSA3eslcE6+ZVXHgWwopXYLNq4Q==
|
||||
dependencies:
|
||||
"@babel/template" "^7.25.0"
|
||||
"@babel/types" "^7.25.0"
|
||||
"@babel/types" "^7.25.6"
|
||||
|
||||
"@babel/highlight@^7.24.7":
|
||||
version "7.24.7"
|
||||
|
@ -191,22 +191,24 @@
|
|||
js-tokens "^4.0.0"
|
||||
picocolors "^1.0.0"
|
||||
|
||||
"@babel/parser@^7.22.6", "@babel/parser@^7.24.8", "@babel/parser@^7.25.0":
|
||||
version "7.25.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.25.0.tgz#9fdc9237504d797b6e7b8f66e78ea7f570d256ad"
|
||||
integrity sha512-CzdIU9jdP0dg7HdyB+bHvDJGagUv+qtzZt5rYCWwW6tITNqV9odjp6Qu41gkG0ca5UfdDUWrKkiAnHHdGRnOrA==
|
||||
"@babel/parser@^7.22.6", "@babel/parser@^7.25.0", "@babel/parser@^7.25.6":
|
||||
version "7.25.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.25.6.tgz#85660c5ef388cbbf6e3d2a694ee97a38f18afe2f"
|
||||
integrity sha512-trGdfBdbD0l1ZPmcJ83eNxB9rbEax4ALFTF7fN386TMYbeCQbyme5cOEXQhbGXKebwGaB/J52w1mrklMcbgy6Q==
|
||||
dependencies:
|
||||
"@babel/types" "^7.25.6"
|
||||
|
||||
"@babel/plugin-syntax-typescript@^7.24.7":
|
||||
version "7.24.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.7.tgz#58d458271b4d3b6bb27ee6ac9525acbb259bad1c"
|
||||
integrity sha512-c/+fVeJBB0FeKsFvwytYiUD+LBvhHjGSI0g446PRGdSVGZLRNArBUno2PETbAly3tpiNAQR5XaZ+JslxkotsbA==
|
||||
version "7.25.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.4.tgz#04db9ce5a9043d9c635e75ae7969a2cd50ca97ff"
|
||||
integrity sha512-uMOCoHVU52BsSWxPOMVv5qKRdeSlPuImUCB2dlPuBSU+W2/ROE7/Zg8F2Kepbk+8yBa68LlRKxO+xgEVWorsDg==
|
||||
dependencies:
|
||||
"@babel/helper-plugin-utils" "^7.24.7"
|
||||
"@babel/helper-plugin-utils" "^7.24.8"
|
||||
|
||||
"@babel/plugin-transform-typescript@^7.22.5":
|
||||
version "7.25.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.25.0.tgz#56f47fb87b86a97caa9c7770920a1967d40ac86e"
|
||||
integrity sha512-LZicxFzHIw+Sa3pzgMgSz6gdpsdkfiMObHUzhSIrwKF0+/rP/nuR49u79pSS+zIFJ1FeGeqQD2Dq4QGFbOVvSw==
|
||||
version "7.25.2"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.25.2.tgz#237c5d10de6d493be31637c6b9fa30b6c5461add"
|
||||
integrity sha512-lBwRvjSmqiMYe/pS0+1gggjJleUJi7NzjvQ1Fkqtt69hBa/0t1YuW/MLQMAPixfwaQOHUXsd6jeU3Z+vdGv3+A==
|
||||
dependencies:
|
||||
"@babel/helper-annotate-as-pure" "^7.24.7"
|
||||
"@babel/helper-create-class-features-plugin" "^7.25.0"
|
||||
|
@ -215,13 +217,13 @@
|
|||
"@babel/plugin-syntax-typescript" "^7.24.7"
|
||||
|
||||
"@babel/runtime@^7.13.10":
|
||||
version "7.25.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.25.0.tgz#3af9a91c1b739c569d5d80cc917280919c544ecb"
|
||||
integrity sha512-7dRy4DwXwtzBrPbZflqxnvfxLF8kdZXPkhymtDeFoFqE6ldzjQFgYTtYIFARcLEYDrqfBfYcZt1WqFxRoyC9Rw==
|
||||
version "7.25.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.25.6.tgz#9afc3289f7184d8d7f98b099884c26317b9264d2"
|
||||
integrity sha512-VBj9MYyDb9tuLq7yzqjgzt6Q+IBQLrGZfdjOekyEirZPHxXWoTSGUTMrpsfi58Up73d13NfYLv8HT9vmznjzhQ==
|
||||
dependencies:
|
||||
regenerator-runtime "^0.14.0"
|
||||
|
||||
"@babel/template@^7.24.7", "@babel/template@^7.25.0":
|
||||
"@babel/template@^7.25.0":
|
||||
version "7.25.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.25.0.tgz#e733dc3134b4fede528c15bc95e89cb98c52592a"
|
||||
integrity sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q==
|
||||
|
@ -230,23 +232,23 @@
|
|||
"@babel/parser" "^7.25.0"
|
||||
"@babel/types" "^7.25.0"
|
||||
|
||||
"@babel/traverse@^7.24.7", "@babel/traverse@^7.24.8", "@babel/traverse@^7.25.0":
|
||||
version "7.25.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.25.0.tgz#e8533c0a57ed97921d1e5b20dd3db63d3efaebf5"
|
||||
integrity sha512-ubALThHQy4GCf6mbb+5ZRNmLLCI7bJ3f8Q6LHBSRlSKSWj5a7dSUzJBLv3VuIhFrFPgjF4IzPF567YG/HSCdZA==
|
||||
"@babel/traverse@^7.24.7", "@babel/traverse@^7.24.8", "@babel/traverse@^7.25.0", "@babel/traverse@^7.25.2", "@babel/traverse@^7.25.4":
|
||||
version "7.25.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.25.6.tgz#04fad980e444f182ecf1520504941940a90fea41"
|
||||
integrity sha512-9Vrcx5ZW6UwK5tvqsj0nGpp/XzqthkT0dqIc9g1AdtygFToNtTF67XzYS//dm+SAK9cp3B9R4ZO/46p63SCjlQ==
|
||||
dependencies:
|
||||
"@babel/code-frame" "^7.24.7"
|
||||
"@babel/generator" "^7.25.0"
|
||||
"@babel/parser" "^7.25.0"
|
||||
"@babel/generator" "^7.25.6"
|
||||
"@babel/parser" "^7.25.6"
|
||||
"@babel/template" "^7.25.0"
|
||||
"@babel/types" "^7.25.0"
|
||||
"@babel/types" "^7.25.6"
|
||||
debug "^4.3.1"
|
||||
globals "^11.1.0"
|
||||
|
||||
"@babel/types@^7.24.7", "@babel/types@^7.24.8", "@babel/types@^7.24.9", "@babel/types@^7.25.0":
|
||||
version "7.25.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.25.0.tgz#e6e3656c581f28da8452ed4f69e38008ec0ba41b"
|
||||
integrity sha512-LcnxQSsd9aXOIgmmSpvZ/1yo46ra2ESYyqLcryaBZOghxy5qqOBjvCWP5JfkI8yl9rlxRgdLTTMCQQRcN2hdCg==
|
||||
"@babel/types@^7.24.7", "@babel/types@^7.24.8", "@babel/types@^7.25.0", "@babel/types@^7.25.2", "@babel/types@^7.25.6":
|
||||
version "7.25.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.25.6.tgz#893942ddb858f32ae7a004ec9d3a76b3463ef8e6"
|
||||
integrity sha512-/l42B1qxpG6RdfYf343Uw1vmDjeNhneUXtzhojE7pDgfpEypmRhI6j1kr17XCVv4Cgl9HdAiQY2x0GwKm7rWCw==
|
||||
dependencies:
|
||||
"@babel/helper-string-parser" "^7.24.8"
|
||||
"@babel/helper-validator-identifier" "^7.24.7"
|
||||
|
@ -285,19 +287,19 @@
|
|||
integrity sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==
|
||||
|
||||
"@floating-ui/core@^1.6.0":
|
||||
version "1.6.5"
|
||||
resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.6.5.tgz#102335cac0d22035b04d70ca5ff092d2d1a26f2b"
|
||||
integrity sha512-8GrTWmoFhm5BsMZOTHeGD2/0FLKLQQHvO/ZmQga4tKempYRLz8aqJGqXVuQgisnMObq2YZ2SgkwctN1LOOxcqA==
|
||||
version "1.6.7"
|
||||
resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.6.7.tgz#7602367795a390ff0662efd1c7ae8ca74e75fb12"
|
||||
integrity sha512-yDzVT/Lm101nQ5TCVeK65LtdN7Tj4Qpr9RTXJ2vPFLqtLxwOrpoxAHAJI8J3yYWUc40J0BDBheaitK5SJmno2g==
|
||||
dependencies:
|
||||
"@floating-ui/utils" "^0.2.5"
|
||||
"@floating-ui/utils" "^0.2.7"
|
||||
|
||||
"@floating-ui/dom@^1.0.0":
|
||||
version "1.6.8"
|
||||
resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.6.8.tgz#45e20532b6d8a061b356a4fb336022cf2609754d"
|
||||
integrity sha512-kx62rP19VZ767Q653wsP1XZCGIirkE09E0QUGNYTM/ttbbQHqcGPdSfWFxUyyNLc/W6aoJRBajOSXhP6GXjC0Q==
|
||||
version "1.6.10"
|
||||
resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.6.10.tgz#b74c32f34a50336c86dcf1f1c845cf3a39e26d6f"
|
||||
integrity sha512-fskgCFv8J8OamCmyun8MfjB1Olfn+uZKjOKZ0vhYF3gRmEUXcGOjxWL8bBr7i4kIuPZ2KD2S3EUIOxnjC8kl2A==
|
||||
dependencies:
|
||||
"@floating-ui/core" "^1.6.0"
|
||||
"@floating-ui/utils" "^0.2.5"
|
||||
"@floating-ui/utils" "^0.2.7"
|
||||
|
||||
"@floating-ui/react-dom@^2.0.0":
|
||||
version "2.1.1"
|
||||
|
@ -306,10 +308,10 @@
|
|||
dependencies:
|
||||
"@floating-ui/dom" "^1.0.0"
|
||||
|
||||
"@floating-ui/utils@^0.2.5":
|
||||
version "0.2.5"
|
||||
resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.2.5.tgz#105c37d9d9620ce69b7f692a20c821bf1ad2cbf9"
|
||||
integrity sha512-sTcG+QZ6fdEUObICavU+aB3Mp8HY4n14wYHdxK4fXjPmv3PXZZeY5RaguJmGyeH/CJQhX3fqKUtS4qc1LoHwhQ==
|
||||
"@floating-ui/utils@^0.2.7":
|
||||
version "0.2.7"
|
||||
resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.2.7.tgz#d0ece53ce99ab5a8e37ebdfe5e32452a2bfc073e"
|
||||
integrity sha512-X8R8Oj771YRl/w+c1HqAC1szL8zWQRwFvgDwT129k9ACdBoud/+/rX9V0qiMl6LWUdP9voC2nDVZYPMQQsb6eA==
|
||||
|
||||
"@hookform/resolvers@^3.9.0":
|
||||
version "3.9.0"
|
||||
|
@ -457,6 +459,11 @@
|
|||
"@nodelib/fs.scandir" "2.1.5"
|
||||
fastq "^1.6.0"
|
||||
|
||||
"@nolyfill/is-core-module@1.0.39":
|
||||
version "1.0.39"
|
||||
resolved "https://registry.yarnpkg.com/@nolyfill/is-core-module/-/is-core-module-1.0.39.tgz#3dc35ba0f1e66b403c00b39344f870298ebb1c8e"
|
||||
integrity sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==
|
||||
|
||||
"@phosphor-icons/react@^2.1.7":
|
||||
version "2.1.7"
|
||||
resolved "https://registry.yarnpkg.com/@phosphor-icons/react/-/react-2.1.7.tgz#b11a4b25849b7e3849970b688d9fe91e5d4fd8d7"
|
||||
|
@ -1220,9 +1227,9 @@
|
|||
integrity sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg==
|
||||
|
||||
"@radix-ui/themes@^3.1.1":
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/themes/-/themes-3.1.1.tgz#a444f181975b8550f548c989ef3a432908c51075"
|
||||
integrity sha512-G+j+x+7kyqQXnn+ftlNPgk1DdZ8h/vVZnLsG4hZB0Mxw4fdKCh1tThQuXDSBNWhFt/vTG79BMzRMiflovENrmA==
|
||||
version "3.1.3"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/themes/-/themes-3.1.3.tgz#9b4287d4e60c9a175e0e453ba620d693fadf6f7e"
|
||||
integrity sha512-GJt4r7Vh0w4yiGuqOKLvrZXLEAxUWfEUUtdj17rCfi+P/zpKUc7TsXro8GftA2Y1tm78Cx9x1HKt23dHc/WqIA==
|
||||
dependencies:
|
||||
"@radix-ui/colors" "3.0.0"
|
||||
"@radix-ui/primitive" "1.1.0"
|
||||
|
@ -1260,6 +1267,11 @@
|
|||
classnames "2.3.2"
|
||||
react-remove-scroll-bar "2.3.4"
|
||||
|
||||
"@rtsao/scc@^1.1.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@rtsao/scc/-/scc-1.1.0.tgz#927dd2fae9bc3361403ac2c7a00c32ddce9ad7e8"
|
||||
integrity sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==
|
||||
|
||||
"@rushstack/eslint-patch@^1.3.3":
|
||||
version "1.10.4"
|
||||
resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.10.4.tgz#427d5549943a9c6fce808e39ea64dbe60d4047f1"
|
||||
|
@ -1338,11 +1350,11 @@
|
|||
integrity sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==
|
||||
|
||||
"@types/node@^20":
|
||||
version "20.14.12"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.14.12.tgz#129d7c3a822cb49fc7ff661235f19cfefd422b49"
|
||||
integrity sha512-r7wNXakLeSsGT0H1AU863vS2wa5wBOK4bWMjZz2wj+8nBx+m5PeIn0k8AloSLpRuiwdRQZwarZqHE4FNArPuJQ==
|
||||
version "20.16.5"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.16.5.tgz#d43c7f973b32ffdf9aa7bd4f80e1072310fd7a53"
|
||||
integrity sha512-VwYCweNo3ERajwy0IUlqqcyZ8/A7Zwa9ZP3MnENWcB11AejO+tLy3pu850goUW2FC/IJMdZUfKpX/yxL1gymCA==
|
||||
dependencies:
|
||||
undici-types "~5.26.4"
|
||||
undici-types "~6.19.2"
|
||||
|
||||
"@types/prop-types@*":
|
||||
version "15.7.12"
|
||||
|
@ -1357,9 +1369,9 @@
|
|||
"@types/react" "*"
|
||||
|
||||
"@types/react@*", "@types/react@^18":
|
||||
version "18.3.3"
|
||||
resolved "https://registry.yarnpkg.com/@types/react/-/react-18.3.3.tgz#9679020895318b0915d7a3ab004d92d33375c45f"
|
||||
integrity sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==
|
||||
version "18.3.5"
|
||||
resolved "https://registry.yarnpkg.com/@types/react/-/react-18.3.5.tgz#5f524c2ad2089c0ff372bbdabc77ca2c4dbadf8f"
|
||||
integrity sha512-WeqMfGJLGuLCqHGYRGHxnKrXcTitc6L/nBUWfWPcTarG3t9PsquqUMuVeXZeca+mglY4Vo5GZjCi0A3Or2lnxA==
|
||||
dependencies:
|
||||
"@types/prop-types" "*"
|
||||
csstype "^3.0.2"
|
||||
|
@ -1533,7 +1545,7 @@ array-buffer-byte-length@^1.0.0, array-buffer-byte-length@^1.0.1:
|
|||
call-bind "^1.0.5"
|
||||
is-array-buffer "^3.0.4"
|
||||
|
||||
array-includes@^3.1.6, array-includes@^3.1.7, array-includes@^3.1.8:
|
||||
array-includes@^3.1.6, array-includes@^3.1.8:
|
||||
version "3.1.8"
|
||||
resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.8.tgz#5e370cbe172fdd5dd6530c1d4aadda25281ba97d"
|
||||
integrity sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==
|
||||
|
@ -1562,7 +1574,7 @@ array.prototype.findlast@^1.2.5:
|
|||
es-object-atoms "^1.0.0"
|
||||
es-shim-unscopables "^1.0.2"
|
||||
|
||||
array.prototype.findlastindex@^1.2.3:
|
||||
array.prototype.findlastindex@^1.2.5:
|
||||
version "1.2.5"
|
||||
resolved "https://registry.yarnpkg.com/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz#8c35a755c72908719453f87145ca011e39334d0d"
|
||||
integrity sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==
|
||||
|
@ -1632,15 +1644,15 @@ ast-types@^0.16.1:
|
|||
tslib "^2.0.1"
|
||||
|
||||
autoprefixer@^10.4.19:
|
||||
version "10.4.19"
|
||||
resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.19.tgz#ad25a856e82ee9d7898c59583c1afeb3fa65f89f"
|
||||
integrity sha512-BaENR2+zBZ8xXhM4pUaKUxlVdxZ0EZhjvbopwnXmxRUfqDmwSpC2lAi/QXvx7NRdPCo1WKEcEF6mV64si1z4Ew==
|
||||
version "10.4.20"
|
||||
resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.20.tgz#5caec14d43976ef42e32dcb4bd62878e96be5b3b"
|
||||
integrity sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==
|
||||
dependencies:
|
||||
browserslist "^4.23.0"
|
||||
caniuse-lite "^1.0.30001599"
|
||||
browserslist "^4.23.3"
|
||||
caniuse-lite "^1.0.30001646"
|
||||
fraction.js "^4.3.7"
|
||||
normalize-range "^0.1.2"
|
||||
picocolors "^1.0.0"
|
||||
picocolors "^1.0.1"
|
||||
postcss-value-parser "^4.2.0"
|
||||
|
||||
available-typed-arrays@^1.0.7:
|
||||
|
@ -1650,17 +1662,15 @@ available-typed-arrays@^1.0.7:
|
|||
dependencies:
|
||||
possible-typed-array-names "^1.0.0"
|
||||
|
||||
axe-core@^4.9.1:
|
||||
version "4.9.1"
|
||||
resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.9.1.tgz#fcd0f4496dad09e0c899b44f6c4bb7848da912ae"
|
||||
integrity sha512-QbUdXJVTpvUTHU7871ppZkdOLBeGUKBQWHkHrvN2V9IQWGMt61zf3B45BtzjxEJzYuj0JBjBZP/hmYS/R9pmAw==
|
||||
axe-core@^4.10.0:
|
||||
version "4.10.0"
|
||||
resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.10.0.tgz#d9e56ab0147278272739a000880196cdfe113b59"
|
||||
integrity sha512-Mr2ZakwQ7XUAjp7pAwQWRhhK8mQQ6JAaNWSjmjxil0R8BPioMtQsTLOolGYkji1rcL++3dCqZA3zWqpT+9Ew6g==
|
||||
|
||||
axobject-query@~3.1.1:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-3.1.1.tgz#3b6e5c6d4e43ca7ba51c5babf99d22a9c68485e1"
|
||||
integrity sha512-goKlv8DZrK9hUh975fnHzhNIO4jUnFCfv/dszV5VwUGDFjI6vQ2VwoyjYjYNEbBE8AH87TduWP5uyDR1D+Iteg==
|
||||
dependencies:
|
||||
deep-equal "^2.0.5"
|
||||
axobject-query@^4.1.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-4.1.0.tgz#28768c76d0e3cff21bc62a9e2d0b6ac30042a1ee"
|
||||
integrity sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==
|
||||
|
||||
balanced-match@^1.0.0:
|
||||
version "1.0.2"
|
||||
|
@ -1708,14 +1718,14 @@ braces@^3.0.3, braces@~3.0.2:
|
|||
dependencies:
|
||||
fill-range "^7.1.1"
|
||||
|
||||
browserslist@^4.23.0, browserslist@^4.23.1:
|
||||
version "4.23.2"
|
||||
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.23.2.tgz#244fe803641f1c19c28c48c4b6ec9736eb3d32ed"
|
||||
integrity sha512-qkqSyistMYdxAcw+CzbZwlBy8AGmS/eEWs+sEV5TnLRGDOL+C5M2EnH6tlZyg0YoAxGJAFKh61En9BR941GnHA==
|
||||
browserslist@^4.23.1, browserslist@^4.23.3:
|
||||
version "4.23.3"
|
||||
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.23.3.tgz#debb029d3c93ebc97ffbc8d9cbb03403e227c800"
|
||||
integrity sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA==
|
||||
dependencies:
|
||||
caniuse-lite "^1.0.30001640"
|
||||
electron-to-chromium "^1.4.820"
|
||||
node-releases "^2.0.14"
|
||||
caniuse-lite "^1.0.30001646"
|
||||
electron-to-chromium "^1.5.4"
|
||||
node-releases "^2.0.18"
|
||||
update-browserslist-db "^1.1.0"
|
||||
|
||||
buffer@^6.0.3:
|
||||
|
@ -1754,10 +1764,10 @@ camelcase-css@^2.0.1:
|
|||
resolved "https://registry.yarnpkg.com/camelcase-css/-/camelcase-css-2.0.1.tgz#ee978f6947914cc30c6b44741b6ed1df7f043fd5"
|
||||
integrity sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==
|
||||
|
||||
caniuse-lite@^1.0.30001579, caniuse-lite@^1.0.30001599, caniuse-lite@^1.0.30001640:
|
||||
version "1.0.30001643"
|
||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001643.tgz#9c004caef315de9452ab970c3da71085f8241dbd"
|
||||
integrity sha512-ERgWGNleEilSrHM6iUz/zJNSQTP8Mr21wDWpdgvRwcTXGAq6jMtOUPP4dqFPTdKqZ2wKTdtB+uucZ3MRpAUSmg==
|
||||
caniuse-lite@^1.0.30001579, caniuse-lite@^1.0.30001646:
|
||||
version "1.0.30001658"
|
||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001658.tgz#b5f7be8ac748a049ab06aa1cf7a1408d83f074ec"
|
||||
integrity sha512-N2YVqWbJELVdrnsW5p+apoQyYt51aBMSsBZki1XZEfeBCexcM/sf4xiAHcXQBkuOwJBXtWF7aW1sYX6tKebPHw==
|
||||
|
||||
chalk@5.2.0:
|
||||
version "5.2.0"
|
||||
|
@ -2003,12 +2013,12 @@ data-view-byte-offset@^1.0.0:
|
|||
es-errors "^1.3.0"
|
||||
is-data-view "^1.0.1"
|
||||
|
||||
debug@4, debug@^4, debug@^4.1.0, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@~4.3.4:
|
||||
version "4.3.5"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.5.tgz#e83444eceb9fedd4a1da56d671ae2446a01a6e1e"
|
||||
integrity sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==
|
||||
debug@4, debug@^4, debug@^4.1.0, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.3.5, debug@~4.3.6:
|
||||
version "4.3.7"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.7.tgz#87945b4151a011d76d95a198d7111c865c360a52"
|
||||
integrity sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==
|
||||
dependencies:
|
||||
ms "2.1.2"
|
||||
ms "^2.1.3"
|
||||
|
||||
debug@^3.2.7:
|
||||
version "3.2.7"
|
||||
|
@ -2122,15 +2132,15 @@ eastasianwidth@^0.2.0:
|
|||
resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb"
|
||||
integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==
|
||||
|
||||
electron-to-chromium@^1.4.820:
|
||||
version "1.5.2"
|
||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.2.tgz#6126ad229ce45e781ec54ca40db0504787f23d19"
|
||||
integrity sha512-kc4r3U3V3WLaaZqThjYz/Y6z8tJe+7K0bbjUVo3i+LWIypVdMx5nXCkwRe6SWbY6ILqLdc1rKcKmr3HoH7wjSQ==
|
||||
electron-to-chromium@^1.5.4:
|
||||
version "1.5.17"
|
||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.17.tgz#292da718d3d96961d022e49bb843e0c4ea10be70"
|
||||
integrity sha512-Q6Q+04tjC2KJ8qsSOSgovvhWcv5t+SmpH6/YfAWmhpE5/r+zw6KQy1/yWVFFNyEBvy68twTTXr2d5eLfCq7QIw==
|
||||
|
||||
emoji-regex@^10.3.0:
|
||||
version "10.3.0"
|
||||
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-10.3.0.tgz#76998b9268409eb3dae3de989254d456e70cfe23"
|
||||
integrity sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==
|
||||
version "10.4.0"
|
||||
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-10.4.0.tgz#03553afea80b3975749cfcb36f776ca268e413d4"
|
||||
integrity sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==
|
||||
|
||||
emoji-regex@^8.0.0:
|
||||
version "8.0.0"
|
||||
|
@ -2142,7 +2152,7 @@ emoji-regex@^9.2.2:
|
|||
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72"
|
||||
integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==
|
||||
|
||||
enhanced-resolve@^5.12.0:
|
||||
enhanced-resolve@^5.15.0:
|
||||
version "5.17.1"
|
||||
resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz#67bfbbcc2f81d511be77d686a90267ef7f898a15"
|
||||
integrity sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==
|
||||
|
@ -2299,9 +2309,9 @@ es-to-primitive@^1.2.1:
|
|||
is-symbol "^1.0.2"
|
||||
|
||||
escalade@^3.1.2:
|
||||
version "3.1.2"
|
||||
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.2.tgz#54076e9ab29ea5bf3d8f1ed62acffbb88272df27"
|
||||
integrity sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==
|
||||
version "3.2.0"
|
||||
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5"
|
||||
integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==
|
||||
|
||||
escape-string-regexp@^1.0.5:
|
||||
version "1.0.5"
|
||||
|
@ -2343,59 +2353,61 @@ eslint-import-resolver-node@^0.3.6, eslint-import-resolver-node@^0.3.9:
|
|||
resolve "^1.22.4"
|
||||
|
||||
eslint-import-resolver-typescript@^3.5.2:
|
||||
version "3.6.1"
|
||||
resolved "https://registry.yarnpkg.com/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.6.1.tgz#7b983680edd3f1c5bce1a5829ae0bc2d57fe9efa"
|
||||
integrity sha512-xgdptdoi5W3niYeuQxKmzVDTATvLYqhpwmykwsh7f6HIOStGWEIL9iqZgQDF9u9OEzrRwR8no5q2VT+bjAujTg==
|
||||
version "3.6.3"
|
||||
resolved "https://registry.yarnpkg.com/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.6.3.tgz#bb8e388f6afc0f940ce5d2c5fd4a3d147f038d9e"
|
||||
integrity sha512-ud9aw4szY9cCT1EWWdGv1L1XR6hh2PaRWif0j2QjQ0pgTY/69iw+W0Z4qZv5wHahOl8isEr+k/JnyAqNQkLkIA==
|
||||
dependencies:
|
||||
debug "^4.3.4"
|
||||
enhanced-resolve "^5.12.0"
|
||||
eslint-module-utils "^2.7.4"
|
||||
fast-glob "^3.3.1"
|
||||
get-tsconfig "^4.5.0"
|
||||
is-core-module "^2.11.0"
|
||||
"@nolyfill/is-core-module" "1.0.39"
|
||||
debug "^4.3.5"
|
||||
enhanced-resolve "^5.15.0"
|
||||
eslint-module-utils "^2.8.1"
|
||||
fast-glob "^3.3.2"
|
||||
get-tsconfig "^4.7.5"
|
||||
is-bun-module "^1.0.2"
|
||||
is-glob "^4.0.3"
|
||||
|
||||
eslint-module-utils@^2.7.4, eslint-module-utils@^2.8.0:
|
||||
version "2.8.1"
|
||||
resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.8.1.tgz#52f2404300c3bd33deece9d7372fb337cc1d7c34"
|
||||
integrity sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==
|
||||
eslint-module-utils@^2.8.1, eslint-module-utils@^2.9.0:
|
||||
version "2.11.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.11.0.tgz#b99b211ca4318243f09661fae088f373ad5243c4"
|
||||
integrity sha512-gbBE5Hitek/oG6MUVj6sFuzEjA/ClzNflVrLovHi/JgLdC7fiN5gLAY1WIPW1a0V5I999MnsrvVrCOGmmVqDBQ==
|
||||
dependencies:
|
||||
debug "^3.2.7"
|
||||
|
||||
eslint-plugin-import@^2.28.1:
|
||||
version "2.29.1"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz#d45b37b5ef5901d639c15270d74d46d161150643"
|
||||
integrity sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==
|
||||
version "2.30.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.30.0.tgz#21ceea0fc462657195989dd780e50c92fe95f449"
|
||||
integrity sha512-/mHNE9jINJfiD2EKkg1BKyPyUk4zdnT54YgbOgfjSakWT5oyX/qQLVNTkehyfpcMxZXMy1zyonZ2v7hZTX43Yw==
|
||||
dependencies:
|
||||
array-includes "^3.1.7"
|
||||
array.prototype.findlastindex "^1.2.3"
|
||||
"@rtsao/scc" "^1.1.0"
|
||||
array-includes "^3.1.8"
|
||||
array.prototype.findlastindex "^1.2.5"
|
||||
array.prototype.flat "^1.3.2"
|
||||
array.prototype.flatmap "^1.3.2"
|
||||
debug "^3.2.7"
|
||||
doctrine "^2.1.0"
|
||||
eslint-import-resolver-node "^0.3.9"
|
||||
eslint-module-utils "^2.8.0"
|
||||
hasown "^2.0.0"
|
||||
is-core-module "^2.13.1"
|
||||
eslint-module-utils "^2.9.0"
|
||||
hasown "^2.0.2"
|
||||
is-core-module "^2.15.1"
|
||||
is-glob "^4.0.3"
|
||||
minimatch "^3.1.2"
|
||||
object.fromentries "^2.0.7"
|
||||
object.groupby "^1.0.1"
|
||||
object.values "^1.1.7"
|
||||
object.fromentries "^2.0.8"
|
||||
object.groupby "^1.0.3"
|
||||
object.values "^1.2.0"
|
||||
semver "^6.3.1"
|
||||
tsconfig-paths "^3.15.0"
|
||||
|
||||
eslint-plugin-jsx-a11y@^6.7.1:
|
||||
version "6.9.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.9.0.tgz#67ab8ff460d4d3d6a0b4a570e9c1670a0a8245c8"
|
||||
integrity sha512-nOFOCaJG2pYqORjK19lqPqxMO/JpvdCZdPtNdxY3kvom3jTvkAbOvQvD8wuD0G8BYR0IGAGYDlzqWJOh/ybn2g==
|
||||
version "6.10.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.10.0.tgz#36fb9dead91cafd085ddbe3829602fb10ef28339"
|
||||
integrity sha512-ySOHvXX8eSN6zz8Bywacm7CvGNhUtdjvqfQDVe6020TUK34Cywkw7m0KsCCk1Qtm9G1FayfTN1/7mMYnYO2Bhg==
|
||||
dependencies:
|
||||
aria-query "~5.1.3"
|
||||
array-includes "^3.1.8"
|
||||
array.prototype.flatmap "^1.3.2"
|
||||
ast-types-flow "^0.0.8"
|
||||
axe-core "^4.9.1"
|
||||
axobject-query "~3.1.1"
|
||||
axe-core "^4.10.0"
|
||||
axobject-query "^4.1.0"
|
||||
damerau-levenshtein "^1.0.8"
|
||||
emoji-regex "^9.2.2"
|
||||
es-iterator-helpers "^1.0.19"
|
||||
|
@ -2421,9 +2433,9 @@ eslint-plugin-prettier@^5.1.3:
|
|||
integrity sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==
|
||||
|
||||
eslint-plugin-react@^7.33.2:
|
||||
version "7.35.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.35.0.tgz#00b1e4559896710e58af6358898f2ff917ea4c41"
|
||||
integrity sha512-v501SSMOWv8gerHkk+IIQBkcGRGrO2nfybfj5pLxuJNFTPxxA3PSryhXTK+9pNbtkggheDdsC0E9Q8CuPk6JKA==
|
||||
version "7.35.2"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.35.2.tgz#d32500d3ec268656d5071918bfec78cfd8b070ed"
|
||||
integrity sha512-Rbj2R9zwP2GYNcIak4xoAMV57hrBh3hTaR0k7hVjwCQgryE/pw5px4b13EYjduOI0hfXyZhwBxaGpOTbWSGzKQ==
|
||||
dependencies:
|
||||
array-includes "^3.1.8"
|
||||
array.prototype.findlast "^1.2.5"
|
||||
|
@ -2584,7 +2596,7 @@ fast-diff@^1.1.2:
|
|||
resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.3.0.tgz#ece407fa550a64d638536cd727e129c61616e0f0"
|
||||
integrity sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==
|
||||
|
||||
fast-glob@^3.2.12, fast-glob@^3.2.9, fast-glob@^3.3.0, fast-glob@^3.3.1, fast-glob@^3.3.2:
|
||||
fast-glob@^3.2.12, fast-glob@^3.2.9, fast-glob@^3.3.0, fast-glob@^3.3.2:
|
||||
version "3.3.2"
|
||||
resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129"
|
||||
integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==
|
||||
|
@ -2664,9 +2676,9 @@ for-each@^0.3.3:
|
|||
is-callable "^1.1.3"
|
||||
|
||||
foreground-child@^3.1.0:
|
||||
version "3.2.1"
|
||||
resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.2.1.tgz#767004ccf3a5b30df39bed90718bab43fe0a59f7"
|
||||
integrity sha512-PXUUyLqrR2XCWICfv6ukppP96sdFwWbNEnfEMt7jNsISjMsvaLNinAHNDYyvkyU+SZG2BTSbT5NjG+vZslfGTA==
|
||||
version "3.3.0"
|
||||
resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.3.0.tgz#0ac8644c06e431439f8561db8ecf29a7b5519c77"
|
||||
integrity sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==
|
||||
dependencies:
|
||||
cross-spawn "^7.0.0"
|
||||
signal-exit "^4.0.1"
|
||||
|
@ -2707,7 +2719,7 @@ function-bind@^1.1.2:
|
|||
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c"
|
||||
integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==
|
||||
|
||||
function.prototype.name@^1.1.5, function.prototype.name@^1.1.6:
|
||||
function.prototype.name@^1.1.6:
|
||||
version "1.1.6"
|
||||
resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.6.tgz#cdf315b7d90ee77a4c6ee216c3c3362da07533fd"
|
||||
integrity sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==
|
||||
|
@ -2767,10 +2779,10 @@ get-symbol-description@^1.0.2:
|
|||
es-errors "^1.3.0"
|
||||
get-intrinsic "^1.2.4"
|
||||
|
||||
get-tsconfig@^4.5.0:
|
||||
version "4.7.6"
|
||||
resolved "https://registry.yarnpkg.com/get-tsconfig/-/get-tsconfig-4.7.6.tgz#118fd5b7b9bae234cc7705a00cd771d7eb65d62a"
|
||||
integrity sha512-ZAqrLlu18NbDdRaHq+AKXzAmqIUPswPWKUchfytdAjiRFnCe5ojG2bstg6mRiZabkKfCoL/e98pbBELIV/YCeA==
|
||||
get-tsconfig@^4.7.5:
|
||||
version "4.8.0"
|
||||
resolved "https://registry.yarnpkg.com/get-tsconfig/-/get-tsconfig-4.8.0.tgz#125dc13a316f61650a12b20c97c11b8fd996fedd"
|
||||
integrity sha512-Pgba6TExTZ0FJAn1qkJAjIeKoDJ3CsI2ChuLohJnZl/tTU8MVrq3b+2t5UOPfRa4RMsorClBjJALkJUMjG1PAw==
|
||||
dependencies:
|
||||
resolve-pkg-maps "^1.0.0"
|
||||
|
||||
|
@ -2942,9 +2954,9 @@ human-signals@^5.0.0:
|
|||
integrity sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==
|
||||
|
||||
husky@^9.0.11:
|
||||
version "9.1.3"
|
||||
resolved "https://registry.yarnpkg.com/husky/-/husky-9.1.3.tgz#46cddff01f9a551f87b39accc67860bce5d00680"
|
||||
integrity sha512-ET3TQmQgdIu0pt+jKkpo5oGyg/4MQZpG6xcam5J5JyNJV+CBT23OBpCF15bKHKycRyMH9k6ONy8g2HdGIsSkMQ==
|
||||
version "9.1.5"
|
||||
resolved "https://registry.yarnpkg.com/husky/-/husky-9.1.5.tgz#2b6edede53ee1adbbd3a3da490628a23f5243b83"
|
||||
integrity sha512-rowAVRUBfI0b4+niA4SJMhfQwc107VLkBUgEYYAOQAbqDCnra1nYh83hF/MDmhYs9t9n1E3DuKOrs2LYNC+0Ag==
|
||||
|
||||
ieee754@^1.2.1:
|
||||
version "1.2.1"
|
||||
|
@ -2957,9 +2969,9 @@ ignore-by-default@^1.0.1:
|
|||
integrity sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==
|
||||
|
||||
ignore@^5.2.0:
|
||||
version "5.3.1"
|
||||
resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.1.tgz#5073e554cd42c5b33b394375f538b8593e34d4ef"
|
||||
integrity sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==
|
||||
version "5.3.2"
|
||||
resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5"
|
||||
integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==
|
||||
|
||||
import-fresh@^3.2.1, import-fresh@^3.3.0:
|
||||
version "3.3.0"
|
||||
|
@ -3001,10 +3013,10 @@ internal-slot@^1.0.4, internal-slot@^1.0.7:
|
|||
hasown "^2.0.0"
|
||||
side-channel "^1.0.4"
|
||||
|
||||
intl-tel-input@^23.8.0:
|
||||
version "23.8.0"
|
||||
resolved "https://registry.yarnpkg.com/intl-tel-input/-/intl-tel-input-23.8.0.tgz#37bec095605516aa72529b3da11335b253b65b2f"
|
||||
integrity sha512-lx8Sz5LfVyIXyjWbfjno89o4qHfIuWulctGaWbP2RKKnHvagdt9gdibCsv9uEH7izb/yjB6Nst0sRo988/lhpw==
|
||||
intl-tel-input@^23.8.1:
|
||||
version "23.9.3"
|
||||
resolved "https://registry.yarnpkg.com/intl-tel-input/-/intl-tel-input-23.9.3.tgz#3870c78c16655bdc13e18cae557efcaa43dce719"
|
||||
integrity sha512-vu/Hm825wPlkg2cOtWWgG5fRw2+M7G0sUhQKdZgP4UMjd+UKmCNBcr9gdz6OnXh9kmW5GDMCy7ArVdYY0yjSxQ==
|
||||
|
||||
invariant@^2.2.4:
|
||||
version "2.2.4"
|
||||
|
@ -3063,15 +3075,22 @@ is-boolean-object@^1.1.0:
|
|||
call-bind "^1.0.2"
|
||||
has-tostringtag "^1.0.0"
|
||||
|
||||
is-bun-module@^1.0.2:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/is-bun-module/-/is-bun-module-1.1.0.tgz#a66b9830869437f6cdad440ba49ab6e4dc837269"
|
||||
integrity sha512-4mTAVPlrXpaN3jtF0lsnPCMGnq4+qZjVIKq0HCpfcqf8OC1SM5oATCIAPM5V5FN05qp2NNnFndphmdZS9CV3hA==
|
||||
dependencies:
|
||||
semver "^7.6.3"
|
||||
|
||||
is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.7:
|
||||
version "1.2.7"
|
||||
resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055"
|
||||
integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==
|
||||
|
||||
is-core-module@^2.11.0, is-core-module@^2.13.0, is-core-module@^2.13.1:
|
||||
version "2.15.0"
|
||||
resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.15.0.tgz#71c72ec5442ace7e76b306e9d48db361f22699ea"
|
||||
integrity sha512-Dd+Lb2/zvk9SKy1TGCt1wFJFo/MWBPMX5x7KcvLajWTGuomczdQX61PvY5yK6SVACwpoexWo81IfFyoKY2QnTA==
|
||||
is-core-module@^2.13.0, is-core-module@^2.15.1:
|
||||
version "2.15.1"
|
||||
resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.15.1.tgz#a7363a25bee942fefab0de13bf6aa372c82dcc37"
|
||||
integrity sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==
|
||||
dependencies:
|
||||
hasown "^2.0.2"
|
||||
|
||||
|
@ -3387,16 +3406,16 @@ levn@^0.4.1:
|
|||
type-check "~0.4.0"
|
||||
|
||||
libphonenumber-js@^1.11.4:
|
||||
version "1.11.4"
|
||||
resolved "https://registry.yarnpkg.com/libphonenumber-js/-/libphonenumber-js-1.11.4.tgz#e63fe553f45661b30bb10bb8c82c9cf2b22ec32a"
|
||||
integrity sha512-F/R50HQuWWYcmU/esP5jrH5LiWYaN7DpN0a/99U8+mnGGtnx8kmRE+649dQh3v+CowXXZc8vpkf5AmYkO0AQ7Q==
|
||||
version "1.11.7"
|
||||
resolved "https://registry.yarnpkg.com/libphonenumber-js/-/libphonenumber-js-1.11.7.tgz#efe4fcf816e1982925e9c800d0013b0ee99b8283"
|
||||
integrity sha512-x2xON4/Qg2bRIS11KIN9yCNYUjhtiEjNyptjX0mX+pyKHecxuJVLIpfX1lq9ZD6CrC/rB+y4GBi18c6CEcUR+A==
|
||||
|
||||
lilconfig@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.1.0.tgz#78e23ac89ebb7e1bfbf25b18043de756548e7f52"
|
||||
integrity sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==
|
||||
|
||||
lilconfig@^3.0.0, lilconfig@~3.1.1:
|
||||
lilconfig@^3.0.0, lilconfig@~3.1.2:
|
||||
version "3.1.2"
|
||||
resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-3.1.2.tgz#e4a7c3cb549e3a606c8dcc32e5ae1005e62c05cb"
|
||||
integrity sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==
|
||||
|
@ -3414,30 +3433,30 @@ linkify-it@^5.0.0:
|
|||
uc.micro "^2.0.0"
|
||||
|
||||
lint-staged@^15.2.7:
|
||||
version "15.2.7"
|
||||
resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-15.2.7.tgz#97867e29ed632820c0fb90be06cd9ed384025649"
|
||||
integrity sha512-+FdVbbCZ+yoh7E/RosSdqKJyUM2OEjTciH0TFNkawKgvFp1zbGlEC39RADg+xKBG1R4mhoH2j85myBQZ5wR+lw==
|
||||
version "15.2.10"
|
||||
resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-15.2.10.tgz#92ac222f802ba911897dcf23671da5bb80643cd2"
|
||||
integrity sha512-5dY5t743e1byO19P9I4b3x8HJwalIznL5E1FWYnU6OWw33KxNBSLAc6Cy7F2PsFEO8FKnLwjwm5hx7aMF0jzZg==
|
||||
dependencies:
|
||||
chalk "~5.3.0"
|
||||
commander "~12.1.0"
|
||||
debug "~4.3.4"
|
||||
debug "~4.3.6"
|
||||
execa "~8.0.1"
|
||||
lilconfig "~3.1.1"
|
||||
listr2 "~8.2.1"
|
||||
micromatch "~4.0.7"
|
||||
lilconfig "~3.1.2"
|
||||
listr2 "~8.2.4"
|
||||
micromatch "~4.0.8"
|
||||
pidtree "~0.6.0"
|
||||
string-argv "~0.3.2"
|
||||
yaml "~2.4.2"
|
||||
yaml "~2.5.0"
|
||||
|
||||
listr2@~8.2.1:
|
||||
version "8.2.3"
|
||||
resolved "https://registry.yarnpkg.com/listr2/-/listr2-8.2.3.tgz#c494bb89b34329cf900e4e0ae8aeef9081d7d7a5"
|
||||
integrity sha512-Lllokma2mtoniUOS94CcOErHWAug5iu7HOmDrvWgpw8jyQH2fomgB+7lZS4HWZxytUuQwkGOwe49FvwVaA85Xw==
|
||||
listr2@~8.2.4:
|
||||
version "8.2.4"
|
||||
resolved "https://registry.yarnpkg.com/listr2/-/listr2-8.2.4.tgz#486b51cbdb41889108cb7e2c90eeb44519f5a77f"
|
||||
integrity sha512-opevsywziHd3zHCVQGAj8zu+Z3yHNkkoYhWIGnq54RrCVwLz0MozotJEDnKsIBLvkfLGN6BLOyAeRrYI0pKA4g==
|
||||
dependencies:
|
||||
cli-truncate "^4.0.0"
|
||||
colorette "^2.0.20"
|
||||
eventemitter3 "^5.0.1"
|
||||
log-update "^6.0.0"
|
||||
log-update "^6.1.0"
|
||||
rfdc "^1.4.1"
|
||||
wrap-ansi "^9.0.0"
|
||||
|
||||
|
@ -3481,7 +3500,7 @@ log-symbols@^5.1.0:
|
|||
chalk "^5.0.0"
|
||||
is-unicode-supported "^1.1.0"
|
||||
|
||||
log-update@^6.0.0:
|
||||
log-update@^6.1.0:
|
||||
version "6.1.0"
|
||||
resolved "https://registry.yarnpkg.com/log-update/-/log-update-6.1.0.tgz#1a04ff38166f94647ae1af562f4bd6a15b1b7cd4"
|
||||
integrity sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==
|
||||
|
@ -3550,10 +3569,10 @@ merge2@^1.3.0, merge2@^1.4.1:
|
|||
resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae"
|
||||
integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
|
||||
|
||||
micromatch@^4.0.4, micromatch@^4.0.5, micromatch@~4.0.7:
|
||||
version "4.0.7"
|
||||
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.7.tgz#33e8190d9fe474a9895525f5618eee136d46c2e5"
|
||||
integrity sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==
|
||||
micromatch@^4.0.4, micromatch@^4.0.5, micromatch@~4.0.8:
|
||||
version "4.0.8"
|
||||
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202"
|
||||
integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==
|
||||
dependencies:
|
||||
braces "^3.0.3"
|
||||
picomatch "^2.3.1"
|
||||
|
@ -3616,12 +3635,7 @@ mkdirp@^2.1.6:
|
|||
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-2.1.6.tgz#964fbcb12b2d8c5d6fbc62a963ac95a273e2cc19"
|
||||
integrity sha512-+hEnITedc8LAtIP9u3HJDFIdcLV2vXP33sqLLIzkv1Db1zO/1OxbvYf0Y1OC/S/Qo5dxHXepofhmxL02PsKe+A==
|
||||
|
||||
ms@2.1.2:
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
|
||||
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
|
||||
|
||||
ms@^2.1.1:
|
||||
ms@^2.1.1, ms@^2.1.3:
|
||||
version "2.1.3"
|
||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
|
||||
integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
|
||||
|
@ -3682,7 +3696,7 @@ node-fetch@^3.3.0:
|
|||
fetch-blob "^3.1.4"
|
||||
formdata-polyfill "^4.0.10"
|
||||
|
||||
node-releases@^2.0.14:
|
||||
node-releases@^2.0.18:
|
||||
version "2.0.18"
|
||||
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.18.tgz#f010e8d35e2fe8d6b2944f03f70213ecedc4ca3f"
|
||||
integrity sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==
|
||||
|
@ -3767,7 +3781,7 @@ object.entries@^1.1.8:
|
|||
define-properties "^1.2.1"
|
||||
es-object-atoms "^1.0.0"
|
||||
|
||||
object.fromentries@^2.0.7, object.fromentries@^2.0.8:
|
||||
object.fromentries@^2.0.8:
|
||||
version "2.0.8"
|
||||
resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.8.tgz#f7195d8a9b97bd95cbc1999ea939ecd1a2b00c65"
|
||||
integrity sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==
|
||||
|
@ -3777,7 +3791,7 @@ object.fromentries@^2.0.7, object.fromentries@^2.0.8:
|
|||
es-abstract "^1.23.2"
|
||||
es-object-atoms "^1.0.0"
|
||||
|
||||
object.groupby@^1.0.1:
|
||||
object.groupby@^1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/object.groupby/-/object.groupby-1.0.3.tgz#9b125c36238129f6f7b61954a1e7176148d5002e"
|
||||
integrity sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==
|
||||
|
@ -3786,7 +3800,7 @@ object.groupby@^1.0.1:
|
|||
define-properties "^1.2.1"
|
||||
es-abstract "^1.23.2"
|
||||
|
||||
object.values@^1.1.6, object.values@^1.1.7, object.values@^1.2.0:
|
||||
object.values@^1.1.6, object.values@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.2.0.tgz#65405a9d92cee68ac2d303002e0b8470a4d9ab1b"
|
||||
integrity sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==
|
||||
|
@ -3930,9 +3944,9 @@ path-type@^4.0.0:
|
|||
integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==
|
||||
|
||||
picocolors@^1.0.0, picocolors@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.1.tgz#a8ad579b571952f0e5d25892de5445bcfe25aaa1"
|
||||
integrity sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.0.tgz#5358b76a78cde483ba5cef6a9dc9671440b27d59"
|
||||
integrity sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==
|
||||
|
||||
picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1:
|
||||
version "2.3.1"
|
||||
|
@ -3991,9 +4005,9 @@ postcss-nested@^6.0.1:
|
|||
postcss-selector-parser "^6.1.1"
|
||||
|
||||
postcss-selector-parser@^6.0.11, postcss-selector-parser@^6.1.1:
|
||||
version "6.1.1"
|
||||
resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.1.1.tgz#5be94b277b8955904476a2400260002ce6c56e38"
|
||||
integrity sha512-b4dlw/9V8A71rLIDsSwVmak9z2DuBUB7CA1/wSdelNEzqsjoSPeADTWNO09lpH49Diy3/JIZ2bSPB1dI3LJCHg==
|
||||
version "6.1.2"
|
||||
resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz#27ecb41fb0e3b6ba7a1ec84fff347f734c7929de"
|
||||
integrity sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==
|
||||
dependencies:
|
||||
cssesc "^3.0.0"
|
||||
util-deprecate "^1.0.2"
|
||||
|
@ -4013,9 +4027,9 @@ postcss@8.4.31:
|
|||
source-map-js "^1.0.2"
|
||||
|
||||
postcss@^8.4.23, postcss@^8.4.38:
|
||||
version "8.4.40"
|
||||
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.40.tgz#eb81f2a4dd7668ed869a6db25999e02e9ad909d8"
|
||||
integrity sha512-YF2kKIUzAofPMpfH6hOi2cGnv/HrUlfucspc7pDyvv7kGdqXrfj8SCl/t8owkEgKEuu8ZcRjSOxFxVLqwChZ2Q==
|
||||
version "8.4.45"
|
||||
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.45.tgz#538d13d89a16ef71edbf75d895284ae06b79e603"
|
||||
integrity sha512-7KTLTdzdZZYscUc65XmjFiB73vBhBfbPztCYdUNvlaso9PrzjzcmjqBPR0lNGkcVlcO4BjiO5rK/qNz+XAen1Q==
|
||||
dependencies:
|
||||
nanoid "^3.3.7"
|
||||
picocolors "^1.0.1"
|
||||
|
@ -4084,9 +4098,9 @@ react-dom@^18:
|
|||
scheduler "^0.23.2"
|
||||
|
||||
react-hook-form@^7.52.1:
|
||||
version "7.52.1"
|
||||
resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-7.52.1.tgz#ec2c96437b977f8b89ae2d541a70736c66284852"
|
||||
integrity sha512-uNKIhaoICJ5KQALYZ4TOaOLElyM+xipord+Ha3crEFhTntdLvWZqVY49Wqd/0GiVCA/f9NjemLeiNPjG7Hpurg==
|
||||
version "7.53.0"
|
||||
resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-7.53.0.tgz#3cf70951bf41fa95207b34486203ebefbd3a05ab"
|
||||
integrity sha512-M1n3HhqCww6S2hxLxciEXy2oISPnAzxY7gvwVPrtlczTM/1dDadXgUxDpHMrMTblDOcm/AXtXxHwZ3jpg1mqKQ==
|
||||
|
||||
react-is@^16.13.1:
|
||||
version "16.13.1"
|
||||
|
@ -4313,7 +4327,7 @@ semver@^6.3.1:
|
|||
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4"
|
||||
integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==
|
||||
|
||||
semver@^7.5.3, semver@^7.5.4:
|
||||
semver@^7.5.3, semver@^7.5.4, semver@^7.6.3:
|
||||
version "7.6.3"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143"
|
||||
integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==
|
||||
|
@ -4647,9 +4661,9 @@ synckit@^0.9.1:
|
|||
tslib "^2.6.2"
|
||||
|
||||
tailwind-merge@^2.3.0:
|
||||
version "2.4.0"
|
||||
resolved "https://registry.yarnpkg.com/tailwind-merge/-/tailwind-merge-2.4.0.tgz#1345209dc1f484f15159c9180610130587703042"
|
||||
integrity sha512-49AwoOQNKdqKPd9CViyH5wJoSKsCDjUlzL8DxuGp3P1FsGY36NJDAa18jLZcaHAUUuTj+JB8IAo8zWgBNvBF7A==
|
||||
version "2.5.2"
|
||||
resolved "https://registry.yarnpkg.com/tailwind-merge/-/tailwind-merge-2.5.2.tgz#000f05a703058f9f9f3829c644235f81d4c08a1f"
|
||||
integrity sha512-kjEBm+pvD+6eAwzJL2Bi+02/9LFLal1Gs61+QB7HvTfQQ0aXwC5LGT8PEt1gS0CWKktKe6ysPTAy3cBC5MeiIg==
|
||||
|
||||
tailwindcss-animate@^1.0.7:
|
||||
version "1.0.7"
|
||||
|
@ -4657,9 +4671,9 @@ tailwindcss-animate@^1.0.7:
|
|||
integrity sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==
|
||||
|
||||
tailwindcss@^3.4.6:
|
||||
version "3.4.7"
|
||||
resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.4.7.tgz#6092f18767f5933f59375b9afe558e592fc77201"
|
||||
integrity sha512-rxWZbe87YJb4OcSopb7up2Ba4U82BoiSGUdoDr3Ydrg9ckxFS/YWsvhN323GMcddgU65QRy7JndC7ahhInhvlQ==
|
||||
version "3.4.10"
|
||||
resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.4.10.tgz#70442d9aeb78758d1f911af29af8255ecdb8ffef"
|
||||
integrity sha512-KWZkVPm7yJRhdu4SRSl9d4AK2wM3a50UsvgHZO7xY77NQr2V+fIrEuoDGQcbvswWvFGbS2f6e+jC/6WJm1Dl0w==
|
||||
dependencies:
|
||||
"@alloc/quick-lru" "^5.2.0"
|
||||
arg "^5.0.2"
|
||||
|
@ -4768,9 +4782,9 @@ tsconfig-paths@^4.2.0:
|
|||
strip-bom "^3.0.0"
|
||||
|
||||
tslib@^2.0.0, tslib@^2.0.1, tslib@^2.1.0, tslib@^2.4.0, tslib@^2.6.2:
|
||||
version "2.6.3"
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.3.tgz#0438f810ad7a9edcde7a241c3d80db693c8cbfe0"
|
||||
integrity sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==
|
||||
version "2.7.0"
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.7.0.tgz#d9b40c5c40ab59e8738f297df3087bf1a2690c01"
|
||||
integrity sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==
|
||||
|
||||
type-check@^0.4.0, type-check@~0.4.0:
|
||||
version "0.4.0"
|
||||
|
@ -4853,10 +4867,10 @@ undefsafe@^2.0.5:
|
|||
resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-2.0.5.tgz#38733b9327bdcd226db889fb723a6efd162e6e2c"
|
||||
integrity sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==
|
||||
|
||||
undici-types@~5.26.4:
|
||||
version "5.26.5"
|
||||
resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617"
|
||||
integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==
|
||||
undici-types@~6.19.2:
|
||||
version "6.19.8"
|
||||
resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.19.8.tgz#35111c9d1437ab83a7cdc0abae2f26d88eda0a02"
|
||||
integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==
|
||||
|
||||
universalify@^2.0.0:
|
||||
version "2.0.1"
|
||||
|
@ -4904,9 +4918,9 @@ util-deprecate@^1.0.1, util-deprecate@^1.0.2:
|
|||
integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==
|
||||
|
||||
vaul@^0.9.1:
|
||||
version "0.9.1"
|
||||
resolved "https://registry.yarnpkg.com/vaul/-/vaul-0.9.1.tgz#3640198e04636b209b1f907fcf3079bec6ecc66b"
|
||||
integrity sha512-fAhd7i4RNMinx+WEm6pF3nOl78DFkAazcN04ElLPFF9BMCNGbY/kou8UMhIcicm0rJCNePJP0Yyza60gGOD0Jw==
|
||||
version "0.9.2"
|
||||
resolved "https://registry.yarnpkg.com/vaul/-/vaul-0.9.2.tgz#fe7ad8a0acf0863b9bc7e956da27a8ce6169ab7c"
|
||||
integrity sha512-m2A7UgAU/JMWiwUhmARK8LMvEfXiudA4trJxfZF5AtH2uBTgN855msZ2yjPnUDfa7i5glocMYLSfML8wriBtBA==
|
||||
dependencies:
|
||||
"@radix-ui/react-dialog" "^1.0.4"
|
||||
|
||||
|
@ -4934,12 +4948,12 @@ which-boxed-primitive@^1.0.2:
|
|||
is-symbol "^1.0.3"
|
||||
|
||||
which-builtin-type@^1.1.3:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/which-builtin-type/-/which-builtin-type-1.1.3.tgz#b1b8443707cc58b6e9bf98d32110ff0c2cbd029b"
|
||||
integrity sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==
|
||||
version "1.1.4"
|
||||
resolved "https://registry.yarnpkg.com/which-builtin-type/-/which-builtin-type-1.1.4.tgz#592796260602fc3514a1b5ee7fa29319b72380c3"
|
||||
integrity sha512-bppkmBSsHFmIMSl8BO9TbsyzsvGjVoppt8xUiGzwiu/bhDCGxnpOKCxgqj6GuyHE0mINMDecBFPlOm2hzY084w==
|
||||
dependencies:
|
||||
function.prototype.name "^1.1.5"
|
||||
has-tostringtag "^1.0.0"
|
||||
function.prototype.name "^1.1.6"
|
||||
has-tostringtag "^1.0.2"
|
||||
is-async-function "^2.0.0"
|
||||
is-date-object "^1.0.5"
|
||||
is-finalizationregistry "^1.0.2"
|
||||
|
@ -4948,10 +4962,10 @@ which-builtin-type@^1.1.3:
|
|||
is-weakref "^1.0.2"
|
||||
isarray "^2.0.5"
|
||||
which-boxed-primitive "^1.0.2"
|
||||
which-collection "^1.0.1"
|
||||
which-typed-array "^1.1.9"
|
||||
which-collection "^1.0.2"
|
||||
which-typed-array "^1.1.15"
|
||||
|
||||
which-collection@^1.0.1:
|
||||
which-collection@^1.0.1, which-collection@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/which-collection/-/which-collection-1.0.2.tgz#627ef76243920a107e7ce8e96191debe4b16c2a0"
|
||||
integrity sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==
|
||||
|
@ -4961,7 +4975,7 @@ which-collection@^1.0.1:
|
|||
is-weakmap "^2.0.2"
|
||||
is-weakset "^2.0.3"
|
||||
|
||||
which-typed-array@^1.1.13, which-typed-array@^1.1.14, which-typed-array@^1.1.15, which-typed-array@^1.1.9:
|
||||
which-typed-array@^1.1.13, which-typed-array@^1.1.14, which-typed-array@^1.1.15:
|
||||
version "1.1.15"
|
||||
resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.15.tgz#264859e9b11a649b388bfaaf4f767df1f779b38d"
|
||||
integrity sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==
|
||||
|
@ -5021,15 +5035,10 @@ yallist@^3.0.2:
|
|||
resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd"
|
||||
integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==
|
||||
|
||||
yaml@^2.3.4:
|
||||
version "2.5.0"
|
||||
resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.5.0.tgz#c6165a721cf8000e91c36490a41d7be25176cf5d"
|
||||
integrity sha512-2wWLbGbYDiSqqIKoPjar3MPgB94ErzCtrNE1FdqGuaO0pi2JGjmE8aW8TDZwzU7vuxcGRdL/4gPQwQ7hD5AMSw==
|
||||
|
||||
yaml@~2.4.2:
|
||||
version "2.4.5"
|
||||
resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.4.5.tgz#60630b206dd6d84df97003d33fc1ddf6296cca5e"
|
||||
integrity sha512-aBx2bnqDzVOyNKfsysjA2ms5ZlnjSAW2eG3/L5G/CSujfjLJTJsEw1bGw8kCf04KodQWk1pxlGnZ56CRxiawmg==
|
||||
yaml@^2.3.4, yaml@~2.5.0:
|
||||
version "2.5.1"
|
||||
resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.5.1.tgz#c9772aacf62cb7494a95b0c4f1fb065b563db130"
|
||||
integrity sha512-bLQOjaX/ADgQ20isPJRvF0iRUHIxVhYvr53Of7wGcWlO2jvtUlH5m87DsmulFVxRpNLOnI4tB6p/oh8D7kpn9Q==
|
||||
|
||||
yocto-queue@^0.1.0:
|
||||
version "0.1.0"
|
||||
|
|
|
@ -757,6 +757,18 @@ class ConversationAdapters:
|
|||
def has_any_conversation_config(user: KhojUser):
|
||||
return ChatModelOptions.objects.filter(user=user).exists()
|
||||
|
||||
@staticmethod
|
||||
def get_all_conversation_configs():
|
||||
return ChatModelOptions.objects.all()
|
||||
|
||||
@staticmethod
|
||||
def get_vision_enabled_config():
|
||||
conversation_configurations = ConversationAdapters.get_all_conversation_configs()
|
||||
for config in conversation_configurations:
|
||||
if config.vision_enabled:
|
||||
return config
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def get_openai_conversation_config():
|
||||
return OpenAIProcessorConversationConfig.objects.filter().first()
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
# Generated by Django 5.0.7 on 2024-08-14 19:43
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("database", "0055_alter_agent_style_icon"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="chatmodeloptions",
|
||||
name="vision_enabled",
|
||||
field=models.BooleanField(default=False),
|
||||
),
|
||||
]
|
13
src/khoj/database/migrations/0057_merge_20240816_1409.py
Normal file
13
src/khoj/database/migrations/0057_merge_20240816_1409.py
Normal file
|
@ -0,0 +1,13 @@
|
|||
# Generated by Django 5.0.7 on 2024-08-16 18:09
|
||||
|
||||
from typing import List
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("database", "0056_chatmodeloptions_vision_enabled"),
|
||||
("database", "0056_searchmodelconfig_cross_encoder_model_config"),
|
||||
]
|
||||
operations: List[migrations.operations.base.Operation] = []
|
14
src/khoj/database/migrations/0060_merge_20240905_1828.py
Normal file
14
src/khoj/database/migrations/0060_merge_20240905_1828.py
Normal file
|
@ -0,0 +1,14 @@
|
|||
# Generated by Django 5.0.7 on 2024-09-05 18:28
|
||||
|
||||
from typing import List
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("database", "0057_merge_20240816_1409"),
|
||||
("database", "0059_searchmodelconfig_bi_encoder_confidence_threshold"),
|
||||
]
|
||||
|
||||
operations: List[str] = []
|
|
@ -93,6 +93,7 @@ class ChatModelOptions(BaseModel):
|
|||
tokenizer = models.CharField(max_length=200, default=None, null=True, blank=True)
|
||||
chat_model = models.CharField(max_length=200, default="bartowski/Meta-Llama-3.1-8B-Instruct-GGUF")
|
||||
model_type = models.CharField(max_length=200, choices=ModelType.choices, default=ModelType.OFFLINE)
|
||||
vision_enabled = models.BooleanField(default=False)
|
||||
openai_config = models.ForeignKey(
|
||||
OpenAIProcessorConversationConfig, on_delete=models.CASCADE, default=None, null=True, blank=True
|
||||
)
|
||||
|
|
|
@ -123,6 +123,8 @@ def converse(
|
|||
location_data: LocationData = None,
|
||||
user_name: str = None,
|
||||
agent: Agent = None,
|
||||
image_url: Optional[str] = None,
|
||||
vision_available: bool = False,
|
||||
):
|
||||
"""
|
||||
Converse with user using OpenAI's ChatGPT
|
||||
|
@ -178,6 +180,8 @@ def converse(
|
|||
model_name=model,
|
||||
max_prompt_size=max_prompt_size,
|
||||
tokenizer_name=tokenizer_name,
|
||||
uploaded_image_url=image_url,
|
||||
vision_enabled=vision_available,
|
||||
)
|
||||
truncated_messages = "\n".join({f"{message.content[:70]}..." for message in messages})
|
||||
logger.debug(f"Conversation Context for GPT: {truncated_messages}")
|
||||
|
|
|
@ -101,12 +101,16 @@ def save_to_conversation_log(
|
|||
client_application: ClientApplication = None,
|
||||
conversation_id: int = None,
|
||||
automation_id: str = None,
|
||||
uploaded_image_url: str = None,
|
||||
):
|
||||
user_message_time = user_message_time or datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
updated_conversation = message_to_log(
|
||||
user_message=q,
|
||||
chat_response=chat_response,
|
||||
user_message_metadata={"created": user_message_time},
|
||||
user_message_metadata={
|
||||
"created": user_message_time,
|
||||
"uploadedImageData": uploaded_image_url,
|
||||
},
|
||||
khoj_message_metadata={
|
||||
"context": compiled_references,
|
||||
"intent": {"inferred-queries": inferred_queries, "type": intent_type},
|
||||
|
@ -141,6 +145,8 @@ def generate_chatml_messages_with_context(
|
|||
loaded_model: Optional[Llama] = None,
|
||||
max_prompt_size=None,
|
||||
tokenizer_name=None,
|
||||
uploaded_image_url=None,
|
||||
vision_enabled=False,
|
||||
):
|
||||
"""Generate messages for ChatGPT with context from previous conversation"""
|
||||
# Set max prompt size from user config or based on pre-configured for model and machine specs
|
||||
|
@ -150,28 +156,40 @@ def generate_chatml_messages_with_context(
|
|||
else:
|
||||
max_prompt_size = model_to_prompt_size.get(model_name, 2000)
|
||||
|
||||
# Format user and system messages to chatml format
|
||||
def construct_structured_message(message, image_url):
|
||||
if image_url and vision_enabled:
|
||||
return [{"type": "text", "text": message}, {"type": "image_url", "image_url": {"url": image_url}}]
|
||||
return message
|
||||
|
||||
# Scale lookback turns proportional to max prompt size supported by model
|
||||
lookback_turns = max_prompt_size // 750
|
||||
|
||||
# Extract Chat History for Context
|
||||
chat_logs = []
|
||||
chatml_messages: List[ChatMessage] = []
|
||||
for chat in conversation_log.get("chat", []):
|
||||
chat_notes = f'\n\n Notes:\n{chat.get("context")}' if chat.get("context") else "\n"
|
||||
chat_logs += [chat["message"] + chat_notes]
|
||||
message_notes = f'\n\n Notes:\n{chat.get("context")}' if chat.get("context") else "\n"
|
||||
role = "user" if chat["by"] == "you" else "assistant"
|
||||
|
||||
rest_backnforths: List[ChatMessage] = []
|
||||
# Extract in reverse chronological order
|
||||
for user_msg, assistant_msg in zip(chat_logs[-2::-2], chat_logs[::-2]):
|
||||
if len(rest_backnforths) >= 2 * lookback_turns:
|
||||
message_content = chat["message"] + message_notes
|
||||
|
||||
if chat.get("uploadedImageData") and vision_enabled:
|
||||
message_content = construct_structured_message(message_content, chat.get("uploadedImageData"))
|
||||
|
||||
reconstructed_message = ChatMessage(content=message_content, role=role)
|
||||
|
||||
chatml_messages.insert(0, reconstructed_message)
|
||||
|
||||
if len(chatml_messages) >= 2 * lookback_turns:
|
||||
break
|
||||
rest_backnforths += reciprocal_conversation_to_chatml([user_msg, assistant_msg])[::-1]
|
||||
|
||||
# Format user and system messages to chatml format
|
||||
messages = []
|
||||
if not is_none_or_empty(user_message):
|
||||
messages.append(ChatMessage(content=user_message, role="user"))
|
||||
if len(rest_backnforths) > 0:
|
||||
messages += rest_backnforths
|
||||
messages.append(
|
||||
ChatMessage(content=construct_structured_message(user_message, uploaded_image_url), role="user")
|
||||
)
|
||||
if len(chatml_messages) > 0:
|
||||
messages += chatml_messages
|
||||
if not is_none_or_empty(system_message):
|
||||
messages.append(ChatMessage(content=system_message, role="system"))
|
||||
|
||||
|
|
|
@ -56,6 +56,7 @@ async def search_online(
|
|||
subscribed: bool = False,
|
||||
send_status_func: Optional[Callable] = None,
|
||||
custom_filters: List[str] = [],
|
||||
uploaded_image_url: str = None,
|
||||
):
|
||||
query += " ".join(custom_filters)
|
||||
if not is_internet_connected():
|
||||
|
@ -64,7 +65,9 @@ async def search_online(
|
|||
return
|
||||
|
||||
# Breakdown the query into subqueries to get the correct answer
|
||||
subqueries = await generate_online_subqueries(query, conversation_history, location, user)
|
||||
subqueries = await generate_online_subqueries(
|
||||
query, conversation_history, location, user, uploaded_image_url=uploaded_image_url
|
||||
)
|
||||
response_dict = {}
|
||||
|
||||
if subqueries:
|
||||
|
@ -138,13 +141,14 @@ async def read_webpages(
|
|||
user: KhojUser,
|
||||
subscribed: bool = False,
|
||||
send_status_func: Optional[Callable] = None,
|
||||
uploaded_image_url: str = None,
|
||||
):
|
||||
"Infer web pages to read from the query and extract relevant information from them"
|
||||
logger.info(f"Inferring web pages to read")
|
||||
if send_status_func:
|
||||
async for event in send_status_func(f"**Inferring web pages to read**"):
|
||||
yield {ChatEvent.STATUS: event}
|
||||
urls = await infer_webpage_urls(query, conversation_history, location, user)
|
||||
urls = await infer_webpage_urls(query, conversation_history, location, user, uploaded_image_url)
|
||||
|
||||
logger.info(f"Reading web pages at: {urls}")
|
||||
if send_status_func:
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import asyncio
|
||||
import base64
|
||||
import json
|
||||
import logging
|
||||
import time
|
||||
|
@ -46,11 +47,13 @@ from khoj.routers.helpers import (
|
|||
update_telemetry_state,
|
||||
validate_conversation_config,
|
||||
)
|
||||
from khoj.routers.storage import upload_image_to_bucket
|
||||
from khoj.utils import state
|
||||
from khoj.utils.helpers import (
|
||||
AsyncIteratorWrapper,
|
||||
ConversationCommand,
|
||||
command_descriptions,
|
||||
convert_image_to_webp,
|
||||
get_device,
|
||||
is_none_or_empty,
|
||||
)
|
||||
|
@ -517,7 +520,11 @@ async def set_conversation_title(
|
|||
)
|
||||
|
||||
|
||||
@api_chat.get("")
|
||||
class ImageUploadObject(BaseModel):
|
||||
image: str
|
||||
|
||||
|
||||
@api_chat.post("")
|
||||
@requires(["authenticated"])
|
||||
async def chat(
|
||||
request: Request,
|
||||
|
@ -532,6 +539,7 @@ async def chat(
|
|||
region: Optional[str] = None,
|
||||
country: Optional[str] = None,
|
||||
timezone: Optional[str] = None,
|
||||
image: Optional[ImageUploadObject] = None,
|
||||
rate_limiter_per_minute=Depends(
|
||||
ApiUserRateLimiter(requests=60, subscribed_requests=60, window=60, slug="chat_minute")
|
||||
),
|
||||
|
@ -539,7 +547,7 @@ async def chat(
|
|||
ApiUserRateLimiter(requests=600, subscribed_requests=600, window=60 * 60 * 24, slug="chat_day")
|
||||
),
|
||||
):
|
||||
async def event_generator(q: str):
|
||||
async def event_generator(q: str, image: ImageUploadObject):
|
||||
start_time = time.perf_counter()
|
||||
ttft = None
|
||||
chat_metadata: dict = {}
|
||||
|
@ -550,6 +558,17 @@ async def chat(
|
|||
q = unquote(q)
|
||||
nonlocal conversation_id
|
||||
|
||||
uploaded_image_url = None
|
||||
if image:
|
||||
decoded_string = unquote(image.image)
|
||||
base64_data = decoded_string.split(",", 1)[1]
|
||||
image_bytes = base64.b64decode(base64_data)
|
||||
webp_image_bytes = convert_image_to_webp(image_bytes)
|
||||
try:
|
||||
uploaded_image_url = upload_image_to_bucket(webp_image_bytes, request.user.object.id)
|
||||
except:
|
||||
uploaded_image_url = None
|
||||
|
||||
async def send_event(event_type: ChatEvent, data: str | dict):
|
||||
nonlocal connection_alive, ttft
|
||||
if not connection_alive or await request.is_disconnected():
|
||||
|
@ -637,7 +656,7 @@ async def chat(
|
|||
|
||||
if conversation_commands == [ConversationCommand.Default] or is_automated_task:
|
||||
conversation_commands = await aget_relevant_information_sources(
|
||||
q, meta_log, is_automated_task, subscribed=subscribed
|
||||
q, meta_log, is_automated_task, subscribed=subscribed, uploaded_image_url=uploaded_image_url
|
||||
)
|
||||
conversation_commands_str = ", ".join([cmd.value for cmd in conversation_commands])
|
||||
async for result in send_event(
|
||||
|
@ -645,7 +664,7 @@ async def chat(
|
|||
):
|
||||
yield result
|
||||
|
||||
mode = await aget_relevant_output_modes(q, meta_log, is_automated_task)
|
||||
mode = await aget_relevant_output_modes(q, meta_log, is_automated_task, uploaded_image_url)
|
||||
async for result in send_event(ChatEvent.STATUS, f"**Decided Response Mode:** {mode.value}"):
|
||||
yield result
|
||||
if mode not in conversation_commands:
|
||||
|
@ -693,7 +712,9 @@ async def chat(
|
|||
):
|
||||
yield result
|
||||
|
||||
response = await extract_relevant_summary(q, contextual_data, subscribed=subscribed)
|
||||
response = await extract_relevant_summary(
|
||||
q, contextual_data, subscribed=subscribed, uploaded_image_url=uploaded_image_url
|
||||
)
|
||||
response_log = str(response)
|
||||
async for result in send_llm_response(response_log):
|
||||
yield result
|
||||
|
@ -711,6 +732,7 @@ async def chat(
|
|||
intent_type="summarize",
|
||||
client_application=request.user.client_app,
|
||||
conversation_id=conversation_id,
|
||||
uploaded_image_url=uploaded_image_url,
|
||||
)
|
||||
return
|
||||
|
||||
|
@ -753,6 +775,7 @@ async def chat(
|
|||
conversation_id=conversation_id,
|
||||
inferred_queries=[query_to_run],
|
||||
automation_id=automation.id,
|
||||
uploaded_image_url=uploaded_image_url,
|
||||
)
|
||||
async for result in send_llm_response(llm_response):
|
||||
yield result
|
||||
|
@ -807,6 +830,7 @@ async def chat(
|
|||
subscribed,
|
||||
partial(send_event, ChatEvent.STATUS),
|
||||
custom_filters,
|
||||
uploaded_image_url=uploaded_image_url,
|
||||
):
|
||||
if isinstance(result, dict) and ChatEvent.STATUS in result:
|
||||
yield result[ChatEvent.STATUS]
|
||||
|
@ -823,7 +847,13 @@ async def chat(
|
|||
if ConversationCommand.Webpage in conversation_commands:
|
||||
try:
|
||||
async for result in read_webpages(
|
||||
defiltered_query, meta_log, location, user, subscribed, partial(send_event, ChatEvent.STATUS)
|
||||
defiltered_query,
|
||||
meta_log,
|
||||
location,
|
||||
user,
|
||||
subscribed,
|
||||
partial(send_event, ChatEvent.STATUS),
|
||||
uploaded_image_url=uploaded_image_url,
|
||||
):
|
||||
if isinstance(result, dict) and ChatEvent.STATUS in result:
|
||||
yield result[ChatEvent.STATUS]
|
||||
|
@ -869,6 +899,7 @@ async def chat(
|
|||
online_results=online_results,
|
||||
subscribed=subscribed,
|
||||
send_status_func=partial(send_event, ChatEvent.STATUS),
|
||||
uploaded_image_url=uploaded_image_url,
|
||||
):
|
||||
if isinstance(result, dict) and ChatEvent.STATUS in result:
|
||||
yield result[ChatEvent.STATUS]
|
||||
|
@ -898,6 +929,7 @@ async def chat(
|
|||
conversation_id=conversation_id,
|
||||
compiled_references=compiled_references,
|
||||
online_results=online_results,
|
||||
uploaded_image_url=uploaded_image_url,
|
||||
)
|
||||
content_obj = {
|
||||
"intentType": intent_type,
|
||||
|
@ -924,6 +956,7 @@ async def chat(
|
|||
conversation_id,
|
||||
location,
|
||||
user_name,
|
||||
uploaded_image_url,
|
||||
)
|
||||
|
||||
# Send Response
|
||||
|
@ -949,9 +982,9 @@ async def chat(
|
|||
|
||||
## Stream Text Response
|
||||
if stream:
|
||||
return StreamingResponse(event_generator(q), media_type="text/plain")
|
||||
return StreamingResponse(event_generator(q, image=image), media_type="text/plain")
|
||||
## Non-Streaming Text Response
|
||||
else:
|
||||
response_iterator = event_generator(q)
|
||||
response_iterator = event_generator(q, image=image)
|
||||
response_data = await read_chat_stream(response_iterator)
|
||||
return Response(content=json.dumps(response_data), media_type="application/json", status_code=200)
|
||||
|
|
|
@ -97,6 +97,7 @@ from khoj.utils.helpers import (
|
|||
LRU,
|
||||
ConversationCommand,
|
||||
ImageIntentType,
|
||||
convert_image_to_webp,
|
||||
is_none_or_empty,
|
||||
is_valid_url,
|
||||
log_telemetry,
|
||||
|
@ -252,7 +253,9 @@ async def acreate_title_from_query(query: str) -> str:
|
|||
return response.strip()
|
||||
|
||||
|
||||
async def aget_relevant_information_sources(query: str, conversation_history: dict, is_task: bool, subscribed: bool):
|
||||
async def aget_relevant_information_sources(
|
||||
query: str, conversation_history: dict, is_task: bool, subscribed: bool, uploaded_image_url: str = None
|
||||
):
|
||||
"""
|
||||
Given a query, determine which of the available tools the agent should use in order to answer appropriately.
|
||||
"""
|
||||
|
@ -266,6 +269,9 @@ async def aget_relevant_information_sources(query: str, conversation_history: di
|
|||
|
||||
chat_history = construct_chat_history(conversation_history)
|
||||
|
||||
if uploaded_image_url:
|
||||
query = f"[placeholder for image attached to this message]\n{query}"
|
||||
|
||||
relevant_tools_prompt = prompts.pick_relevant_information_collection_tools.format(
|
||||
query=query,
|
||||
tools=tool_options_str,
|
||||
|
@ -274,7 +280,9 @@ async def aget_relevant_information_sources(query: str, conversation_history: di
|
|||
|
||||
with timer("Chat actor: Infer information sources to refer", logger):
|
||||
response = await send_message_to_model_wrapper(
|
||||
relevant_tools_prompt, response_type="json_object", subscribed=subscribed
|
||||
relevant_tools_prompt,
|
||||
response_type="json_object",
|
||||
subscribed=subscribed,
|
||||
)
|
||||
|
||||
try:
|
||||
|
@ -302,7 +310,9 @@ async def aget_relevant_information_sources(query: str, conversation_history: di
|
|||
return [ConversationCommand.Default]
|
||||
|
||||
|
||||
async def aget_relevant_output_modes(query: str, conversation_history: dict, is_task: bool = False):
|
||||
async def aget_relevant_output_modes(
|
||||
query: str, conversation_history: dict, is_task: bool = False, uploaded_image_url: str = None
|
||||
):
|
||||
"""
|
||||
Given a query, determine which of the available tools the agent should use in order to answer appropriately.
|
||||
"""
|
||||
|
@ -319,6 +329,9 @@ async def aget_relevant_output_modes(query: str, conversation_history: dict, is_
|
|||
|
||||
chat_history = construct_chat_history(conversation_history)
|
||||
|
||||
if uploaded_image_url:
|
||||
query = f"[placeholder for image attached to this message]\n{query}"
|
||||
|
||||
relevant_mode_prompt = prompts.pick_relevant_output_mode.format(
|
||||
query=query,
|
||||
modes=mode_options_str,
|
||||
|
@ -347,7 +360,7 @@ async def aget_relevant_output_modes(query: str, conversation_history: dict, is_
|
|||
|
||||
|
||||
async def infer_webpage_urls(
|
||||
q: str, conversation_history: dict, location_data: LocationData, user: KhojUser
|
||||
q: str, conversation_history: dict, location_data: LocationData, user: KhojUser, uploaded_image_url: str = None
|
||||
) -> List[str]:
|
||||
"""
|
||||
Infer webpage links from the given query
|
||||
|
@ -366,7 +379,9 @@ async def infer_webpage_urls(
|
|||
)
|
||||
|
||||
with timer("Chat actor: Infer webpage urls to read", logger):
|
||||
response = await send_message_to_model_wrapper(online_queries_prompt, response_type="json_object")
|
||||
response = await send_message_to_model_wrapper(
|
||||
online_queries_prompt, uploaded_image_url=uploaded_image_url, response_type="json_object"
|
||||
)
|
||||
|
||||
# Validate that the response is a non-empty, JSON-serializable list of URLs
|
||||
try:
|
||||
|
@ -381,7 +396,7 @@ async def infer_webpage_urls(
|
|||
|
||||
|
||||
async def generate_online_subqueries(
|
||||
q: str, conversation_history: dict, location_data: LocationData, user: KhojUser
|
||||
q: str, conversation_history: dict, location_data: LocationData, user: KhojUser, uploaded_image_url: str = None
|
||||
) -> List[str]:
|
||||
"""
|
||||
Generate subqueries from the given query
|
||||
|
@ -400,7 +415,9 @@ async def generate_online_subqueries(
|
|||
)
|
||||
|
||||
with timer("Chat actor: Generate online search subqueries", logger):
|
||||
response = await send_message_to_model_wrapper(online_queries_prompt, response_type="json_object")
|
||||
response = await send_message_to_model_wrapper(
|
||||
online_queries_prompt, uploaded_image_url=uploaded_image_url, response_type="json_object"
|
||||
)
|
||||
|
||||
# Validate that the response is a non-empty, JSON-serializable list
|
||||
try:
|
||||
|
@ -419,7 +436,7 @@ async def generate_online_subqueries(
|
|||
return [q]
|
||||
|
||||
|
||||
async def schedule_query(q: str, conversation_history: dict) -> Tuple[str, ...]:
|
||||
async def schedule_query(q: str, conversation_history: dict, uploaded_image_url: str = None) -> Tuple[str, ...]:
|
||||
"""
|
||||
Schedule the date, time to run the query. Assume the server timezone is UTC.
|
||||
"""
|
||||
|
@ -430,7 +447,9 @@ async def schedule_query(q: str, conversation_history: dict) -> Tuple[str, ...]:
|
|||
chat_history=chat_history,
|
||||
)
|
||||
|
||||
raw_response = await send_message_to_model_wrapper(crontime_prompt, response_type="json_object")
|
||||
raw_response = await send_message_to_model_wrapper(
|
||||
crontime_prompt, uploaded_image_url=uploaded_image_url, response_type="json_object"
|
||||
)
|
||||
|
||||
# Validate that the response is a non-empty, JSON-serializable list
|
||||
try:
|
||||
|
@ -468,7 +487,9 @@ async def extract_relevant_info(q: str, corpus: str, subscribed: bool) -> Union[
|
|||
return response.strip()
|
||||
|
||||
|
||||
async def extract_relevant_summary(q: str, corpus: str, subscribed: bool = False) -> Union[str, None]:
|
||||
async def extract_relevant_summary(
|
||||
q: str, corpus: str, subscribed: bool = False, uploaded_image_url: str = None
|
||||
) -> Union[str, None]:
|
||||
"""
|
||||
Extract relevant information for a given query from the target corpus
|
||||
"""
|
||||
|
@ -489,6 +510,7 @@ async def extract_relevant_summary(q: str, corpus: str, subscribed: bool = False
|
|||
prompts.system_prompt_extract_relevant_summary,
|
||||
chat_model_option=chat_model,
|
||||
subscribed=subscribed,
|
||||
uploaded_image_url=uploaded_image_url,
|
||||
)
|
||||
return response.strip()
|
||||
|
||||
|
@ -501,6 +523,7 @@ async def generate_better_image_prompt(
|
|||
online_results: Optional[dict] = None,
|
||||
model_type: Optional[str] = None,
|
||||
subscribed: bool = False,
|
||||
uploaded_image_url: Optional[str] = None,
|
||||
) -> str:
|
||||
"""
|
||||
Generate a better image prompt from the given query
|
||||
|
@ -549,7 +572,7 @@ async def generate_better_image_prompt(
|
|||
|
||||
with timer("Chat actor: Generate contextual image prompt", logger):
|
||||
response = await send_message_to_model_wrapper(
|
||||
image_prompt, chat_model_option=chat_model, subscribed=subscribed
|
||||
image_prompt, chat_model_option=chat_model, subscribed=subscribed, uploaded_image_url=uploaded_image_url
|
||||
)
|
||||
response = response.strip()
|
||||
if response.startswith(('"', "'")) and response.endswith(('"', "'")):
|
||||
|
@ -564,11 +587,19 @@ async def send_message_to_model_wrapper(
|
|||
response_type: str = "text",
|
||||
chat_model_option: ChatModelOptions = None,
|
||||
subscribed: bool = False,
|
||||
uploaded_image_url: str = None,
|
||||
):
|
||||
conversation_config: ChatModelOptions = (
|
||||
chat_model_option or await ConversationAdapters.aget_default_conversation_config()
|
||||
)
|
||||
|
||||
vision_available = conversation_config.vision_enabled
|
||||
if not vision_available and uploaded_image_url:
|
||||
vision_enabled_config = ConversationAdapters.get_vision_enabled_config()
|
||||
if vision_enabled_config:
|
||||
conversation_config = vision_enabled_config
|
||||
vision_available = True
|
||||
|
||||
chat_model = conversation_config.chat_model
|
||||
max_tokens = (
|
||||
conversation_config.subscribed_max_prompt_size
|
||||
|
@ -576,6 +607,7 @@ async def send_message_to_model_wrapper(
|
|||
else conversation_config.max_prompt_size
|
||||
)
|
||||
tokenizer = conversation_config.tokenizer
|
||||
vision_available = conversation_config.vision_enabled
|
||||
|
||||
if conversation_config.model_type == "offline":
|
||||
if state.offline_chat_processor_config is None or state.offline_chat_processor_config.loaded_model is None:
|
||||
|
@ -589,6 +621,7 @@ async def send_message_to_model_wrapper(
|
|||
loaded_model=loaded_model,
|
||||
tokenizer_name=tokenizer,
|
||||
max_prompt_size=max_tokens,
|
||||
vision_enabled=vision_available,
|
||||
)
|
||||
|
||||
return send_message_to_model_offline(
|
||||
|
@ -609,6 +642,8 @@ async def send_message_to_model_wrapper(
|
|||
model_name=chat_model,
|
||||
max_prompt_size=max_tokens,
|
||||
tokenizer_name=tokenizer,
|
||||
vision_enabled=vision_available,
|
||||
uploaded_image_url=uploaded_image_url,
|
||||
)
|
||||
|
||||
openai_response = send_message_to_model(
|
||||
|
@ -628,6 +663,7 @@ async def send_message_to_model_wrapper(
|
|||
model_name=chat_model,
|
||||
max_prompt_size=max_tokens,
|
||||
tokenizer_name=tokenizer,
|
||||
vision_enabled=vision_available,
|
||||
)
|
||||
|
||||
return anthropic_send_message_to_model(
|
||||
|
@ -651,6 +687,7 @@ def send_message_to_model_wrapper_sync(
|
|||
|
||||
chat_model = conversation_config.chat_model
|
||||
max_tokens = conversation_config.max_prompt_size
|
||||
vision_available = conversation_config.vision_enabled
|
||||
|
||||
if conversation_config.model_type == "offline":
|
||||
if state.offline_chat_processor_config is None or state.offline_chat_processor_config.loaded_model is None:
|
||||
|
@ -658,7 +695,11 @@ def send_message_to_model_wrapper_sync(
|
|||
|
||||
loaded_model = state.offline_chat_processor_config.loaded_model
|
||||
truncated_messages = generate_chatml_messages_with_context(
|
||||
user_message=message, system_message=system_message, model_name=chat_model, loaded_model=loaded_model
|
||||
user_message=message,
|
||||
system_message=system_message,
|
||||
model_name=chat_model,
|
||||
loaded_model=loaded_model,
|
||||
vision_enabled=vision_available,
|
||||
)
|
||||
|
||||
return send_message_to_model_offline(
|
||||
|
@ -672,7 +713,10 @@ def send_message_to_model_wrapper_sync(
|
|||
elif conversation_config.model_type == "openai":
|
||||
api_key = conversation_config.openai_config.api_key
|
||||
truncated_messages = generate_chatml_messages_with_context(
|
||||
user_message=message, system_message=system_message, model_name=chat_model
|
||||
user_message=message,
|
||||
system_message=system_message,
|
||||
model_name=chat_model,
|
||||
vision_enabled=vision_available,
|
||||
)
|
||||
|
||||
openai_response = send_message_to_model(
|
||||
|
@ -688,6 +732,7 @@ def send_message_to_model_wrapper_sync(
|
|||
system_message=system_message,
|
||||
model_name=chat_model,
|
||||
max_prompt_size=max_tokens,
|
||||
vision_enabled=vision_available,
|
||||
)
|
||||
|
||||
return anthropic_send_message_to_model(
|
||||
|
@ -712,6 +757,7 @@ def generate_chat_response(
|
|||
conversation_id: int = None,
|
||||
location_data: LocationData = None,
|
||||
user_name: Optional[str] = None,
|
||||
uploaded_image_url: Optional[str] = None,
|
||||
) -> Tuple[Union[ThreadedGenerator, Iterator[str]], Dict[str, str]]:
|
||||
# Initialize Variables
|
||||
chat_response = None
|
||||
|
@ -719,7 +765,6 @@ def generate_chat_response(
|
|||
|
||||
metadata = {}
|
||||
agent = AgentAdapters.get_conversation_agent_by_id(conversation.agent.id) if conversation.agent else None
|
||||
|
||||
try:
|
||||
partial_completion = partial(
|
||||
save_to_conversation_log,
|
||||
|
@ -731,9 +776,17 @@ def generate_chat_response(
|
|||
inferred_queries=inferred_queries,
|
||||
client_application=client_application,
|
||||
conversation_id=conversation_id,
|
||||
uploaded_image_url=uploaded_image_url,
|
||||
)
|
||||
|
||||
conversation_config = ConversationAdapters.get_valid_conversation_config(user, conversation)
|
||||
vision_available = conversation_config.vision_enabled
|
||||
if not vision_available and uploaded_image_url:
|
||||
vision_enabled_config = ConversationAdapters.get_vision_enabled_config()
|
||||
if vision_enabled_config:
|
||||
conversation_config = vision_enabled_config
|
||||
vision_available = True
|
||||
|
||||
if conversation_config.model_type == "offline":
|
||||
loaded_model = state.offline_chat_processor_config.loaded_model
|
||||
chat_response = converse_offline(
|
||||
|
@ -759,6 +812,7 @@ def generate_chat_response(
|
|||
chat_response = converse(
|
||||
compiled_references,
|
||||
q,
|
||||
image_url=uploaded_image_url,
|
||||
online_results=online_results,
|
||||
conversation_log=meta_log,
|
||||
model=chat_model,
|
||||
|
@ -771,6 +825,7 @@ def generate_chat_response(
|
|||
location_data=location_data,
|
||||
user_name=user_name,
|
||||
agent=agent,
|
||||
vision_available=vision_available,
|
||||
)
|
||||
|
||||
elif conversation_config.model_type == "anthropic":
|
||||
|
@ -809,6 +864,7 @@ async def text_to_image(
|
|||
online_results: Dict[str, Any],
|
||||
subscribed: bool = False,
|
||||
send_status_func: Optional[Callable] = None,
|
||||
uploaded_image_url: Optional[str] = None,
|
||||
):
|
||||
status_code = 200
|
||||
image = None
|
||||
|
@ -845,6 +901,7 @@ async def text_to_image(
|
|||
online_results=online_results,
|
||||
model_type=text_to_image_config.model_type,
|
||||
subscribed=subscribed,
|
||||
uploaded_image_url=uploaded_image_url,
|
||||
)
|
||||
|
||||
if send_status_func:
|
||||
|
@ -908,13 +965,7 @@ async def text_to_image(
|
|||
|
||||
with timer("Convert image to webp", logger):
|
||||
# Convert png to webp for faster loading
|
||||
image_io = io.BytesIO(decoded_image)
|
||||
png_image = Image.open(image_io)
|
||||
webp_image_io = io.BytesIO()
|
||||
png_image.save(webp_image_io, "WEBP")
|
||||
webp_image_bytes = webp_image_io.getvalue()
|
||||
webp_image_io.close()
|
||||
image_io.close()
|
||||
webp_image_bytes = convert_image_to_webp(decoded_image)
|
||||
|
||||
with timer("Upload image to S3", logger):
|
||||
image_url = upload_image(webp_image_bytes, user.uuid)
|
||||
|
@ -1095,6 +1146,7 @@ def should_notify(original_query: str, executed_query: str, ai_response: str) ->
|
|||
|
||||
with timer("Chat actor: Decide to notify user of automation response", logger):
|
||||
try:
|
||||
# TODO Replace with async call so we don't have to maintain a sync version
|
||||
response = send_message_to_model_wrapper_sync(to_notify_or_not)
|
||||
should_notify_result = "no" not in response.lower()
|
||||
logger.info(f'Decided to {"not " if not should_notify_result else ""}notify user of automation response.')
|
||||
|
|
|
@ -33,3 +33,31 @@ def upload_image(image: bytes, user_id: uuid.UUID):
|
|||
except Exception as e:
|
||||
logger.error(f"Failed to upload image to S3: {e}")
|
||||
return None
|
||||
|
||||
|
||||
AWS_USER_UPLOADED_IMAGES_BUCKET_NAME = os.getenv("AWS_USER_UPLOADED_IMAGES_BUCKET_NAME")
|
||||
|
||||
|
||||
def upload_image_to_bucket(image: bytes, user_id: uuid.UUID):
|
||||
"""Upload the image to the S3 bucket"""
|
||||
if not aws_enabled:
|
||||
logger.info("AWS is not enabled. Skipping image upload")
|
||||
return None
|
||||
|
||||
image_key = f"{user_id}/{uuid.uuid4()}.webp"
|
||||
if not AWS_USER_UPLOADED_IMAGES_BUCKET_NAME:
|
||||
logger.error("AWS_USER_UPLOADED_IMAGES_BUCKET_NAME is not set")
|
||||
return None
|
||||
|
||||
try:
|
||||
s3_client.put_object(
|
||||
Bucket=AWS_USER_UPLOADED_IMAGES_BUCKET_NAME,
|
||||
Key=image_key,
|
||||
Body=image,
|
||||
ACL="public-read",
|
||||
ContentType="image/webp",
|
||||
)
|
||||
return f"https://{AWS_USER_UPLOADED_IMAGES_BUCKET_NAME}/{image_key}"
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to upload image to S3: {e}")
|
||||
return None
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
from __future__ import annotations # to avoid quoting type hints
|
||||
|
||||
import datetime
|
||||
import io
|
||||
import logging
|
||||
import os
|
||||
import platform
|
||||
|
@ -22,6 +23,7 @@ import requests
|
|||
import torch
|
||||
from asgiref.sync import sync_to_async
|
||||
from magika import Magika
|
||||
from PIL import Image
|
||||
|
||||
from khoj.utils import constants
|
||||
|
||||
|
@ -416,3 +418,16 @@ def is_internet_connected():
|
|||
return response.status_code == 200
|
||||
except:
|
||||
return False
|
||||
|
||||
|
||||
def convert_image_to_webp(image_bytes):
|
||||
"""Convert image bytes to webp format for faster loading"""
|
||||
image_io = io.BytesIO(image_bytes)
|
||||
with Image.open(image_io) as original_image:
|
||||
webp_image_io = io.BytesIO()
|
||||
original_image.save(webp_image_io, "WEBP")
|
||||
|
||||
# Encode the WebP image back to base64
|
||||
webp_image_bytes = webp_image_io.getvalue()
|
||||
webp_image_io.close()
|
||||
return webp_image_bytes
|
||||
|
|
|
@ -462,8 +462,8 @@ async def test_chat_with_unauthenticated_user(chat_client_with_auth, api_user2:
|
|||
headers = {"Authorization": f"Bearer {api_user2.token}"}
|
||||
|
||||
# Act
|
||||
auth_response = chat_client_with_auth.get(f'/api/chat?q="Hello!"', headers=headers)
|
||||
no_auth_response = chat_client_with_auth.get(f'/api/chat?q="Hello!"')
|
||||
auth_response = chat_client_with_auth.post(f'/api/chat?q="Hello!"', headers=headers)
|
||||
no_auth_response = chat_client_with_auth.post(f'/api/chat?q="Hello!"')
|
||||
|
||||
# Assert
|
||||
assert auth_response.status_code == 200
|
||||
|
|
|
@ -49,7 +49,7 @@ def create_conversation(message_list, user, agent=None):
|
|||
@pytest.mark.django_db(transaction=True)
|
||||
def test_offline_chat_with_no_chat_history_or_retrieved_content(client_offline_chat):
|
||||
# Act
|
||||
response = client_offline_chat.get(f'/api/chat?q="Hello, my name is Testatron. Who are you?"&stream=true')
|
||||
response = client_offline_chat.post(f'/api/chat?q="Hello, my name is Testatron. Who are you?"&stream=true')
|
||||
response_message = response.content.decode("utf-8")
|
||||
|
||||
# Assert
|
||||
|
@ -67,7 +67,7 @@ def test_chat_with_online_content(client_offline_chat):
|
|||
# Act
|
||||
q = "/online give me the link to paul graham's essay how to do great work"
|
||||
encoded_q = quote(q, safe="")
|
||||
response = client_offline_chat.get(f"/api/chat?q={encoded_q}")
|
||||
response = client_offline_chat.post(f"/api/chat?q={encoded_q}")
|
||||
response_message = response.json()["response"]
|
||||
|
||||
# Assert
|
||||
|
@ -89,7 +89,7 @@ def test_chat_with_online_webpage_content(client_offline_chat):
|
|||
# Act
|
||||
q = "/online how many firefighters were involved in the great chicago fire and which year did it take place?"
|
||||
encoded_q = quote(q, safe="")
|
||||
response = client_offline_chat.get(f"/api/chat?q={encoded_q}")
|
||||
response = client_offline_chat.post(f"/api/chat?q={encoded_q}")
|
||||
response_message = response.json()["response"]
|
||||
|
||||
# Assert
|
||||
|
@ -112,7 +112,7 @@ def test_answer_from_chat_history(client_offline_chat, default_user2):
|
|||
create_conversation(message_list, default_user2)
|
||||
|
||||
# Act
|
||||
response = client_offline_chat.get(f'/api/chat?q="What is my name?"&stream=true')
|
||||
response = client_offline_chat.post(f'/api/chat?q="What is my name?"&stream=true')
|
||||
response_message = response.content.decode("utf-8")
|
||||
|
||||
# Assert
|
||||
|
@ -139,7 +139,7 @@ def test_answer_from_currently_retrieved_content(client_offline_chat, default_us
|
|||
create_conversation(message_list, default_user2)
|
||||
|
||||
# Act
|
||||
response = client_offline_chat.get(f'/api/chat?q="Where was Xi Li born?"')
|
||||
response = client_offline_chat.post(f'/api/chat?q="Where was Xi Li born?"')
|
||||
response_message = response.content.decode("utf-8")
|
||||
|
||||
# Assert
|
||||
|
@ -163,7 +163,7 @@ def test_answer_from_chat_history_and_previously_retrieved_content(client_offlin
|
|||
create_conversation(message_list, default_user2)
|
||||
|
||||
# Act
|
||||
response = client_offline_chat.get(f'/api/chat?q="Where was I born?"')
|
||||
response = client_offline_chat.post(f'/api/chat?q="Where was I born?"')
|
||||
response_message = response.content.decode("utf-8")
|
||||
|
||||
# Assert
|
||||
|
@ -185,7 +185,7 @@ def test_answer_from_chat_history_and_currently_retrieved_content(client_offline
|
|||
create_conversation(message_list, default_user2)
|
||||
|
||||
# Act
|
||||
response = client_offline_chat.get(f'/api/chat?q="Where was I born?"')
|
||||
response = client_offline_chat.post(f'/api/chat?q="Where was I born?"')
|
||||
response_message = response.content.decode("utf-8")
|
||||
|
||||
# Assert
|
||||
|
@ -211,7 +211,7 @@ def test_no_answer_in_chat_history_or_retrieved_content(client_offline_chat, def
|
|||
create_conversation(message_list, default_user2)
|
||||
|
||||
# Act
|
||||
response = client_offline_chat.get(f'/api/chat?q="Where was I born?"&stream=true')
|
||||
response = client_offline_chat.post(f'/api/chat?q="Where was I born?"&stream=true')
|
||||
response_message = response.content.decode("utf-8")
|
||||
|
||||
# Assert
|
||||
|
@ -232,7 +232,7 @@ def test_answer_using_general_command(client_offline_chat, default_user2):
|
|||
create_conversation(message_list, default_user2)
|
||||
|
||||
# Act
|
||||
response = client_offline_chat.get(f"/api/chat?q={query}&stream=true")
|
||||
response = client_offline_chat.post(f"/api/chat?q={query}&stream=true")
|
||||
response_message = response.content.decode("utf-8")
|
||||
|
||||
# Assert
|
||||
|
@ -250,7 +250,7 @@ def test_answer_from_retrieved_content_using_notes_command(client_offline_chat,
|
|||
create_conversation(message_list, default_user2)
|
||||
|
||||
# Act
|
||||
response = client_offline_chat.get(f"/api/chat?q={query}&stream=true")
|
||||
response = client_offline_chat.post(f"/api/chat?q={query}&stream=true")
|
||||
response_message = response.content.decode("utf-8")
|
||||
|
||||
# Assert
|
||||
|
@ -269,8 +269,8 @@ def test_answer_using_file_filter(client_offline_chat, default_user2):
|
|||
create_conversation(message_list, default_user2)
|
||||
|
||||
# Act
|
||||
no_answer_response = client_offline_chat.get(f"/api/chat?q={no_answer_query}&stream=true").content.decode("utf-8")
|
||||
answer_response = client_offline_chat.get(f"/api/chat?q={answer_query}&stream=true").content.decode("utf-8")
|
||||
no_answer_response = client_offline_chat.post(f"/api/chat?q={no_answer_query}&stream=true").content.decode("utf-8")
|
||||
answer_response = client_offline_chat.post(f"/api/chat?q={answer_query}&stream=true").content.decode("utf-8")
|
||||
|
||||
# Assert
|
||||
assert "Fujiang" not in no_answer_response
|
||||
|
@ -287,7 +287,7 @@ def test_answer_not_known_using_notes_command(client_offline_chat, default_user2
|
|||
create_conversation(message_list, default_user2)
|
||||
|
||||
# Act
|
||||
response = client_offline_chat.get(f"/api/chat?q={query}&stream=true")
|
||||
response = client_offline_chat.post(f"/api/chat?q={query}&stream=true")
|
||||
response_message = response.content.decode("utf-8")
|
||||
|
||||
# Assert
|
||||
|
@ -320,7 +320,7 @@ def test_summarize_one_file(client_offline_chat, default_user2: KhojUser):
|
|||
json={"filename": summarization_file, "conversation_id": str(conversation.id)},
|
||||
)
|
||||
query = urllib.parse.quote("/summarize")
|
||||
response = client_offline_chat.get(f"/api/chat?q={query}&conversation_id={conversation.id}&stream=true")
|
||||
response = client_offline_chat.post(f"/api/chat?q={query}&conversation_id={conversation.id}&stream=true")
|
||||
response_message = response.content.decode("utf-8")
|
||||
# Assert
|
||||
assert response_message != ""
|
||||
|
@ -352,7 +352,7 @@ def test_summarize_extra_text(client_offline_chat, default_user2: KhojUser):
|
|||
json={"filename": summarization_file, "conversation_id": str(conversation.id)},
|
||||
)
|
||||
query = urllib.parse.quote("/summarize tell me about Xiu")
|
||||
response = client_offline_chat.get(f"/api/chat?q={query}&conversation_id={conversation.id}&stream=true")
|
||||
response = client_offline_chat.post(f"/api/chat?q={query}&conversation_id={conversation.id}&stream=true")
|
||||
response_message = response.content.decode("utf-8")
|
||||
# Assert
|
||||
assert response_message != ""
|
||||
|
@ -380,7 +380,7 @@ def test_summarize_multiple_files(client_offline_chat, default_user2: KhojUser):
|
|||
)
|
||||
|
||||
query = urllib.parse.quote("/summarize")
|
||||
response = client_offline_chat.get(f"/api/chat?q={query}&conversation_id={conversation.id}&stream=true")
|
||||
response = client_offline_chat.post(f"/api/chat?q={query}&conversation_id={conversation.id}&stream=true")
|
||||
response_message = response.content.decode("utf-8")
|
||||
|
||||
# Assert
|
||||
|
@ -393,7 +393,7 @@ def test_summarize_no_files(client_offline_chat, default_user2: KhojUser):
|
|||
message_list = []
|
||||
conversation = create_conversation(message_list, default_user2)
|
||||
query = urllib.parse.quote("/summarize")
|
||||
response = client_offline_chat.get(f"/api/chat?q={query}&conversation_id={conversation.id}&stream=true")
|
||||
response = client_offline_chat.post(f"/api/chat?q={query}&conversation_id={conversation.id}&stream=true")
|
||||
response_message = response.content.decode("utf-8")
|
||||
# Assert
|
||||
assert response_message == "No files selected for summarization. Please add files using the section on the left."
|
||||
|
@ -425,14 +425,14 @@ def test_summarize_different_conversation(client_offline_chat, default_user2: Kh
|
|||
)
|
||||
|
||||
query = urllib.parse.quote("/summarize")
|
||||
response = client_offline_chat.get(f"/api/chat?q={query}&conversation_id={conversation2.id}&stream=true")
|
||||
response = client_offline_chat.post(f"/api/chat?q={query}&conversation_id={conversation2.id}&stream=true")
|
||||
response_message = response.content.decode("utf-8")
|
||||
|
||||
# Assert
|
||||
assert response_message == "No files selected for summarization. Please add files using the section on the left."
|
||||
|
||||
# now make sure that the file filter is still in conversation 1
|
||||
response = client_offline_chat.get(f"/api/chat?q={query}&conversation_id={conversation1.id}&stream=true")
|
||||
response = client_offline_chat.post(f"/api/chat?q={query}&conversation_id={conversation1.id}&stream=true")
|
||||
response_message = response.content.decode("utf-8")
|
||||
|
||||
# Assert
|
||||
|
@ -452,7 +452,7 @@ def test_summarize_nonexistant_file(client_offline_chat, default_user2: KhojUser
|
|||
json={"filename": "imaginary.markdown", "conversation_id": str(conversation.id)},
|
||||
)
|
||||
query = urllib.parse.quote("/summarize")
|
||||
response = client_offline_chat.get(f"/api/chat?q={query}&conversation_id={conversation.id}&stream=true")
|
||||
response = client_offline_chat.post(f"/api/chat?q={query}&conversation_id={conversation.id}&stream=true")
|
||||
response_message = response.content.decode("utf-8")
|
||||
# Assert
|
||||
assert response_message == "No files selected for summarization. Please add files using the section on the left."
|
||||
|
@ -483,7 +483,7 @@ def test_summarize_diff_user_file(
|
|||
json={"filename": summarization_file, "conversation_id": str(conversation.id)},
|
||||
)
|
||||
query = urllib.parse.quote("/summarize")
|
||||
response = client_offline_chat.get(f"/api/chat?q={query}&conversation_id={conversation.id}&stream=true")
|
||||
response = client_offline_chat.post(f"/api/chat?q={query}&conversation_id={conversation.id}&stream=true")
|
||||
response_message = response.content.decode("utf-8")
|
||||
# Assert
|
||||
assert response_message == "No files selected for summarization. Please add files using the section on the left."
|
||||
|
@ -499,7 +499,7 @@ def test_answer_requires_current_date_awareness(client_offline_chat):
|
|||
query = urllib.parse.quote("Where did I have lunch today?")
|
||||
|
||||
# Act
|
||||
response = client_offline_chat.get(f"/api/chat?q={query}&stream=true")
|
||||
response = client_offline_chat.post(f"/api/chat?q={query}&stream=true")
|
||||
response_message = response.content.decode("utf-8")
|
||||
|
||||
# Assert
|
||||
|
@ -518,7 +518,7 @@ def test_answer_requires_current_date_awareness(client_offline_chat):
|
|||
def test_answer_requires_date_aware_aggregation_across_provided_notes(client_offline_chat):
|
||||
"Chat director should be able to answer questions that require date aware aggregation across multiple notes"
|
||||
# Act
|
||||
response = client_offline_chat.get(f'/api/chat?q="How much did I spend on dining this year?"&stream=true')
|
||||
response = client_offline_chat.post(f'/api/chat?q="How much did I spend on dining this year?"&stream=true')
|
||||
response_message = response.content.decode("utf-8")
|
||||
|
||||
# Assert
|
||||
|
@ -559,7 +559,7 @@ def test_answer_general_question_not_in_chat_history_or_retrieved_content(client
|
|||
@pytest.mark.django_db(transaction=True)
|
||||
def test_ask_for_clarification_if_not_enough_context_in_question(client_offline_chat, default_user2):
|
||||
# Act
|
||||
response = client_offline_chat.get(f'/api/chat?q="What is the name of Namitas older son"&stream=true')
|
||||
response = client_offline_chat.post(f'/api/chat?q="What is the name of Namitas older son"&stream=true')
|
||||
response_message = response.content.decode("utf-8")
|
||||
|
||||
# Assert
|
||||
|
@ -589,7 +589,7 @@ def test_answer_in_chat_history_beyond_lookback_window(client_offline_chat, defa
|
|||
create_conversation(message_list, default_user2)
|
||||
|
||||
# Act
|
||||
response = client_offline_chat.get(f'/api/chat?q="What is my name?"&stream=true')
|
||||
response = client_offline_chat.post(f'/api/chat?q="What is my name?"&stream=true')
|
||||
response_message = response.content.decode("utf-8")
|
||||
|
||||
# Assert
|
||||
|
@ -653,7 +653,7 @@ def test_answer_in_chat_history_by_conversation_id_with_agent(
|
|||
|
||||
# Act
|
||||
query = urllib.parse.quote("/general What did I eat for breakfast?")
|
||||
response = client_offline_chat.get(f"/api/chat?q={query}&conversation_id={conversation.id}&stream=true")
|
||||
response = client_offline_chat.post(f"/api/chat?q={query}&conversation_id={conversation.id}&stream=true")
|
||||
response_message = response.content.decode("utf-8")
|
||||
|
||||
# Assert that agent only responds with the summary of spending
|
||||
|
@ -673,7 +673,7 @@ def test_answer_chat_history_very_long(client_offline_chat, default_user2):
|
|||
create_conversation(message_list, default_user2)
|
||||
|
||||
# Act
|
||||
response = client_offline_chat.get(f'/api/chat?q="What is my name?"&stream=true')
|
||||
response = client_offline_chat.post(f'/api/chat?q="What is my name?"&stream=true')
|
||||
response_message = response.content.decode("utf-8")
|
||||
|
||||
# Assert
|
||||
|
@ -687,7 +687,7 @@ def test_answer_chat_history_very_long(client_offline_chat, default_user2):
|
|||
def test_answer_requires_multiple_independent_searches(client_offline_chat):
|
||||
"Chat director should be able to answer by doing multiple independent searches for required information"
|
||||
# Act
|
||||
response = client_offline_chat.get(f'/api/chat?q="Is Xi older than Namita?"&stream=true')
|
||||
response = client_offline_chat.post(f'/api/chat?q="Is Xi older than Namita?"&stream=true')
|
||||
response_message = response.content.decode("utf-8")
|
||||
|
||||
# Assert
|
||||
|
|
|
@ -49,7 +49,7 @@ def create_conversation(message_list, user, agent=None):
|
|||
@pytest.mark.django_db(transaction=True)
|
||||
def test_chat_with_no_chat_history_or_retrieved_content(chat_client):
|
||||
# Act
|
||||
response = chat_client.get(f'/api/chat?q="Hello, my name is Testatron. Who are you?"')
|
||||
response = chat_client.post(f'/api/chat?q="Hello, my name is Testatron. Who are you?"')
|
||||
response_message = response.json()["response"]
|
||||
|
||||
# Assert
|
||||
|
@ -67,7 +67,7 @@ def test_chat_with_online_content(chat_client):
|
|||
# Act
|
||||
q = "/online give me the link to paul graham's essay how to do great work"
|
||||
encoded_q = quote(q, safe="")
|
||||
response = chat_client.get(f"/api/chat?q={encoded_q}")
|
||||
response = chat_client.post(f"/api/chat?q={encoded_q}")
|
||||
response_message = response.json()["response"]
|
||||
|
||||
# Assert
|
||||
|
@ -88,7 +88,7 @@ def test_chat_with_online_webpage_content(chat_client):
|
|||
# Act
|
||||
q = "/online how many firefighters were involved in the great chicago fire and which year did it take place?"
|
||||
encoded_q = quote(q, safe="")
|
||||
response = chat_client.get(f"/api/chat?q={encoded_q}")
|
||||
response = chat_client.post(f"/api/chat?q={encoded_q}")
|
||||
response_message = response.json()["response"]
|
||||
|
||||
# Assert
|
||||
|
@ -111,7 +111,7 @@ def test_answer_from_chat_history(chat_client, default_user2: KhojUser):
|
|||
create_conversation(message_list, default_user2)
|
||||
|
||||
# Act
|
||||
response = chat_client.get(f'/api/chat?q="What is my name?"')
|
||||
response = chat_client.post(f'/api/chat?q="What is my name?"')
|
||||
response_message = response.content.decode("utf-8")
|
||||
|
||||
# Assert
|
||||
|
@ -138,7 +138,7 @@ def test_answer_from_currently_retrieved_content(chat_client, default_user2: Kho
|
|||
create_conversation(message_list, default_user2)
|
||||
|
||||
# Act
|
||||
response = chat_client.get(f'/api/chat?q="Where was Xi Li born?"')
|
||||
response = chat_client.post(f'/api/chat?q="Where was Xi Li born?"')
|
||||
response_message = response.json()["response"]
|
||||
|
||||
# Assert
|
||||
|
@ -162,7 +162,7 @@ def test_answer_from_chat_history_and_previously_retrieved_content(chat_client_n
|
|||
create_conversation(message_list, default_user2)
|
||||
|
||||
# Act
|
||||
response = chat_client_no_background.get(f'/api/chat?q="Where was I born?"')
|
||||
response = chat_client_no_background.post(f'/api/chat?q="Where was I born?"')
|
||||
response_message = response.json()["response"]
|
||||
|
||||
# Assert
|
||||
|
@ -185,7 +185,7 @@ def test_answer_from_chat_history_and_currently_retrieved_content(chat_client, d
|
|||
create_conversation(message_list, default_user2)
|
||||
|
||||
# Act
|
||||
response = chat_client.get(f'/api/chat?q="Where was I born?"')
|
||||
response = chat_client.post(f'/api/chat?q="Where was I born?"')
|
||||
response_message = response.json()["response"]
|
||||
|
||||
# Assert
|
||||
|
@ -210,7 +210,7 @@ def test_no_answer_in_chat_history_or_retrieved_content(chat_client, default_use
|
|||
create_conversation(message_list, default_user2)
|
||||
|
||||
# Act
|
||||
response = chat_client.get(f'/api/chat?q="Where was I born?"')
|
||||
response = chat_client.post(f'/api/chat?q="Where was I born?"')
|
||||
response_message = response.json()["response"]
|
||||
|
||||
# Assert
|
||||
|
@ -240,7 +240,7 @@ def test_answer_using_general_command(chat_client, default_user2: KhojUser):
|
|||
create_conversation(message_list, default_user2)
|
||||
|
||||
# Act
|
||||
response = chat_client.get(f"/api/chat?q={query}&stream=true")
|
||||
response = chat_client.post(f"/api/chat?q={query}&stream=true")
|
||||
response_message = response.content.decode("utf-8")
|
||||
|
||||
# Assert
|
||||
|
@ -258,7 +258,7 @@ def test_answer_from_retrieved_content_using_notes_command(chat_client, default_
|
|||
create_conversation(message_list, default_user2)
|
||||
|
||||
# Act
|
||||
response = chat_client.get(f"/api/chat?q={query}")
|
||||
response = chat_client.post(f"/api/chat?q={query}")
|
||||
response_message = response.json()["response"]
|
||||
|
||||
# Assert
|
||||
|
@ -276,7 +276,7 @@ def test_answer_not_known_using_notes_command(chat_client_no_background, default
|
|||
create_conversation(message_list, default_user2)
|
||||
|
||||
# Act
|
||||
response = chat_client_no_background.get(f"/api/chat?q={query}")
|
||||
response = chat_client_no_background.post(f"/api/chat?q={query}")
|
||||
response_message = response.json()["response"]
|
||||
|
||||
# Assert
|
||||
|
@ -309,7 +309,7 @@ def test_summarize_one_file(chat_client, default_user2: KhojUser):
|
|||
json={"filename": summarization_file, "conversation_id": str(conversation.id)},
|
||||
)
|
||||
query = urllib.parse.quote("/summarize")
|
||||
response = chat_client.get(f"/api/chat?q={query}&conversation_id={conversation.id}")
|
||||
response = chat_client.post(f"/api/chat?q={query}&conversation_id={conversation.id}")
|
||||
response_message = response.json()["response"]
|
||||
# Assert
|
||||
assert response_message != ""
|
||||
|
@ -341,7 +341,7 @@ def test_summarize_extra_text(chat_client, default_user2: KhojUser):
|
|||
json={"filename": summarization_file, "conversation_id": str(conversation.id)},
|
||||
)
|
||||
query = urllib.parse.quote("/summarize tell me about Xiu")
|
||||
response = chat_client.get(f"/api/chat?q={query}&conversation_id={conversation.id}")
|
||||
response = chat_client.post(f"/api/chat?q={query}&conversation_id={conversation.id}")
|
||||
response_message = response.json()["response"]
|
||||
# Assert
|
||||
assert response_message != ""
|
||||
|
@ -369,7 +369,7 @@ def test_summarize_multiple_files(chat_client, default_user2: KhojUser):
|
|||
)
|
||||
|
||||
query = urllib.parse.quote("/summarize")
|
||||
response = chat_client.get(f"/api/chat?q={query}&conversation_id={conversation.id}")
|
||||
response = chat_client.post(f"/api/chat?q={query}&conversation_id={conversation.id}")
|
||||
response_message = response.json()["response"]
|
||||
|
||||
# Assert
|
||||
|
@ -382,7 +382,7 @@ def test_summarize_no_files(chat_client, default_user2: KhojUser):
|
|||
message_list = []
|
||||
conversation = create_conversation(message_list, default_user2)
|
||||
query = urllib.parse.quote("/summarize")
|
||||
response = chat_client.get(f"/api/chat?q={query}&conversation_id={conversation.id}")
|
||||
response = chat_client.post(f"/api/chat?q={query}&conversation_id={conversation.id}")
|
||||
response_message = response.json()["response"]
|
||||
# Assert
|
||||
assert response_message == "No files selected for summarization. Please add files using the section on the left."
|
||||
|
@ -414,14 +414,14 @@ def test_summarize_different_conversation(chat_client, default_user2: KhojUser):
|
|||
)
|
||||
|
||||
query = urllib.parse.quote("/summarize")
|
||||
response = chat_client.get(f"/api/chat?q={query}&conversation_id={conversation2.id}")
|
||||
response = chat_client.post(f"/api/chat?q={query}&conversation_id={conversation2.id}")
|
||||
response_message = response.json()["response"]
|
||||
|
||||
# Assert
|
||||
assert response_message == "No files selected for summarization. Please add files using the section on the left."
|
||||
|
||||
# now make sure that the file filter is still in conversation 1
|
||||
response = chat_client.get(f"/api/chat?q={query}&conversation_id={conversation1.id}")
|
||||
response = chat_client.post(f"/api/chat?q={query}&conversation_id={conversation1.id}")
|
||||
response_message = response.json()["response"]
|
||||
|
||||
# Assert
|
||||
|
@ -441,7 +441,7 @@ def test_summarize_nonexistant_file(chat_client, default_user2: KhojUser):
|
|||
json={"filename": "imaginary.markdown", "conversation_id": str(conversation.id)},
|
||||
)
|
||||
query = urllib.parse.quote("/summarize")
|
||||
response = chat_client.get(f"/api/chat?q={query}&conversation_id={conversation.id}")
|
||||
response = chat_client.post(f"/api/chat?q={query}&conversation_id={conversation.id}")
|
||||
response_message = response.json()["response"]
|
||||
# Assert
|
||||
assert response_message == "No files selected for summarization. Please add files using the section on the left."
|
||||
|
@ -470,7 +470,7 @@ def test_summarize_diff_user_file(chat_client, default_user: KhojUser, pdf_confi
|
|||
json={"filename": summarization_file, "conversation_id": str(conversation.id)},
|
||||
)
|
||||
query = urllib.parse.quote("/summarize")
|
||||
response = chat_client.get(f"/api/chat?q={query}&conversation_id={conversation.id}")
|
||||
response = chat_client.post(f"/api/chat?q={query}&conversation_id={conversation.id}")
|
||||
response_message = response.json()["response"]
|
||||
# Assert
|
||||
assert response_message == "No files selected for summarization. Please add files using the section on the left."
|
||||
|
@ -484,7 +484,7 @@ def test_summarize_diff_user_file(chat_client, default_user: KhojUser, pdf_confi
|
|||
def test_answer_requires_current_date_awareness(chat_client):
|
||||
"Chat actor should be able to answer questions relative to current date using provided notes"
|
||||
# Act
|
||||
response = chat_client.get(f'/api/chat?q="Where did I have lunch today?"&stream=true')
|
||||
response = chat_client.post(f'/api/chat?q="Where did I have lunch today?"&stream=true')
|
||||
response_message = response.content.decode("utf-8")
|
||||
|
||||
# Assert
|
||||
|
@ -502,7 +502,7 @@ def test_answer_requires_current_date_awareness(chat_client):
|
|||
def test_answer_requires_date_aware_aggregation_across_provided_notes(chat_client):
|
||||
"Chat director should be able to answer questions that require date aware aggregation across multiple notes"
|
||||
# Act
|
||||
response = chat_client.get(f'/api/chat?q="How much did I spend on dining this year?"')
|
||||
response = chat_client.post(f'/api/chat?q="How much did I spend on dining this year?"')
|
||||
response_message = response.json()["response"]
|
||||
|
||||
# Assert
|
||||
|
@ -523,7 +523,7 @@ def test_answer_general_question_not_in_chat_history_or_retrieved_content(chat_c
|
|||
create_conversation(message_list, default_user2)
|
||||
|
||||
# Act
|
||||
response = chat_client.get(f'/api/chat?q="Write a haiku about unit testing. Do not say anything else.')
|
||||
response = chat_client.post(f'/api/chat?q="Write a haiku about unit testing. Do not say anything else.')
|
||||
response_message = response.json()["response"]
|
||||
|
||||
# Assert
|
||||
|
@ -540,7 +540,7 @@ def test_answer_general_question_not_in_chat_history_or_retrieved_content(chat_c
|
|||
@pytest.mark.chatquality
|
||||
def test_ask_for_clarification_if_not_enough_context_in_question(chat_client_no_background):
|
||||
# Act
|
||||
response = chat_client_no_background.get(f'/api/chat?q="What is the name of Namitas older son?"')
|
||||
response = chat_client_no_background.post(f'/api/chat?q="What is the name of Namitas older son?"')
|
||||
response_message = response.json()["response"].lower()
|
||||
|
||||
# Assert
|
||||
|
@ -574,7 +574,7 @@ def test_answer_in_chat_history_beyond_lookback_window(chat_client, default_user
|
|||
create_conversation(message_list, default_user2)
|
||||
|
||||
# Act
|
||||
response = chat_client.get(f'/api/chat?q="What is my name?"')
|
||||
response = chat_client.post(f'/api/chat?q="What is my name?"')
|
||||
response_message = response.json()["response"]
|
||||
|
||||
# Assert
|
||||
|
@ -607,7 +607,7 @@ def test_answer_in_chat_history_by_conversation_id(chat_client, default_user2: K
|
|||
|
||||
# Act
|
||||
query = urllib.parse.quote("/general What is my favorite color?")
|
||||
response = chat_client.get(f"/api/chat?q={query}&conversation_id={conversation.id}&stream=true")
|
||||
response = chat_client.post(f"/api/chat?q={query}&conversation_id={conversation.id}&stream=true")
|
||||
response_message = response.content.decode("utf-8")
|
||||
|
||||
# Assert
|
||||
|
@ -640,7 +640,7 @@ def test_answer_in_chat_history_by_conversation_id_with_agent(
|
|||
|
||||
# Act
|
||||
query = urllib.parse.quote("/general What did I buy for breakfast?")
|
||||
response = chat_client.get(f"/api/chat?q={query}&conversation_id={conversation.id}")
|
||||
response = chat_client.post(f"/api/chat?q={query}&conversation_id={conversation.id}")
|
||||
response_message = response.json()["response"]
|
||||
|
||||
# Assert that agent only responds with the summary of spending
|
||||
|
@ -657,7 +657,7 @@ def test_answer_in_chat_history_by_conversation_id_with_agent(
|
|||
def test_answer_requires_multiple_independent_searches(chat_client):
|
||||
"Chat director should be able to answer by doing multiple independent searches for required information"
|
||||
# Act
|
||||
response = chat_client.get(f'/api/chat?q="Is Xi Li older than Namita? Just say the older persons full name"')
|
||||
response = chat_client.post(f'/api/chat?q="Is Xi Li older than Namita? Just say the older persons full name"')
|
||||
response_message = response.json()["response"].lower()
|
||||
|
||||
# Assert
|
||||
|
@ -682,7 +682,7 @@ def test_answer_using_file_filter(chat_client):
|
|||
'Is Xi Li older than Namita? Just say the older persons full name. file:"Namita.markdown" file:"Xi Li.markdown"'
|
||||
)
|
||||
|
||||
response = chat_client.get(f"/api/chat?q={query}")
|
||||
response = chat_client.post(f"/api/chat?q={query}")
|
||||
response_message = response.json()["response"].lower()
|
||||
|
||||
# Assert
|
||||
|
|
Loading…
Reference in a new issue