mirror of
https://github.com/StanGirard/quivr.git
synced 2024-11-24 05:55:13 +03:00
fix(Analytics): no tags tracking for upload & crawl (#1024)
* 🚚 create useCrawlApi to use in useCrawler hook * 🚑 fix tracking in Crawl * 🧑💻 add hot reloading within docker containers * 🚑 fix tracking for upload * 🚚 create useUploadApi for fileUpload request * 📈 add june tag for Language change * 🩹 revert dependencies
This commit is contained in:
parent
0ca25e2af5
commit
2b74ebc1f0
@ -32,7 +32,7 @@ services:
|
|||||||
context: backend
|
context: backend
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
container_name: backend-core
|
container_name: backend-core
|
||||||
command: uvicorn main:app --host 0.0.0.0 --port 5050
|
command: uvicorn main:app --reload --host 0.0.0.0 --port 5050
|
||||||
restart: always
|
restart: always
|
||||||
volumes:
|
volumes:
|
||||||
- ./backend/:/code/
|
- ./backend/:/code/
|
||||||
@ -49,7 +49,7 @@ services:
|
|||||||
context: backend
|
context: backend
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
container_name: backend-chat
|
container_name: backend-chat
|
||||||
command: uvicorn chat_service:app --host 0.0.0.0 --port 5050
|
command: uvicorn --reload chat_service:app --host 0.0.0.0 --port 5050
|
||||||
restart: always
|
restart: always
|
||||||
volumes:
|
volumes:
|
||||||
- ./backend/:/code/
|
- ./backend/:/code/
|
||||||
@ -66,7 +66,7 @@ services:
|
|||||||
context: backend
|
context: backend
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
container_name: backend-crawl
|
container_name: backend-crawl
|
||||||
command: uvicorn crawl_service:app --host 0.0.0.0 --port 5050
|
command: uvicorn --reload crawl_service:app --host 0.0.0.0 --port 5050
|
||||||
restart: always
|
restart: always
|
||||||
volumes:
|
volumes:
|
||||||
- ./backend/:/code/
|
- ./backend/:/code/
|
||||||
@ -83,7 +83,7 @@ services:
|
|||||||
context: backend
|
context: backend
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
container_name: backend-upload
|
container_name: backend-upload
|
||||||
command: uvicorn upload_service:app --host 0.0.0.0 --port 5050
|
command: uvicorn --reload upload_service:app --host 0.0.0.0 --port 5050
|
||||||
restart: always
|
restart: always
|
||||||
volumes:
|
volumes:
|
||||||
- ./backend/:/code/
|
- ./backend/:/code/
|
||||||
|
@ -1,41 +1,41 @@
|
|||||||
/* eslint-disable */
|
import { UUID } from "crypto";
|
||||||
import { useCallback, useRef, useState } from "react";
|
import { useCallback, useRef, useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
|
import { useCrawlApi } from "@/lib/api/crawl/useCrawlApi";
|
||||||
import { useSupabase } from "@/lib/context/SupabaseProvider";
|
import { useSupabase } from "@/lib/context/SupabaseProvider";
|
||||||
import { useAxios, useToast } from "@/lib/hooks";
|
import { useToast } from "@/lib/hooks";
|
||||||
|
import { redirectToLogin } from "@/lib/router/redirectToLogin";
|
||||||
import { useEventTracking } from "@/services/analytics/useEventTracking";
|
import { useEventTracking } from "@/services/analytics/useEventTracking";
|
||||||
|
|
||||||
import { redirectToLogin } from "@/lib/router/redirectToLogin";
|
|
||||||
import { UUID } from "crypto";
|
|
||||||
import { isValidUrl } from "../helpers/isValidUrl";
|
import { isValidUrl } from "../helpers/isValidUrl";
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
||||||
export const useCrawler = () => {
|
export const useCrawler = () => {
|
||||||
const [isCrawling, setCrawling] = useState(false);
|
const [isCrawling, setCrawling] = useState(false);
|
||||||
const urlInputRef = useRef<HTMLInputElement | null>(null);
|
const urlInputRef = useRef<HTMLInputElement | null>(null);
|
||||||
const { session } = useSupabase();
|
const { session } = useSupabase();
|
||||||
const { publish } = useToast();
|
const { publish } = useToast();
|
||||||
const { axiosInstance } = useAxios();
|
|
||||||
const { track } = useEventTracking();
|
const { track } = useEventTracking();
|
||||||
|
|
||||||
|
const { crawlWebsiteUrl } = useCrawlApi();
|
||||||
if (session === null) {
|
if (session === null) {
|
||||||
redirectToLogin();
|
redirectToLogin();
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
const { t } = useTranslation(["translation", "upload"]);
|
||||||
const {t, i18n} = useTranslation(["translation","upload"]);
|
|
||||||
|
|
||||||
const crawlWebsite = useCallback(
|
const crawlWebsite = useCallback(
|
||||||
async (brainId: UUID | undefined) => {
|
async (brainId: UUID | undefined) => {
|
||||||
// Validate URL
|
// Validate URL
|
||||||
const url = urlInputRef.current ? urlInputRef.current.value : null;
|
const url = urlInputRef.current ? urlInputRef.current.value : null;
|
||||||
|
|
||||||
if (!url || !isValidUrl(url)) {
|
if (url === null || !isValidUrl(url)) {
|
||||||
void track("URL_INVALID");
|
void track("URL_INVALID");
|
||||||
|
|
||||||
publish({
|
publish({
|
||||||
variant: "danger",
|
variant: "danger",
|
||||||
text: t("invalidUrl",{ns:"upload"})
|
text: t("invalidUrl", { ns: "upload" }),
|
||||||
});
|
});
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@ -51,15 +51,16 @@ export const useCrawler = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
setCrawling(true);
|
setCrawling(true);
|
||||||
|
|
||||||
void track("URL_CRAWLED");
|
void track("URL_CRAWLED");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
console.log("Crawling website...", brainId);
|
console.log("Crawling website...", brainId);
|
||||||
if (brainId !== undefined) {
|
if (brainId !== undefined) {
|
||||||
const response = await axiosInstance.post(
|
const response = await crawlWebsiteUrl({
|
||||||
`/crawl?brain_id=${brainId}`,
|
brainId,
|
||||||
config
|
config,
|
||||||
);
|
});
|
||||||
|
|
||||||
publish({
|
publish({
|
||||||
variant: response.data.type,
|
variant: response.data.type,
|
||||||
@ -69,19 +70,21 @@ export const useCrawler = () => {
|
|||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
publish({
|
publish({
|
||||||
variant: "danger",
|
variant: "danger",
|
||||||
text: t("crawlFailed",{ message: JSON.stringify(error),ns:"upload"})
|
text: t("crawlFailed", {
|
||||||
|
message: JSON.stringify(error),
|
||||||
|
ns: "upload",
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
} finally {
|
} finally {
|
||||||
setCrawling(false);
|
setCrawling(false);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[session.access_token, publish]
|
[session.access_token]
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
isCrawling,
|
isCrawling,
|
||||||
urlInputRef,
|
urlInputRef,
|
||||||
|
|
||||||
crawlWebsite,
|
crawlWebsite,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
/* eslint-disable */
|
|
||||||
"use client";
|
"use client";
|
||||||
import { Suspense } from "react";
|
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
import Button from "@/lib/components/ui/Button";
|
import Button from "@/lib/components/ui/Button";
|
||||||
@ -14,44 +12,35 @@ export const Crawler = (): JSX.Element => {
|
|||||||
const { urlInputRef, isCrawling, crawlWebsite } = useCrawler();
|
const { urlInputRef, isCrawling, crawlWebsite } = useCrawler();
|
||||||
const { currentBrain } = useBrainContext();
|
const { currentBrain } = useBrainContext();
|
||||||
|
|
||||||
const {t, i18n} = useTranslation(["translation","upload"]);
|
const { t } = useTranslation(["translation", "upload"]);
|
||||||
|
|
||||||
function Crawler() {
|
return (
|
||||||
return (
|
<div className="w-full">
|
||||||
<div className="w-full">
|
<div className="flex justify-center gap-5 px-6">
|
||||||
<div className="flex justify-center gap-5 px-6">
|
<div className="max-w-xl w-full">
|
||||||
<div className="max-w-xl w-full">
|
<div className="flex-col justify-center gap-5">
|
||||||
<div className="flex-col justify-center gap-5">
|
<Card className="h-32 flex gap-5 justify-center items-center px-5">
|
||||||
<Card className="h-32 flex gap-5 justify-center items-center px-5">
|
<div className="text-center max-w-sm w-full flex flex-col gap-5 items-center">
|
||||||
<div className="text-center max-w-sm w-full flex flex-col gap-5 items-center">
|
<Field
|
||||||
<Field
|
name="crawlurl"
|
||||||
name="crawlurl"
|
ref={urlInputRef}
|
||||||
ref={urlInputRef}
|
type="text"
|
||||||
type="text"
|
placeholder={t("webSite", { ns: "upload" })}
|
||||||
placeholder={t("webSite",{ ns: "upload"})}
|
className="w-full"
|
||||||
className="w-full"
|
/>
|
||||||
/>
|
</div>
|
||||||
</div>
|
<div className="flex flex-col items-center justify-center gap-5">
|
||||||
<div className="flex flex-col items-center justify-center gap-5">
|
<Button
|
||||||
<Button
|
isLoading={isCrawling}
|
||||||
isLoading={isCrawling}
|
onClick={() => void crawlWebsite(currentBrain?.id)}
|
||||||
onClick={() => void crawlWebsite(currentBrain?.id)}
|
>
|
||||||
>
|
{t("crawlButton")}
|
||||||
{t("crawlButton")}
|
</Button>
|
||||||
</Button>
|
</div>
|
||||||
</div>
|
</Card>
|
||||||
</Card>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
</div>
|
||||||
}
|
);
|
||||||
|
|
||||||
return (
|
|
||||||
<Suspense fallback = {"Loading..."}>
|
|
||||||
<Crawler />
|
|
||||||
</Suspense>
|
|
||||||
)
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -1,32 +1,32 @@
|
|||||||
/* eslint-disable */
|
/* eslint-disable max-lines */
|
||||||
import { useCallback, useState } from "react";
|
|
||||||
import { FileRejection, useDropzone } from "react-dropzone";
|
|
||||||
|
|
||||||
import { useBrainContext } from "@/lib/context/BrainProvider/hooks/useBrainContext";
|
|
||||||
import { useSupabase } from "@/lib/context/SupabaseProvider";
|
|
||||||
import { useAxios, useToast } from "@/lib/hooks";
|
|
||||||
import { redirectToLogin } from "@/lib/router/redirectToLogin";
|
|
||||||
import { useEventTracking } from "@/services/analytics/useEventTracking";
|
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { UUID } from "crypto";
|
import { UUID } from "crypto";
|
||||||
|
import { useCallback, useState } from "react";
|
||||||
|
import { FileRejection, useDropzone } from "react-dropzone";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
|
import { useUploadApi } from "@/lib/api/upload/useUploadApi";
|
||||||
|
import { useBrainContext } from "@/lib/context/BrainProvider/hooks/useBrainContext";
|
||||||
|
import { useSupabase } from "@/lib/context/SupabaseProvider";
|
||||||
|
import { useToast } from "@/lib/hooks";
|
||||||
|
import { redirectToLogin } from "@/lib/router/redirectToLogin";
|
||||||
|
import { useEventTracking } from "@/services/analytics/useEventTracking";
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
||||||
export const useFileUploader = () => {
|
export const useFileUploader = () => {
|
||||||
const { track } = useEventTracking();
|
const { track } = useEventTracking();
|
||||||
const [isPending, setIsPending] = useState(false);
|
const [isPending, setIsPending] = useState(false);
|
||||||
const { publish } = useToast();
|
const { publish } = useToast();
|
||||||
const [files, setFiles] = useState<File[]>([]);
|
const [files, setFiles] = useState<File[]>([]);
|
||||||
const { session } = useSupabase();
|
const { session } = useSupabase();
|
||||||
|
const { uploadFile } = useUploadApi();
|
||||||
const { currentBrain } = useBrainContext();
|
const { currentBrain } = useBrainContext();
|
||||||
const { axiosInstance } = useAxios();
|
|
||||||
|
|
||||||
if (session === null) {
|
if (session === null) {
|
||||||
redirectToLogin();
|
redirectToLogin();
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
const { t } = useTranslation(["upload"]);
|
||||||
const {t, i18n} = useTranslation(["upload"]);
|
|
||||||
|
|
||||||
const upload = useCallback(
|
const upload = useCallback(
|
||||||
async (file: File, brainId: UUID) => {
|
async (file: File, brainId: UUID) => {
|
||||||
@ -34,18 +34,13 @@ export const useFileUploader = () => {
|
|||||||
formData.append("uploadFile", file);
|
formData.append("uploadFile", file);
|
||||||
try {
|
try {
|
||||||
void track("FILE_UPLOADED");
|
void track("FILE_UPLOADED");
|
||||||
const response = await axiosInstance.post(
|
const response = await uploadFile({ brainId, formData });
|
||||||
`/upload?brain_id=${brainId}`,
|
|
||||||
formData
|
|
||||||
);
|
|
||||||
track("FILE_UPLOADED");
|
|
||||||
publish({
|
publish({
|
||||||
variant: response.data.type,
|
variant: response.data.type,
|
||||||
text:
|
text:
|
||||||
(response.data.type === "success"
|
response.data.type === "success"
|
||||||
? t("success",{ ns: "upload" })
|
? t("success", { ns: "upload" })
|
||||||
: t("error",{ message: response.data.message, ns: "upload" })
|
: t("error", { message: response.data.message, ns: "upload" }),
|
||||||
)
|
|
||||||
});
|
});
|
||||||
} catch (e: unknown) {
|
} catch (e: unknown) {
|
||||||
if (axios.isAxiosError(e) && e.response?.status === 403) {
|
if (axios.isAxiosError(e) && e.response?.status === 403) {
|
||||||
@ -62,17 +57,17 @@ export const useFileUploader = () => {
|
|||||||
} else {
|
} else {
|
||||||
publish({
|
publish({
|
||||||
variant: "danger",
|
variant: "danger",
|
||||||
text: t("error",{ message: e, ns: "upload" })
|
text: t("error", { message: e, ns: "upload" }),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[session.access_token, publish]
|
[session.access_token]
|
||||||
);
|
);
|
||||||
|
|
||||||
const onDrop = (acceptedFiles: File[], fileRejections: FileRejection[]) => {
|
const onDrop = (acceptedFiles: File[], fileRejections: FileRejection[]) => {
|
||||||
if (fileRejections.length > 0) {
|
if (fileRejections.length > 0) {
|
||||||
publish({ variant: "danger", text: t("maxSizeError",{ ns: "upload" }) });
|
publish({ variant: "danger", text: t("maxSizeError", { ns: "upload" }) });
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -85,11 +80,12 @@ export const useFileUploader = () => {
|
|||||||
if (isAlreadyInFiles) {
|
if (isAlreadyInFiles) {
|
||||||
publish({
|
publish({
|
||||||
variant: "warning",
|
variant: "warning",
|
||||||
text: t("alreadyAdded",{ fileName: file.name, ns: "upload" }),
|
text: t("alreadyAdded", { fileName: file.name, ns: "upload" }),
|
||||||
});
|
});
|
||||||
acceptedFiles.splice(i, 1);
|
acceptedFiles.splice(i, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-shadow
|
||||||
setFiles((files) => [...files, ...acceptedFiles]);
|
setFiles((files) => [...files, ...acceptedFiles]);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -104,7 +100,7 @@ export const useFileUploader = () => {
|
|||||||
}
|
}
|
||||||
setIsPending(true);
|
setIsPending(true);
|
||||||
if (currentBrain?.id !== undefined) {
|
if (currentBrain?.id !== undefined) {
|
||||||
await Promise.all(files.map((file) => upload(file, currentBrain?.id)));
|
await Promise.all(files.map((file) => upload(file, currentBrain.id)));
|
||||||
setFiles([]);
|
setFiles([]);
|
||||||
} else {
|
} else {
|
||||||
publish({
|
publish({
|
||||||
@ -128,7 +124,6 @@ export const useFileUploader = () => {
|
|||||||
isDragActive,
|
isDragActive,
|
||||||
open,
|
open,
|
||||||
uploadAllFiles,
|
uploadAllFiles,
|
||||||
|
|
||||||
files,
|
files,
|
||||||
setFiles,
|
setFiles,
|
||||||
};
|
};
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
/* eslint-disable */
|
|
||||||
"use client";
|
"use client";
|
||||||
import { AnimatePresence } from "framer-motion";
|
import { AnimatePresence } from "framer-motion";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
@ -21,8 +20,7 @@ export const FileUploader = (): JSX.Element => {
|
|||||||
setFiles,
|
setFiles,
|
||||||
} = useFileUploader();
|
} = useFileUploader();
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
const { t } = useTranslation(["translation", "upload"]);
|
||||||
const {t, i18n} = useTranslation(["translation","upload"]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section
|
<section
|
||||||
@ -35,13 +33,13 @@ export const FileUploader = (): JSX.Element => {
|
|||||||
<input {...getInputProps()} />
|
<input {...getInputProps()} />
|
||||||
<div className="text-center p-6 max-w-sm w-full flex flex-col gap-5 items-center">
|
<div className="text-center p-6 max-w-sm w-full flex flex-col gap-5 items-center">
|
||||||
{isDragActive ? (
|
{isDragActive ? (
|
||||||
<p className="text-blue-600">{t("drop",{"ns":"upload"})}</p>
|
<p className="text-blue-600">{t("drop", { ns: "upload" })}</p>
|
||||||
) : (
|
) : (
|
||||||
<button
|
<button
|
||||||
onClick={open}
|
onClick={open}
|
||||||
className="opacity-50 h-full cursor-pointer hover:opacity-100 hover:underline transition-opacity"
|
className="opacity-50 h-full cursor-pointer hover:opacity-100 hover:underline transition-opacity"
|
||||||
>
|
>
|
||||||
{t("dragAndDrop",{"ns":"upload"})}
|
{t("dragAndDrop", { ns: "upload" })}
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@ -73,6 +71,4 @@ export const FileUploader = (): JSX.Element => {
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -57,8 +57,8 @@ const UploadPage = (): JSX.Element => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const Upload = () => {
|
return (
|
||||||
return (
|
<Suspense fallback="Loading...">
|
||||||
<main className="pt-10">
|
<main className="pt-10">
|
||||||
<PageHeading
|
<PageHeading
|
||||||
title={t("title", { ns: "upload" })}
|
title={t("title", { ns: "upload" })}
|
||||||
@ -75,12 +75,6 @@ const UploadPage = (): JSX.Element => {
|
|||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Suspense fallback="Loading...">
|
|
||||||
<Upload />
|
|
||||||
</Suspense>
|
</Suspense>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
43
frontend/lib/api/crawl/__tests__/useCrawlApi.test.ts
Normal file
43
frontend/lib/api/crawl/__tests__/useCrawlApi.test.ts
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
import { renderHook } from "@testing-library/react";
|
||||||
|
import { describe, expect, it, vi } from "vitest";
|
||||||
|
|
||||||
|
import { CrawlInputProps } from "../crawl";
|
||||||
|
import { useCrawlApi } from "../useCrawlApi";
|
||||||
|
|
||||||
|
const axiosPostMock = vi.fn(() => ({}));
|
||||||
|
|
||||||
|
vi.mock("@/lib/hooks", () => ({
|
||||||
|
useAxios: () => ({
|
||||||
|
axiosInstance: {
|
||||||
|
post: axiosPostMock,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe("useCrawlApi", () => {
|
||||||
|
// TODO: Create a test user within preview and prod databases to interact with
|
||||||
|
it("should call updateUserIdentity with the correct parameters", async () => {
|
||||||
|
const {
|
||||||
|
result: {
|
||||||
|
current: { crawlWebsiteUrl },
|
||||||
|
},
|
||||||
|
} = renderHook(() => useCrawlApi());
|
||||||
|
const crawlInputProps: CrawlInputProps = {
|
||||||
|
brainId: "e7001ccd-6d90-4eab-8c50-2f23d39441e4",
|
||||||
|
config: {
|
||||||
|
url: "https://en.wikipedia.org/wiki/Mali",
|
||||||
|
js: false,
|
||||||
|
depth: 1,
|
||||||
|
max_pages: 100,
|
||||||
|
max_time: 60,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
await crawlWebsiteUrl(crawlInputProps);
|
||||||
|
|
||||||
|
expect(axiosPostMock).toHaveBeenCalledTimes(1);
|
||||||
|
expect(axiosPostMock).toHaveBeenCalledWith(
|
||||||
|
`/crawl?brain_id=${crawlInputProps.brainId}`,
|
||||||
|
crawlInputProps.config
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
25
frontend/lib/api/crawl/crawl.ts
Normal file
25
frontend/lib/api/crawl/crawl.ts
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import { AxiosInstance } from "axios";
|
||||||
|
import { UUID } from "crypto";
|
||||||
|
|
||||||
|
import { ToastData } from "@/lib/components/ui/Toast/domain/types";
|
||||||
|
|
||||||
|
export type CrawlInputProps = {
|
||||||
|
brainId: UUID;
|
||||||
|
config: {
|
||||||
|
url: string;
|
||||||
|
js: boolean;
|
||||||
|
depth: number;
|
||||||
|
max_pages: number;
|
||||||
|
max_time: number;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export type CrawlResponse = {
|
||||||
|
data: { type: ToastData["variant"]; message: ToastData["text"] };
|
||||||
|
};
|
||||||
|
|
||||||
|
export const crawlWebsiteUrl = async (
|
||||||
|
props: CrawlInputProps,
|
||||||
|
axiosInstance: AxiosInstance
|
||||||
|
): Promise<CrawlResponse> =>
|
||||||
|
axiosInstance.post(`/crawl?brain_id=${props.brainId}`, props.config);
|
13
frontend/lib/api/crawl/useCrawlApi.ts
Normal file
13
frontend/lib/api/crawl/useCrawlApi.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { useAxios } from "@/lib/hooks";
|
||||||
|
|
||||||
|
import { CrawlInputProps, crawlWebsiteUrl } from "./crawl";
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
||||||
|
export const useCrawlApi = () => {
|
||||||
|
const { axiosInstance } = useAxios();
|
||||||
|
|
||||||
|
return {
|
||||||
|
crawlWebsiteUrl: async (props: CrawlInputProps) =>
|
||||||
|
crawlWebsiteUrl(props, axiosInstance),
|
||||||
|
};
|
||||||
|
};
|
19
frontend/lib/api/upload/upload.ts
Normal file
19
frontend/lib/api/upload/upload.ts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import { AxiosInstance } from "axios";
|
||||||
|
import { UUID } from "crypto";
|
||||||
|
|
||||||
|
import { ToastData } from "@/lib/components/ui/Toast/domain/types";
|
||||||
|
|
||||||
|
export type UploadResponse = {
|
||||||
|
data: { type: ToastData["variant"]; message: ToastData["text"] };
|
||||||
|
};
|
||||||
|
|
||||||
|
export type UploadInputProps = {
|
||||||
|
brainId: UUID;
|
||||||
|
formData: FormData;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const uploadFile = async (
|
||||||
|
props: UploadInputProps,
|
||||||
|
axiosInstance: AxiosInstance
|
||||||
|
): Promise<UploadResponse> =>
|
||||||
|
axiosInstance.post(`/upload?brain_id=${props.brainId}`, props.formData);
|
13
frontend/lib/api/upload/useUploadApi.ts
Normal file
13
frontend/lib/api/upload/useUploadApi.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { useAxios } from "@/lib/hooks";
|
||||||
|
|
||||||
|
import { uploadFile, UploadInputProps } from "./upload";
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
||||||
|
export const useUploadApi = () => {
|
||||||
|
const { axiosInstance } = useAxios();
|
||||||
|
|
||||||
|
return {
|
||||||
|
uploadFile: async (props: UploadInputProps) =>
|
||||||
|
uploadFile(props, axiosInstance),
|
||||||
|
};
|
||||||
|
};
|
@ -1,6 +1,8 @@
|
|||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
|
import { useEventTracking } from "@/services/analytics/useEventTracking";
|
||||||
|
|
||||||
export type Language = {
|
export type Language = {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
@ -14,6 +16,8 @@ export const useLanguageHook = (): {
|
|||||||
const { i18n } = useTranslation();
|
const { i18n } = useTranslation();
|
||||||
const [allLanguages, setAllLanguages] = useState<Language[]>([]);
|
const [allLanguages, setAllLanguages] = useState<Language[]>([]);
|
||||||
const [currentLanguage, setCurrentLanguage] = useState<Language | null>(null);
|
const [currentLanguage, setCurrentLanguage] = useState<Language | null>(null);
|
||||||
|
const { track } = useEventTracking();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const languages = [
|
const languages = [
|
||||||
{
|
{
|
||||||
@ -63,6 +67,7 @@ export const useLanguageHook = (): {
|
|||||||
}, [i18n]);
|
}, [i18n]);
|
||||||
|
|
||||||
const change = (newLanguage: Language) => {
|
const change = (newLanguage: Language) => {
|
||||||
|
void track("CHANGE_LANGUAGE");
|
||||||
setCurrentLanguage(newLanguage);
|
setCurrentLanguage(newLanguage);
|
||||||
localStorage.setItem("selectedLanguage", newLanguage.id);
|
localStorage.setItem("selectedLanguage", newLanguage.id);
|
||||||
void i18n.changeLanguage(newLanguage.id);
|
void i18n.changeLanguage(newLanguage.id);
|
||||||
|
Loading…
Reference in New Issue
Block a user