id from frontend

parent 7c00ed5b
......@@ -8,7 +8,7 @@ RUN pip install --no-cache-dir -r requirements.txt
COPY . .
#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
#CMD ["python", "main.py"]
CMD ["python", "main.py"]
......@@ -64,13 +64,17 @@ def create_app() -> FastAPI:
@app.post("/chat")
async def chat_handler(
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).
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")
async def get_audio_response():
......@@ -90,14 +94,14 @@ def create_app() -> FastAPI:
# Agent management endpoints
@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"""
return container.chat_service.get_agent_stats(conversation_id)
return container.chat_service.get_agent_stats(student_id)
@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"""
return container.chat_service.clear_conversation(conversation_id)
return container.chat_service.clear_conversation(student_id)
@app.post("/agent/system-prompt")
async def set_system_prompt(request: dict):
......@@ -116,11 +120,11 @@ def create_app() -> FastAPI:
}
@app.get("/conversation/export")
async def export_conversation(conversation_id: str = "default"):
async def export_conversation(student_id: str = "student_001"):
"""Export conversation history"""
history = container.agent_service.export_conversation(conversation_id)
history = container.agent_service.export_conversation(student_id)
return {
"conversation_id": conversation_id,
"student_id": student_id,
"messages": history,
"total_messages": len(history)
}
......@@ -128,16 +132,16 @@ def create_app() -> FastAPI:
@app.post("/conversation/import")
async def import_conversation(request: dict):
"""Import conversation history"""
conversation_id = request.get("conversation_id", "default")
student_id = request.get("student_id", "student_001")
messages = request.get("messages", [])
if not messages:
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 {
"status": "success",
"message": f"Imported {len(messages)} messages to conversation {conversation_id}"
"message": f"Imported {len(messages)} messages to conversation {student_id}"
}
@app.get("/")
......@@ -151,10 +155,11 @@ def create_app() -> FastAPI:
"Local AI agent responses using OpenAI GPT",
"Audio transcription using OpenAI Whisper",
"Text-to-speech using OpenAI TTS",
"Conversation history management"
"Conversation history management",
"Student-specific conversations"
],
"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)",
"conversation_stats": "/conversation/stats (get conversation statistics)",
"clear_conversation": "/conversation/clear (clear conversation history)",
......
......@@ -94,16 +94,48 @@ class AgentService:
if not nationality_str:
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()
print(f"DEBUG - Looking for nationality: '{nationality_lower}'")
# Try explicit mapping first
nationality_mapping = {
'egyptian': StudentNationality.EGYPTIAN,
'saudi': StudentNationality.SAUDI
}
nationality = nationality_mapping.get(nationality_lower, StudentNationality.EGYPTIAN)
if nationality_lower not in nationality_mapping:
logger.warning(f"Unknown nationality '{nationality_str}' for student {student_id}, defaulting to EGYPTIAN")
if nationality_lower in nationality_mapping:
nationality = nationality_mapping[nationality_lower]
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
self.add_message_to_history(student_id, user_message, "user")
......@@ -113,6 +145,8 @@ class AgentService:
# Pick system prompt using the enum value
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
messages = []
......@@ -178,7 +212,7 @@ class AgentService:
if __name__ == "__main__":
logging.basicConfig(level=logging.INFO)
agent = AgentService(use_pgvector=True)
agent = AgentService(use_pgvector=False)
if agent.is_available():
try:
......
......@@ -37,6 +37,20 @@
gap: 15px;
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 {
display: flex;
align-items: center;
......@@ -49,6 +63,13 @@
border-radius: 5px;
font-size: 16px;
}
#studentIdInput {
flex-grow: 1;
padding: 8px;
border: 1px solid #ced4da;
border-radius: 4px;
font-size: 14px;
}
button {
background: #007bff;
color: white;
......@@ -143,6 +164,10 @@
<h1>الدردشة</h1>
<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">
<input type="text" id="textInput" placeholder="اكتب رسالتك هنا..." />
<button id="sendTextBtn">إرسال نص</button>
......@@ -355,6 +380,7 @@
}
initializeElements() {
this.studentIdInput = document.getElementById('studentIdInput');
this.textInput = document.getElementById('textInput');
this.sendTextBtn = document.getElementById('sendTextBtn');
this.startBtn = document.getElementById('startBtn');
......@@ -396,6 +422,7 @@
this.stopBtn.disabled = true;
this.textInput.disabled = false;
this.sendTextBtn.disabled = false;
this.studentIdInput.disabled = false;
break;
case RecordingState.RECORDING:
......@@ -405,6 +432,7 @@
this.stopBtn.disabled = false;
this.textInput.disabled = true;
this.sendTextBtn.disabled = true;
this.studentIdInput.disabled = true;
break;
case RecordingState.PROCESSING:
......@@ -415,6 +443,7 @@
this.stopBtn.disabled = true;
this.textInput.disabled = true;
this.sendTextBtn.disabled = true;
this.studentIdInput.disabled = true;
break;
}
}
......@@ -426,6 +455,10 @@
getTextInput() {
return this.textInput.value.trim();
}
getStudentId() {
return this.studentIdInput.value.trim() || 'student_001';
}
}
// Message Manager
......@@ -461,18 +494,24 @@
this.uiManager = uiManager;
}
async sendTextMessage(text) {
async sendTextMessage(text, studentId) {
if (!text) {
this.uiManager.showStatus('الرجاء إدخال رسالة.', StatusType.ERROR);
return false;
}
if (!studentId) {
this.uiManager.showStatus('الرجاء إدخال رقم الطالب.', StatusType.ERROR);
return false;
}
this.uiManager.showStatus('يتم إرسال النص...', StatusType.PROCESSING);
this.messageManager.addUserMessage(text);
try {
const formData = new FormData();
formData.append('text', text);
formData.append('student_id', studentId);
const response = await this.apiClient.sendFormData(Config.BACKEND_URL, formData);
if (response.status === 'success') {
......@@ -489,10 +528,16 @@
}
}
async sendAudioMessage(audioBlob) {
async sendAudioMessage(audioBlob, studentId) {
if (!studentId) {
this.uiManager.showStatus('الرجاء إدخال رقم الطالب.', StatusType.ERROR);
return false;
}
try {
const formData = new FormData();
formData.append('file', audioBlob, `voice_message_${Date.now()}.webm`);
formData.append('student_id', studentId);
const response = await this.apiClient.sendFormData(Config.BACKEND_URL, formData);
if (response.status === 'success') {
......@@ -563,14 +608,20 @@
async handleSendText() {
const text = this.uiManager.getTextInput();
const studentId = this.uiManager.getStudentId();
if (!text) return;
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
}
async handleStartRecording() {
const studentId = this.uiManager.getStudentId();
if (!studentId) {
this.uiManager.showStatus('الرجاء إدخال رقم الطالب أولاً.', StatusType.ERROR);
return;
}
await this.audioRecorder.startRecording();
}
......@@ -579,8 +630,9 @@
}
async handleAudioRecorded(audioBlob) {
const studentId = this.uiManager.getStudentId();
this.messageManager.addUserMessage("تم إرسال الرسالة الصوتية.");
const success = await this.chatService.sendAudioMessage(audioBlob);
const success = await this.chatService.sendAudioMessage(audioBlob, studentId);
this.stateMachine.setState(RecordingState.IDLE);
}
}
......@@ -599,7 +651,7 @@
// Initialize application when DOM is ready
document.addEventListener('DOMContentLoaded', () => {
UnifiedChatApp.initialize();
console.log('Simplified chat application initialized successfully!');
console.log('Chat application with Student ID support initialized successfully!');
});
</script>
</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