Compare commits
2 Commits
mb/update-
...
mb/update-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
755b019b9f | ||
|
|
fd46a545b6 |
@@ -12,15 +12,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- Added a new RTVI message called `disconnect-bot`, which when handled pushes
|
||||
an `EndFrame` to trigger the pipeline to stop.
|
||||
|
||||
- Added support for the new Pipecat Flows package (pipecat-ai-flows). Learn
|
||||
- Added support for the new Pipecat Flows package (`pipecat-ai-flows`). Learn
|
||||
more at: https://github.com/pipecat-ai/pipecat-flows.
|
||||
|
||||
- Added foundational example `25-conversation-flow.py` showing how to use
|
||||
Pipecat Flows.
|
||||
- Added three Pipecat Flows foundational examples: `25a-flow-food-ordering.py`,
|
||||
`25b-flow-movie-booking.py`, and `25c-flow-travel-planner.py`.
|
||||
|
||||
### Changed
|
||||
|
||||
- Expanded the transcriptions.language module to support a superset of
|
||||
- Expanded the `transcriptions.language` module to support a superset of
|
||||
languages.
|
||||
|
||||
- Updated STT and TTS services with language options that match the supported
|
||||
|
||||
@@ -28,7 +28,7 @@ load_dotenv(override=True)
|
||||
logger.remove(0)
|
||||
logger.add(sys.stderr, level="DEBUG")
|
||||
|
||||
# Flow Configuration
|
||||
# Flow Configuration - Food ordering
|
||||
#
|
||||
# This configuration defines a simple food ordering system with the following states:
|
||||
#
|
||||
@@ -64,7 +64,7 @@ flow_config = {
|
||||
"messages": [
|
||||
{
|
||||
"role": "system",
|
||||
"content": "You are an order-taking assistant. You must ALWAYS use one of the available functions to progress the conversation. For this step, ask the user if they want pizza or sushi, and wait for them to use a function to choose. Start off by greeting them. Be friendly and casual; you're taking an order for food over the phone.",
|
||||
"content": "For this step, ask the user if they want pizza or sushi, and wait for them to use a function to choose. Start off by greeting them. Be friendly and casual; you're taking an order for food over the phone.",
|
||||
}
|
||||
],
|
||||
"functions": [
|
||||
@@ -90,15 +90,7 @@ flow_config = {
|
||||
"messages": [
|
||||
{
|
||||
"role": "system",
|
||||
"content": """You are handling a pizza order. Use the available functions:
|
||||
- Use select_pizza_size when the user specifies a size (can be used multiple times if they change their mind)
|
||||
- Use the end function ONLY when the user confirms they are done with their order
|
||||
|
||||
After each size selection, confirm the selection and ask if they want to change it or complete their order.
|
||||
Only use the end function after the user confirms they are satisfied with their order.
|
||||
|
||||
Start off by acknowledging the user's choice. Once they've chosen a size, ask if they'd like anything else.
|
||||
Remember to be friendly and casual.""",
|
||||
"content": "You are handling a pizza order. Use the available functions:\n - Use select_pizza_size when the user specifies a size (can be used multiple times if they change their mind or want to order multiple pizzas)\n - Use the end function ONLY when the user confirms they are done with their order\n\nAfter each size selection, confirm the selection and ask if they want to change it or complete their order. Only use the end function after the user confirms they are satisfied with their order.\n\nStart off by acknowledging the user's choice. Once they've chosen a size, ask if they'd like anything else. Remember to be friendly and casual.",
|
||||
}
|
||||
],
|
||||
"functions": [
|
||||
@@ -137,15 +129,7 @@ flow_config = {
|
||||
"messages": [
|
||||
{
|
||||
"role": "system",
|
||||
"content": """You are handling a sushi order. Use the available functions:
|
||||
- Use select_roll_count when the user specifies how many rolls (can be used multiple times if they change their mind)
|
||||
- Use the end function ONLY when the user confirms they are done with their order
|
||||
|
||||
After each roll count selection, confirm the count and ask if they want to change it or complete their order.
|
||||
Only use the end function after the user confirms they are satisfied with their order.
|
||||
|
||||
Start off by acknowledging the user's choice. Once they've chosen a size, ask if they'd like anything else.
|
||||
Remember to be friendly and casual.""",
|
||||
"content": "You are handling a sushi order. Use the available functions:\n - Use select_roll_count when the user specifies how many rolls (can be used multiple times if they change their mind or if they want to order multiple sushi rolls)\n - Use the end function ONLY when the user confirms they are done with their order\n\nAfter each roll count selection, confirm the count and ask if they want to change it or complete their order. Only use the end function after the user confirms they are satisfied with their order.\n\nStart off by acknowledging the user's choice. Once they've chosen a size, ask if they'd like anything else. Remember to be friendly and casual.",
|
||||
}
|
||||
],
|
||||
"functions": [
|
||||
@@ -214,7 +198,7 @@ async def main():
|
||||
|
||||
stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY"))
|
||||
tts = DeepgramTTSService(api_key=os.getenv("DEEPGRAM_API_KEY"), voice="aura-helios-en")
|
||||
llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4")
|
||||
llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4o")
|
||||
|
||||
# Get initial tools from the first node
|
||||
initial_tools = flow_config["nodes"]["start"]["functions"]
|
||||
@@ -223,7 +207,7 @@ async def main():
|
||||
messages = [
|
||||
{
|
||||
"role": "system",
|
||||
"content": "You are an order-taking assistant. You must ALWAYS use the available functions to progress the conversation. Never assume an order is complete without the proper function calls. Your responses will be converted to audio so avoid special characters.",
|
||||
"content": "You are an order-taking assistant. You must ALWAYS use the available functions to progress the conversation. This is a phone conversations and your responses will be converted to audio. Avoid outputting special characters and emojis.",
|
||||
}
|
||||
]
|
||||
|
||||
297
examples/foundational/25b-flow-movie-booking.py
Normal file
297
examples/foundational/25b-flow-movie-booking.py
Normal file
@@ -0,0 +1,297 @@
|
||||
#
|
||||
# Copyright (c) 2024, Daily
|
||||
#
|
||||
# SPDX-License-Identifier: BSD 2-Clause License
|
||||
#
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
import sys
|
||||
|
||||
import aiohttp
|
||||
from dotenv import load_dotenv
|
||||
from loguru import logger
|
||||
from pipecat_flows import FlowManager
|
||||
from runner import configure
|
||||
|
||||
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
||||
from pipecat.pipeline.pipeline import Pipeline
|
||||
from pipecat.pipeline.runner import PipelineRunner
|
||||
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
||||
from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContext
|
||||
from pipecat.services.deepgram import DeepgramSTTService, DeepgramTTSService
|
||||
from pipecat.services.openai import OpenAILLMService
|
||||
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
||||
|
||||
load_dotenv(override=True)
|
||||
|
||||
logger.remove(0)
|
||||
logger.add(sys.stderr, level="DEBUG")
|
||||
|
||||
# Flow Configuration - Movie Booking
|
||||
#
|
||||
# This configuration defines a movie ticket booking system with the following states:
|
||||
#
|
||||
# 1. start
|
||||
# - Initial state where user chooses between today or tomorrow's showings
|
||||
# - Functions: check_today, check_tomorrow
|
||||
# - Pre-action: Welcome message
|
||||
# - Transitions to: check_today or check_tomorrow
|
||||
#
|
||||
# 2. check_today
|
||||
# - Handles movie selection for today's showings
|
||||
# - Functions:
|
||||
# * select_movie (terminal function with today's movies)
|
||||
# * select_showtime (terminal function with available times)
|
||||
# * end (transitions to end node after confirmation)
|
||||
# - Pre-action: Today's movie listing message
|
||||
#
|
||||
# 3. check_tomorrow
|
||||
# - Handles movie selection for tomorrow's showings
|
||||
# - Functions:
|
||||
# * select_movie (terminal function with tomorrow's movies)
|
||||
# * select_showtime (terminal function with available times)
|
||||
# * end (transitions to end node after confirmation)
|
||||
# - Pre-action: Tomorrow's movie listing message
|
||||
#
|
||||
# 4. end
|
||||
# - Final state that closes the conversation
|
||||
# - No functions available
|
||||
# - Pre-action: Ticket confirmation message
|
||||
# - Post-action: Ends conversation
|
||||
#
|
||||
# Note: Both check_today and check_tomorrow allow multiple selections
|
||||
# until the user confirms their final choice
|
||||
|
||||
flow_config = {
|
||||
"initial_node": "start",
|
||||
"nodes": {
|
||||
"start": {
|
||||
"messages": [
|
||||
{
|
||||
"role": "system",
|
||||
"content": "For this step, ask if they want to see what's playing today or tomorrow, and wait for them to choose. Start with a warm greeting and be helpful and enthusiastic; you're helping them plan their entertainment.",
|
||||
}
|
||||
],
|
||||
"functions": [
|
||||
{
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "check_today",
|
||||
"description": "User wants to see today's movies",
|
||||
"parameters": {"type": "object", "properties": {}},
|
||||
},
|
||||
},
|
||||
{
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "check_tomorrow",
|
||||
"description": "User wants to see tomorrow's movies",
|
||||
"parameters": {"type": "object", "properties": {}},
|
||||
},
|
||||
},
|
||||
],
|
||||
"pre_actions": [
|
||||
{
|
||||
"type": "tts_say",
|
||||
"text": "Welcome to MoviePlex! Let me help you book some tickets.",
|
||||
}
|
||||
],
|
||||
},
|
||||
"check_today": {
|
||||
"messages": [
|
||||
{
|
||||
"role": "system",
|
||||
"content": "You are handling today's movie selection. Use the available functions:\n - Use select_movie when the user chooses a movie (can be used multiple times if they change their mind)\n - Use select_showtime after they've chosen a movie to pick their preferred time\n - Use the end function ONLY when the user confirms their final selection\n\nAfter each selection, confirm their choice and ask about the next step. Remember to be enthusiastic and helpful.\n\nStart by telling them today's available movies: 'Jurassic Park' at 3:00 PM and 7:00 PM, or 'The Matrix' at 4:00 PM and 8:00 PM.",
|
||||
}
|
||||
],
|
||||
"functions": [
|
||||
{
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "select_movie",
|
||||
"description": "Record the selected movie",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"movie": {
|
||||
"type": "string",
|
||||
"enum": ["Jurassic Park", "The Matrix"],
|
||||
"description": "Selected movie",
|
||||
}
|
||||
},
|
||||
"required": ["movie"],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "select_showtime",
|
||||
"description": "Record the selected showtime",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"time": {
|
||||
"type": "string",
|
||||
"enum": ["3:00 PM", "4:00 PM", "7:00 PM", "8:00 PM"],
|
||||
"description": "Selected showtime",
|
||||
}
|
||||
},
|
||||
"required": ["time"],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "end",
|
||||
"description": "Complete the booking (use only after user confirms)",
|
||||
"parameters": {"type": "object", "properties": {}},
|
||||
},
|
||||
},
|
||||
],
|
||||
"pre_actions": [{"type": "tts_say", "text": "Let me show you what's playing today..."}],
|
||||
},
|
||||
"check_tomorrow": {
|
||||
"messages": [
|
||||
{
|
||||
"role": "system",
|
||||
"content": "You are handling tomorrow's movie selection. Use the available functions:\n - Use select_movie when the user chooses a movie (can be used multiple times if they change their mind)\n - Use select_showtime after they've chosen a movie to pick their preferred time\n - Use the end function ONLY when the user confirms their final selection\n\nAfter each selection, confirm their choice and ask about the next step. Remember to be enthusiastic and helpful.\n\nStart by telling them tomorrow's available movies: 'The Lion King' at 2:00 PM and 6:00 PM, or 'Inception' at 3:00 PM and 7:00 PM.",
|
||||
}
|
||||
],
|
||||
"functions": [
|
||||
{
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "select_movie",
|
||||
"description": "Record the selected movie",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"movie": {
|
||||
"type": "string",
|
||||
"enum": ["The Lion King", "Inception"],
|
||||
"description": "Selected movie",
|
||||
}
|
||||
},
|
||||
"required": ["movie"],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "select_showtime",
|
||||
"description": "Record the selected showtime",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"time": {
|
||||
"type": "string",
|
||||
"enum": ["2:00 PM", "3:00 PM", "6:00 PM", "7:00 PM"],
|
||||
"description": "Selected showtime",
|
||||
}
|
||||
},
|
||||
"required": ["time"],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "end",
|
||||
"description": "Complete the booking (use only after user confirms)",
|
||||
"parameters": {"type": "object", "properties": {}},
|
||||
},
|
||||
},
|
||||
],
|
||||
"pre_actions": [
|
||||
{"type": "tts_say", "text": "Let me show you what's playing tomorrow..."}
|
||||
],
|
||||
},
|
||||
"end": {
|
||||
"messages": [
|
||||
{
|
||||
"role": "system",
|
||||
"content": "The booking is complete. Thank the user enthusiastically and end the conversation.",
|
||||
}
|
||||
],
|
||||
"functions": [],
|
||||
"pre_actions": [
|
||||
{"type": "tts_say", "text": "Your tickets are confirmed! Enjoy the show!"}
|
||||
],
|
||||
"post_actions": [{"type": "end_conversation"}],
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
async def main():
|
||||
async with aiohttp.ClientSession() as session:
|
||||
(room_url, _) = await configure(session)
|
||||
|
||||
transport = DailyTransport(
|
||||
room_url,
|
||||
None,
|
||||
"Respond bot",
|
||||
DailyParams(
|
||||
audio_out_enabled=True,
|
||||
vad_enabled=True,
|
||||
vad_analyzer=SileroVADAnalyzer(),
|
||||
vad_audio_passthrough=True,
|
||||
),
|
||||
)
|
||||
|
||||
stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY"))
|
||||
tts = DeepgramTTSService(api_key=os.getenv("DEEPGRAM_API_KEY"), voice="aura-helios-en")
|
||||
llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4o")
|
||||
|
||||
# Get initial tools from the first node
|
||||
initial_tools = flow_config["nodes"]["start"]["functions"]
|
||||
|
||||
# Create initial context
|
||||
messages = [
|
||||
{
|
||||
"role": "system",
|
||||
"content": "You are a movie ticket booking assistant. You must ALWAYS use one of the available functions to progress the conversation. This is a phone conversations and your responses will be converted to audio. Avoid outputting special characters and emojis.",
|
||||
}
|
||||
]
|
||||
|
||||
context = OpenAILLMContext(messages, initial_tools)
|
||||
context_aggregator = llm.create_context_aggregator(context)
|
||||
|
||||
pipeline = Pipeline(
|
||||
[
|
||||
transport.input(), # Transport user input
|
||||
stt, # STT
|
||||
context_aggregator.user(), # User responses
|
||||
llm, # LLM
|
||||
tts, # TTS
|
||||
transport.output(), # Transport bot output
|
||||
context_aggregator.assistant(), # Assistant spoken responses
|
||||
]
|
||||
)
|
||||
|
||||
task = PipelineTask(pipeline, PipelineParams(allow_interruptions=True))
|
||||
|
||||
# Initialize flow manager
|
||||
flow_manager = FlowManager(flow_config, task, tts)
|
||||
|
||||
# Register functions with LLM service
|
||||
await flow_manager.register_functions(llm)
|
||||
|
||||
@transport.event_handler("on_first_participant_joined")
|
||||
async def on_first_participant_joined(transport, participant):
|
||||
await transport.capture_participant_transcription(participant["id"])
|
||||
# Initialize the flow processor
|
||||
await flow_manager.initialize(messages)
|
||||
# Kick off the conversation using the context aggregator
|
||||
await task.queue_frames([context_aggregator.user().get_context_frame()])
|
||||
|
||||
runner = PipelineRunner()
|
||||
await runner.run(task)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
396
examples/foundational/25c-flow-travel-planner.py
Normal file
396
examples/foundational/25c-flow-travel-planner.py
Normal file
@@ -0,0 +1,396 @@
|
||||
#
|
||||
# Copyright (c) 2024, Daily
|
||||
#
|
||||
# SPDX-License-Identifier: BSD 2-Clause License
|
||||
#
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
import sys
|
||||
|
||||
import aiohttp
|
||||
from dotenv import load_dotenv
|
||||
from loguru import logger
|
||||
from pipecat_flows import FlowManager
|
||||
from runner import configure
|
||||
|
||||
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
||||
from pipecat.pipeline.pipeline import Pipeline
|
||||
from pipecat.pipeline.runner import PipelineRunner
|
||||
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
||||
from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContext
|
||||
from pipecat.services.deepgram import DeepgramSTTService, DeepgramTTSService
|
||||
from pipecat.services.openai import OpenAILLMService
|
||||
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
||||
|
||||
load_dotenv(override=True)
|
||||
|
||||
logger.remove(0)
|
||||
logger.add(sys.stderr, level="DEBUG")
|
||||
|
||||
# Flow Configuration - Travel Planner
|
||||
#
|
||||
# This configuration defines a vacation planning system with the following states:
|
||||
#
|
||||
# 1. start
|
||||
# - Initial state where user chooses between beach or mountain vacation
|
||||
# - Functions: choose_beach, choose_mountain
|
||||
# - Pre-action: Welcome message
|
||||
# - Transitions to: choose_beach or choose_mountain
|
||||
#
|
||||
# 2. choose_beach/choose_mountain
|
||||
# - Handles destination selection for chosen vacation type
|
||||
# - Functions:
|
||||
# * select_destination (terminal function with location-specific options)
|
||||
# * get_dates (transitions to date selection)
|
||||
# - Pre-action: Destination-specific welcome message
|
||||
#
|
||||
# 3. get_dates
|
||||
# - Handles travel date selection
|
||||
# - Functions:
|
||||
# * record_dates (terminal function, can be modified)
|
||||
# * get_activities (transitions to activity selection)
|
||||
#
|
||||
# 4. get_activities
|
||||
# - Handles activity preference selection
|
||||
# - Functions:
|
||||
# * record_activities (terminal function, array-based selection)
|
||||
# * verify_itinerary (transitions to verification)
|
||||
#
|
||||
# 5. verify_itinerary
|
||||
# - Reviews complete vacation plan
|
||||
# - Functions:
|
||||
# * revise_plan (loops back to get_dates)
|
||||
# * confirm_booking (transitions to confirmation)
|
||||
#
|
||||
# 6. confirm_booking
|
||||
# - Handles final confirmation and tips
|
||||
# - Functions: end
|
||||
# - Pre-action: Confirmation message
|
||||
#
|
||||
# 7. end
|
||||
# - Final state that closes the conversation
|
||||
# - No functions available
|
||||
# - Post-action: Ends conversation
|
||||
|
||||
flow_config = {
|
||||
"initial_node": "start",
|
||||
"nodes": {
|
||||
"start": {
|
||||
"messages": [
|
||||
{
|
||||
"role": "system",
|
||||
"content": "For this step, ask if they're interested in planning a beach vacation or a mountain retreat, and wait for them to choose. Start with an enthusiastic greeting and be conversational; you're helping them plan their dream vacation.",
|
||||
}
|
||||
],
|
||||
"functions": [
|
||||
{
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "choose_beach",
|
||||
"description": "User wants to plan a beach vacation",
|
||||
"parameters": {"type": "object", "properties": {}},
|
||||
},
|
||||
},
|
||||
{
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "choose_mountain",
|
||||
"description": "User wants to plan a mountain retreat",
|
||||
"parameters": {"type": "object", "properties": {}},
|
||||
},
|
||||
},
|
||||
],
|
||||
"pre_actions": [
|
||||
{
|
||||
"type": "tts_say",
|
||||
"text": "Welcome to Dream Vacations! I'll help you plan your perfect getaway.",
|
||||
}
|
||||
],
|
||||
},
|
||||
"choose_beach": {
|
||||
"messages": [
|
||||
{
|
||||
"role": "system",
|
||||
"content": "You are handling beach vacation planning. Use the available functions:\n - Use select_destination when the user chooses their preferred beach location\n - Use get_dates once they've selected a destination\n\nAvailable beach destinations are: 'Maui', 'Cancun', or 'Maldives'. After they choose, confirm their selection and proceed to dates. Be enthusiastic and paint a picture of each destination.",
|
||||
}
|
||||
],
|
||||
"functions": [
|
||||
{
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "select_destination",
|
||||
"description": "Record the selected beach destination",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"destination": {
|
||||
"type": "string",
|
||||
"enum": ["Maui", "Cancun", "Maldives"],
|
||||
"description": "Selected beach destination",
|
||||
}
|
||||
},
|
||||
"required": ["destination"],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "get_dates",
|
||||
"description": "Proceed to date selection",
|
||||
"parameters": {"type": "object", "properties": {}},
|
||||
},
|
||||
},
|
||||
],
|
||||
"pre_actions": [
|
||||
{"type": "tts_say", "text": "Let's find your perfect beach paradise..."}
|
||||
],
|
||||
},
|
||||
"choose_mountain": {
|
||||
"messages": [
|
||||
{
|
||||
"role": "system",
|
||||
"content": "You are handling mountain retreat planning. Use the available functions:\n - Use select_destination when the user chooses their preferred mountain location\n - Use get_dates once they've selected a destination\n\nAvailable mountain destinations are: 'Swiss Alps', 'Rocky Mountains', or 'Himalayas'. After they choose, confirm their selection and proceed to dates. Be enthusiastic and paint a picture of each destination.",
|
||||
}
|
||||
],
|
||||
"functions": [
|
||||
{
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "select_destination",
|
||||
"description": "Record the selected mountain destination",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"destination": {
|
||||
"type": "string",
|
||||
"enum": ["Swiss Alps", "Rocky Mountains", "Himalayas"],
|
||||
"description": "Selected mountain destination",
|
||||
}
|
||||
},
|
||||
"required": ["destination"],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "get_dates",
|
||||
"description": "Proceed to date selection",
|
||||
"parameters": {"type": "object", "properties": {}},
|
||||
},
|
||||
},
|
||||
],
|
||||
"pre_actions": [
|
||||
{"type": "tts_say", "text": "Let's find your perfect mountain getaway..."}
|
||||
],
|
||||
},
|
||||
"get_dates": {
|
||||
"messages": [
|
||||
{
|
||||
"role": "system",
|
||||
"content": "Handle travel date selection. Use the available functions:\n - Use record_dates when the user specifies their travel dates (can be used multiple times if they change their mind)\n - Use get_activities once dates are confirmed\n\nAsk for their preferred travel dates within the next 6 months. After recording dates, confirm the selection and proceed to activities.",
|
||||
}
|
||||
],
|
||||
"functions": [
|
||||
{
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "record_dates",
|
||||
"description": "Record the selected travel dates",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"check_in": {
|
||||
"type": "string",
|
||||
"format": "date",
|
||||
"description": "Check-in date (YYYY-MM-DD)",
|
||||
},
|
||||
"check_out": {
|
||||
"type": "string",
|
||||
"format": "date",
|
||||
"description": "Check-out date (YYYY-MM-DD)",
|
||||
},
|
||||
},
|
||||
"required": ["check_in", "check_out"],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "get_activities",
|
||||
"description": "Proceed to activity selection",
|
||||
"parameters": {"type": "object", "properties": {}},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
"get_activities": {
|
||||
"messages": [
|
||||
{
|
||||
"role": "system",
|
||||
"content": "Handle activity preferences. Use the available functions:\n - Use record_activities to save their activity preferences\n - Use verify_itinerary once activities are selected\n\nFor beach destinations, suggest: snorkeling, surfing, sunset cruise\nFor mountain destinations, suggest: hiking, skiing, mountain biking\n\nAfter they choose, confirm their selections and proceed to verification.",
|
||||
}
|
||||
],
|
||||
"functions": [
|
||||
{
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "record_activities",
|
||||
"description": "Record selected activities",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"activities": {
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"minItems": 1,
|
||||
"maxItems": 3,
|
||||
"description": "Selected activities",
|
||||
}
|
||||
},
|
||||
"required": ["activities"],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "verify_itinerary",
|
||||
"description": "Proceed to itinerary verification",
|
||||
"parameters": {"type": "object", "properties": {}},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
"verify_itinerary": {
|
||||
"messages": [
|
||||
{
|
||||
"role": "system",
|
||||
"content": "Review the complete itinerary with the user. Summarize their destination, dates, and chosen activities. Use the available functions:\n - Use get_dates if they want to make changes\n - Use confirm_booking if they're happy with everything\n\nBe thorough in reviewing all details and ask for their confirmation.",
|
||||
}
|
||||
],
|
||||
"functions": [
|
||||
{
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "get_dates",
|
||||
"description": "Return to date selection to revise the plan",
|
||||
"parameters": {"type": "object", "properties": {}},
|
||||
},
|
||||
},
|
||||
{
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "confirm_booking",
|
||||
"description": "Confirm the booking and proceed to end",
|
||||
"parameters": {"type": "object", "properties": {}},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
"confirm_booking": {
|
||||
"messages": [
|
||||
{
|
||||
"role": "system",
|
||||
"content": "The booking is confirmed. Share some relevant tips about their chosen destination, thank them warmly, and use end to complete the conversation.",
|
||||
}
|
||||
],
|
||||
"functions": [
|
||||
{
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "end",
|
||||
"description": "End the conversation",
|
||||
"parameters": {"type": "object", "properties": {}},
|
||||
},
|
||||
}
|
||||
],
|
||||
"pre_actions": [
|
||||
{"type": "tts_say", "text": "Fantastic! Your dream vacation is confirmed!"}
|
||||
],
|
||||
},
|
||||
"end": {
|
||||
"messages": [
|
||||
{
|
||||
"role": "system",
|
||||
"content": "Wish them a wonderful trip and end the conversation.",
|
||||
}
|
||||
],
|
||||
"functions": [],
|
||||
"post_actions": [{"type": "end_conversation"}],
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
async def main():
|
||||
async with aiohttp.ClientSession() as session:
|
||||
(room_url, _) = await configure(session)
|
||||
|
||||
transport = DailyTransport(
|
||||
room_url,
|
||||
None,
|
||||
"Respond bot",
|
||||
DailyParams(
|
||||
audio_out_enabled=True,
|
||||
vad_enabled=True,
|
||||
vad_analyzer=SileroVADAnalyzer(),
|
||||
vad_audio_passthrough=True,
|
||||
),
|
||||
)
|
||||
|
||||
stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY"))
|
||||
tts = DeepgramTTSService(api_key=os.getenv("DEEPGRAM_API_KEY"), voice="aura-helios-en")
|
||||
llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4o")
|
||||
|
||||
# Get initial tools from the first node
|
||||
initial_tools = flow_config["nodes"]["start"]["functions"]
|
||||
|
||||
# Create initial context
|
||||
messages = [
|
||||
{
|
||||
"role": "system",
|
||||
"content": "You are a travel planning assistant. You must ALWAYS use one of the available functions to progress the conversation. This is a phone conversations and your responses will be converted to audio. Avoid outputting special characters and emojis.",
|
||||
}
|
||||
]
|
||||
|
||||
context = OpenAILLMContext(messages, initial_tools)
|
||||
context_aggregator = llm.create_context_aggregator(context)
|
||||
|
||||
pipeline = Pipeline(
|
||||
[
|
||||
transport.input(), # Transport user input
|
||||
stt, # STT
|
||||
context_aggregator.user(), # User responses
|
||||
llm, # LLM
|
||||
tts, # TTS
|
||||
transport.output(), # Transport bot output
|
||||
context_aggregator.assistant(), # Assistant spoken responses
|
||||
]
|
||||
)
|
||||
|
||||
task = PipelineTask(pipeline, PipelineParams(allow_interruptions=True))
|
||||
|
||||
# Initialize flow manager
|
||||
flow_manager = FlowManager(flow_config, task, tts)
|
||||
|
||||
# Register functions with LLM service
|
||||
await flow_manager.register_functions(llm)
|
||||
|
||||
@transport.event_handler("on_first_participant_joined")
|
||||
async def on_first_participant_joined(transport, participant):
|
||||
await transport.capture_participant_transcription(participant["id"])
|
||||
# Initialize the flow processor
|
||||
await flow_manager.initialize(messages)
|
||||
# Kick off the conversation using the context aggregator
|
||||
await task.queue_frames([context_aggregator.user().get_context_frame()])
|
||||
|
||||
runner = PipelineRunner()
|
||||
await runner.run(task)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
Reference in New Issue
Block a user