Skip to content

Commit fdbab15

Browse files
committed
DEVT-53 DEVT-54 Get LLM augmentation for each line, display diff, display reason for change
1 parent 1bf40a4 commit fdbab15

File tree

7 files changed

+1288
-41
lines changed

7 files changed

+1288
-41
lines changed

app/classrooms/[classroomId]/augment/AugmentNotes.tsx

Lines changed: 72 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,11 @@ import { Input } from "@shared/components/ui/input";
77
import { FileText, Upload } from "lucide-react";
88
import { toast } from "sonner";
99

10+
import pdfToText from "react-pdftotext";
11+
12+
import NotesViewer from "./NotesViewer";
13+
1014
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
1315
classroomId,
1416
}: {
1517
classroomId: string;
@@ -19,15 +21,22 @@ export default function AugmentComponent({
1921
const [file, setFile] = useState<File | null>(null);
2022
const inputFile = useRef<HTMLInputElement>(null);
2123

24+
const [notesContent, setNotesContent] = useState<string[]>([]);
25+
2226
const handleFileChange = (event: React.ChangeEvent<HTMLInputElement>) => {
2327
const selectedFile = event.target.files?.[0];
2428
if (!selectedFile) return;
2529

2630
// Double-check that file passed by user is markdown or pdf
2731
const fileExtension = selectedFile.name.split(".").at(-1)?.toLowerCase();
28-
if (fileExtension !== "pdf" && fileExtension !== "md") {
32+
if (
33+
fileExtension !== "pdf" &&
34+
fileExtension !== "md" &&
35+
fileExtension !== "txt"
36+
) {
2937
toast.error("Invalid file format", {
30-
description: "Please upload a Markdown (.md) or PDF (.pdf) file",
38+
description:
39+
"Please upload a Markdown (.md), PDF (.pdf), or TXT (.txt) file",
3140
});
3241
return;
3342
}
@@ -36,48 +45,78 @@ export default function AugmentComponent({
3645
};
3746

3847
const handleUpload = async () => {
39-
// TODO
48+
if (file != null) {
49+
const fileExtension = file.name.split(".").at(-1)?.toLowerCase();
50+
51+
let splitByLines: string[] = [];
52+
53+
// if txt or md
54+
if (fileExtension == "txt" || fileExtension == "md") {
55+
const endText: string = await file.text();
56+
endText.replaceAll("\r", "");
57+
splitByLines = endText.split("\n");
58+
59+
// if pdf
60+
} else if (fileExtension == "pdf") {
61+
splitByLines = await pdfToText(file)
62+
.then((text) => {
63+
return text.split(" ");
64+
})
65+
.catch((error) => {
66+
console.error("Failed to extract text from pdf", error);
67+
return [""];
68+
});
69+
}
70+
71+
setNotesContent(splitByLines);
72+
}
4073
};
4174

4275
return (
4376
<div className="flex flex-col items-center justify-center gap-4 p-8">
4477
<h1 className="text-3xl font-bold">Augment Notes</h1>
78+
4579
<p className="text-muted-foreground">
4680
Upload your notes to get AI-powered enhancements and improvements
4781
</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 && (
82+
83+
{notesContent.length == 0 ? (
84+
<div className="flex items-center gap-2">
85+
<Input
86+
type="file"
87+
onChange={handleFileChange}
88+
ref={inputFile}
89+
className="hidden"
90+
accept=".md,.pdf,.txt"
91+
/>
7192
<Button
72-
variant="default"
93+
variant="outline"
7394
size="lg"
74-
onClick={handleUpload}
95+
className="cursor-pointer"
7596
disabled={isProcessing}
97+
onClick={() => inputFile.current?.click()}
7698
>
77-
Process Notes
99+
{isProcessing ? (
100+
<Upload className="mr-2 h-4 w-4 animate-spin" />
101+
) : (
102+
<FileText className="mr-2 h-4 w-4" />
103+
)}
104+
Upload Notes
78105
</Button>
79-
)}
80-
</div>
106+
{file && (
107+
<Button
108+
variant="default"
109+
size="lg"
110+
onClick={handleUpload}
111+
disabled={isProcessing}
112+
>
113+
Process Notes
114+
</Button>
115+
)}
116+
</div>
117+
) : (
118+
<NotesViewer notesContent={notesContent} classroomId={classroomId} />
119+
)}
81120
</div>
82121
);
83122
}
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
"use server";
2+
3+
import { createClient } from "@shared/utils/supabase/server";
4+
import {
5+
ChatClientWithSession,
6+
createChatClient,
7+
sendMessage,
8+
} from "@shared/lib/ragflow/chat/chat-client";
9+
10+
import { getUserAndClassroomData } from "@shared/lib/userContext/contextFetcher";
11+
12+
import { AugmentConfigTemplate } from "@shared/lib/ragflow/chat/chat-configs";
13+
14+
// import { revalidatePath } from "next/cache";
15+
// import {
16+
// ChatClientWithSession,
17+
// createChatClient,
18+
// deleteSession,
19+
// sendMessage,
20+
// } from "@shared/lib/ragflow/chat/chat-client";
21+
// import { createDatasetClient } from "@shared/lib/ragflow/dataset-client";
22+
23+
export async function createNotesClient(classroomId: string) {
24+
//create a session for that set of notes
25+
26+
//first get the dataset ID
27+
const supabase = await createClient();
28+
const { data, error } = await supabase
29+
.from("Classrooms")
30+
.select()
31+
.eq("id", Number(classroomId))
32+
.single();
33+
34+
if (error) {
35+
console.error("Error fetching classroom data:", error);
36+
throw new Error("Error fetching classroom data");
37+
}
38+
39+
const datasetId: string = data?.ragflow_dataset_id || "";
40+
41+
// console.log("datasetId", datasetId);
42+
// console.log("classroomId", classroomId);
43+
44+
// const params = { dataset_ids: [datasetId], name: datasetId };
45+
46+
// const res = await fetch(`${process.env.RAGFLOW_API_URL}/v1/chats`, {
47+
// method: "POST", // or 'PUT'
48+
// headers: {
49+
// Authorization: `Bearer ${process.env.RAGFLOW_API_KEY}`,
50+
// "Content-Type": "application/json",
51+
// },
52+
// body: JSON.stringify(params),
53+
// });
54+
55+
// console.log("res", res);
56+
57+
const userAndClassData = await getUserAndClassroomData();
58+
59+
const resClient = await createChatClient(
60+
{
61+
...AugmentConfigTemplate,
62+
associatedClassroomName: "Classroom",
63+
primaryKeyValuesAssistant: [{ key: "id", value: classroomId }],
64+
primaryKeyValuesSession: [
65+
{ key: "classroom_id", value: classroomId },
66+
{ key: "user_id", value: userAndClassData?.userData.id },
67+
],
68+
datasets: [datasetId],
69+
}
70+
// classroomInfo.chat_assistant_id
71+
);
72+
73+
if (!resClient.client) {
74+
console.error("Client is null");
75+
throw new Error("Invalid chat client instance");
76+
}
77+
78+
if (!("sessionId" in resClient.client)) {
79+
console.error("Client not of correct type");
80+
throw new Error("Invalid chat client instance: Missing sessionId");
81+
}
82+
const chatClient: ChatClientWithSession = resClient.client;
83+
84+
// console.log(
85+
// "chatClient",
86+
// chatClient.clientConfig.modelSettings.promptSettings
87+
// );
88+
89+
// console.log("datasetId", datasetId);
90+
91+
return chatClient;
92+
}
93+
94+
export async function reviseNotesLine(
95+
chatClient: ChatClientWithSession,
96+
passedLine: string
97+
) {
98+
const passMessage: string = `Below is a line of text notes taken by a student.
99+
Please augment these notes with you comments and revise them primarily based on accuracy.
100+
Only change the parts you want to revise.
101+
Do not rewrite the notes, simply make small edits for correctness.
102+
Do not make style and diction revisions.
103+
Return the notes exactly as given if they are already correct.
104+
If they notes are accurate, leave them exactly as is.
105+
Also, please do not use any markdown formatting.
106+
${passedLine}
107+
`;
108+
109+
const messageResponse = await sendMessage(chatClient, passMessage);
110+
111+
if (!messageResponse.ragflowCallSuccess) {
112+
console.error("Error sending message");
113+
throw new Error("Error sending message");
114+
}
115+
116+
const revisedNotes: string = messageResponse.response
117+
.replace("Notes: ", "")
118+
.replaceAll("##0$$\n", "");
119+
// console.log("revisedNotes", revisedNotes);
120+
121+
const reason: string = await getAugmentReason(
122+
chatClient,
123+
passedLine,
124+
revisedNotes
125+
);
126+
127+
return [revisedNotes, reason];
128+
}
129+
130+
export async function getAugmentReason(
131+
chatClient: ChatClientWithSession,
132+
originalNotes: string,
133+
augmentedNotes: string
134+
) {
135+
const passMessage: string = `In a previous message, you augmented the following notes:
136+
"${originalNotes}"
137+
to
138+
"${augmentedNotes}"
139+
140+
Can you explain why you made this change?
141+
Please do not use any markdown formatting in your response.
142+
`;
143+
144+
const messageResponse = await sendMessage(chatClient, passMessage);
145+
146+
if (!messageResponse.ragflowCallSuccess) {
147+
console.error("Error getting explanation");
148+
throw new Error("Error getting explanation");
149+
}
150+
151+
return messageResponse.response;
152+
}

app/classrooms/[classroomId]/augment/DiffViewer.tsx

Whitespace-only changes.

0 commit comments

Comments
 (0)