soprano-sdk 0.2.15__tar.gz → 0.2.17__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/PKG-INFO +1 -1
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/examples/concert_booking/concert_ticket_booking.yaml +30 -6
- soprano_sdk-0.2.17/examples/concert_booking/concert_tools.py +253 -0
- soprano_sdk-0.2.17/examples/concert_booking/example_runner.py +602 -0
- soprano_sdk-0.2.17/examples/concert_booking/tool.py +330 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/pyproject.toml +1 -1
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/soprano_sdk/agents/adaptor.py +56 -10
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/soprano_sdk/agents/factory.py +88 -19
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/soprano_sdk/authenticators/mfa.py +42 -39
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/soprano_sdk/validation/schema.py +1 -1
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/soprano_sdk/validation/validator.py +0 -4
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/.github/workflows/test_build_and_publish.yaml +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/.gitignore +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/.python-version +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/CLAUDE.md +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/LICENSE +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/README.md +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/examples/concert_booking/__init__.py +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/examples/concert_booking/booking_helpers.py +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/examples/framework_example.yaml +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/examples/greeting_functions.py +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/examples/greeting_workflow.yaml +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/examples/main.py +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/examples/payment_async_functions.py +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/examples/payment_async_workflow.yaml +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/examples/persistence/README.md +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/examples/persistence/conversation_based.py +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/examples/persistence/entity_based.py +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/examples/persistence/mongodb_demo.py +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/examples/return_functions.py +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/examples/return_workflow.yaml +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/examples/structured_output_example.yaml +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/examples/supervisors/README.md +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/examples/supervisors/crewai_supervisor_ui.py +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/examples/supervisors/langgraph_supervisor_ui.py +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/examples/supervisors/tools/__init__.py +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/examples/supervisors/tools/crewai_tools.py +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/examples/supervisors/tools/langgraph_tools.py +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/examples/supervisors/workflow_tools.py +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/examples/test_payment_async.py +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/examples/tools/__init__.py +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/examples/tools/address.py +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/examples/validator.py +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/legacy/langgraph_demo.py +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/legacy/langgraph_selfloop_demo.py +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/legacy/langgraph_v.py +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/legacy/main.py +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/legacy/return_fsm.excalidraw +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/legacy/return_state_machine.png +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/legacy/ui.py +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/scripts/visualize_workflow.py +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/scripts/workflow_demo.py +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/scripts/workflow_demo_ui.py +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/soprano_sdk/__init__.py +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/soprano_sdk/agents/__init__.py +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/soprano_sdk/agents/structured_output.py +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/soprano_sdk/authenticators/__init__.py +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/soprano_sdk/core/__init__.py +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/soprano_sdk/core/constants.py +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/soprano_sdk/core/engine.py +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/soprano_sdk/core/rollback_strategies.py +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/soprano_sdk/core/state.py +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/soprano_sdk/engine.py +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/soprano_sdk/nodes/__init__.py +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/soprano_sdk/nodes/async_function.py +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/soprano_sdk/nodes/base.py +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/soprano_sdk/nodes/call_function.py +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/soprano_sdk/nodes/collect_input.py +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/soprano_sdk/nodes/factory.py +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/soprano_sdk/routing/__init__.py +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/soprano_sdk/routing/router.py +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/soprano_sdk/tools.py +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/soprano_sdk/utils/__init__.py +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/soprano_sdk/utils/function.py +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/soprano_sdk/utils/logger.py +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/soprano_sdk/utils/template.py +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/soprano_sdk/utils/tool.py +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/soprano_sdk/utils/tracing.py +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/soprano_sdk/validation/__init__.py +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/tests/debug_jinja2.py +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/tests/test_adaptor_logging.py +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/tests/test_agent_factory.py +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/tests/test_async_function.py +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/tests/test_collect_input_refactor.py +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/tests/test_external_values.py +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/tests/test_inputs_validation.py +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/tests/test_jinja2_path.py +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/tests/test_jinja2_standalone.py +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/tests/test_mfa_scenarios.py +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/tests/test_persistence.py +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/tests/test_structured_output.py +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/tests/test_transition_routing.py +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/tests/test_workflow_tool_context_update.py +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/todo.md +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/workflow-visualizer/.eslintrc.cjs +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/workflow-visualizer/.gitignore +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/workflow-visualizer/README.md +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/workflow-visualizer/index.html +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/workflow-visualizer/package-lock.json +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/workflow-visualizer/package.json +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/workflow-visualizer/src/App.jsx +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/workflow-visualizer/src/CustomNode.jsx +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/workflow-visualizer/src/StepDetailsModal.jsx +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/workflow-visualizer/src/WorkflowGraph.jsx +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/workflow-visualizer/src/WorkflowInfoPanel.jsx +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/workflow-visualizer/src/assets/react.svg +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/workflow-visualizer/src/main.jsx +0 -0
- {soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/workflow-visualizer/vite.config.js +0 -0
{soprano_sdk-0.2.15 → soprano_sdk-0.2.17}/examples/concert_booking/concert_ticket_booking.yaml
RENAMED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
name: Concert Ticket Booking
|
|
2
2
|
description: Manages concert ticket booking with seat selection, payment processing, and confirmation
|
|
3
3
|
version: '1.0.0'
|
|
4
|
+
agent_framework: "crewai"
|
|
4
5
|
|
|
5
6
|
data:
|
|
6
7
|
- name: bearer_token
|
|
@@ -58,7 +59,6 @@ steps:
|
|
|
58
59
|
max_attempts: 3
|
|
59
60
|
agent:
|
|
60
61
|
name: Customer Name Collector
|
|
61
|
-
model: gpt-4o-mini
|
|
62
62
|
initial_message: "Welcome to Concert Ticket Booking! Please provide your full name."
|
|
63
63
|
instructions: >
|
|
64
64
|
Extract the customer's full name from their message.
|
|
@@ -76,11 +76,19 @@ steps:
|
|
|
76
76
|
max_attempts: 3
|
|
77
77
|
agent:
|
|
78
78
|
name: Concert Details Collector
|
|
79
|
-
model: gpt-4o-mini
|
|
80
79
|
initial_message: "Hi {{customer_name}}! Which concert would you like to attend? Please specify the concert name."
|
|
81
80
|
instructions: >
|
|
82
81
|
Extract concert name from the user's message.
|
|
82
|
+
|
|
83
|
+
IMPORTANT: Use the available tools to help the user:
|
|
84
|
+
- check_concert_availability: Check if a concert is available and get details
|
|
85
|
+
- search_venue_info: Get venue information
|
|
86
|
+
|
|
87
|
+
When user mentions a concert, check its availability first before proceeding.
|
|
83
88
|
Return: CONCERT_CAPTURED: [concert_name] or CANCEL_REQUEST:
|
|
89
|
+
tools:
|
|
90
|
+
- check_concert_availability
|
|
91
|
+
- search_venue_info
|
|
84
92
|
transitions:
|
|
85
93
|
- next: collect_seat_preference
|
|
86
94
|
pattern: "CONCERT_CAPTURED:"
|
|
@@ -116,11 +124,16 @@ steps:
|
|
|
116
124
|
max_attempts: 3
|
|
117
125
|
agent:
|
|
118
126
|
name: Ticket Quantity Collector
|
|
119
|
-
model: gpt-4o-mini
|
|
120
127
|
initial_message: "How many {{seat_preference}} tickets would you like to book? (Maximum 8 per booking)"
|
|
121
128
|
instructions: >
|
|
122
129
|
Extract the number of tickets (1-8).
|
|
130
|
+
|
|
131
|
+
IMPORTANT: Use the calculate_total_price tool to show the user the total cost
|
|
132
|
+
when they specify a quantity. This helps them make an informed decision.
|
|
133
|
+
|
|
123
134
|
Return: QUANTITY_CAPTURED: [ticket_quantity] or INVALID_QUANTITY:
|
|
135
|
+
tools:
|
|
136
|
+
- calculate_total_price
|
|
124
137
|
transitions:
|
|
125
138
|
- next: check_seat_availability
|
|
126
139
|
pattern: "QUANTITY_CAPTURED:"
|
|
@@ -145,7 +158,6 @@ steps:
|
|
|
145
158
|
max_attempts: 3
|
|
146
159
|
agent:
|
|
147
160
|
name: Alternative Seat Offer
|
|
148
|
-
model: gpt-4o-mini
|
|
149
161
|
initial_message: >
|
|
150
162
|
Sorry {{customer_name}}, {{seat_preference}} seats are not available for {{concert_name}}.
|
|
151
163
|
Would you like to try a different section?
|
|
@@ -187,7 +199,6 @@ steps:
|
|
|
187
199
|
function: booking_helpers.send_confirmation
|
|
188
200
|
output: confirmation_sent
|
|
189
201
|
mfa:
|
|
190
|
-
model: gpt-4o-mini
|
|
191
202
|
type: REST
|
|
192
203
|
payload:
|
|
193
204
|
transactionType: SEND_TICKET_CONFIRMATION
|
|
@@ -203,7 +214,6 @@ steps:
|
|
|
203
214
|
max_attempts: 3
|
|
204
215
|
agent:
|
|
205
216
|
name: Modification Request Collector
|
|
206
|
-
model: gpt-4o-mini
|
|
207
217
|
initial_message: >
|
|
208
218
|
Booking confirmed for {{concert_name}}, {{customer_name}}!
|
|
209
219
|
Reference: {{booking_reference}}
|
|
@@ -242,3 +252,17 @@ outcomes:
|
|
|
242
252
|
- id: payment_failed
|
|
243
253
|
type: failure
|
|
244
254
|
message: "Payment failed. Please check your payment method and try again."
|
|
255
|
+
|
|
256
|
+
tool_config:
|
|
257
|
+
tools:
|
|
258
|
+
- name: check_concert_availability
|
|
259
|
+
description: Check if a concert is available for booking with dates and pricing
|
|
260
|
+
callable: concert_tools.check_concert_availability
|
|
261
|
+
|
|
262
|
+
- name: calculate_total_price
|
|
263
|
+
description: Calculate the total price for concert tickets with discounts
|
|
264
|
+
callable: concert_tools.calculate_total_price
|
|
265
|
+
|
|
266
|
+
- name: search_venue_info
|
|
267
|
+
description: Get detailed information about a concert venue
|
|
268
|
+
callable: concert_tools.search_venue_info
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Concert booking tool functions for agent use
|
|
3
|
+
These functions are exposed as tools to AI agents in the workflow
|
|
4
|
+
"""
|
|
5
|
+
from typing import Annotated, Any
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def check_concert_availability(
|
|
9
|
+
concert_name: Annotated[str, "Name of the concert to check availability for"],
|
|
10
|
+
**state: Any
|
|
11
|
+
) -> str:
|
|
12
|
+
"""
|
|
13
|
+
Check if a concert is available for booking with dates and pricing.
|
|
14
|
+
|
|
15
|
+
Args:
|
|
16
|
+
concert_name: Name of the concert to check
|
|
17
|
+
|
|
18
|
+
Returns:
|
|
19
|
+
String with concert availability details including dates and venue
|
|
20
|
+
"""
|
|
21
|
+
# Mock concert database
|
|
22
|
+
concerts = {
|
|
23
|
+
"Coldplay": {
|
|
24
|
+
"available": True,
|
|
25
|
+
"venue": "DY Patil Stadium, Mumbai",
|
|
26
|
+
"date": "2026-03-15",
|
|
27
|
+
"seats_left": 5000,
|
|
28
|
+
"genres": ["Rock", "Pop"]
|
|
29
|
+
},
|
|
30
|
+
"AR Rahman": {
|
|
31
|
+
"available": True,
|
|
32
|
+
"venue": "Jawaharlal Nehru Stadium, Delhi",
|
|
33
|
+
"date": "2026-04-20",
|
|
34
|
+
"seats_left": 3500,
|
|
35
|
+
"genres": ["Classical", "Bollywood"]
|
|
36
|
+
},
|
|
37
|
+
"Ed Sheeran": {
|
|
38
|
+
"available": True,
|
|
39
|
+
"venue": "Phoenix Marketcity, Chennai",
|
|
40
|
+
"date": "2026-05-10",
|
|
41
|
+
"seats_left": 2000,
|
|
42
|
+
"genres": ["Pop", "Folk"]
|
|
43
|
+
},
|
|
44
|
+
"Arijit Singh": {
|
|
45
|
+
"available": True,
|
|
46
|
+
"venue": "MMRDA Grounds, Mumbai",
|
|
47
|
+
"date": "2026-06-05",
|
|
48
|
+
"seats_left": 8000,
|
|
49
|
+
"genres": ["Bollywood", "Romantic"]
|
|
50
|
+
},
|
|
51
|
+
"Imagine Dragons": {
|
|
52
|
+
"available": False,
|
|
53
|
+
"venue": "Bangalore Palace Grounds",
|
|
54
|
+
"date": "2026-02-28",
|
|
55
|
+
"seats_left": 0,
|
|
56
|
+
"genres": ["Rock", "Alternative"]
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
# Check if concert exists
|
|
61
|
+
concert_name_normalized = concert_name.strip()
|
|
62
|
+
|
|
63
|
+
# Try exact match first
|
|
64
|
+
concert_info = concerts.get(concert_name_normalized)
|
|
65
|
+
|
|
66
|
+
# Try case-insensitive match
|
|
67
|
+
if not concert_info:
|
|
68
|
+
for name, info in concerts.items():
|
|
69
|
+
if name.lower() == concert_name_normalized.lower():
|
|
70
|
+
concert_info = info
|
|
71
|
+
concert_name_normalized = name
|
|
72
|
+
break
|
|
73
|
+
|
|
74
|
+
if not concert_info:
|
|
75
|
+
# Concert not found
|
|
76
|
+
available_concerts = ", ".join(concerts.keys())
|
|
77
|
+
return f"Sorry, '{concert_name}' is not in our system. Available concerts: {available_concerts}"
|
|
78
|
+
|
|
79
|
+
# Return availability information
|
|
80
|
+
if concert_info["available"]:
|
|
81
|
+
return (
|
|
82
|
+
f"✓ {concert_name_normalized} is AVAILABLE!\n"
|
|
83
|
+
f"Venue: {concert_info['venue']}\n"
|
|
84
|
+
f"Date: {concert_info['date']}\n"
|
|
85
|
+
f"Seats Available: {concert_info['seats_left']}\n"
|
|
86
|
+
f"Genres: {', '.join(concert_info['genres'])}"
|
|
87
|
+
)
|
|
88
|
+
else:
|
|
89
|
+
return (
|
|
90
|
+
f"✗ {concert_name_normalized} is SOLD OUT\n"
|
|
91
|
+
f"Venue: {concert_info['venue']}\n"
|
|
92
|
+
f"Original Date: {concert_info['date']}\n"
|
|
93
|
+
f"Check back later for additional dates!"
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def calculate_total_price(
|
|
98
|
+
seat_preference: Annotated[str, "Seating section (VIP, Premium, or General)"],
|
|
99
|
+
ticket_quantity: Annotated[int, "Number of tickets to purchase"],
|
|
100
|
+
vip_price: Annotated[float, "Price per VIP ticket"],
|
|
101
|
+
premium_price: Annotated[float, "Price per Premium ticket"],
|
|
102
|
+
general_price: Annotated[float, "Price per General ticket"],
|
|
103
|
+
**state: Any
|
|
104
|
+
|
|
105
|
+
) -> str:
|
|
106
|
+
"""
|
|
107
|
+
Calculate the total price for concert tickets with discounts.
|
|
108
|
+
|
|
109
|
+
Args:
|
|
110
|
+
seat_preference: Seating section (VIP, Premium, General)
|
|
111
|
+
ticket_quantity: Number of tickets
|
|
112
|
+
vip_price: Price per VIP ticket
|
|
113
|
+
premium_price: Price per Premium ticket
|
|
114
|
+
general_price: Price per General ticket
|
|
115
|
+
|
|
116
|
+
Returns:
|
|
117
|
+
String with price breakdown and total
|
|
118
|
+
"""
|
|
119
|
+
# Normalize seat preference
|
|
120
|
+
seat_preference = seat_preference.strip().title()
|
|
121
|
+
|
|
122
|
+
# Map seat preference to price
|
|
123
|
+
prices = {
|
|
124
|
+
'VIP': vip_price,
|
|
125
|
+
'Vip': vip_price,
|
|
126
|
+
'Premium': premium_price,
|
|
127
|
+
'General': general_price
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
price_per_ticket = prices.get(seat_preference, general_price)
|
|
131
|
+
subtotal = price_per_ticket * ticket_quantity
|
|
132
|
+
|
|
133
|
+
# Apply discounts based on quantity
|
|
134
|
+
discount = 0
|
|
135
|
+
discount_percent = 0
|
|
136
|
+
|
|
137
|
+
if ticket_quantity >= 5:
|
|
138
|
+
discount_percent = 10
|
|
139
|
+
discount = subtotal * 0.10
|
|
140
|
+
elif ticket_quantity >= 3:
|
|
141
|
+
discount_percent = 5
|
|
142
|
+
discount = subtotal * 0.05
|
|
143
|
+
|
|
144
|
+
total = subtotal - discount
|
|
145
|
+
|
|
146
|
+
# Build response
|
|
147
|
+
response = "💰 Price Breakdown:\n"
|
|
148
|
+
response += f" Seat Type: {seat_preference}\n"
|
|
149
|
+
response += f" Price per ticket: ₹{price_per_ticket:,.0f}\n"
|
|
150
|
+
response += f" Quantity: {ticket_quantity}\n"
|
|
151
|
+
response += f" Subtotal: ₹{subtotal:,.0f}\n"
|
|
152
|
+
|
|
153
|
+
if discount > 0:
|
|
154
|
+
response += f" Discount ({discount_percent}%): -₹{discount:,.0f}\n"
|
|
155
|
+
response += " ──────────────────\n"
|
|
156
|
+
response += f" TOTAL: ₹{total:,.0f} ✨"
|
|
157
|
+
else:
|
|
158
|
+
response += " ──────────────────\n"
|
|
159
|
+
response += f" TOTAL: ₹{total:,.0f}"
|
|
160
|
+
|
|
161
|
+
# Add discount tip if applicable
|
|
162
|
+
if ticket_quantity < 3:
|
|
163
|
+
response += "\n\n💡 Tip: Book 3+ tickets for 5% off, or 5+ for 10% off!"
|
|
164
|
+
|
|
165
|
+
return response
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def search_venue_info(
|
|
169
|
+
venue_name: Annotated[str, "Name of the venue to search for"],
|
|
170
|
+
**state: Any
|
|
171
|
+
) -> str:
|
|
172
|
+
"""
|
|
173
|
+
Get detailed information about a concert venue.
|
|
174
|
+
|
|
175
|
+
Args:
|
|
176
|
+
venue_name: Name or partial name of the venue
|
|
177
|
+
|
|
178
|
+
Returns:
|
|
179
|
+
String with venue details including capacity, location, and facilities
|
|
180
|
+
"""
|
|
181
|
+
# Mock venue database
|
|
182
|
+
venues = {
|
|
183
|
+
"DY Patil Stadium": {
|
|
184
|
+
"full_name": "DY Patil Stadium",
|
|
185
|
+
"location": "Navi Mumbai, Maharashtra",
|
|
186
|
+
"capacity": 55000,
|
|
187
|
+
"facilities": ["Parking", "Food Courts", "VIP Lounges", "Wheelchair Access"],
|
|
188
|
+
"transport": "Metro: Nerul Station (3km), Bus routes available",
|
|
189
|
+
"website": "www.dypstadium.com"
|
|
190
|
+
},
|
|
191
|
+
"Jawaharlal Nehru Stadium": {
|
|
192
|
+
"full_name": "Jawaharlal Nehru Stadium",
|
|
193
|
+
"location": "Delhi",
|
|
194
|
+
"capacity": 60000,
|
|
195
|
+
"facilities": ["Parking", "Metro Connectivity", "Multiple Entry Gates", "Food Stalls"],
|
|
196
|
+
"transport": "Metro: Jawaharlal Nehru Stadium (direct), Well connected by roads",
|
|
197
|
+
"website": "www.jnstadium.in"
|
|
198
|
+
},
|
|
199
|
+
"Phoenix Marketcity": {
|
|
200
|
+
"full_name": "Phoenix Marketcity Arena",
|
|
201
|
+
"location": "Chennai, Tamil Nadu",
|
|
202
|
+
"capacity": 15000,
|
|
203
|
+
"facilities": ["Mall Complex", "Restaurants", "Parking", "AC Indoor Arena"],
|
|
204
|
+
"transport": "Bus: Multiple routes, Taxi/App cabs recommended",
|
|
205
|
+
"website": "www.phoenixmarketcity.com"
|
|
206
|
+
},
|
|
207
|
+
"MMRDA Grounds": {
|
|
208
|
+
"full_name": "MMRDA Grounds (Bandra-Kurla Complex)",
|
|
209
|
+
"location": "Mumbai, Maharashtra",
|
|
210
|
+
"capacity": 45000,
|
|
211
|
+
"facilities": ["Open Air Venue", "Multiple Stages", "Food Trucks", "Parking"],
|
|
212
|
+
"transport": "Metro: BKC Station (walkable), Well connected by roads",
|
|
213
|
+
"website": "www.mmrdagrounds.com"
|
|
214
|
+
},
|
|
215
|
+
"Bangalore Palace Grounds": {
|
|
216
|
+
"full_name": "Bangalore Palace Grounds",
|
|
217
|
+
"location": "Bangalore, Karnataka",
|
|
218
|
+
"capacity": 50000,
|
|
219
|
+
"facilities": ["Historic Venue", "Spacious Grounds", "Parking", "Food Courts"],
|
|
220
|
+
"transport": "Metro: Sampige Road (2km), Easily accessible by cab",
|
|
221
|
+
"website": "www.bangalorepalace.gov.in"
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
# Normalize search query
|
|
226
|
+
venue_name_normalized = venue_name.strip()
|
|
227
|
+
|
|
228
|
+
# Try exact match
|
|
229
|
+
venue_info = venues.get(venue_name_normalized)
|
|
230
|
+
|
|
231
|
+
# Try case-insensitive partial match
|
|
232
|
+
if not venue_info:
|
|
233
|
+
for name, info in venues.items():
|
|
234
|
+
if venue_name_normalized.lower() in name.lower():
|
|
235
|
+
venue_info = info
|
|
236
|
+
break
|
|
237
|
+
|
|
238
|
+
if not venue_info:
|
|
239
|
+
# Venue not found
|
|
240
|
+
available_venues = ", ".join(venues.keys())
|
|
241
|
+
return f"Venue '{venue_name}' not found. Available venues: {available_venues}"
|
|
242
|
+
|
|
243
|
+
# Build detailed response
|
|
244
|
+
response = f"📍 {venue_info['full_name']}\n\n"
|
|
245
|
+
response += f"Location: {venue_info['location']}\n"
|
|
246
|
+
response += f"Capacity: {venue_info['capacity']:,} people\n\n"
|
|
247
|
+
response += "Facilities:\n"
|
|
248
|
+
for facility in venue_info['facilities']:
|
|
249
|
+
response += f" • {facility}\n"
|
|
250
|
+
response += f"\nTransport: {venue_info['transport']}\n"
|
|
251
|
+
response += f"Website: {venue_info['website']}"
|
|
252
|
+
|
|
253
|
+
return response
|