First_agent_template / tools /dialog_handler.py
kumar4372's picture
openai key
3696fe2
import typing
from tools import nlu_tool, scheduler, requests_store
from app import propose_slots, notify_operator
import yaml
import os
PROMPTS_PATH = 'prompts.yaml'
def _load_prompts():
with open(PROMPTS_PATH, 'r') as f:
txt = f.read()
# If file contains a fenced code block (```yaml ... ```), strip fences
stripped = txt
lines = txt.splitlines()
if lines and lines[0].strip().startswith("```") and lines[-1].strip().startswith("```"):
stripped = "\n".join(lines[1:-1])
data = yaml.safe_load(stripped)
# recursively search for collection_assistant
def find_collection(obj):
if isinstance(obj, dict):
if 'collection_assistant' in obj:
return obj['collection_assistant']
for v in obj.values():
found = find_collection(v)
if found is not None:
return found
elif isinstance(obj, list):
for item in obj:
found = find_collection(item)
if found is not None:
return found
return None
found = find_collection(data)
if found is not None:
# If the value is a YAML block string (from |-) parse it into a dict
if isinstance(found, str):
try:
inner = yaml.safe_load(found)
if isinstance(inner, dict):
return inner
except Exception:
pass
return found
raise KeyError('collection_assistant')
def handle_message(message: str, context: dict = None) -> dict:
"""High-level handler that accepts a user message and performs:
- NLU (intent + slots)
- Minimal slot-filling for payment_commitment
- Confirmation and request creation
- Scheduling flow for human-operator requests
Returns a dict with response text and any created request record.
"""
prompts = _load_prompts()
nlu = nlu_tool.extract_intent_and_slots(message)
intent = nlu.get('intent')
slots = nlu.get('slots', {})
response = ""
created = None
if intent == 'payment_commitment':
# find payment_commitment intent meta
slot_meta = next((x for x in prompts.get('intents', []) if x.get('name') == 'payment_commitment'), None)
# ensure required slots: customer_name, account_number, amount, date_by_when
missing = []
for s in ['customer_name', 'account_number', 'amount', 'date_by_when']:
if s not in slots or not slots[s]:
missing.append(s)
if missing:
# return prompt for the first missing slot (simple)
if slot_meta:
slot_prompt = next((x.get('prompt') for x in slot_meta.get('slots', []) if x.get('id') == missing[0]), None)
response = slot_prompt or f"Please provide {missing[0]}"
else:
response = f"Please provide {missing[0]}"
return {'response': response, 'request': None}
# All required slots present -> confirm and create request
tpl = slot_meta.get('confirmation_template') if slot_meta else "Thank you. I recorded your commitment."
response = tpl.format(customer_name=slots.get('customer_name', '[unknown]'), account_number=slots.get('account_number', '[unknown]'), amount=slots.get('amount'), date_by_when=slots.get('date_by_when'))
handoff_tpl = slot_meta.get('handoff_payload_template') if slot_meta else None
if handoff_tpl:
handoff_json = handoff_tpl.format(customer_name=slots.get('customer_name', ''), account_number=slots.get('account_number', ''), amount=slots.get('amount', ''), date_by_when=slots.get('date_by_when', ''), contact_preference=slots.get('contact_preference', ''), nlu_confidence=nlu.get('nlu_confidence', 0))
else:
handoff_json = str({'type': 'payment_commitment', 'slots': slots})
# persist
created = requests_store.create_request({'raw_payload': handoff_json})
# notify operator stub
notify_operator(f"HANDOFF: {handoff_json}")
return {'response': response, 'request': created}
if intent == 'request_human_operator':
# find intent meta
req_meta = next((x for x in prompts.get('intents', []) if x.get('name') == 'request_human_operator'), None)
preferred = []
if 'preferred_windows' in slots and slots['preferred_windows']:
preferred = [{'start': slots['preferred_windows'], 'end': slots['preferred_windows']}]
candidates = propose_slots(preferred)
if req_meta:
response = req_meta.get('propose_slots_template', '').format(slot1_local=candidates[0] if len(candidates) > 0 else '', slot2_local=candidates[1] if len(candidates) > 1 else '', slot3_local=candidates[2] if len(candidates) > 2 else '')
else:
response = f"I can connect you at: {', '.join(candidates)}"
return {'response': response, 'request': None}
# fallback
response = prompts.get('behaviors', {}).get('fallback', {}).get('prompt', "I didn't understand. Can you rephrase?")
if not response:
response = "I didn't understand. Can you rephrase?"
return {'response': response, 'request': None}