Skip to content

Commit c3ab264

Browse files
committed
It is working
1 parent 8b2951e commit c3ab264

File tree

14 files changed

+185
-139
lines changed

14 files changed

+185
-139
lines changed

backend/Dockerfile

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
FROM python:3.13-alpine AS builder
2+
3+
# Install build dependencies only in builder
4+
RUN apk add --no-cache \
5+
build-base \
6+
libffi-dev \
7+
musl-dev \
8+
gcc \
9+
python3-dev \
10+
linux-headers
11+
12+
WORKDIR /app
13+
14+
COPY requirements.txt .
15+
16+
# Install dependencies in a virtual environment
17+
RUN python -m venv /opt/venv && \
18+
/opt/venv/bin/pip install --no-cache-dir --upgrade pip && \
19+
/opt/venv/bin/pip install --no-cache-dir -r requirements.txt
20+
21+
# ---- Final image ----
22+
FROM python:3.13-alpine
23+
24+
# Install runtime dependencies only (no build tools)
25+
RUN apk add --no-cache libffi
26+
27+
# Create user
28+
RUN adduser -D myuser
29+
30+
WORKDIR /app
31+
32+
COPY --from=builder /opt/venv /opt/venv
33+
COPY . .
34+
35+
# Set permissions
36+
RUN chown -R myuser:myuser /app
37+
38+
USER myuser
39+
40+
ENV PATH="/opt/venv/bin:$PATH"
41+
42+
EXPOSE 8080
43+
44+
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8080"]

backend/Pipfile

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,7 @@ verify_ssl = true
44
name = "pypi"
55

66
[packages]
7-
fastapi = "*"
87
uvicore = "*"
9-
pydantic = "*"
10-
uvicorn = "*"
118
google-adk = "*"
129

1310
[dev-packages]

backend/Pipfile.lock

Lines changed: 84 additions & 79 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

backend/main.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import os
2+
3+
import uvicorn
4+
from google.adk.cli.fast_api import get_fast_api_app
5+
6+
7+
AGENT_DIR = os.path.dirname(os.path.abspath(__file__))
8+
ALLOWED_ORIGINS = ["http://localhost", "http://localhost:8080", "*"]
9+
SERVE_WEB_INTERFACE = True
10+
11+
app = get_fast_api_app(
12+
agents_dir=AGENT_DIR,
13+
allow_origins=ALLOWED_ORIGINS,
14+
web=SERVE_WEB_INTERFACE,
15+
)
16+
17+
18+
if __name__ == "__main__":
19+
uvicorn.run(app, host="0.0.0.0", port=int(os.environ.get("PORT", 8080)))

backend/requirements.txt

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@
22
aiohttp==3.7.4.post0; python_version >= '3.6'
33
aioredis==1.3.1
44
annotated-types==0.7.0; python_version >= '3.8'
5-
anyio==4.9.0; python_version >= '3.9'
5+
anyio==4.9.0; python_version >= '3.10'
66
argon2-cffi==20.1.0; python_version >= '3.7'
77
async-timeout==3.0.1; python_full_version >= '3.5.3'
88
asyncclick==7.1.2.3
99
attrs==25.3.0; python_version >= '3.8'
1010
authlib==1.6.0; python_version >= '3.9'
1111
cachetools==5.5.2; python_version >= '3.7'
1212
certifi==2025.6.15; python_version >= '3.7'
13-
cffi==1.17.1; platform_python_implementation != 'PyPy'
13+
cffi==1.17.1; python_version >= '3.8'
1414
chardet==4.0.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'
1515
charset-normalizer==3.4.2; python_version >= '3.7'
1616
click==8.2.1; python_version >= '3.10'
@@ -21,12 +21,12 @@ cryptography==3.4.8; python_version >= '3.6'
2121
docstring-parser==0.16; python_version >= '3.6' and python_version < '4.0'
2222
environs==9.3.5; python_version >= '3.6'
2323
fastapi==0.115.13; python_version >= '3.8'
24-
google-adk==1.3.0; python_version >= '3.9'
24+
google-adk==1.4.2; python_version >= '3.9'
2525
google-api-core[grpc]==2.25.1; python_version >= '3.7'
26-
google-api-python-client==2.172.0; python_version >= '3.7'
26+
google-api-python-client==2.173.0; python_version >= '3.7'
2727
google-auth==2.40.3; python_version >= '3.7'
2828
google-auth-httplib2==0.2.0
29-
google-cloud-aiplatform[agent-engines]==1.97.0; python_version >= '3.9'
29+
google-cloud-aiplatform[agent-engines]==1.98.0; python_version >= '3.9'
3030
google-cloud-appengine-logging==1.6.2; python_version >= '3.7'
3131
google-cloud-audit-log==0.3.2; python_version >= '3.7'
3232
google-cloud-bigquery==3.34.0; python_version >= '3.9'
@@ -38,7 +38,7 @@ google-cloud-speech==2.33.0; python_version >= '3.7'
3838
google-cloud-storage==2.19.0; python_version >= '3.7'
3939
google-cloud-trace==1.16.2
4040
google-crc32c==1.7.1; python_version >= '3.9'
41-
google-genai==1.20.0; python_version >= '3.9'
41+
google-genai==1.21.1; python_version >= '3.9'
4242
google-resumable-media==2.7.2; python_version >= '3.7'
4343
googleapis-common-protos[grpc]==1.70.0; python_version >= '3.7'
4444
graphviz==0.21; python_version >= '3.9'
@@ -57,7 +57,7 @@ importlib-metadata==8.7.0; python_version >= '3.9'
5757
marshmallow==4.0.0; python_version >= '3.9'
5858
mcp==1.9.4; python_version >= '3.10'
5959
multidict==6.5.0; python_version >= '3.9'
60-
numpy==2.3.0; python_version >= '3.11'
60+
numpy==2.3.1; python_version >= '3.11'
6161
opentelemetry-api==1.34.1; python_version >= '3.9'
6262
opentelemetry-exporter-gcp-trace==1.9.0; python_version >= '3.7'
6363
opentelemetry-resourcedetector-gcp==1.9.0a0; python_version >= '3.7'
@@ -73,8 +73,8 @@ pyasn1-modules==0.4.2; python_version >= '3.8'
7373
pycparser==2.22; python_version >= '3.8'
7474
pydantic==2.11.7; python_version >= '3.9'
7575
pydantic-core==2.33.2; python_version >= '3.9'
76-
pydantic-settings==2.9.1; python_version >= '3.9'
77-
pygments==2.19.1; python_version >= '3.8'
76+
pydantic-settings==2.10.0; python_version >= '3.9'
77+
pygments==2.19.2; python_version >= '3.8'
7878
pyparsing==3.2.3; python_version >= '3.1'
7979
python-dateutil==2.9.0.post0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'
8080
python-dotenv==1.1.0; python_version >= '3.9'
@@ -88,11 +88,12 @@ sniffio==1.3.1; python_version >= '3.7'
8888
sqlalchemy==2.0.41; python_version >= '3.7'
8989
sse-starlette==2.3.6; python_version >= '3.9'
9090
starlette==0.46.2; python_version >= '3.9'
91+
tenacity==8.5.0; python_version >= '3.8'
9192
typing-extensions==4.14.0; python_version >= '3.9'
9293
typing-inspection==0.4.1; python_version >= '3.9'
9394
tzlocal==5.3.1; python_version >= '3.9'
9495
uritemplate==4.2.0; python_version >= '3.9'
95-
urllib3==2.4.0; python_version >= '3.9'
96+
urllib3==2.5.0; python_version >= '3.9'
9697
uvicore==0.1.14; python_version >= '3.7' and python_version < '4.0'
9798
uvicorn==0.34.3; python_version >= '3.9'
9899
websockets==15.0.1; python_version >= '3.9'

frontend/Pipfile

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

frontend/src/ai/flows/generate-flashcards.ts

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import {genkit} from 'genkit';
1212
import {googleAI} from '@genkit-ai/googleai';
1313
import {z} from 'genkit';
1414
import { extractJsonFromResponse } from './flow_utils';
15-
import { useAuth } from '@/contexts/AuthContext';
1615

1716
const ai = genkit({
1817
plugins: [googleAI()],
@@ -33,15 +32,12 @@ const GenerateFlashcardsOutputSchema = z.object({
3332
});
3433
export type GenerateFlashcardsOutput = z.infer<typeof GenerateFlashcardsOutputSchema>;
3534

36-
export async function generateFlashcards(input: GenerateFlashcardsInput): Promise<GenerateFlashcardsOutput> {
35+
export async function generateFlashcards(input: GenerateFlashcardsInput, userId: string, sessionId: string): Promise<GenerateFlashcardsOutput> {
3736

3837
// Use ADK /run endpoint with configurable backend URL
3938
const ADK_URL = process.env.NEXT_PUBLIC_AGENT_API_URL || "http://localhost:8000";
39+
console.log("ADK_URL: ", ADK_URL, "userId: ", userId, "sessionId: ", sessionId)
4040
try {
41-
const { user, signOut } = useAuth();
42-
const userId = user?.email || 'u_123'; // TODO: Get from AuthContext
43-
const sessionId = localStorage.getItem('sessionId') || 's_' + Math.random().toString(36).substr(2, 9);
44-
4541
const res = await fetch(`${ADK_URL}/run`, {
4642
method: "POST",
4743
headers: { "Content-Type": "application/json" },
@@ -58,7 +54,9 @@ export async function generateFlashcards(input: GenerateFlashcardsInput): Promis
5854
})
5955
});
6056
if (!res.ok) throw new Error(`Failed to generate flashcards from backend agent: ${res.status}`);
61-
const data = await extractJsonFromResponse(await res.text());
57+
58+
const output = (await res.json())[0]?.content?.parts?.[0]?.text;
59+
const data = await extractJsonFromResponse(output);
6260

6361
// ADK returns response in data.output
6462
let result;

frontend/src/ai/flows/generate-quizzes.ts

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
import {ai} from '@/ai/genkit';
1313
import {z} from 'genkit';
1414
import { extractJsonFromResponse } from './flow_utils';
15-
import { useAuth } from '@/contexts/AuthContext';
1615

1716
const GenerateQuizzesInputSchema = z.object({
1817
courseMaterial: z
@@ -37,16 +36,11 @@ const GenerateQuizzesOutputSchema = z.object({
3736
export type GenerateQuizzesOutput = z.infer<typeof GenerateQuizzesOutputSchema>;
3837

3938
export async function generateQuizzes(
40-
input: GenerateQuizzesInput
39+
input: GenerateQuizzesInput, userId: string, sessionId: string
4140
): Promise<GenerateQuizzesOutput> {
4241
// Use ADK /run endpoint with configurable backend URL
4342
const ADK_URL = process.env.NEXT_PUBLIC_AGENT_API_URL || "http://localhost:8000";
4443
try {
45-
const { user, signOut } = useAuth();
46-
47-
const userId = user?.email || 'u_123'; // TODO: Get from AuthContext
48-
const sessionId = localStorage.getItem('sessionId') || 's_' + Math.random().toString(36).substr(2, 9);
49-
5044
const res = await fetch(`${ADK_URL}/run`, {
5145
method: "POST",
5246
headers: { "Content-Type": "application/json" },
@@ -63,11 +57,11 @@ export async function generateQuizzes(
6357
})
6458
});
6559

66-
if (!res.ok) {
67-
throw new Error(`Failed to generate quizzes: ${res.statusText}`);
68-
}
60+
if (!res.ok) throw new Error(`Failed to generate flashcards from backend agent: ${res.status}`);
61+
62+
const output = (await res.json())[0]?.content?.parts?.[0]?.text;
63+
const data = await extractJsonFromResponse(output);
6964

70-
const data = await extractJsonFromResponse(await res.text());
7165
let result;
7266
try {
7367
result = typeof data === 'string' ? JSON.parse(data) : data;

frontend/src/ai/flows/suggest-resources.ts

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
import {ai} from '@/ai/genkit';
1212
import {z} from 'genkit';
1313
import { extractJsonFromResponse } from './flow_utils';
14-
import { useAuth } from '@/contexts/AuthContext';
1514

1615
const SuggestResourcesInputSchema = z.object({
1716
courseContent: z
@@ -29,14 +28,10 @@ const SuggestedResourceSchema = z.object({
2928
const SuggestResourcesOutputSchema = z.array(SuggestedResourceSchema).describe('An array of suggested resources.');
3029
export type SuggestResourcesOutput = z.infer<typeof SuggestResourcesOutputSchema>;
3130

32-
export async function suggestResources(input: SuggestResourcesInput): Promise<SuggestResourcesOutput> {
31+
export async function suggestResources(input: SuggestResourcesInput, userId: string, sessionId: string): Promise<SuggestResourcesOutput> {
3332
// Use ADK /run endpoint with configurable backend URL
3433
const ADK_URL = process.env.NEXT_PUBLIC_AGENT_API_URL || "http://localhost:8000";
3534
try {
36-
const { user, signOut } = useAuth();
37-
const userId = user?.email || 'u_123';
38-
const sessionId = localStorage.getItem('sessionId') || 's_' + Math.random().toString(36).substr(2, 9);
39-
4035
const res = await fetch(`${ADK_URL}/run`, {
4136
method: "POST",
4237
headers: { "Content-Type": "application/json" },
@@ -53,11 +48,11 @@ export async function suggestResources(input: SuggestResourcesInput): Promise<Su
5348
})
5449
});
5550

56-
if (!res.ok) {
57-
throw new Error(`Failed to suggest resources: ${res.statusText}`);
58-
}
51+
if (!res.ok) throw new Error(`Failed to generate flashcards from backend agent: ${res.status}`);
52+
53+
const output = (await res.json())[0]?.content?.parts?.[0]?.text;
54+
const data = await extractJsonFromResponse(output);
5955

60-
const data = extractJsonFromResponse(await res.text());
6156
let result;
6257
try {
6358
result = typeof data === 'string' ? JSON.parse(data) : data;

frontend/src/app/dashboard/page.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,11 @@ export default function DashboardPage() {
4747
];
4848

4949
const userID = user?.email || 'u_123';
50+
localStorage.setItem('userID', userID);
5051
const sessionId = localStorage.getItem('sessionId') || 's_' + Math.random().toString(36).substr(2, 9);
51-
52+
const ADK_URL = process.env.NEXT_PUBLIC_AGENT_API_URL || "http://localhost:8000"
5253
const makeSession = async () => {
53-
const session = await fetch('http://localhost:8000/apps/EduAssistant_Agents/users/' + userID + '/sessions/' + sessionId, {
54+
const session = await fetch(`${ADK_URL}/apps/EduAssistant_Agents/users/${userID}/sessions/${sessionId}`, {
5455
method: 'POST',
5556
headers: {
5657
'Content-Type': 'application/json',

0 commit comments

Comments
 (0)