Skip to content
This repository has been archived by the owner on Feb 15, 2025. It is now read-only.

Commit

Permalink
merge with main
Browse files Browse the repository at this point in the history
  • Loading branch information
justinthelaw committed Aug 16, 2024
2 parents 71ae444 + 6e3e5b8 commit e066ac3
Show file tree
Hide file tree
Showing 35 changed files with 907 additions and 90 deletions.
1 change: 0 additions & 1 deletion src/leapfrogai_api/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ dependencies = [
"unstructured[md,xlsx,pptx] >= 0.15.3", # Only specify necessary filetypes to prevent package bloat (e.g. 130MB vs 6GB)
"pylibmagic >= 0.5.0", # Resolves issue with libmagic not being bundled with OS - https://github.com/ahupp/python-magic/issues/233, may not be needed after this is merged https://github.com/ahupp/python-magic/pull/294
"python-magic >= 0.4.27",
"nltk >= 3.8.2", # This version is explicitly set to prevent accidentally importing a version of nltk with a serious vulnerability (https://github.com/nltk/nltk/issues/3266)
"storage3>=0.7.6", # required by supabase, bug when using previous versions
"postgrest>=0.16.8", # required by supabase, bug when using previous versions
"openpyxl >= 3.1.5",
Expand Down
11 changes: 11 additions & 0 deletions src/leapfrogai_ui/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,15 @@
FROM node:18-alpine AS builder
RUN apk update && apk upgrade && apk add --no-cache libreoffice openjdk11-jre

# Add fonts for converting docs to pdfs
RUN apk add --no-cache \
fontconfig \
msttcorefonts-installer \
&& update-ms-fonts \
&& fc-cache -f

ENV JAVA_HOME=/usr/lib/jvm/java-11-openjdk
ENV PATH=${JAVA_HOME}/bin:$PATH

WORKDIR /app

Expand Down
26 changes: 26 additions & 0 deletions src/leapfrogai_ui/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions src/leapfrogai_ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@
"fuse.js": "^7.0.0",
"highlight.js": "^11.10.0",
"isomorphic-dompurify": "^2.13.0",
"libreoffice-convert": "^1.6.0",
"lit": "^3.1.4",
"markdown-it": "^14.1.0",
"openai": "^4.52.7",
Expand Down
1 change: 1 addition & 0 deletions src/leapfrogai_ui/src/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
display: flex;
flex-grow: 1;
flex-direction: column;
max-width: calc(100% - 255px);
overflow: auto;
padding-top: 2rem;
height: calc(100vh - var(--header-height));
Expand Down
1 change: 1 addition & 0 deletions src/leapfrogai_ui/src/app.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ declare global {
safeGetSession: () => Promise<{ session: Session | null; user: User | null }>;
session: Session | null;
user: User | null;
isUsingOpenAI: boolean;
}
interface PageData {
session: Session | null;
Expand Down
2 changes: 2 additions & 0 deletions src/leapfrogai_ui/src/hooks.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { createServerClient } from '@supabase/ssr';
import { type Handle, redirect } from '@sveltejs/kit';
import { sequence } from '@sveltejs/kit/hooks';
import { env } from '$env/dynamic/public';
import { env as envPrivate } from '$env/dynamic/private';

const supabase: Handle = async ({ event, resolve }) => {
/**
Expand Down Expand Up @@ -69,6 +70,7 @@ const authGuard: Handle = async ({ event, resolve }) => {
const { session, user } = await event.locals.safeGetSession();
event.locals.session = session;
event.locals.user = user;
event.locals.isUsingOpenAI = !!envPrivate.OPENAI_API_KEY;

// protect all routes under /chat
if (!event.locals.session && event.url.pathname.startsWith('/chat')) {
Expand Down
140 changes: 140 additions & 0 deletions src/leapfrogai_ui/src/lib/components/Citatation.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
import { getFakeFiles } from '$testUtils/fakeData';
import {
mockConvertFile,
mockConvertFileError,
mockGetFile,
mockGetFileError
} from '$lib/mocks/file-mocks';
import Citation from '$components/Citation.svelte';
import { render, screen } from '@testing-library/svelte';
import { afterAll, beforeEach, vi } from 'vitest';
import userEvent from '@testing-library/user-event';
import { toastStore, uiStore } from '$stores';
import {
CONVERT_FILE_ERROR_MSG_TOAST,
FILE_DOWNLOAD_ERROR_MSG_TOAST,
OPENAI_DOWNLOAD_DISABLED_MSG_TOAST
} from '$constants/toastMessages';

vi.mock('$app/environment', () => ({
browser: true
}));

vi.stubGlobal('window', {
...window,
open: vi.fn(),
URL: {
...window.URL,
createObjectURL: vi.fn(() => 'blob:http://localhost/file'),
revokeObjectURL: vi.fn()
},
navigator: {
clipboard: {
writeText: vi.fn()
}
}
});

describe('Citation', () => {
const toastSpy = vi.spyOn(toastStore, 'addToast');

beforeEach(() => {
uiStore.set({
openSidebar: true,
isUsingOpenAI: false
});
});

afterAll(() => {
vi.restoreAllMocks();
vi.unstubAllGlobals();
});

it('renders an iframe when a pdf is clicked', async () => {
const file = getFakeFiles({ numFiles: 1 })[0];
mockGetFile(file.id, 'test');

render(Citation, { file, index: 1 });

await userEvent.click(screen.getByTestId(`${file.id}-citation-btn`));
await screen.findByTitle(`${file.id}-iframe`);
});

it('renders an iframe when a non-pdf file type is clicked (converted to pdf)', async () => {
const file = getFakeFiles({ numFiles: 1 })[0];
mockGetFile(file.id, 'test', 'text/plain');
mockConvertFile('fake content');

render(Citation, { file, index: 1 });

await userEvent.click(screen.getByTestId(`${file.id}-citation-btn`));
await screen.findByTitle(`${file.id}-iframe`);
});

it('shows a toast and does not render an iframe when OpenAI is being used', async () => {
const file = getFakeFiles({ numFiles: 1 })[0];
mockGetFile(file.id, 'test');
uiStore.set({
openSidebar: true,
isUsingOpenAI: true
});
render(Citation, { file, index: 1 });

await userEvent.click(screen.getByTestId(`${file.id}-citation-btn`));
expect(screen.queryByTitle(`${file.id}-iframe`)).not.toBeInTheDocument();
expect(toastSpy).toHaveBeenCalledWith({
...OPENAI_DOWNLOAD_DISABLED_MSG_TOAST
});
});
it('displays a toast when an error occurs after clicking a citation', async () => {
const file = getFakeFiles({ numFiles: 1 })[0];
mockGetFileError(file.id);

render(Citation, { file, index: 1 });
await userEvent.click(screen.getByTestId(`${file.id}-citation-btn`));

expect(toastSpy).toHaveBeenCalledWith({
...FILE_DOWNLOAD_ERROR_MSG_TOAST
});
});

it('displays a toast when an error occurs when converting a file to pdf', async () => {
const file = getFakeFiles({ numFiles: 1 })[0];
mockGetFile(file.id, 'test', 'text/plain');
mockConvertFileError();

render(Citation, { file, index: 1 });
await userEvent.click(screen.getByTestId(`${file.id}-citation-btn`));

expect(toastSpy).toHaveBeenCalledWith({
...FILE_DOWNLOAD_ERROR_MSG_TOAST
});
});
it('displays a toast when the file type is not supported for download', async () => {
const file = getFakeFiles({ numFiles: 1 })[0];
mockGetFile(file.id, 'test', 'fakeFileType');

render(Citation, { file, index: 1 });
await userEvent.click(screen.getByTestId(`${file.id}-citation-btn`));

expect(toastSpy).toHaveBeenCalledWith({
...CONVERT_FILE_ERROR_MSG_TOAST
});
});
it('open a new tab when the open in new tab button is clicked', async () => {
const windowOpenSpy = vi.spyOn(window, 'open');
const file = getFakeFiles({ numFiles: 1 })[0];

mockGetFile(file.id, 'test');

render(Citation, { file, index: 1 });

await userEvent.click(screen.getByTestId(`${file.id}-citation-btn`));
await screen.findByTitle(`${file.id}-iframe`);
await userEvent.click(screen.getByTestId(`file-${file.id}-open-new-tab-btn`));
expect(windowOpenSpy).toHaveBeenCalledTimes(1);
expect(windowOpenSpy).toHaveBeenCalledWith('blob:http://localhost/file', '_blank');
});

// Note - downloading of file tested via E2E
});
Loading

0 comments on commit e066ac3

Please sign in to comment.