Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
94 changes: 0 additions & 94 deletions DEVELOPMENT.md

This file was deleted.

42 changes: 23 additions & 19 deletions examples/audio_moderation/main.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
#!/usr/bin/env python3
"""
Example: Real-time Call Transcription with Deepgram STT
"""Example: Real-time Call Transcription with Deepgram STT

This example demonstrates how to:
1. Join a Stream video call
Expand All @@ -18,46 +17,46 @@
import argparse
import asyncio
import logging
import warnings
import os
import time
import uuid
import warnings
import webbrowser
from urllib.parse import urlencode

from dotenv import load_dotenv

from getstream.models import UserRequest
from getstream.models import CheckResponse, ModerationPayload, UserRequest
from getstream.plugins.deepgram.stt import DeepgramSTT
from getstream.stream import Stream
from getstream.video import rtc
from getstream.video.rtc.track_util import PcmData
from getstream.models import CheckResponse, ModerationPayload
from getstream.plugins.deepgram.stt import DeepgramSTT

logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s")

# Suppress dataclasses_json missing value RuntimeWarnings
warnings.filterwarnings(
"ignore", category=RuntimeWarning, module="dataclasses_json.core"
"ignore",
category=RuntimeWarning,
module="dataclasses_json.core",
)


def create_user(client: Stream, id: str, name: str) -> None:
"""
Create a user with a unique Stream ID.
"""Create a user with a unique Stream ID.

Args:
client: Stream client instance
id: Unique user ID
name: Display name for the user

"""
user_request = UserRequest(id=id, name=name)
client.upsert_users(user_request)


def open_browser(api_key: str, token: str, call_id: str) -> str:
"""
Helper function to open browser with Stream call link.
"""Helper function to open browser with Stream call link.

Args:
api_key: Stream API key
Expand All @@ -66,6 +65,7 @@ def open_browser(api_key: str, token: str, call_id: str) -> str:

Returns:
The URL that was opened

"""
base_url = f"{os.getenv('EXAMPLE_BASE_URL')}/join/"
params = {"api_key": api_key, "token": token, "skip_lobby": "true"}
Expand All @@ -90,7 +90,6 @@ def moderate(client: Stream, text: str, user_name: str) -> CheckResponse:
thread with ``asyncio.to_thread`` from async code without blocking the event
loop.
"""

return client.moderation.check(
config_key="custom:python-ai-test", # your moderation config key
entity_creator_id=user_name,
Expand Down Expand Up @@ -127,7 +126,7 @@ async def main(client: Stream):
print("\n🤖 Starting moderation bot...")
print("The bot will join the call and moderate all audio it receives.")
print(
"Join the call in your browser and speak to see moderation results appear here!"
"Join the call in your browser and speak to see moderation results appear here!",
)
print("\nPress Ctrl+C to stop the moderation bot.\n")

Expand All @@ -153,21 +152,26 @@ async def on_transcript(event):
user = event.user_metadata["user"]
user_info = user.name if hasattr(user, "name") else str(user)
print(f"[{timestamp}] {user_info}: {event.text}")
if hasattr(event, 'confidence') and event.confidence:
if hasattr(event, "confidence") and event.confidence:
print(f" └─ confidence: {event.confidence:.2%}")
if hasattr(event, 'processing_time_ms') and event.processing_time_ms:
if hasattr(event, "processing_time_ms") and event.processing_time_ms:
print(f" └─ processing time: {event.processing_time_ms:.1f}ms")

# Moderation check (executed in a background thread to avoid blocking)
moderation = await asyncio.to_thread(moderate, client, event.text, user_info)
moderation = await asyncio.to_thread(
moderate,
client,
event.text,
user_info,
)
print(
f" └─ moderation recommended action: {moderation.recommended_action} for transcript: {event.text}"
f" └─ moderation recommended action: {moderation.recommended_action} for transcript: {event.text}",
)

@stt.on("error")
async def on_stt_error(event):
print(f"\n❌ STT Error: {event.error_message}")
if hasattr(event, 'context') and event.context:
if hasattr(event, "context") and event.context:
print(f" └─ context: {event.context}")

# Keep the connection alive and wait for audio
Expand All @@ -189,7 +193,7 @@ async def on_stt_error(event):

def parse_args():
parser = argparse.ArgumentParser(
description="Stream Real-time Audio Moderation Example"
description="Stream Real-time Audio Moderation Example",
)
parser.add_argument("--setup", action="store_true", help="Setup moderation config")
return parser.parse_args()
Expand Down
3 changes: 2 additions & 1 deletion examples/audio_moderation/view_flagged.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from getstream import Stream
from dotenv import load_dotenv

from getstream import Stream
from getstream.models import QueryReviewQueueResponse, ReviewQueueItemResponse

load_dotenv()
Expand Down
30 changes: 16 additions & 14 deletions examples/event_system/event_system_example.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
#!/usr/bin/env python3
"""
Example demonstrating the GetStream AI Plugins Event System.
"""Example demonstrating the GetStream AI Plugins Event System.

This example shows how to:
1. Use structured events with different plugin types
Expand All @@ -22,21 +21,21 @@
STT,
TTS,
VAD,
EventType,
STTTranscriptEvent,
VADAudioEvent,
# Event utilities
EventFilter,
EventRegistry,
EventType,
STTTranscriptEvent,
VADAudioEvent,
get_global_registry,
)
from getstream.plugins.common.event_metrics import (
calculate_stt_metrics,
calculate_tts_metrics,
)
from getstream.plugins.common.event_serialization import (
serialize_events,
deserialize_event,
serialize_events,
)

# Set up logging
Expand Down Expand Up @@ -76,7 +75,7 @@ async def _process_audio_impl(self, pcm_data, user_metadata=None):

async def close(self):
logger.info(
f"Closing STT plugin after {self.transcription_count} transcriptions"
f"Closing STT plugin after {self.transcription_count} transcriptions",
)
await super().close()

Expand Down Expand Up @@ -165,7 +164,8 @@ def analyze_stt_performance(registry: EventRegistry):
def analyze_tts_performance(registry: EventRegistry):
"""Analyze TTS performance from events."""
tts_filter = EventFilter(
event_types=[EventType.TTS_SYNTHESIS_COMPLETE], time_window_ms=60000
event_types=[EventType.TTS_SYNTHESIS_COMPLETE],
time_window_ms=60000,
)

tts_events = registry.get_events(tts_filter)
Expand Down Expand Up @@ -195,15 +195,16 @@ def demonstrate_event_filtering(registry: EventRegistry):

# Filter by event type
error_filter = EventFilter(
event_types=[EventType.STT_ERROR, EventType.TTS_ERROR, EventType.VAD_ERROR]
event_types=[EventType.STT_ERROR, EventType.TTS_ERROR, EventType.VAD_ERROR],
)

error_events = registry.get_events(error_filter)
print(f"Total error events: {len(error_events)}")

# Filter by confidence threshold
high_confidence_filter = EventFilter(
event_types=[EventType.STT_TRANSCRIPT], min_confidence=0.9
event_types=[EventType.STT_TRANSCRIPT],
min_confidence=0.9,
)

high_confidence_events = registry.get_events(high_confidence_filter)
Expand Down Expand Up @@ -243,7 +244,7 @@ def demonstrate_event_serialization(registry: EventRegistry):
print(f"Saved events to {filename}")

# Load and deserialize
with open(filename, "r") as f:
with open(filename) as f:
loaded_json = f.read()

events_data = json.loads(loaded_json)
Expand All @@ -254,7 +255,7 @@ def demonstrate_event_serialization(registry: EventRegistry):
# Verify restoration
for original, restored in zip(recent_events, restored_events):
print(
f"Original: {original.event_type.value} - Restored: {restored.event_type.value}"
f"Original: {original.event_type.value} - Restored: {restored.event_type.value}",
)


Expand All @@ -275,7 +276,7 @@ async def on_stt_transcript(event: STTTranscriptEvent):
@tts_plugin.on("synthesis_complete")
async def on_tts_complete(event):
print(
f"🔊 TTS Complete: {event.total_audio_bytes} bytes in {event.synthesis_time_ms:.1f}ms"
f"🔊 TTS Complete: {event.total_audio_bytes} bytes in {event.synthesis_time_ms:.1f}ms",
)

@vad_plugin.on("speech_start")
Expand All @@ -300,9 +301,10 @@ async def write(self, data):

# Simulate STT processing
print("--- STT Processing ---")
from getstream.video.rtc.track_util import PcmData
import numpy as np

from getstream.video.rtc.track_util import PcmData

for i in range(3):
# Create mock audio data
mock_audio = np.random.randint(-32768, 32767, 1600, dtype=np.int16)
Expand Down
Loading
Loading