{
- navigator.clipboard.writeText(props.chatMessage.message);
+ navigator.clipboard.writeText(textRendered);
setCopySuccess(true);
}}
>
diff --git a/src/interface/web/app/factchecker/page.tsx b/src/interface/web/app/factchecker/page.tsx
index 1bc7a54f..d44f3259 100644
--- a/src/interface/web/app/factchecker/page.tsx
+++ b/src/interface/web/app/factchecker/page.tsx
@@ -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();
diff --git a/src/interface/web/app/layout.tsx b/src/interface/web/app/layout.tsx
index 007298c3..b7e6c0be 100644
--- a/src/interface/web/app/layout.tsx
+++ b/src/interface/web/app/layout.tsx
@@ -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';"
diff --git a/src/interface/web/app/page.tsx b/src/interface/web/app/page.tsx
index 05c3dd40..c5cf7012 100644
--- a/src/interface/web/app/page.tsx
+++ b/src/interface/web/app/page.tsx
@@ -43,6 +43,7 @@ function FisherYatesShuffle(array: any[]) {
function ChatBodyData(props: ChatBodyDataProps) {
const [message, setMessage] = useState("");
+ const [image, setImage] = useState
(null);
const [processingMessage, setProcessingMessage] = useState(false);
const [greeting, setGreeting] = useState("");
const [shuffledOptions, setShuffledOptions] = useState([]);
@@ -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) {
setMessage(message)}
+ sendImage={(image) => setImage(image)}
sendDisabled={processingMessage}
chatOptionsData={props.chatOptionsData}
conversationId={null}
@@ -310,6 +315,7 @@ function ChatBodyData(props: ChatBodyDataProps) {
setMessage(message)}
+ sendImage={(image) => setImage(image)}
sendDisabled={processingMessage}
chatOptionsData={props.chatOptionsData}
conversationId={null}
diff --git a/src/interface/web/app/share/chat/layout.tsx b/src/interface/web/app/share/chat/layout.tsx
index 8c243190..095a12a2 100644
--- a/src/interface/web/app/share/chat/layout.tsx
+++ b/src/interface/web/app/share/chat/layout.tsx
@@ -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';"
diff --git a/src/interface/web/app/share/chat/page.tsx b/src/interface/web/app/share/chat/page.tsx
index b07a6df2..eefc159c 100644
--- a/src/interface/web/app/share/chat/page.tsx
+++ b/src/interface/web/app/share/chat/page.tsx
@@ -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(null);
const [processingMessage, setProcessingMessage] = useState(false);
const [agentMetadata, setAgentMetadata] = useState(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) {
/>
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([]);
const [paramSlug, setParamSlug] = useState(undefined);
+ const [image64, setImage64] = useState("");
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 ;
}
@@ -275,6 +274,7 @@ export default function SharedChat() {
setTitle={setTitle}
setUploadedFiles={setUploadedFiles}
isMobileWidth={isMobileWidth}
+ setImage64={setImage64}
/>
diff --git a/src/interface/web/app/share/chat/sharedChat.module.css b/src/interface/web/app/share/chat/sharedChat.module.css
index 6adf821c..703b0fb1 100644
--- a/src/interface/web/app/share/chat/sharedChat.module.css
+++ b/src/interface/web/app/share/chat/sharedChat.module.css
@@ -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;
}
-
}
diff --git a/src/interface/web/package.json b/src/interface/web/package.json
index 4d79e700..e942aebd 100644
--- a/src/interface/web/package.json
+++ b/src/interface/web/package.json
@@ -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",
diff --git a/src/interface/web/yarn.lock b/src/interface/web/yarn.lock
index e697f948..e6fc7f36 100644
--- a/src/interface/web/yarn.lock
+++ b/src/interface/web/yarn.lock
@@ -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"
diff --git a/src/khoj/database/adapters/__init__.py b/src/khoj/database/adapters/__init__.py
index f21f8aef..df693a70 100644
--- a/src/khoj/database/adapters/__init__.py
+++ b/src/khoj/database/adapters/__init__.py
@@ -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()
diff --git a/src/khoj/database/migrations/0056_chatmodeloptions_vision_enabled.py b/src/khoj/database/migrations/0056_chatmodeloptions_vision_enabled.py
new file mode 100644
index 00000000..dc914169
--- /dev/null
+++ b/src/khoj/database/migrations/0056_chatmodeloptions_vision_enabled.py
@@ -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),
+ ),
+ ]
diff --git a/src/khoj/database/migrations/0057_merge_20240816_1409.py b/src/khoj/database/migrations/0057_merge_20240816_1409.py
new file mode 100644
index 00000000..91c981da
--- /dev/null
+++ b/src/khoj/database/migrations/0057_merge_20240816_1409.py
@@ -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] = []
diff --git a/src/khoj/database/migrations/0060_merge_20240905_1828.py b/src/khoj/database/migrations/0060_merge_20240905_1828.py
new file mode 100644
index 00000000..00ce0dd7
--- /dev/null
+++ b/src/khoj/database/migrations/0060_merge_20240905_1828.py
@@ -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] = []
diff --git a/src/khoj/database/models/__init__.py b/src/khoj/database/models/__init__.py
index 99e5191a..5b995194 100644
--- a/src/khoj/database/models/__init__.py
+++ b/src/khoj/database/models/__init__.py
@@ -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
)
diff --git a/src/khoj/processor/conversation/openai/gpt.py b/src/khoj/processor/conversation/openai/gpt.py
index d6e2a281..f2e87884 100644
--- a/src/khoj/processor/conversation/openai/gpt.py
+++ b/src/khoj/processor/conversation/openai/gpt.py
@@ -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}")
diff --git a/src/khoj/processor/conversation/utils.py b/src/khoj/processor/conversation/utils.py
index 976e0d0e..8b4e34e6 100644
--- a/src/khoj/processor/conversation/utils.py
+++ b/src/khoj/processor/conversation/utils.py
@@ -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"))
diff --git a/src/khoj/processor/tools/online_search.py b/src/khoj/processor/tools/online_search.py
index 8678e2bb..e0f97cd0 100644
--- a/src/khoj/processor/tools/online_search.py
+++ b/src/khoj/processor/tools/online_search.py
@@ -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:
diff --git a/src/khoj/routers/api_chat.py b/src/khoj/routers/api_chat.py
index 7fb48347..38cf5d3d 100644
--- a/src/khoj/routers/api_chat.py
+++ b/src/khoj/routers/api_chat.py
@@ -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)
diff --git a/src/khoj/routers/helpers.py b/src/khoj/routers/helpers.py
index 638dbb0e..da688ddb 100644
--- a/src/khoj/routers/helpers.py
+++ b/src/khoj/routers/helpers.py
@@ -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.')
diff --git a/src/khoj/routers/storage.py b/src/khoj/routers/storage.py
index 8d7b08e5..e0b9b91a 100644
--- a/src/khoj/routers/storage.py
+++ b/src/khoj/routers/storage.py
@@ -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
diff --git a/src/khoj/utils/helpers.py b/src/khoj/utils/helpers.py
index 9775e7ce..1ebb1fdd 100644
--- a/src/khoj/utils/helpers.py
+++ b/src/khoj/utils/helpers.py
@@ -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
diff --git a/tests/test_client.py b/tests/test_client.py
index 0f09a0c5..d5bc2ba1 100644
--- a/tests/test_client.py
+++ b/tests/test_client.py
@@ -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
diff --git a/tests/test_offline_chat_director.py b/tests/test_offline_chat_director.py
index c0532c4b..82f53b69 100644
--- a/tests/test_offline_chat_director.py
+++ b/tests/test_offline_chat_director.py
@@ -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
diff --git a/tests/test_openai_chat_director.py b/tests/test_openai_chat_director.py
index f0998f5d..371ff5a4 100644
--- a/tests/test_openai_chat_director.py
+++ b/tests/test_openai_chat_director.py
@@ -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