Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
A
AI Tutor
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Salma Mohammed Hamed
AI Tutor
Commits
97fd9871
Commit
97fd9871
authored
Oct 13, 2025
by
SalmaMohammedHamedMustafa
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
change /chat endpoint to return a url
parent
b0bf570e
Changes
6
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
36 additions
and
33 deletions
+36
-33
game.tar
self_hosted_env/voice_agent/game.tar
+0
-0
main.py
self_hosted_env/voice_agent/main.py
+6
-21
storage.py
self_hosted_env/voice_agent/repositories/storage.py
+14
-1
chat_service.py
self_hosted_env/voice_agent/services/chat_service.py
+13
-8
openai_service.py
self_hosted_env/voice_agent/services/openai_service.py
+1
-1
response_manager.py
self_hosted_env/voice_agent/services/response_manager.py
+2
-2
No files found.
self_hosted_env/voice_agent/game.tar
deleted
100644 → 0
View file @
b0bf570e
File deleted
self_hosted_env/voice_agent/main.py
View file @
97fd9871
...
@@ -148,32 +148,17 @@ def create_app() -> FastAPI:
...
@@ -148,32 +148,17 @@ def create_app() -> FastAPI:
"""Fetches the agent's text and audio response with proper CORS headers."""
"""Fetches the agent's text and audio response with proper CORS headers."""
try
:
try
:
print
(
"Getting audio response..."
)
print
(
"Getting audio response..."
)
result
=
container
.
response_service
.
get_agent_response
(
student_id
=
student_id
)
result
=
container
.
response_service
.
get_agent_response
(
student_id
=
student_id
)
if
hasattr
(
result
,
'status_code'
):
if
hasattr
(
result
,
'status_code'
):
# This is already a Response object from response_service
# This is already a Response object from response_service
print
(
f
"Response headers: {dict(result.headers)}"
)
print
(
f
"Response headers: {dict(result.headers)}"
)
print
(
f
"Response audio raw bytes size: {len(result.body) if result.body else 'N/A'}"
)
print
(
f
"Response audio first 20 bytes: {result.body[:20] if result.body else 'N/A'}"
)
return
result
return
result
else
:
# If it's not a Response object, create one
print
(
"Creating new response object"
)
response_text
=
result
.
get
(
'text'
,
'No response available'
)
# Encode the response text in base64 for the header
encoded_text
=
base64
.
b64encode
(
response_text
.
encode
(
'utf-8'
))
.
decode
(
'utf-8'
)
# Create response with proper headers
response
=
Response
(
content
=
result
.
get
(
'audio'
,
b
''
),
media_type
=
"audio/mpeg"
,
headers
=
{
"X-Response-Text"
:
encoded_text
,
"Access-Control-Expose-Headers"
:
"X-Response-Text"
,
"Access-Control-Allow-Origin"
:
"*"
,
"Access-Control-Allow-Methods"
:
"GET, POST, OPTIONS"
,
"Access-Control-Allow-Headers"
:
"*"
}
)
print
(
f
"Created response with headers: {dict(response.headers)}"
)
print
(
f
"Created response with headers: {dict(response.headers)}"
)
return
response
return
response
...
...
self_hosted_env/voice_agent/repositories/storage.py
View file @
97fd9871
...
@@ -44,3 +44,16 @@ class MinIOStorageRepository(StorageRepository):
...
@@ -44,3 +44,16 @@ class MinIOStorageRepository(StorageRepository):
return
"connected"
return
"connected"
except
Exception
as
e
:
except
Exception
as
e
:
return
f
"error: {str(e)}"
return
f
"error: {str(e)}"
def
get_file_url
(
self
,
bucket
:
str
,
file_path
:
str
,
expires
:
int
=
3600
)
->
str
:
"""Generate a presigned URL to share an S3 object"""
try
:
url
=
self
.
client
.
generate_presigned_url
(
'get_object'
,
Params
=
{
'Bucket'
:
bucket
,
'Key'
:
file_path
},
ExpiresIn
=
expires
)
return
url
except
ClientError
as
e
:
print
(
f
"Error generating presigned URL: {e}"
)
return
None
\ No newline at end of file
self_hosted_env/voice_agent/services/chat_service.py
View file @
97fd9871
...
@@ -60,7 +60,7 @@ class ChatService:
...
@@ -60,7 +60,7 @@ class ChatService:
self
.
response_manager
.
store_response
(
self
.
response_manager
.
store_response
(
student_id
=
student_id
,
student_id
=
student_id
,
text
=
agent_response_text
,
text
=
agent_response_text
,
audio_file
name
=
audio_data
.
get
(
"filename
"
),
audio_file
path
=
audio_data
.
get
(
"filepath
"
),
audio_bytes
=
audio_data
.
get
(
"bytes"
)
audio_bytes
=
audio_data
.
get
(
"bytes"
)
)
)
...
@@ -71,7 +71,7 @@ class ChatService:
...
@@ -71,7 +71,7 @@ class ChatService:
"message"
:
"Message processed and agent response ready"
,
"message"
:
"Message processed and agent response ready"
,
"student_id"
:
student_id
,
"student_id"
:
student_id
,
"agent_response"
:
agent_response_text
,
"agent_response"
:
agent_response_text
,
"audio_file
name"
:
audio_data
.
get
(
"filename
"
)
"audio_file
path"
:
audio_data
.
get
(
"filepath
"
)
}
}
except
Exception
as
e
:
except
Exception
as
e
:
...
@@ -93,11 +93,11 @@ class ChatService:
...
@@ -93,11 +93,11 @@ class ChatService:
# 3. Determine filename and upload (same as before)
# 3. Determine filename and upload (same as before)
provider
=
os
.
getenv
(
"TTS_PROVIDER"
,
"openai"
)
.
lower
()
provider
=
os
.
getenv
(
"TTS_PROVIDER"
,
"openai"
)
.
lower
()
file_extension
=
"wav"
if
provider
==
"custom"
else
"mp3"
file_extension
=
"wav"
content_type
=
"audio/wav"
if
provider
==
"custom"
else
"audio/mpeg"
content_type
=
"audio/wav"
timestamp
=
int
(
time
.
time
())
timestamp
=
int
(
time
.
time
())
filename
=
f
"agent_response_{timestamp}.{file_extension}"
filename
=
f
"agent_response_{timestamp}
_{student_id}
.{file_extension}"
minio_file_path
=
f
"audio/{filename}"
minio_file_path
=
f
"audio/{filename}"
self
.
storage_repo
.
upload_file
(
self
.
storage_repo
.
upload_file
(
...
@@ -106,9 +106,14 @@ class ChatService:
...
@@ -106,9 +106,14 @@ class ChatService:
file_path
=
minio_file_path
file_path
=
minio_file_path
)
)
full_url
=
self
.
storage_repo
.
get_file_url
(
bucket
=
self
.
config
.
minio_bucket
,
file_path
=
minio_file_path
,
expires
=
3600
# 1 hour
)
print
(
f
"Successfully generated and uploaded stitched TTS audio: {filename}"
)
print
(
f
"Successfully generated and uploaded stitched TTS audio: {filename}"
)
return
{
"bytes"
:
audio_bytes
,
"file
name"
:
filename
}
return
{
"bytes"
:
audio_bytes
,
"file
path"
:
full_url
}
except
Exception
as
e
:
except
Exception
as
e
:
print
(
f
"Error in _generate_and_upload_audio: {e}"
)
print
(
f
"Error in _generate_and_upload_audio: {e}"
)
return
{
"bytes"
:
None
,
"filename"
:
None
}
return
{
"bytes"
:
None
,
"filepath"
:
None
}
\ No newline at end of file
\ No newline at end of file
self_hosted_env/voice_agent/services/openai_service.py
View file @
97fd9871
...
@@ -69,7 +69,7 @@ class OpenAIService(BaseTTSService):
...
@@ -69,7 +69,7 @@ class OpenAIService(BaseTTSService):
model
=
Models
.
tts
,
model
=
Models
.
tts
,
voice
=
voice
,
voice
=
voice
,
input
=
text
,
input
=
text
,
response_format
=
"
mp3
"
response_format
=
"
wav
"
)
)
audio_bytes
=
response
.
content
audio_bytes
=
response
.
content
...
...
self_hosted_env/voice_agent/services/response_manager.py
View file @
97fd9871
...
@@ -22,7 +22,7 @@ class ResponseManager:
...
@@ -22,7 +22,7 @@ class ResponseManager:
"""Creates a consistent key for Redis to avoid conflicts."""
"""Creates a consistent key for Redis to avoid conflicts."""
return
f
"student_response:{student_id}"
return
f
"student_response:{student_id}"
def
store_response
(
self
,
student_id
:
str
,
text
:
str
,
audio_file
name
:
Optional
[
str
]
=
None
,
audio_bytes
:
Optional
[
bytes
]
=
None
)
->
None
:
def
store_response
(
self
,
student_id
:
str
,
text
:
str
,
audio_file
path
:
Optional
[
str
]
=
None
,
audio_bytes
:
Optional
[
bytes
]
=
None
)
->
None
:
"""Stores a response for a specific student_id in Redis."""
"""Stores a response for a specific student_id in Redis."""
key
=
self
.
_get_key
(
student_id
)
key
=
self
.
_get_key
(
student_id
)
...
@@ -31,7 +31,7 @@ class ResponseManager:
...
@@ -31,7 +31,7 @@ class ResponseManager:
payload
=
{
payload
=
{
"text"
:
text
,
"text"
:
text
,
"audio_file
name"
:
audio_filename
,
"audio_file
path"
:
audio_filepath
,
"audio_bytes_b64"
:
encoded_audio
"audio_bytes_b64"
:
encoded_audio
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment