id from frontend

parent 7c00ed5b
...@@ -8,7 +8,7 @@ RUN pip install --no-cache-dir -r requirements.txt ...@@ -8,7 +8,7 @@ RUN pip install --no-cache-dir -r requirements.txt
COPY . . COPY . .
#just keep the container running without doing anything #just keep the container running without doing anything
CMD ["sh", "-c", "while :; do sleep 10; done"] #CMD ["sh", "-c", "while :; do sleep 10; done"]
#run the app automatically when the container starts #run the app automatically when the container starts
#CMD ["python", "main.py"] CMD ["python", "main.py"]
...@@ -64,13 +64,17 @@ def create_app() -> FastAPI: ...@@ -64,13 +64,17 @@ def create_app() -> FastAPI:
@app.post("/chat") @app.post("/chat")
async def chat_handler( async def chat_handler(
file: Optional[UploadFile] = File(None), file: Optional[UploadFile] = File(None),
text: Optional[str] = Form(None) text: Optional[str] = Form(None),
student_id: str = Form("student_001") # Default student_id, but can be overridden
): ):
""" """
Handles incoming chat messages (either text or audio). Handles incoming chat messages (either text or audio).
Generates responses locally using the agent service. Generates responses locally using the agent service.
""" """
return container.chat_service.process_message(student_id="student_002", file=file, text=text) if not student_id.strip():
raise HTTPException(status_code=400, detail="Student ID is required")
return container.chat_service.process_message(student_id=student_id, file=file, text=text)
@app.get("/get-audio-response") @app.get("/get-audio-response")
async def get_audio_response(): async def get_audio_response():
...@@ -90,14 +94,14 @@ def create_app() -> FastAPI: ...@@ -90,14 +94,14 @@ def create_app() -> FastAPI:
# Agent management endpoints # Agent management endpoints
@app.get("/conversation/stats") @app.get("/conversation/stats")
async def get_conversation_stats(conversation_id: str = "default"): async def get_conversation_stats(student_id: str = "student_001"):
"""Get conversation statistics""" """Get conversation statistics"""
return container.chat_service.get_agent_stats(conversation_id) return container.chat_service.get_agent_stats(student_id)
@app.post("/conversation/clear") @app.post("/conversation/clear")
async def clear_conversation(conversation_id: str = "default"): async def clear_conversation(student_id: str = Form("student_001")):
"""Clear conversation history""" """Clear conversation history"""
return container.chat_service.clear_conversation(conversation_id) return container.chat_service.clear_conversation(student_id)
@app.post("/agent/system-prompt") @app.post("/agent/system-prompt")
async def set_system_prompt(request: dict): async def set_system_prompt(request: dict):
...@@ -116,11 +120,11 @@ def create_app() -> FastAPI: ...@@ -116,11 +120,11 @@ def create_app() -> FastAPI:
} }
@app.get("/conversation/export") @app.get("/conversation/export")
async def export_conversation(conversation_id: str = "default"): async def export_conversation(student_id: str = "student_001"):
"""Export conversation history""" """Export conversation history"""
history = container.agent_service.export_conversation(conversation_id) history = container.agent_service.export_conversation(student_id)
return { return {
"conversation_id": conversation_id, "student_id": student_id,
"messages": history, "messages": history,
"total_messages": len(history) "total_messages": len(history)
} }
...@@ -128,16 +132,16 @@ def create_app() -> FastAPI: ...@@ -128,16 +132,16 @@ def create_app() -> FastAPI:
@app.post("/conversation/import") @app.post("/conversation/import")
async def import_conversation(request: dict): async def import_conversation(request: dict):
"""Import conversation history""" """Import conversation history"""
conversation_id = request.get("conversation_id", "default") student_id = request.get("student_id", "student_001")
messages = request.get("messages", []) messages = request.get("messages", [])
if not messages: if not messages:
raise HTTPException(status_code=400, detail="Messages list cannot be empty") raise HTTPException(status_code=400, detail="Messages list cannot be empty")
container.agent_service.import_conversation(messages, conversation_id) container.agent_service.import_conversation(messages, student_id)
return { return {
"status": "success", "status": "success",
"message": f"Imported {len(messages)} messages to conversation {conversation_id}" "message": f"Imported {len(messages)} messages to conversation {student_id}"
} }
@app.get("/") @app.get("/")
...@@ -151,10 +155,11 @@ def create_app() -> FastAPI: ...@@ -151,10 +155,11 @@ def create_app() -> FastAPI:
"Local AI agent responses using OpenAI GPT", "Local AI agent responses using OpenAI GPT",
"Audio transcription using OpenAI Whisper", "Audio transcription using OpenAI Whisper",
"Text-to-speech using OpenAI TTS", "Text-to-speech using OpenAI TTS",
"Conversation history management" "Conversation history management",
"Student-specific conversations"
], ],
"endpoints": { "endpoints": {
"chat": "/chat (accepts audio or text, generates local agent response)", "chat": "/chat (accepts audio or text with student_id, generates local agent response)",
"get_audio_response": "/get-audio-response (fetches agent's audio and text response)", "get_audio_response": "/get-audio-response (fetches agent's audio and text response)",
"conversation_stats": "/conversation/stats (get conversation statistics)", "conversation_stats": "/conversation/stats (get conversation statistics)",
"clear_conversation": "/conversation/clear (clear conversation history)", "clear_conversation": "/conversation/clear (clear conversation history)",
......
...@@ -94,16 +94,48 @@ class AgentService: ...@@ -94,16 +94,48 @@ class AgentService:
if not nationality_str: if not nationality_str:
raise HTTPException(status_code=404, detail=f"Student with ID {student_id} not found") raise HTTPException(status_code=404, detail=f"Student with ID {student_id} not found")
# Convert database nationality to enum (handle case-insensitive conversion) logger.info(f"Retrieved nationality from DB: '{nationality_str}' for student: {student_id}")
# Debug the enum
print(f"DEBUG - StudentNationality enum:")
for enum_item in StudentNationality:
print(f" {enum_item.name} = '{enum_item.value}'")
# Debug the conversion
nationality_lower = nationality_str.lower().strip()
print(f"DEBUG - DB value: '{nationality_str}' -> lowercase: '{nationality_lower}'")
print(f"DEBUG - Is 'saudi' in enum values? {'saudi' in [e.value for e in StudentNationality]}")
print(f"DEBUG - Direct enum creation test:")
# Test direct enum creation
try:
test_saudi = StudentNationality('saudi')
print(f" StudentNationality('saudi') = {test_saudi}")
except Exception as e:
print(f" StudentNationality('saudi') failed: {e}")
try:
test_egyptian = StudentNationality('egyptian')
print(f" StudentNationality('egyptian') = {test_egyptian}")
except Exception as e:
print(f" StudentNationality('egyptian') failed: {e}")
# Convert string to StudentNationality enum
nationality_lower = nationality_str.lower().strip() nationality_lower = nationality_str.lower().strip()
print(f"DEBUG - Looking for nationality: '{nationality_lower}'")
# Try explicit mapping first
nationality_mapping = { nationality_mapping = {
'egyptian': StudentNationality.EGYPTIAN, 'egyptian': StudentNationality.EGYPTIAN,
'saudi': StudentNationality.SAUDI 'saudi': StudentNationality.SAUDI
} }
nationality = nationality_mapping.get(nationality_lower, StudentNationality.EGYPTIAN) if nationality_lower in nationality_mapping:
if nationality_lower not in nationality_mapping: nationality = nationality_mapping[nationality_lower]
logger.warning(f"Unknown nationality '{nationality_str}' for student {student_id}, defaulting to EGYPTIAN") logger.info(f"Successfully mapped '{nationality_str}' to {nationality}")
else:
logger.warning(f"Unknown nationality '{nationality_str}' ('{nationality_lower}') for student {student_id}, defaulting to EGYPTIAN")
nationality = StudentNationality.EGYPTIAN
# Add user message to database # Add user message to database
self.add_message_to_history(student_id, user_message, "user") self.add_message_to_history(student_id, user_message, "user")
...@@ -113,6 +145,8 @@ class AgentService: ...@@ -113,6 +145,8 @@ class AgentService:
# Pick system prompt using the enum value # Pick system prompt using the enum value
system_prompt = SYSTEM_PROMPTS.get(nationality, SYSTEM_PROMPTS[StudentNationality.EGYPTIAN]) system_prompt = SYSTEM_PROMPTS.get(nationality, SYSTEM_PROMPTS[StudentNationality.EGYPTIAN])
logger.info(f"Using nationality: {nationality} for student: {student_id}")
print(f"DEBUG - Selected system_prompt: {system_prompt}") # Debug print
# Prepare messages # Prepare messages
messages = [] messages = []
...@@ -178,7 +212,7 @@ class AgentService: ...@@ -178,7 +212,7 @@ class AgentService:
if __name__ == "__main__": if __name__ == "__main__":
logging.basicConfig(level=logging.INFO) logging.basicConfig(level=logging.INFO)
agent = AgentService(use_pgvector=True) agent = AgentService(use_pgvector=False)
if agent.is_available(): if agent.is_available():
try: try:
......
...@@ -37,6 +37,20 @@ ...@@ -37,6 +37,20 @@
gap: 15px; gap: 15px;
margin-bottom: 30px; margin-bottom: 30px;
} }
.student-id-controls {
display: flex;
align-items: center;
gap: 10px;
padding: 10px;
background: #f8f9fa;
border-radius: 5px;
border: 1px solid #dee2e6;
}
.student-id-controls label {
font-weight: bold;
color: #495057;
min-width: 80px;
}
.voice-controls, .text-controls { .voice-controls, .text-controls {
display: flex; display: flex;
align-items: center; align-items: center;
...@@ -49,6 +63,13 @@ ...@@ -49,6 +63,13 @@
border-radius: 5px; border-radius: 5px;
font-size: 16px; font-size: 16px;
} }
#studentIdInput {
flex-grow: 1;
padding: 8px;
border: 1px solid #ced4da;
border-radius: 4px;
font-size: 14px;
}
button { button {
background: #007bff; background: #007bff;
color: white; color: white;
...@@ -143,6 +164,10 @@ ...@@ -143,6 +164,10 @@
<h1>الدردشة</h1> <h1>الدردشة</h1>
<div class="controls"> <div class="controls">
<div class="student-id-controls">
<label for="studentIdInput">رقم الطالب:</label>
<input type="text" id="studentIdInput" value="student_001" placeholder="أدخل رقم الطالب..." />
</div>
<div class="text-controls"> <div class="text-controls">
<input type="text" id="textInput" placeholder="اكتب رسالتك هنا..." /> <input type="text" id="textInput" placeholder="اكتب رسالتك هنا..." />
<button id="sendTextBtn">إرسال نص</button> <button id="sendTextBtn">إرسال نص</button>
...@@ -355,6 +380,7 @@ ...@@ -355,6 +380,7 @@
} }
initializeElements() { initializeElements() {
this.studentIdInput = document.getElementById('studentIdInput');
this.textInput = document.getElementById('textInput'); this.textInput = document.getElementById('textInput');
this.sendTextBtn = document.getElementById('sendTextBtn'); this.sendTextBtn = document.getElementById('sendTextBtn');
this.startBtn = document.getElementById('startBtn'); this.startBtn = document.getElementById('startBtn');
...@@ -396,6 +422,7 @@ ...@@ -396,6 +422,7 @@
this.stopBtn.disabled = true; this.stopBtn.disabled = true;
this.textInput.disabled = false; this.textInput.disabled = false;
this.sendTextBtn.disabled = false; this.sendTextBtn.disabled = false;
this.studentIdInput.disabled = false;
break; break;
case RecordingState.RECORDING: case RecordingState.RECORDING:
...@@ -405,6 +432,7 @@ ...@@ -405,6 +432,7 @@
this.stopBtn.disabled = false; this.stopBtn.disabled = false;
this.textInput.disabled = true; this.textInput.disabled = true;
this.sendTextBtn.disabled = true; this.sendTextBtn.disabled = true;
this.studentIdInput.disabled = true;
break; break;
case RecordingState.PROCESSING: case RecordingState.PROCESSING:
...@@ -415,6 +443,7 @@ ...@@ -415,6 +443,7 @@
this.stopBtn.disabled = true; this.stopBtn.disabled = true;
this.textInput.disabled = true; this.textInput.disabled = true;
this.sendTextBtn.disabled = true; this.sendTextBtn.disabled = true;
this.studentIdInput.disabled = true;
break; break;
} }
} }
...@@ -426,6 +455,10 @@ ...@@ -426,6 +455,10 @@
getTextInput() { getTextInput() {
return this.textInput.value.trim(); return this.textInput.value.trim();
} }
getStudentId() {
return this.studentIdInput.value.trim() || 'student_001';
}
} }
// Message Manager // Message Manager
...@@ -461,18 +494,24 @@ ...@@ -461,18 +494,24 @@
this.uiManager = uiManager; this.uiManager = uiManager;
} }
async sendTextMessage(text) { async sendTextMessage(text, studentId) {
if (!text) { if (!text) {
this.uiManager.showStatus('الرجاء إدخال رسالة.', StatusType.ERROR); this.uiManager.showStatus('الرجاء إدخال رسالة.', StatusType.ERROR);
return false; return false;
} }
if (!studentId) {
this.uiManager.showStatus('الرجاء إدخال رقم الطالب.', StatusType.ERROR);
return false;
}
this.uiManager.showStatus('يتم إرسال النص...', StatusType.PROCESSING); this.uiManager.showStatus('يتم إرسال النص...', StatusType.PROCESSING);
this.messageManager.addUserMessage(text); this.messageManager.addUserMessage(text);
try { try {
const formData = new FormData(); const formData = new FormData();
formData.append('text', text); formData.append('text', text);
formData.append('student_id', studentId);
const response = await this.apiClient.sendFormData(Config.BACKEND_URL, formData); const response = await this.apiClient.sendFormData(Config.BACKEND_URL, formData);
if (response.status === 'success') { if (response.status === 'success') {
...@@ -489,10 +528,16 @@ ...@@ -489,10 +528,16 @@
} }
} }
async sendAudioMessage(audioBlob) { async sendAudioMessage(audioBlob, studentId) {
if (!studentId) {
this.uiManager.showStatus('الرجاء إدخال رقم الطالب.', StatusType.ERROR);
return false;
}
try { try {
const formData = new FormData(); const formData = new FormData();
formData.append('file', audioBlob, `voice_message_${Date.now()}.webm`); formData.append('file', audioBlob, `voice_message_${Date.now()}.webm`);
formData.append('student_id', studentId);
const response = await this.apiClient.sendFormData(Config.BACKEND_URL, formData); const response = await this.apiClient.sendFormData(Config.BACKEND_URL, formData);
if (response.status === 'success') { if (response.status === 'success') {
...@@ -563,14 +608,20 @@ ...@@ -563,14 +608,20 @@
async handleSendText() { async handleSendText() {
const text = this.uiManager.getTextInput(); const text = this.uiManager.getTextInput();
const studentId = this.uiManager.getStudentId();
if (!text) return; if (!text) return;
this.uiManager.clearTextInput(); this.uiManager.clearTextInput();
const success = await this.chatService.sendTextMessage(text); const success = await this.chatService.sendTextMessage(text, studentId);
// UI state is handled within the chat service // UI state is handled within the chat service
} }
async handleStartRecording() { async handleStartRecording() {
const studentId = this.uiManager.getStudentId();
if (!studentId) {
this.uiManager.showStatus('الرجاء إدخال رقم الطالب أولاً.', StatusType.ERROR);
return;
}
await this.audioRecorder.startRecording(); await this.audioRecorder.startRecording();
} }
...@@ -579,8 +630,9 @@ ...@@ -579,8 +630,9 @@
} }
async handleAudioRecorded(audioBlob) { async handleAudioRecorded(audioBlob) {
const studentId = this.uiManager.getStudentId();
this.messageManager.addUserMessage("تم إرسال الرسالة الصوتية."); this.messageManager.addUserMessage("تم إرسال الرسالة الصوتية.");
const success = await this.chatService.sendAudioMessage(audioBlob); const success = await this.chatService.sendAudioMessage(audioBlob, studentId);
this.stateMachine.setState(RecordingState.IDLE); this.stateMachine.setState(RecordingState.IDLE);
} }
} }
...@@ -599,7 +651,7 @@ ...@@ -599,7 +651,7 @@
// Initialize application when DOM is ready // Initialize application when DOM is ready
document.addEventListener('DOMContentLoaded', () => { document.addEventListener('DOMContentLoaded', () => {
UnifiedChatApp.initialize(); UnifiedChatApp.initialize();
console.log('Simplified chat application initialized successfully!'); console.log('Chat application with Student ID support initialized successfully!');
}); });
</script> </script>
</body> </body>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment