Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
e474085
Added AudioStream library for robot test to be able to simulate stream
thestumonkey Nov 22, 2025
5c20a55
removed * which breaks windows
thestumonkey Nov 22, 2025
f96cc0f
Added middleware so server shows API responses in logs and masks the …
thestumonkey Nov 22, 2025
d3c3d2d
removed old task manager
thestumonkey Nov 22, 2025
cd40b67
enable job filtering by type
thestumonkey Nov 22, 2025
17afc41
removed deprecvated processors
thestumonkey Nov 22, 2025
67af57d
Enabled creation and update of users to get tests to pass
thestumonkey Nov 22, 2025
167168e
added computed properties for conversation model to get active transc…
thestumonkey Nov 22, 2025
554c632
moved queue health endpoint, and added better job query functions
thestumonkey Nov 22, 2025
9b96486
added params to force waiting for chunk queue to be empty
thestumonkey Nov 22, 2025
32b2802
ensure segments are updated on transcript versions
thestumonkey Nov 22, 2025
be6aa05
added self healing function if redis loses the worker connection
thestumonkey Nov 22, 2025
81a0149
Changed function to get the conversation audio in order to properly auth
thestumonkey Nov 22, 2025
3a8f349
Thinned out the payload from conversation controller
thestumonkey Nov 22, 2025
107c46b
moved metadatalinking to jobs
thestumonkey Nov 22, 2025
9e2fbd3
added memory version addiing
thestumonkey Nov 22, 2025
763494d
added lib for mcp and test framework
thestumonkey Nov 22, 2025
a9a627c
Moved testing framework setup files to own folder
thestumonkey Nov 22, 2025
074874a
added tagging file to segment tests that run at different speeds
thestumonkey Nov 22, 2025
3b6d3c3
Added tests to check queues with audio streaming
thestumonkey Nov 22, 2025
db325ed
Updated robot tests
thestumonkey Nov 22, 2025
0ef9408
Override ON method in order to return API response messages back to t…
thestumonkey Nov 22, 2025
c1c899a
Added test to check for failing workers
thestumonkey Nov 22, 2025
0f6e3a6
Add Robot Framework tests workflow for CI/CD
thestumonkey Nov 22, 2025
87fb186
testing env
thestumonkey Nov 22, 2025
bea431f
Fix duplicate environment keys in Robot tests workflow
thestumonkey Nov 22, 2025
fabdbc1
Fix test environment file location
thestumonkey Nov 22, 2025
47dcc45
Fix service startup issues in Robot tests workflow
thestumonkey Nov 22, 2025
a942b9f
Fix test asset path and improve HTML report instructions
thestumonkey Nov 22, 2025
6c2e08b
Add test audio assets and fix environment variables
thestumonkey Nov 22, 2025
32dd97c
Start RQ workers in CI environment
thestumonkey Nov 22, 2025
83ae75d
Add service logs output after tests run
thestumonkey Nov 22, 2025
2648e0f
Add OPENAI_BASE_URL to backend and worker containers
thestumonkey Nov 22, 2025
7edbc74
Add worker registration verification step before tests
thestumonkey Nov 22, 2025
93f5b1a
Check if workers container is running and show logs if not
thestumonkey Nov 22, 2025
b8559a4
Add environment variables to worker verification step
thestumonkey Nov 22, 2025
a4b6347
Start workers after backend is healthy, not with infrastructure services
thestumonkey Nov 22, 2025
ef9fffa
Add GitHub Pages deployment for HTML test reports
thestumonkey Nov 22, 2025
6b9930b
Merge branch 'main' into robot_tests
thestumonkey Nov 29, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
**/__pycache__
*.wav
!tests/test_assets/*.wav
**/*.env
!**/.env.template
**/memory_config.yaml
Expand Down
192 changes: 192 additions & 0 deletions backends/advanced/docker-compose-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
# docker-compose-ci.yml
# CI/CD environment for GitHub Actions
# Uses built image without source code mounts to ensure memory_config.yaml is included

services:
friend-backend-test:
build:
context: .
dockerfile: Dockerfile
ports:
- "8001:8000" # Avoid conflict with dev on 8000
volumes:
# No src mount for CI - use built image with all files included
- ./data/test_audio_chunks:/app/audio_chunks
- ./data/test_debug_dir:/app/debug_dir
- ./data/test_data:/app/data
environment:
# Override with test-specific settings
- MONGODB_URI=mongodb://mongo-test:27017/test_db
- QDRANT_BASE_URL=qdrant-test
- QDRANT_PORT=6333
- REDIS_URL=redis://redis-test:6379/0
- DEBUG_DIR=/app/debug_dir
# Import API keys from environment
- DEEPGRAM_API_KEY=${DEEPGRAM_API_KEY}
- OPENAI_API_KEY=${OPENAI_API_KEY}
# LLM provider configuration (required for memory service)
- LLM_PROVIDER=${LLM_PROVIDER:-openai}
- OPENAI_BASE_URL=${OPENAI_BASE_URL:-https://api.openai.com/v1}
- OPENAI_MODEL=${OPENAI_MODEL:-gpt-4o-mini}
# Authentication (test-specific)
- AUTH_SECRET_KEY=test-jwt-signing-key-for-integration-tests
- ADMIN_PASSWORD=test-admin-password-123
- ADMIN_EMAIL=test-admin@example.com
# Transcription provider configuration
- TRANSCRIPTION_PROVIDER=${TRANSCRIPTION_PROVIDER:-deepgram}
# - PARAKEET_ASR_URL=${PARAKEET_ASR_URL}
# Memory provider configuration
- MEMORY_PROVIDER=${MEMORY_PROVIDER:-friend_lite}
- OPENMEMORY_MCP_URL=${OPENMEMORY_MCP_URL:-http://host.docker.internal:8765}
- OPENMEMORY_USER_ID=${OPENMEMORY_USER_ID:-openmemory}
# Disable speaker recognition in test environment to prevent segment duplication
- DISABLE_SPEAKER_RECOGNITION=false
- SPEAKER_SERVICE_URL=https://localhost:8085
- CORS_ORIGINS=http://localhost:3001,http://localhost:8001,https://localhost:3001,https://localhost:8001
# Set low inactivity timeout for tests (2 seconds instead of 60)
- SPEECH_INACTIVITY_THRESHOLD_SECONDS=2
# Wait for audio queue to drain before timing out (test mode)
- WAIT_FOR_AUDIO_QUEUE_DRAIN=true
depends_on:
qdrant-test:
condition: service_started
mongo-test:
condition: service_healthy
redis-test:
condition: service_started
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/readiness"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
restart: unless-stopped

webui-test:
build:
context: ./webui
dockerfile: Dockerfile
args:
- VITE_BACKEND_URL=http://localhost:8001
- BACKEND_URL=http://localhost:8001
volumes:
- ./webui/src:/app/src # Mount source code for easier development
ports:
- "3001:80" # Avoid conflict with dev on 3000
depends_on:
friend-backend-test:
condition: service_healthy
mongo-test:
condition: service_healthy
qdrant-test:
condition: service_started
redis-test:
condition: service_started

qdrant-test:
image: qdrant/qdrant:latest
ports:
- "6337:6333" # gRPC - avoid conflict with dev 6333
- "6338:6334" # HTTP - avoid conflict with dev 6334
volumes:
- ./data/test_qdrant_data:/qdrant/storage

mongo-test:
image: mongo:8.0.14
ports:
- "27018:27017" # Avoid conflict with dev on 27017
volumes:
- ./data/test_mongo_data:/data/db
# Use test database name to ensure isolation
command: mongod --dbpath /data/db --bind_ip_all
healthcheck:
test: ["CMD", "mongosh", "--eval", "db.runCommand('ping').ok", "--quiet"]
interval: 5s
timeout: 5s
retries: 10
start_period: 10s

redis-test:
image: redis:7-alpine
ports:
- "6380:6379" # Avoid conflict with dev on 6379
volumes:
- ./data/test_redis_data:/data
command: redis-server --appendonly yes
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 3s
retries: 5

workers-test:
build:
context: .
dockerfile: Dockerfile
command: ./start-workers.sh
volumes:
# No src mount for CI - use built image
- ./data/test_audio_chunks:/app/audio_chunks
- ./data/test_debug_dir:/app/debug_dir
- ./data/test_data:/app/data
environment:
# Same environment as backend
- MONGODB_URI=mongodb://mongo-test:27017/test_db
- QDRANT_BASE_URL=qdrant-test
- QDRANT_PORT=6333
- REDIS_URL=redis://redis-test:6379/0
- DEBUG_DIR=/app/debug_dir
- DEEPGRAM_API_KEY=${DEEPGRAM_API_KEY}
- OPENAI_API_KEY=${OPENAI_API_KEY}
- LLM_PROVIDER=${LLM_PROVIDER:-openai}
- OPENAI_BASE_URL=${OPENAI_BASE_URL:-https://api.openai.com/v1}
- OPENAI_MODEL=${OPENAI_MODEL:-gpt-4o-mini}
- AUTH_SECRET_KEY=test-jwt-signing-key-for-integration-tests
- ADMIN_PASSWORD=test-admin-password-123
- ADMIN_EMAIL=test-admin@example.com
- TRANSCRIPTION_PROVIDER=${TRANSCRIPTION_PROVIDER:-deepgram}
- MEMORY_PROVIDER=${MEMORY_PROVIDER:-friend_lite}
- OPENMEMORY_MCP_URL=${OPENMEMORY_MCP_URL:-http://host.docker.internal:8765}
- OPENMEMORY_USER_ID=${OPENMEMORY_USER_ID:-openmemory}
- DISABLE_SPEAKER_RECOGNITION=false
- SPEAKER_SERVICE_URL=https://localhost:8085
# Set low inactivity timeout for tests (2 seconds instead of 60)
- SPEECH_INACTIVITY_THRESHOLD_SECONDS=2
# Wait for audio queue to drain before timing out (test mode)
- WAIT_FOR_AUDIO_QUEUE_DRAIN=true
depends_on:
friend-backend-test:
condition: service_healthy
mongo-test:
condition: service_healthy
redis-test:
condition: service_started
qdrant-test:
condition: service_started
restart: unless-stopped

# caddy:
# image: caddy:2-alpine
# ports:
# - "443:443"
# - "80:80" # HTTP redirect to HTTPS
# volumes:
# - ./Caddyfile-test:/etc/caddy/Caddyfile:ro
# - ./data/caddy_data:/data
# - ./data/caddy_config:/config
# depends_on:
# webui-test:
# condition: service_started
# friend-backend-test:
# condition: service_healthy
# restart: unless-stopped

# CI Considerations (for future implementation):
# - GitHub Actions can run these services in isolated containers
# - Port conflicts won't exist in CI since each job runs in isolation
# - For CI, we could add:
# - --build flag for fresh builds
# - --force-recreate for clean state
# - Volume cleanup between test runs
# - Environment variables can be injected via GitHub secrets
# - Health checks ensure services are ready before tests run
8 changes: 8 additions & 0 deletions backends/advanced/docker-compose-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ services:
- DISABLE_SPEAKER_RECOGNITION=false
- SPEAKER_SERVICE_URL=https://localhost:8085
- CORS_ORIGINS=http://localhost:3001,http://localhost:8001,https://localhost:3001,https://localhost:8001
# Set low inactivity timeout for tests (2 seconds instead of 60)
- SPEECH_INACTIVITY_THRESHOLD_SECONDS=2
# Wait for audio queue to drain before timing out (test mode)
- WAIT_FOR_AUDIO_QUEUE_DRAIN=true
depends_on:
qdrant-test:
condition: service_started
Expand Down Expand Up @@ -144,6 +148,10 @@ services:
- OPENMEMORY_USER_ID=${OPENMEMORY_USER_ID:-openmemory}
- DISABLE_SPEAKER_RECOGNITION=false
- SPEAKER_SERVICE_URL=https://localhost:8085
# Set low inactivity timeout for tests (2 seconds instead of 60)
- SPEECH_INACTIVITY_THRESHOLD_SECONDS=2
# Wait for audio queue to drain before timing out (test mode)
- WAIT_FOR_AUDIO_QUEUE_DRAIN=true
depends_on:
friend-backend-test:
condition: service_healthy
Expand Down
2 changes: 2 additions & 0 deletions backends/advanced/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ requires-python = ">=3.12"
dependencies = [
"easy-audio-interfaces>=0.7.1", # we need to add local-audio for scripts/local-audio.py | If we don't need that, we can remove this, and then remove portaudio19-dev from Dockerfile
"fastapi>=0.115.12",
"fastmcp>=0.5.0", # MCP server for conversation access
"mem0ai", # Using main branch with PR #3250 AsyncMemory fix
"langchain_neo4j",
"motor>=3.7.1",
Expand All @@ -24,6 +25,7 @@ dependencies = [
"redis>=5.0.0",
"rq>=1.16.0",
"soundfile>=0.12.1",
"websockets>=12.0",
]

[project.optional-dependencies]
Expand Down
9 changes: 0 additions & 9 deletions backends/advanced/src/advanced_omi_backend/app_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,6 @@ async def lifespan(app: FastAPI):
application_logger.error(f"Failed to create admin user: {e}")
# Don't raise here as this is not critical for startup

# Initialize task manager
task_manager = init_task_manager()
await task_manager.start()
application_logger.info("Task manager started")

# Initialize Redis connection for RQ
try:
Expand Down Expand Up @@ -156,11 +152,6 @@ async def lifespan(app: FastAPI):
except Exception as e:
application_logger.error(f"Error closing Redis audio streaming client: {e}")

# Shutdown task manager
task_manager = get_task_manager()
await task_manager.shutdown()
application_logger.info("Task manager shut down")

# Stop metrics collection and save final report
application_logger.info("Metrics collection stopped")

Expand Down
29 changes: 29 additions & 0 deletions backends/advanced/src/advanced_omi_backend/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,9 +119,38 @@ def get_jwt_strategy() -> JWTStrategy:

# User dependencies for protecting endpoints
current_active_user = fastapi_users.current_user(active=True)
current_active_user_optional = fastapi_users.current_user(active=True, optional=True)
current_superuser = fastapi_users.current_user(active=True, superuser=True)


async def get_user_from_token_param(token: str) -> Optional[User]:
"""
Get user from JWT token string (for query parameter authentication).

This is useful for endpoints that need to support token-based auth via query params,
such as HTML audio elements that can't set custom headers.

Args:
token: JWT token string

Returns:
User object if token is valid and user is active, None otherwise
"""
if not token:
return None
try:
strategy = get_jwt_strategy()
user_db_gen = get_user_db()
user_db = await user_db_gen.__anext__()
user_manager = UserManager(user_db)
user = await strategy.read_token(token, user_manager)
if user and user.is_active:
return user
except Exception:
pass
return None


def get_accessible_user_ids(user: User) -> list[str] | None:
"""
Get list of user IDs that the current user can access data for.
Expand Down
4 changes: 0 additions & 4 deletions backends/advanced/src/advanced_omi_backend/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,10 +169,6 @@ async def disconnect(self):
# Close current conversation
await self.close_current_conversation()

# Cancel any tasks for this client
task_manager = get_task_manager()
await task_manager.cancel_tasks_for_client(self.client_id)

# Clean up state
self.speech_segments.clear()
self.current_speech_start.clear()
Expand Down
11 changes: 11 additions & 0 deletions backends/advanced/src/advanced_omi_backend/clients/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
"""Client implementations for Friend-Lite backend.

This module provides reusable client implementations that can be used for:
- Integration testing
- CLI tools
- External integrations
"""

from advanced_omi_backend.clients.audio_stream_client import AudioStreamClient

__all__ = ["AudioStreamClient"]
Loading