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
f28c6e7a
Commit
f28c6e7a
authored
Oct 22, 2025
by
SalmaMohammedHamedMustafa
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix caprover log problem
parent
498fa39d
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
15 additions
and
26 deletions
+15
-26
gunicorn.conf.py
self_hosted_env/voice_agent/gunicorn.conf.py
+7
-0
requirements.txt
self_hosted_env/voice_agent/requirements.txt
+1
-0
response_manager.py
self_hosted_env/voice_agent/services/response_manager.py
+6
-25
start.sh
self_hosted_env/voice_agent/start.sh
+1
-1
No files found.
self_hosted_env/voice_agent/gunicorn.conf.py
0 → 100644
View file @
f28c6e7a
# gunicorn.conf.py
bind
=
"0.0.0.0:8000"
worker_class
=
"uvicorn.workers.UvicornWorker"
workers
=
4
# Or read from an environment variable
accesslog
=
"-"
errorlog
=
"-"
loglevel
=
"info"
\ No newline at end of file
self_hosted_env/voice_agent/requirements.txt
View file @
f28c6e7a
...
...
@@ -4,6 +4,7 @@ sounddevice
soundfile
fastapi
uvicorn[standard]
gunicorn
python-multipart
openai
psycopg2-binary
...
...
self_hosted_env/voice_agent/services/response_manager.py
View file @
f28c6e7a
...
...
@@ -2,8 +2,6 @@
import
json
import
base64
from
typing
import
Optional
,
Dict
# Import the Redis client that all workers will share
from
.redis_client
import
redis_client
class
ResponseManager
:
...
...
@@ -14,70 +12,53 @@ class ResponseManager:
"""
def
__init__
(
self
):
"""Initializes by connecting to the shared Redis client."""
if
redis_client
is
None
:
raise
ConnectionError
(
"ResponseManager requires a valid Redis connection."
)
self
.
redis
=
redis_client
self
.
ttl_seconds
=
600
# A
key will expire 10 mins after the LAST
item is added
self
.
ttl_seconds
=
600
# A
student's queue will expire 10 mins after the last
item is added
def
_get_key
(
self
,
student_id
:
str
)
->
str
:
"""Creates a consistent key for the student's queue."""
return
f
"student_queue:{student_id}"
def
store_response
(
self
,
student_id
:
str
,
text
:
str
,
audio_filepath
:
Optional
[
str
]
=
None
,
audio_bytes
:
Optional
[
bytes
]
=
None
)
->
None
:
"""
Adds a new response to the END of the queue for a specific student.
"""
"""Adds a new response to the END of the queue for a specific student."""
key
=
self
.
_get_key
(
student_id
)
encoded_audio
=
base64
.
b64encode
(
audio_bytes
)
.
decode
(
'utf-8'
)
if
audio_bytes
else
None
payload
=
{
"text"
:
text
,
"audio_filepath"
:
audio_filepath
,
"audio_bytes_b64"
:
encoded_audio
}
# RPUSH adds the new item to the right (end) of the list.
self
.
redis
.
rpush
(
key
,
json
.
dumps
(
payload
))
# Reset the expiration time for the whole queue each time a new item is added.
self
.
redis
.
expire
(
key
,
self
.
ttl_seconds
)
def
get_response
(
self
,
student_id
:
str
)
->
Dict
:
"""
Atomically retrieves and removes the OLDEST response from the front of the queue.
"""
"""Atomically retrieves and removes the OLDEST response from the front of the queue."""
key
=
self
.
_get_key
(
student_id
)
# LPOP atomically retrieves and removes the item from the left (start) of the list.
json_value
=
self
.
redis
.
lpop
(
key
)
if
not
json_value
:
return
{
"text"
:
None
,
"audio_filepath"
:
None
,
"audio_bytes"
:
None
}
# Decode the payload.
payload
=
json
.
loads
(
json_value
)
if
payload
.
get
(
"audio_bytes_b64"
):
payload
[
"audio_bytes"
]
=
base64
.
b64decode
(
payload
[
"audio_bytes_b64"
])
else
:
payload
[
"audio_bytes"
]
=
None
del
payload
[
"audio_bytes_b64"
]
return
payload
def
clear_response
(
self
,
student_id
:
str
)
->
None
:
"""
Completely deletes the entire queue for a student. Useful for '/clear' endpoints.
"""
"""Completely deletes the entire queue for a student."""
key
=
self
.
_get_key
(
student_id
)
self
.
redis
.
delete
(
key
)
def
is_response_fresh
(
self
,
student_id
:
str
)
->
bool
:
"""
Checks if there are any items in the student's queue.
"""
"""Checks if there are any items in the student's queue."""
key
=
self
.
_get_key
(
student_id
)
# LLEN gets the length of the list. If it's > 0,
there's a response
ready.
# LLEN gets the length of the list. If it's > 0,
a response is
ready.
return
self
.
redis
.
llen
(
key
)
>
0
\ No newline at end of file
self_hosted_env/voice_agent/start.sh
View file @
f28c6e7a
...
...
@@ -13,4 +13,4 @@ echo "Curriculum structure setup complete."
sleep
5
# Start the web server and keep it as the main process
exec
uvicorn main:app
--host
0.0.0.0
--port
8000
\ No newline at end of file
exec
gunicorn
-c
gunicorn.conf.py main:app
\ No newline at end of file
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