Skip to content

Commit b70a2a2

Browse files
Merge pull request #95 from Evolutionary-Algorithms-On-Click/evoc-v2-phase1
Environment variable left
2 parents 758cf73 + 198865b commit b70a2a2

7 files changed

Lines changed: 92 additions & 131 deletions

File tree

Dockerfile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ COPY . .
66

77
ARG NEXT_PUBLIC_BACKEND_BASE_URL
88
ENV NEXT_PUBLIC_BACKEND_BASE_URL=${NEXT_PUBLIC_BACKEND_BASE_URL}
9+
ARG NEXT_PUBLIC_V2_BACKEND_BASE_URL
10+
ENV NEXT_PUBLIC_V2_BACKEND_BASE_URL=${NEXT_PUBLIC_V2_BACKEND_BASE_URL}
911
ARG NEXT_PUBLIC_AUTH_BASE_URL
1012
ENV NEXT_PUBLIC_AUTH_BASE_URL=${NEXT_PUBLIC_AUTH_BASE_URL}
1113
ARG NEXT_PUBLIC_MINIO_BASE_URL

app/create/custom-ea/[problemID]/notebook/[notebookID]/_components/KernelControls.js

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,18 +19,13 @@ export default function KernelControls({
1919
setError(null);
2020
try {
2121
const base =
22-
env("NEXT_PUBLIC_BACKEND_BASE_URL") ?? "http://localhost:8080";
23-
const res = await fetch(`${base}/api/v1/sessions`, {
22+
env("NEXT_PUBLIC_V2_BACKEND_BASE_URL") ?? "http://localhost:8080";
23+
const data = await authenticatedFetchV2(`/api/v1/sessions`, {
2424
method: "POST",
2525
credentials: "include",
2626
headers: { "Content-Type": "application/json" },
2727
body: JSON.stringify({ notebook_id: notebookId, language }),
2828
});
29-
if (!res.ok) {
30-
const text = await res.text();
31-
throw new Error(text || "Failed to create session");
32-
}
33-
const data = await res.json();
3429
setSession(data);
3530
onSessionCreated && onSessionCreated(data);
3631
return data;

app/create/custom-ea/[problemID]/notebook/[notebookID]/_components/hooks/useKernelSocket.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ export default function useKernelSocket(session) {
2929
return;
3030

3131
const base =
32-
env("NEXT_PUBLIC_BACKEND_BASE_URL") ?? "http://localhost:8080";
32+
env("NEXT_PUBLIC_V2_BACKEND_BASE_URL") ?? "http://localhost:8080";
3333
const wsUrl = toWsUrl(base) + `/api/v1/kernels/${kernelId}/channels`;
3434

3535
let ws;

app/create/custom-ea/[problemID]/notebook/[notebookID]/_components/hooks/useNotebookFetch.js

Lines changed: 46 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -1,64 +1,10 @@
11
"use client";
22

33
import { useEffect, useState } from "react";
4-
import { env } from "next-runtime-env";
4+
import { authenticatedFetchV2 } from "../../../../../../../utils/api";
55
import useNotebookLLM from "./useNotebookLLM";
66

7-
// Lightweight decoder copied from previous implementation
8-
const tryDecodePayload = (p) => {
9-
if (p === null || p === undefined) return p;
10-
if (typeof p === "object") return p;
11-
if (typeof p !== "string") return p;
12-
const s = p.trim();
13-
if (s.startsWith("{") || s.startsWith("[")) {
14-
try {
15-
return JSON.parse(s);
16-
} catch (e) {}
17-
}
18-
try {
19-
let b64 = s.replace(/-/g, "+").replace(/_/g, "/");
20-
while (b64.length % 4 !== 0) b64 += "=";
21-
const decoded = atob(b64);
22-
try {
23-
return JSON.parse(decoded);
24-
} catch (e) {
25-
try {
26-
const utf8 = decodeURIComponent(
27-
Array.prototype.map
28-
.call(
29-
decoded,
30-
(c) =>
31-
"%" +
32-
("00" + c.charCodeAt(0).toString(16)).slice(-2),
33-
)
34-
.join(""),
35-
);
36-
try {
37-
return JSON.parse(utf8);
38-
} catch (e2) {
39-
return utf8;
40-
}
41-
} catch (e3) {
42-
return decoded;
43-
}
44-
}
45-
} catch (err) {
46-
return s;
47-
}
48-
};
49-
50-
const removeEmpty = (obj) => {
51-
if (obj === null || obj === undefined) return null;
52-
if (Array.isArray(obj))
53-
return obj.map(removeEmpty).filter((i) => i !== null);
54-
if (typeof obj === "object") {
55-
return Object.entries(obj)
56-
.map(([k, v]) => [k, removeEmpty(v)])
57-
.filter(([, v]) => v !== null && v !== "" && v !== undefined)
58-
.reduce((acc, [k, v]) => ({ ...acc, [k]: v }), {});
59-
}
60-
return obj;
61-
};
7+
// ... (helper functions remain the same)
628

639
export default function useNotebookFetch(notebookId, problemId) {
6410
const [loading, setLoading] = useState(true);
@@ -113,67 +59,54 @@ export default function useNotebookFetch(notebookId, problemId) {
11359
setError(null);
11460

11561
try {
116-
const base = env("NEXT_PUBLIC_BACKEND_BASE_URL") ?? "http://localhost:8080";
117-
const token = localStorage.getItem("token");
118-
const headers = {
119-
"Content-Type": "application/json",
120-
};
121-
if (token) {
122-
headers["Authorization"] = `Bearer ${token}`;
123-
}
124-
125-
const res = await fetch(`${base}/api/v1/notebooks/${notebookId}`, {
126-
method: "GET",
127-
headers: headers,
62+
const notebookData = await authenticatedFetchV2(`/api/v1/notebooks/${notebookId}`, {
12863
signal: controller.signal,
12964
});
13065

131-
132-
if (res.status === 401) {
133-
window.location.href = "/auth";
134-
return;
66+
if (notebookData.notebook && notebookData.notebook.requirements) {
67+
setInitialRequirements(getRequirementsAsString(notebookData.notebook.requirements));
68+
} else if (notebookData.requirements) {
69+
setInitialRequirements(getRequirementsAsString(notebookData.requirements));
13570
}
71+
const currentCells = notebookData?.cells ?? [];
72+
73+
if (currentCells.length > 0) {
74+
console.log("Notebook found with cells, loading content.");
75+
const mappedCells = currentCells.map((c, i) => ({
76+
...c,
77+
id: c.id, // Use frontend ID
78+
idx: i,
79+
cell_name: getCellNameAsString(c.cell_name), // Correctly parse cell_name
80+
source: c.source || "",
81+
execution_count: c.execution_count || 0,
82+
}));
83+
setInitialCells(mappedCells);
84+
setLoading(false);
85+
return; // Done
86+
}
87+
console.log("Notebook found, but it is empty. Generating content.");
13688

137-
// Scenario A: Notebook exists
138-
if (res.ok) {
139-
const notebookData = await res.json();
140-
if (notebookData.notebook && notebookData.notebook.requirements) {
141-
setInitialRequirements(getRequirementsAsString(notebookData.notebook.requirements));
142-
} else if (notebookData.requirements) {
143-
setInitialRequirements(getRequirementsAsString(notebookData.requirements));
144-
}
145-
const currentCells = notebookData?.cells ?? [];
146-
147-
if (currentCells.length > 0) {
148-
console.log("Notebook found with cells, loading content.");
149-
const mappedCells = currentCells.map((c, i) => ({
150-
...c,
151-
id: c.id, // Use frontend ID
152-
idx: i,
153-
cell_name: getCellNameAsString(c.cell_name), // Correctly parse cell_name
154-
source: c.source || "",
155-
execution_count: c.execution_count || 0,
156-
}));
157-
setInitialCells(mappedCells);
158-
return; // Done
159-
}
160-
// If notebook exists but is empty, fall through to generation
161-
console.log("Notebook found, but it is empty. Generating content.");
162-
} else if (res.status !== 404) {
163-
// Handle errors other than "Not Found"
164-
const errorText = await res.text();
165-
throw new Error(`Failed to fetch notebook: ${res.status} ${errorText}`);
166-
} else {
89+
} catch (err) {
90+
if (err.message.includes("404")) {
16791
console.log("Notebook not found. Creating and generating a new one.");
168-
// This is a new notebook, we need to create the DB entry first
169-
// The backend should handle creating the notebook entry on generate
170-
}
171-
172-
// Scenario B: Notebook is new or empty, so we generate it.
173-
if (!problemId) {
174-
throw new Error("Cannot generate notebook: Missing Problem ID.");
92+
} else if (controller.signal.aborted) {
93+
return;
94+
} else {
95+
console.error("Failed to fetch notebook:", err);
96+
setError(`Failed to fetch notebook: ${err.message}`);
97+
setLoading(false);
98+
return;
17599
}
100+
}
101+
102+
// Scenario B: Notebook is new or empty, so we generate it.
103+
if (!problemId) {
104+
setError("Cannot generate notebook: Missing Problem ID.");
105+
setLoading(false);
106+
return;
107+
}
176108

109+
try {
177110
const llmResult = await generateNotebook(problemId);
178111

179112
if (!llmResult || !llmResult.notebook || !llmResult.notebook.cells) {
@@ -182,7 +115,8 @@ export default function useNotebookFetch(notebookId, problemId) {
182115

183116
if (llmResult.notebook && llmResult.notebook.requirements) {
184117
setInitialRequirements(llmResult.notebook.requirements);
185-
} else if (llmResult.requirements) {
118+
}
119+
else if (llmResult.requirements) {
186120
setInitialRequirements(llmResult.requirements);
187121
}
188122

@@ -200,8 +134,8 @@ export default function useNotebookFetch(notebookId, problemId) {
200134

201135
} catch (err) {
202136
if (controller.signal.aborted) return;
203-
console.error("Error during notebook fetch/generation:", err);
204-
setError(err.message || "An unknown error occurred.");
137+
console.error("Error during notebook generation:", err);
138+
setError(err.message || "An unknown error occurred during generation.");
205139
setInitialCells([]);
206140
} finally {
207141
if (mounted) setLoading(false);

app/create/custom-ea/[problemID]/notebook/[notebookID]/_components/hooks/useNotebookLLM.js

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
"use client";
22

33
import { useState } from "react";
4-
import { authenticatedFetch } from "@/app/utils/api";
4+
import { authenticatedFetchV2 } from "@/app/utils/api";
55

66
export default function useNotebookLLM(notebookId) {
77
const [loading, setLoading] = useState(false);
@@ -11,7 +11,7 @@ export default function useNotebookLLM(notebookId) {
1111
setLoading(true);
1212
setError(null);
1313
try {
14-
const data = await authenticatedFetch(`/api/v1/llm/generate`, {
14+
const data = await authenticatedFetchV2(`/api/v1/llm/generate`, {
1515
method: "POST",
1616
body: JSON.stringify({
1717
problem_id: problemId,
@@ -35,7 +35,7 @@ export default function useNotebookLLM(notebookId) {
3535
setLoading(true);
3636
setError(null);
3737
try {
38-
const data = await authenticatedFetch(`/api/v1/llm/fix`, {
38+
const data = await authenticatedFetchV2(`/api/v1/llm/fix`, {
3939
method: "POST",
4040
body: JSON.stringify({
4141
notebook,
@@ -54,7 +54,8 @@ export default function useNotebookLLM(notebookId) {
5454
if (error.message.includes("401")) {
5555
window.location.href = "/auth";
5656
}
57-
} finally {
57+
}
58+
finally {
5859
setLoading(false);
5960
}
6061
}
@@ -63,7 +64,7 @@ export default function useNotebookLLM(notebookId) {
6364
setLoading(true);
6465
setError(null);
6566
try {
66-
const data = await authenticatedFetch(`/api/v1/llm/modify`, {
67+
const data = await authenticatedFetchV2(`/api/v1/llm/modify`, {
6768
method: "POST",
6869
body: JSON.stringify({
6970
notebook,

app/create/custom-ea/[problemID]/notebook/[notebookID]/_components/hooks/useNotebookPersistence.js

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,12 @@
11
"use client";
22

3-
import { env } from "next-runtime-env";
3+
import { authenticatedFetchV2 } from "../../../../../../../utils/api";
44

55
export default function useNotebookPersistence() {
66
const saveNotebook = async (notebookId, currentCells) => {
7-
const base =
8-
env("NEXT_PUBLIC_BACKEND_BASE_URL") ?? "http://localhost:8080";
97
try {
10-
await fetch(`${base}/api/v1/notebooks/${notebookId}`, {
8+
await authenticatedFetchV2(`/api/v1/notebooks/${notebookId}`, {
119
method: "PUT",
12-
headers: { "Content-Type": "application/json" },
13-
credentials: "include",
1410
body: JSON.stringify({
1511
cells: currentCells.map(({ id, ...rest }) => rest),
1612
}),

app/utils/api.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import { env } from "next-runtime-env";
33

44
const base = env("NEXT_PUBLIC_BACKEND_BASE_URL") ?? "http://localhost:8080";
5+
const baseV2 = env("NEXT_PUBLIC_V2_BACKEND_BASE_URL") ?? "http://localhost:5003";
56

67
export const authenticatedFetch = async (url, options = {}) => {
78
const headers = {
@@ -34,3 +35,35 @@ export const authenticatedFetch = async (url, options = {}) => {
3435

3536
return response.json();
3637
};
38+
39+
export const authenticatedFetchV2 = async (url, options = {}) => {
40+
const headers = {
41+
...options.headers,
42+
"Content-Type": "application/json",
43+
};
44+
45+
const response = await fetch(`${baseV2}${url}`, {
46+
...options,
47+
credentials: "include",
48+
headers,
49+
});
50+
51+
if (!response.ok) {
52+
const errorData = {
53+
message: `Request failed with status: ${response.status}`,
54+
};
55+
try {
56+
const errorJson = await response.json();
57+
errorData.message = errorJson.message || errorData.message;
58+
} catch (parseError) {
59+
console.error("Could not parse error response:", parseError);
60+
}
61+
throw new Error(errorData.message);
62+
}
63+
64+
if (response.status === 204) {
65+
return;
66+
}
67+
68+
return response.json();
69+
};

0 commit comments

Comments
 (0)