Skip to content

Commit 523cbaa

Browse files
Add limerick example
1 parent 4e41b5d commit 523cbaa

File tree

12 files changed

+853
-2
lines changed

12 files changed

+853
-2
lines changed

examples/poet_chat/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Trivia Chat
2+
3+

examples/poet_chat/main.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import asyncio
2+
3+
from poet_chat.agent import poet_runner
4+
from poet_chat.config import (
5+
PEER_OPTIONS,
6+
fishjam_client,
7+
)
8+
from poet_chat.notifier import make_notifier
9+
10+
from fishjam.agent import AudioTrackOptions
11+
12+
CHUNK_SIZE = 12000
13+
14+
15+
async def main():
16+
room = fishjam_client.create_room()
17+
_, token = fishjam_client.create_peer(room.id, PEER_OPTIONS)
18+
print(f"Join the chat with the following token: {token}")
19+
20+
agent = fishjam_client.create_agent(room.id)
21+
async with (
22+
agent.connect() as fishjam_session,
23+
await poet_runner.run() as openai_session,
24+
):
25+
track = await fishjam_session.add_track(
26+
AudioTrackOptions(sample_rate=24000, metadata={"type": "microphone"})
27+
)
28+
29+
async def _openai_recv():
30+
msg = ""
31+
async for event in openai_session:
32+
if event.type == "audio":
33+
audio = event.audio.data
34+
await track.send_chunk(audio)
35+
elif event.type == "raw_model_event":
36+
if event.data.type == "input_audio_transcription_completed":
37+
print(f"Peer said:\n{event.data.transcript}\n")
38+
elif event.data.type == "transcript_delta":
39+
msg += event.data.delta
40+
elif event.data.type == "turn_ended":
41+
print(f"Agent said:\n{msg}\n")
42+
msg = ""
43+
44+
async def _fishjam_recv():
45+
async for event in fishjam_session.receive():
46+
await openai_session.send_audio(event.data)
47+
48+
async with asyncio.TaskGroup() as tg:
49+
tg.create_task(make_notifier(openai_session).connect())
50+
tg.create_task(_openai_recv())
51+
tg.create_task(_fishjam_recv())
52+
53+
54+
if __name__ == "__main__":
55+
asyncio.run(main())

examples/poet_chat/poet_chat/__init__.py

Whitespace-only changes.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
from agents.realtime import RealtimeAgent, RealtimeRunner
2+
3+
from poet_chat.config import OPENAI_INSTRUCTIONS
4+
5+
poet = RealtimeAgent(name="Poet", instructions=OPENAI_INSTRUCTIONS)
6+
poet_runner = RealtimeRunner(
7+
starting_agent=poet,
8+
config={
9+
"model_settings": {
10+
"voice": "alloy",
11+
"modalities": ["audio", "text"],
12+
"input_audio_format": "pcm16",
13+
"output_audio_format": "pcm16",
14+
"turn_detection": {
15+
"interrupt_response": True,
16+
"create_response": True,
17+
},
18+
}
19+
},
20+
)
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import os
2+
from pathlib import Path
3+
4+
from fishjam import FishjamClient, PeerOptions
5+
from fishjam.peer import SubscribeOptions, SubscribeOptionsAudioSampleRate
6+
7+
FISHJAM_ID = os.environ["FISHJAM_ID"]
8+
FISHJAM_TOKEN = os.environ["FISHJAM_MANAGEMENT_TOKEN"]
9+
FISHJAM_URL = os.getenv("FISHJAM_URL")
10+
11+
PEER_OPTIONS = PeerOptions(
12+
subscribe=SubscribeOptions(
13+
audio_sample_rate=SubscribeOptionsAudioSampleRate.VALUE_24000
14+
)
15+
)
16+
17+
OPENAI_MODEL = "gpt-realtime"
18+
19+
PROMPT_DIR = Path(__file__).parents[1] / "prompts"
20+
21+
INSTRUCTION_PATH = PROMPT_DIR / "instructions.md"
22+
GREET_PATH = PROMPT_DIR / "greet.md"
23+
24+
with open(INSTRUCTION_PATH) as prompt:
25+
OPENAI_INSTRUCTIONS = prompt.read()
26+
27+
with open(GREET_PATH) as prompt:
28+
OPENAI_GREET = prompt.read()
29+
30+
fishjam_client = FishjamClient(FISHJAM_ID, FISHJAM_TOKEN, fishjam_url=FISHJAM_URL)
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
from agents.realtime import RealtimeSession
2+
3+
from fishjam import FishjamNotifier
4+
from fishjam.events import (
5+
ServerMessagePeerConnected,
6+
ServerMessagePeerType,
7+
)
8+
from fishjam.events.allowed_notifications import AllowedNotification
9+
10+
from .config import FISHJAM_ID, FISHJAM_TOKEN, FISHJAM_URL, OPENAI_GREET
11+
12+
13+
def make_notifier(poet: RealtimeSession) -> FishjamNotifier:
14+
notifier = FishjamNotifier(FISHJAM_ID, FISHJAM_TOKEN, fishjam_url=FISHJAM_URL)
15+
16+
@notifier.on_server_notification
17+
async def _(notification: AllowedNotification):
18+
match notification:
19+
case ServerMessagePeerConnected(
20+
peer_type=ServerMessagePeerType.PEER_TYPE_WEBRTC,
21+
):
22+
await handle_peer_connected()
23+
24+
async def handle_peer_connected():
25+
await poet.send_message(OPENAI_GREET)
26+
27+
return notifier
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
**Objective:** Welcome users to the real-time limerick generation experience by introducing yourself as their poetic guide and requesting a list of words for personalized poetry creation.
2+
3+
**Instructions:**
4+
5+
1. **Introduction:**
6+
7+
- Begin with a warm and engaging introduction, presenting yourself as a creative and friendly poet eager to craft delightful limericks.
8+
- Briefly explain the purpose of the session: to create fun and custom limericks based on the user's input.
9+
10+
2. **Request for Words:**
11+
12+
- Invite the user to share a list of words that capture their current mood, interests, or thoughts triggered by listening to the audio.
13+
- Encourage them to be imaginative and creative in their word selection to make the limerick more personalized and engaging.
14+
15+
3. **Set Expectations:**
16+
- Assure the user that each limerick will be crafted uniquely with their provided words, promising a lighthearted and entertaining poetic experience.
17+
- Mention the traditional limerick structure (AABBA) that will guide the creation process.
18+
19+
By following these instructions, create a welcoming and interactive atmosphere that encourages user participation and sets the stage for crafting personalized limericks.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
**Objective:** Craft limericks in real-time, using input audio clips or live audio feeds to prompt user interaction. The generated poetry should be based solely on a list of words provided by the user in response to the audio.
2+
3+
**Instructions:**
4+
5+
1. **User Interaction:**
6+
7+
- Prompt the user to listen to the audio and provide a list of words that capture their response or impression from it.
8+
9+
2. **Limerick Construction:**
10+
11+
- Use the user-provided list of words to guide the theme and imagery of the limerick.
12+
- Ensure the limerick adheres to the traditional AABBA rhyme scheme and rhythm, typically with lines 1, 2, and 5 containing three metrical feet and lines 3 and 4 containing two metrical feet.
13+
- Creativity is key—incorporate humor or cleverness where possible to enhance the impact.
14+
15+
3. **Language and Performance:**
16+
- Ensure all poetry is crafted and recited in English.
17+
- Use expressive language to vividly depict themes inspired by the provided words, aiming to entertain and engage the listener.
18+
19+
By following these instructions, generate limericks that transform user-provided words inspired by audio inputs into lively and entertaining poetic pieces.

examples/poet_chat/pyproject.toml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
[project]
2+
name = "poet_chat"
3+
version = "0.1.0"
4+
description = "Fishjam voice agent example"
5+
readme = "README.md"
6+
requires-python = ">=3.11"
7+
dependencies = [
8+
"fishjam-server-sdk",
9+
"litestar[standard]>=2.17.0",
10+
"openai-agents[voice]>=0.2.11",
11+
]
12+
13+
[tool.uv.sources]
14+
fishjam-server-sdk = { workspace = true }

examples/transcription/.python-version

Lines changed: 0 additions & 1 deletion
This file was deleted.

0 commit comments

Comments
 (0)