Skip to content

Commit 6bcddf0

Browse files
committed
fix: build fix
1 parent cf55981 commit 6bcddf0

6 files changed

Lines changed: 259 additions & 178 deletions

File tree

backend/app/main.py

Lines changed: 33 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
1-
from fastapi import FastAPI, WebSocket, WebSocketDisconnect, HTTPException
2-
from fastapi.middleware.cors import CORSMiddleware
3-
from pydantic import BaseModel
41
import json
52
import uuid
6-
from typing import Dict, List, Optional
7-
import asyncio
83

9-
from .websockets.room_manager import RoomManager
4+
from fastapi import FastAPI, HTTPException, WebSocket, WebSocketDisconnect
5+
from fastapi.middleware.cors import CORSMiddleware
6+
7+
from .models.classroom import ClassroomCreate
108
from .websockets.chat_handler import ChatHandler
11-
from .models.classroom import Classroom, ClassroomCreate
9+
from .websockets.room_manager import RoomManager
1210

13-
app = FastAPI(title="Instructify API", description="EdTech Platform with AI-powered features")
11+
app = FastAPI(
12+
title="Instructify API", description="EdTech Platform with AI-powered features"
13+
)
1414

1515
# CORS middleware for Next.js frontend
1616
app.add_middleware(
@@ -25,22 +25,26 @@
2525
room_manager = RoomManager()
2626
chat_handler = ChatHandler(room_manager)
2727

28+
2829
@app.get("/")
2930
async def root():
3031
return {"message": "Instructify API is running"}
3132

33+
3234
@app.get("/health")
3335
async def health():
3436
return {"status": "healthy"}
3537

38+
3639
# Classroom management endpoints
3740
@app.post("/api/classroom/create")
3841
async def create_classroom(classroom_data: ClassroomCreate):
3942
"""Create a new classroom and return classroom ID"""
4043
class_id = str(uuid.uuid4())[:8] # Short ID for easy sharing
41-
classroom = await room_manager.create_room(class_id, classroom_data.teacher_name)
44+
await room_manager.create_room(class_id, classroom_data.teacher_name)
4245
return {"class_id": class_id, "teacher_name": classroom_data.teacher_name}
4346

47+
4448
@app.get("/api/classroom/{class_id}")
4549
async def get_classroom(class_id: str):
4650
"""Get classroom information"""
@@ -49,42 +53,49 @@ async def get_classroom(class_id: str):
4953
raise HTTPException(status_code=404, detail="Classroom not found")
5054
return classroom.dict()
5155

56+
5257
@app.websocket("/ws/classroom/{class_id}")
5358
async def websocket_endpoint(websocket: WebSocket, class_id: str):
5459
"""Main WebSocket endpoint for classroom communication"""
5560
await websocket.accept()
56-
61+
5762
try:
5863
# Wait for initial message to determine user type (teacher/student)
5964
data = await websocket.receive_text()
6065
message = json.loads(data)
61-
66+
6267
user_type = message.get("user_type") # "teacher" or "student"
6368
user_name = message.get("user_name", "Anonymous")
64-
69+
6570
# Add user to room
6671
await room_manager.add_user_to_room(class_id, websocket, user_type, user_name)
67-
72+
6873
# Send confirmation
69-
await websocket.send_text(json.dumps({
70-
"type": "connection_confirmed",
71-
"user_type": user_type,
72-
"class_id": class_id
73-
}))
74-
74+
await websocket.send_text(
75+
json.dumps(
76+
{
77+
"type": "connection_confirmed",
78+
"user_type": user_type,
79+
"class_id": class_id,
80+
}
81+
)
82+
)
83+
7584
# Handle incoming messages
7685
while True:
7786
data = await websocket.receive_text()
7887
message = json.loads(data)
79-
88+
8089
await chat_handler.handle_message(class_id, websocket, message)
81-
90+
8291
except WebSocketDisconnect:
8392
await room_manager.remove_user_from_room(class_id, websocket)
8493
except Exception as e:
8594
print(f"WebSocket error: {e}")
8695
await websocket.close()
8796

97+
8898
if __name__ == "__main__":
8999
import uvicorn
90-
uvicorn.run(app, host="0.0.0.0", port=8000)
100+
101+
uvicorn.run(app, host="0.0.0.0", port=8000)
Lines changed: 57 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,140 +1,151 @@
1-
import httpx
21
import json
3-
from typing import Optional, Dict, Any
4-
import asyncio
2+
from typing import Any, Dict, Optional
3+
4+
import httpx
5+
56

67
class OllamaClient:
78
"""Client for interacting with Ollama local LLM server"""
8-
9+
910
def __init__(self, base_url: str = "http://localhost:11434"):
1011
self.base_url = base_url
1112
self.model_name = "Instructify"
12-
13+
1314
async def is_available(self) -> bool:
1415
"""Check if Ollama server is available"""
1516
try:
1617
async with httpx.AsyncClient() as client:
1718
response = await client.get(f"{self.base_url}/api/tags")
1819
return response.status_code == 200
19-
except:
20+
except Exception:
2021
return False
21-
22+
2223
async def generate_text(self, prompt: str, context: str = "") -> Optional[str]:
2324
"""Generate text using Gemma 270M model"""
2425
try:
2526
full_prompt = f"{context}\n\n{prompt}" if context else prompt
26-
27+
2728
async with httpx.AsyncClient(timeout=30.0) as client:
2829
response = await client.post(
2930
f"{self.base_url}/api/generate",
3031
json={
3132
"model": self.model_name,
3233
"prompt": full_prompt,
33-
"stream": False
34-
}
34+
"stream": False,
35+
},
3536
)
36-
37+
3738
if response.status_code == 200:
3839
result = response.json()
39-
return result.get("response", "").strip()
40+
response_text = result.get("response", "")
41+
return str(response_text).strip() if response_text else None
4042
else:
4143
print(f"Ollama error: {response.status_code}")
4244
return None
43-
45+
4446
except Exception as e:
4547
print(f"Ollama client error: {e}")
4648
return None
47-
49+
4850
async def generate_notes(self, transcription: str) -> Optional[str]:
4951
"""Generate structured notes from class transcription"""
50-
prompt = """Please create structured class notes from the following transcription.
51-
Format the response as markdown with the following sections:
52-
52+
prompt = """Please create structured class notes from the transcription.
53+
Format the response as markdown with these sections:
54+
5355
## Summary
5456
[Brief overview of the class]
55-
57+
5658
## Key Topics
5759
[Main topics covered with bullet points]
58-
60+
5961
## Important Definitions
6062
[Key terms and their definitions]
61-
63+
6264
## Action Items
6365
[Any assignments or tasks mentioned]
64-
66+
6567
## Questions for Review
6668
[3-5 review questions based on the content]
67-
69+
6870
Transcription:
6971
"""
70-
72+
7173
return await self.generate_text(prompt, transcription)
72-
74+
7375
async def classify_doubt(self, message: str, context: str = "") -> Dict[str, Any]:
7476
"""Classify if a message is a genuine doubt that should go to teacher"""
75-
prompt = f"""Analyze this student message and determine if it's a genuine academic doubt that should be forwarded to the teacher.
76-
77+
prompt = f"""Analyze this student message and determine if it's a genuine
78+
academic doubt that should be forwarded to the teacher.
79+
7780
Context: {context}
78-
81+
7982
Student message: "{message}"
80-
83+
8184
Respond in JSON format with:
8285
{{
8386
"is_genuine_doubt": true/false,
8487
"confidence": 0.0-1.0,
8588
"reason": "brief explanation",
8689
"category": "academic_question|personal_ai_query|spam|off_topic"
8790
}}
88-
91+
8992
Only classify as "genuine_doubt" if it's:
9093
- A specific academic question about the subject
9194
- Request for clarification on course material
9295
- Question about assignments or course logistics
93-
96+
9497
Do NOT classify as genuine_doubt if it's:
9598
- General knowledge questions
9699
- Personal queries to AI
97100
- Off-topic discussions
98101
- Spam or inappropriate content
99102
"""
100-
103+
101104
try:
102105
response = await self.generate_text(prompt)
103106
if response:
104107
# Try to extract JSON from response
105108
import re
106-
json_match = re.search(r'\{.*\}', response, re.DOTALL)
109+
110+
json_match = re.search(r"\{.*\}", response, re.DOTALL)
107111
if json_match:
108-
return json.loads(json_match.group())
109-
112+
parsed_json = json.loads(json_match.group())
113+
if isinstance(parsed_json, dict):
114+
return parsed_json
115+
return {}
116+
110117
# Fallback response
111118
return {
112119
"is_genuine_doubt": False,
113120
"confidence": 0.5,
114121
"reason": "Could not analyze message",
115-
"category": "unknown"
122+
"category": "unknown",
116123
}
117-
124+
118125
except Exception as e:
119126
print(f"Error classifying doubt: {e}")
120127
return {
121128
"is_genuine_doubt": False,
122129
"confidence": 0.0,
123130
"reason": "Analysis failed",
124-
"category": "error"
131+
"category": "error",
125132
}
126-
127-
async def answer_student_query(self, query: str, lecture_context: str = "") -> Optional[str]:
133+
134+
async def answer_student_query(
135+
self, query: str, lecture_context: str = ""
136+
) -> Optional[str]:
128137
"""Answer student query using lecture context"""
129-
prompt = f"""You are an AI teaching assistant. Answer the student's question based on the lecture context provided.
130-
138+
prompt = f"""You are an AI teaching assistant. Answer the student's
139+
question based on the lecture context provided.
140+
131141
Lecture Context:
132142
{lecture_context}
133-
143+
134144
Student Question: {query}
135-
136-
Provide a helpful, educational response. If the question is outside the lecture scope,
137-
provide general guidance and suggest asking the teacher for more specific help.
145+
146+
Provide a helpful, educational response. If the question is outside
147+
the lecture scope, provide general guidance and suggest asking the
148+
teacher for more specific help.
138149
"""
139-
150+
140151
return await self.generate_text(prompt)

backend/app/utils/auth.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
1-
from typing import Optional
21
import uuid
32

3+
44
class SimpleAuth:
55
"""Simple authentication helper for prototype"""
6-
6+
77
@staticmethod
88
def generate_session_id() -> str:
99
"""Generate a simple session ID"""
1010
return str(uuid.uuid4())
11-
11+
1212
@staticmethod
1313
def validate_user_type(user_type: str) -> bool:
1414
"""Validate user type"""
1515
return user_type in ["teacher", "student"]
16-
16+
1717
@staticmethod
1818
def generate_class_id() -> str:
1919
"""Generate a short, shareable class ID"""
20-
return str(uuid.uuid4())[:8].upper()
20+
return str(uuid.uuid4())[:8].upper()

0 commit comments

Comments
 (0)