Skip to content

Commit 1bf40a4

Browse files
committed
Upload preview page + augment notes button
1 parent 2171ae2 commit 1bf40a4

File tree

10 files changed

+291
-68
lines changed

10 files changed

+291
-68
lines changed

app/api/document/[datasetId]/[documentId]/route.ts

Lines changed: 0 additions & 40 deletions
This file was deleted.

app/chatrooms/[chatroomId]/components/message-area.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ const MessageArea = ({
198198
const askResult = await askLLM(classroomInfo, chatroomId, chatClient);
199199
if (!askResult.clientCreationSuccess) {
200200
if (!askResult.failedBecauseEmptyDataset) {
201-
// TODO: ask result has more detailed error differntiations if we want to tell the user
201+
// TODO: ask result has more detailed error differentiations if we want to tell the user
202202
toast.error("Error sending communicating with LLM", {
203203
description: "Please refresh and try again",
204204
});
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
"use client";
2+
import { useState, useRef } from "react";
3+
4+
import { Button } from "@shared/components/ui/button";
5+
import { Input } from "@shared/components/ui/input";
6+
7+
import { FileText, Upload } from "lucide-react";
8+
import { toast } from "sonner";
9+
10+
export default function AugmentComponent({
11+
// TODO: remove for classroomId and setIsProcessing once we actually implement augments
12+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
13+
classroomId,
14+
}: {
15+
classroomId: string;
16+
}) {
17+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
18+
const [isProcessing, setIsProcessing] = useState(false);
19+
const [file, setFile] = useState<File | null>(null);
20+
const inputFile = useRef<HTMLInputElement>(null);
21+
22+
const handleFileChange = (event: React.ChangeEvent<HTMLInputElement>) => {
23+
const selectedFile = event.target.files?.[0];
24+
if (!selectedFile) return;
25+
26+
// Double-check that file passed by user is markdown or pdf
27+
const fileExtension = selectedFile.name.split(".").at(-1)?.toLowerCase();
28+
if (fileExtension !== "pdf" && fileExtension !== "md") {
29+
toast.error("Invalid file format", {
30+
description: "Please upload a Markdown (.md) or PDF (.pdf) file",
31+
});
32+
return;
33+
}
34+
35+
setFile(selectedFile);
36+
};
37+
38+
const handleUpload = async () => {
39+
// TODO
40+
};
41+
42+
return (
43+
<div className="flex flex-col items-center justify-center gap-4 p-8">
44+
<h1 className="text-3xl font-bold">Augment Notes</h1>
45+
<p className="text-muted-foreground">
46+
Upload your notes to get AI-powered enhancements and improvements
47+
</p>
48+
<div className="flex items-center gap-2">
49+
<Input
50+
type="file"
51+
onChange={handleFileChange}
52+
ref={inputFile}
53+
className="hidden"
54+
accept=".md,.pdf"
55+
/>
56+
<Button
57+
variant="outline"
58+
size="lg"
59+
className="cursor-pointer"
60+
disabled={isProcessing}
61+
onClick={() => inputFile.current?.click()}
62+
>
63+
{isProcessing ? (
64+
<Upload className="mr-2 h-4 w-4 animate-spin" />
65+
) : (
66+
<FileText className="mr-2 h-4 w-4" />
67+
)}
68+
Upload Notes
69+
</Button>
70+
{file && (
71+
<Button
72+
variant="default"
73+
size="lg"
74+
onClick={handleUpload}
75+
disabled={isProcessing}
76+
>
77+
Process Notes
78+
</Button>
79+
)}
80+
</div>
81+
</div>
82+
);
83+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { createClient } from "@shared/utils/supabase/server";
2+
import { notFound } from "next/navigation";
3+
4+
import AugmentComponent from "./AugmentNotes";
5+
6+
export default async function UploadPage({
7+
params,
8+
}: {
9+
params: Promise<{ classroomId: string }>;
10+
}) {
11+
const { classroomId } = await params;
12+
13+
const supabase = await createClient();
14+
const { data, error } = await supabase
15+
.from("Classrooms")
16+
.select("name")
17+
.eq("id", Number(classroomId))
18+
.single();
19+
20+
if (error || !data || !data.name) {
21+
console.error("Error fetching classroom or its name:", error);
22+
notFound();
23+
}
24+
25+
return (
26+
<>
27+
<h1>Classroom: {data.name}</h1>
28+
<AugmentComponent classroomId={classroomId} />
29+
</>
30+
);
31+
}

app/classrooms/[classroomId]/manage/_components/inviteMember.tsx

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,7 @@ export default function InviteMember({ classroomId }: { classroomId: number }) {
1515
} catch (error: unknown) {
1616
//type unknown for typescript lint
1717
if (error instanceof Error) {
18-
toast.error(
19-
"The user is already part of the classroom."
20-
// description: { email } + "was added to the class.",
21-
);
18+
toast.error("The user is already part of the classroom.");
2219
// console.error(error.message);
2320
} else {
2421
console.error("Error Occured");

app/classrooms/[classroomId]/upload/page.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1-
import { isUserAdminForClassroom } from "./actions";
2-
import UploadComponent from "./uploadComponent";
1+
import { notFound } from "next/navigation";
32
import { createClient } from "@shared/utils/supabase/server";
43

4+
import UploadComponent from "./uploadComponent";
5+
import { isUserAdminForClassroom } from "./actions";
6+
57
export default async function UploadPage({
68
params,
79
}: {
@@ -10,9 +12,7 @@ export default async function UploadPage({
1012
const { classroomId } = await params;
1113
const isAdmin = await isUserAdminForClassroom(Number(classroomId));
1214
if (!isAdmin) {
13-
return (
14-
<h1> Not the admin for this classroom! But change this to 404 page </h1>
15-
);
15+
notFound();
1616
}
1717

1818
// #TODO: move this out to general supabase place
@@ -25,7 +25,7 @@ export default async function UploadPage({
2525

2626
if (error || !data || !data.name) {
2727
console.error("Error fetching classroom or its name:", error);
28-
return <h1> Insert 404 page here</h1>;
28+
notFound();
2929
}
3030

3131
return (
Lines changed: 45 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,54 @@
1+
import {
2+
createDatasetClient,
3+
downloadDocument,
4+
} from "@/shared/lib/ragflow/dataset-client";
5+
16
export default async function PreviewPage({
27
searchParams,
38
}: {
49
searchParams: Promise<{ documentId: string; datasetId: string }>;
510
}) {
611
const { documentId, datasetId } = await searchParams;
712

8-
return (
9-
<div className="h-screen w-screen">
10-
<embed
11-
src={`/api/document/${datasetId}/${documentId}`}
12-
width="100%"
13-
height="100%"
14-
/>
15-
</div>
13+
// Create a temporary client to access the dataset
14+
const datasetClientResult = await createDatasetClient(
15+
{
16+
classroomId: "0", // We don't actually need a real classroom ID for preview
17+
classroomName: "preview",
18+
},
19+
datasetId
1620
);
21+
22+
if (!datasetClientResult) {
23+
return <>Unable to access document. Please try refreshing.</>;
24+
}
25+
26+
const { content, mimeType, fileName } = await downloadDocument(
27+
datasetClientResult.client,
28+
documentId
29+
);
30+
console.log(`Rendering file: ${fileName}, with MIME type: ${mimeType}`);
31+
32+
if (mimeType === "application/octet-stream") {
33+
// For text content, decode the ArrayBuffer using TextDecoder
34+
const text = new TextDecoder().decode(new Uint8Array(content));
35+
return (
36+
<div className="mx-auto h-screen w-4/5">
37+
<pre className="overflow-auto whitespace-pre-wrap p-4">{text}</pre>
38+
</div>
39+
);
40+
} else {
41+
// Convert binary content to base64 for embedding non-text file types
42+
// Allows us to render PDFs, images and other binary formats directly in the browser
43+
const base64Content = Buffer.from(content).toString("base64");
44+
return (
45+
<div className="mx-auto h-screen w-4/5">
46+
<embed
47+
src={`data:${mimeType};base64,${base64Content}`}
48+
width="100%"
49+
height="100%"
50+
/>
51+
</div>
52+
);
53+
}
1754
}

app/classrooms/[classroomId]/upload/uploadComponent.tsx

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ export default function UploadComponent({
4646
const inputFile = useRef<HTMLInputElement>(null);
4747

4848
useEffect(() => {
49-
async function fetchFiles() {
49+
const fetchFiles = async () => {
5050
let clientToUse = datasetClient;
5151
if (!clientToUse) {
5252
const result = await createDatasetClient({
@@ -66,20 +66,19 @@ export default function UploadComponent({
6666
return;
6767
}
6868
setUploadedFiles(retrieveResult.files);
69-
}
69+
};
7070

7171
fetchFiles();
7272
const interval = setInterval(fetchFiles, 5000);
7373
return () => clearInterval(interval);
7474
}, [classroomId, classroomName, datasetClient]);
7575

76-
const handleFileChange = (e: ChangeEvent<HTMLInputElement>) => {
77-
if (e.target.files && e.target.files.length > 0) {
78-
setFile(e.target.files[0]);
79-
}
76+
const handleFileChange = (event: ChangeEvent<HTMLInputElement>) => {
77+
const selectedFile = event.target.files?.[0];
78+
if (selectedFile) setFile(selectedFile);
8079
};
8180

82-
async function handleSubmit(e: FormEvent<HTMLFormElement>) {
81+
const handleSubmit = async (e: FormEvent<HTMLFormElement>) => {
8382
e.preventDefault();
8483
if (!file) return;
8584

@@ -128,7 +127,7 @@ export default function UploadComponent({
128127
} else if (toastError) {
129128
(toastError as unknown as (value: unknown) => void)(null);
130129
}
131-
}
130+
};
132131

133132
return (
134133
<div className="flex min-h-screen flex-col items-center justify-center p-6">

app/classrooms/page.tsx

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,14 @@ import {
2626
} from "./clientUtils";
2727

2828
import { useSearchParams } from "next/navigation";
29-
import { Edit, LogOut, MessageSquareMore, UserPlus, Users } from "lucide-react";
29+
import {
30+
Edit,
31+
LogOut,
32+
MessageSquareMore,
33+
UserPlus,
34+
Users,
35+
FileText,
36+
} from "lucide-react";
3037
import { Button } from "@shared/components/ui/button";
3138
import SaveClassroomDialog from "./_components/saveClassroomDialog";
3239
import { toast } from "sonner";
@@ -367,6 +374,17 @@ function ClassroomList({ userContext }: { userContext: UserContextType }) {
367374
userId={userId}
368375
/>
369376
)}
377+
378+
<TooltipUtil
379+
trigger={
380+
<Button type="button" variant={"ghost"} size={"iconLg"} asChild>
381+
<Link href={`/classrooms/${classroom.id}/augment`} passHref>
382+
<FileText className="scale-[200%]" />
383+
</Link>
384+
</Button>
385+
}
386+
content={"Augment Notes"}
387+
/>
370388
</div>
371389
{!isAdmin && (
372390
<TooltipUtil

0 commit comments

Comments
 (0)