-
Notifications
You must be signed in to change notification settings - Fork 1
Add limerick example #41
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 13 commits
Commits
Show all changes
16 commits
Select commit
Hold shift + click to select a range
523cbaa
Add limerick example
AHGIJMKLKKZNPJKQR 1b5ed20
Remove redundant var
AHGIJMKLKKZNPJKQR 3ec40d1
Add interruptions to agents and update poet example
AHGIJMKLKKZNPJKQR 2d00723
Update dockerfile
AHGIJMKLKKZNPJKQR a4efe9e
Update dockerfile
AHGIJMKLKKZNPJKQR 8541b3a
Update openapi
AHGIJMKLKKZNPJKQR eab3dc1
Update tests
AHGIJMKLKKZNPJKQR f19ed00
Update README
AHGIJMKLKKZNPJKQR aba61b9
Remove litestar from deps
AHGIJMKLKKZNPJKQR a673ac8
Fix readme format
AHGIJMKLKKZNPJKQR 986a1be
Fix typo in README
AHGIJMKLKKZNPJKQR 8afac4b
Handle OpenAI errors
AHGIJMKLKKZNPJKQR 899c5bb
Print raw OpenAI server errors
AHGIJMKLKKZNPJKQR 88a6119
Remove errors
AHGIJMKLKKZNPJKQR 629aec7
Use dotenv
AHGIJMKLKKZNPJKQR f14e480
Make note more clear
AHGIJMKLKKZNPJKQR File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| # Limerick Poet demo | ||
|
|
||
| This directory contains an example implementation of a real-time chat agent using the [Fishjam](https://fishjam.io) and [OpenAI Agents](https://github.com/openai/openai-agents-python) Python SDKs. | ||
|
|
||
| The agent introduces itself when the user joins and creates limericks based on what the user says. | ||
| The agent handles interruptions from users to ensure a natural conversation flow. | ||
|
|
||
| ## Running | ||
|
|
||
| > [!IMPORTANT] | ||
| > All commands should be run from the parent directory of this README | ||
AHGIJMKLKKZNPJKQR marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| Make sure to [install uv](https://docs.astral.sh/uv/getting-started/installation/) if you don't have it already. | ||
| Once you have `uv` installed, fetch the dependencies with | ||
|
|
||
| ```bash | ||
| uv sync | ||
| ``` | ||
|
|
||
| To run the app, you will need 3 environment variables: | ||
|
|
||
| - `FISHJAM_ID`: Your Fishjam ID, which you can get on the [Fishjam website](https://fishjam.io/app) | ||
| - `FISHJAM_MANAGEMENT_TOKEN`: Your Fishjam management token, which you can get on the [Fishjam website](https://fishjam.io/app) | ||
| - `OPENAI_API_KEY`: An API key for the OpenAI Realtime API. You can generate one on the [OpenAI website](https://platform.openai.com/api-keys). | ||
|
|
||
| Once you have these variables, you can run the demo with | ||
|
|
||
| ```bash | ||
| FISHJAM_ID=<your-fishjam-id> \ | ||
| FISHJAM_MANAGEMENT_TOKEN=<your-management-token> \ | ||
| OPENAI_API_KEY=<your-api-token> \ | ||
| uv run ./main.py | ||
| ``` | ||
|
|
||
| A peer token should be generated and printed to standard output. | ||
| You can then use the [minimal-react](https://github.com/fishjam-cloud/web-client-sdk/tree/main/examples/react-client) | ||
| demo app to connect with this token and talk with the agent! | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,67 @@ | ||
| import asyncio | ||
|
|
||
| from poet_chat.agent import poet_runner | ||
| from poet_chat.config import ( | ||
| AGENT_OPTIONS, | ||
| fishjam_client, | ||
| ) | ||
| from poet_chat.notifier import make_notifier | ||
|
|
||
| from fishjam.agent import OutgoingAudioTrackOptions | ||
|
|
||
|
|
||
| async def main(): | ||
| room = fishjam_client.create_room() | ||
| _, token = fishjam_client.create_peer(room.id) | ||
| print(f"Join the chat with the following token: {token}") | ||
|
|
||
| agent = fishjam_client.create_agent(room.id, AGENT_OPTIONS) | ||
| async with ( | ||
| agent.connect() as fishjam_session, | ||
| await poet_runner.run() as openai_session, | ||
| ): | ||
| track = await fishjam_session.add_track( | ||
| OutgoingAudioTrackOptions( | ||
| sample_rate=24000, metadata={"type": "microphone"} | ||
| ) | ||
| ) | ||
|
|
||
| async def _openai_recv(): | ||
| msg = "" | ||
| async for event in openai_session: | ||
| if event.type == "audio": | ||
| audio = event.audio.data | ||
| await track.send_chunk(audio) | ||
| elif event.type == "audio_interrupted": | ||
| await track.interrupt() | ||
| elif event.type == "raw_model_event": | ||
| if event.data.type == "input_audio_transcription_completed": | ||
| print(f"Peer said:\n{event.data.transcript}\n") | ||
| elif event.data.type == "transcript_delta": | ||
| msg += event.data.delta | ||
| elif event.data.type == "turn_ended": | ||
| print(f"Agent said:\n{msg}\n") | ||
| msg = "" | ||
| elif event.data.type == "error": | ||
| print(event.data.error) | ||
| raise RuntimeError("Unexpected error from OpenAI API!") | ||
| elif event.data.type == "exception": | ||
| raise event.data.exception | ||
| elif event.data.type == "raw_server_event": | ||
| match event.data.data: | ||
| case {"response": {"status": "failed"}}: | ||
| print(event.data.data) | ||
| raise RuntimeError("Raw server error from OpenAI API!") | ||
|
|
||
| async def _fishjam_recv(): | ||
| async for event in fishjam_session.receive(): | ||
| await openai_session.send_audio(event.data) | ||
|
|
||
| async with asyncio.TaskGroup() as tg: | ||
| tg.create_task(make_notifier(openai_session).connect()) | ||
| tg.create_task(_openai_recv()) | ||
| tg.create_task(_fishjam_recv()) | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| asyncio.run(main()) |
Empty file.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| from agents.realtime import RealtimeAgent, RealtimeRunner | ||
|
|
||
| from poet_chat.config import OPENAI_INSTRUCTIONS | ||
|
|
||
| poet = RealtimeAgent(name="Poet", instructions=OPENAI_INSTRUCTIONS) | ||
| poet_runner = RealtimeRunner( | ||
| starting_agent=poet, | ||
| config={ | ||
| "model_settings": { | ||
| "voice": "alloy", | ||
| "modalities": ["audio", "text"], | ||
| "input_audio_format": "pcm16", | ||
| "output_audio_format": "pcm16", | ||
| "turn_detection": { | ||
| "interrupt_response": True, | ||
| "create_response": True, | ||
| "type": "semantic_vad", | ||
| }, | ||
| } | ||
| }, | ||
| ) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| import os | ||
| from pathlib import Path | ||
|
|
||
| from fishjam import AgentOptions, AgentOutputOptions, FishjamClient | ||
|
|
||
| FISHJAM_ID = os.environ["FISHJAM_ID"] | ||
AHGIJMKLKKZNPJKQR marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| FISHJAM_TOKEN = os.environ["FISHJAM_MANAGEMENT_TOKEN"] | ||
| FISHJAM_URL = os.getenv("FISHJAM_URL") | ||
|
|
||
| AGENT_OPTIONS = AgentOptions(output=AgentOutputOptions(audio_sample_rate=24000)) | ||
|
|
||
| OPENAI_MODEL = "gpt-realtime" | ||
|
|
||
| PROMPT_DIR = Path(__file__).parents[1] / "prompts" | ||
|
|
||
| INSTRUCTION_PATH = PROMPT_DIR / "instructions.md" | ||
| GREET_PATH = PROMPT_DIR / "greet.md" | ||
|
|
||
| with open(INSTRUCTION_PATH) as prompt: | ||
| OPENAI_INSTRUCTIONS = prompt.read() | ||
|
|
||
| with open(GREET_PATH) as prompt: | ||
| OPENAI_GREET = prompt.read() | ||
|
|
||
| fishjam_client = FishjamClient(FISHJAM_ID, FISHJAM_TOKEN, fishjam_url=FISHJAM_URL) | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| from agents.realtime import RealtimeSession | ||
|
|
||
| from fishjam import FishjamNotifier | ||
| from fishjam.events import ( | ||
| ServerMessagePeerConnected, | ||
| ServerMessagePeerType, | ||
| ) | ||
| from fishjam.events.allowed_notifications import AllowedNotification | ||
|
|
||
| from .config import FISHJAM_ID, FISHJAM_TOKEN, FISHJAM_URL, OPENAI_GREET | ||
|
|
||
|
|
||
| def make_notifier(poet: RealtimeSession) -> FishjamNotifier: | ||
| notifier = FishjamNotifier(FISHJAM_ID, FISHJAM_TOKEN, fishjam_url=FISHJAM_URL) | ||
|
|
||
| @notifier.on_server_notification | ||
| async def _(notification: AllowedNotification): | ||
| match notification: | ||
| case ServerMessagePeerConnected( | ||
| peer_type=ServerMessagePeerType.PEER_TYPE_WEBRTC, | ||
| ): | ||
| await handle_peer_connected() | ||
|
|
||
| async def handle_peer_connected(): | ||
| await poet.send_message(OPENAI_GREET) | ||
|
|
||
| return notifier |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| **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. | ||
|
|
||
| **Instructions:** | ||
|
|
||
| 1. **Introduction:** | ||
|
|
||
| - Begin with a warm and engaging introduction, presenting yourself as a creative and friendly poet eager to craft delightful limericks. | ||
AHGIJMKLKKZNPJKQR marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| - Briefly explain the purpose of the session: to create fun and custom limericks based on the user's input. | ||
|
|
||
| 2. **Request for Words:** | ||
|
|
||
| - Invite the user to share a list of words that capture their current mood, interests, or thoughts triggered by listening to the audio. | ||
| - Encourage them to be imaginative and creative in their word selection to make the limerick more personalized and engaging. | ||
|
|
||
| 3. **Set Expectations:** | ||
| - Assure the user that each limerick will be crafted uniquely with their provided words, promising a lighthearted and entertaining poetic experience. | ||
| - Mention the traditional limerick structure (AABBA) that will guide the creation process. | ||
|
|
||
| By following these instructions, create a welcoming and interactive atmosphere that encourages user participation and sets the stage for crafting personalized limericks. | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| **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. | ||
|
|
||
| **Instructions:** | ||
|
|
||
| 1. **User Interaction:** | ||
|
|
||
| - Prompt the user to listen to the audio and provide a list of words that capture their response or impression from it. | ||
|
|
||
| 2. **Limerick Construction:** | ||
|
|
||
| - Use the user-provided list of words to guide the theme and imagery of the limerick. | ||
| - 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. | ||
| - Creativity is key—incorporate humor or cleverness where possible to enhance the impact. | ||
|
|
||
| 3. **Language and Performance:** | ||
| - Ensure all poetry is crafted and recited in English. | ||
| - Use expressive language to vividly depict themes inspired by the provided words, aiming to entertain and engage the listener. | ||
|
|
||
| By following these instructions, generate limericks that transform user-provided words inspired by audio inputs into lively and entertaining poetic pieces. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| [project] | ||
| name = "poet_chat" | ||
| version = "0.1.0" | ||
| description = "Fishjam voice agent example" | ||
| readme = "README.md" | ||
| requires-python = ">=3.11" | ||
| dependencies = ["fishjam-server-sdk", "openai-agents[voice]>=0.2.11"] | ||
|
|
||
| [tool.uv.sources] | ||
| fishjam-server-sdk = { workspace = true } |
This file was deleted.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.