Skip to content

Instantly share code, notes, and snippets.

@johnjosephhorton
Created October 21, 2025 19:33
Show Gist options
  • Save johnjosephhorton/eb427b494c7187b261461164b2fb12cd to your computer and use it in GitHub Desktop.
Save johnjosephhorton/eb427b494c7187b261461164b2fb12cd to your computer and use it in GitHub Desktop.
Analyze a customer call transcript, as macro
import textwrap
from edsl.agents import Agent
from edsl.questions import (
QuestionFreeText,
QuestionLinearScale,
QuestionMultipleChoice,
)
from edsl.surveys import Survey
from edsl.macros import Macro
from edsl.macros import OutputFormatter
# Initial survey to gather the transcript and optional parameters
initial_survey = Survey(
[
QuestionFreeText(
question_name="transcript",
question_text="Please provide the transcript of the customer call to analyze",
),
QuestionFreeText(
question_name="persona",
question_text="What persona should the reviewer have? (Leave blank for default: expert business development representative)",
),
]
)
# Create the evaluator questions with transcript in question text
q1 = QuestionMultipleChoice(
question_name="understanding",
question_text=textwrap.dedent(
"""\
You are being asked to review the following transcript of a business development call
between a representative and a potential customer and provide critical feedback.
Transcript:
{{ scenario.transcript }}
How would you rate the representative's understanding of the customer's needs?
"""
),
question_options=["Excellent", "Good", "Fair", "Poor"],
)
q2 = QuestionMultipleChoice(
question_name="explain_features",
question_text=textwrap.dedent(
"""\
Based on this transcript:
{{ scenario.transcript }}
How well did the representative explain the features relevant to the customer's business?
"""
),
question_options=["Very clearly", "Somewhat clearly", "Unclear", "Not explained"],
)
q3 = QuestionMultipleChoice(
question_name="address_concerns",
question_text=textwrap.dedent(
"""\
Based on this transcript:
{{ scenario.transcript }}
How well did the representative address the questions and concerns of the customer?
"""
),
question_options=[
"Very effectively",
"Mostly effectively",
"Somewhat effectively",
"Not effectively",
],
)
q4 = QuestionMultipleChoice(
question_name="product_knowledge",
question_text=textwrap.dedent(
"""\
Based on this transcript:
{{ scenario.transcript }}
How would you rate the representative's knowledge of the products and services discussed?
"""
),
question_options=["Excellent", "Good", "Fair", "Poor"],
)
q5 = QuestionMultipleChoice(
question_name="attentive",
question_text=textwrap.dedent(
"""\
Based on this transcript:
{{ scenario.transcript }}
Did the representative appear attentive to the customer's needs and concerns?
"""
),
question_options=[
"Very attentive",
"Mostly attentive",
"Somewhat attentive",
"Not attentive",
],
)
q6 = QuestionLinearScale(
question_name="likely_sale",
question_text=textwrap.dedent(
"""\
Based on this transcript:
{{ scenario.transcript }}
On a scale from 1 to 10, how likely is the customer to use the products and services discussed?
"""
),
question_options=[1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
)
q7 = QuestionMultipleChoice(
question_name="next_steps",
question_text=textwrap.dedent(
"""\
Based on this transcript:
{{ scenario.transcript }}
Did the representative offer relevant next steps for implementation or testing products?
"""
),
question_options=[
"Yes, very clear and actionable",
"Somewhat clear",
"Not clear",
"No next steps offered",
],
)
q8 = QuestionFreeText(
question_name="helpful_approaches",
question_text=textwrap.dedent(
"""\
Based on this transcript:
{{ scenario.transcript }}
What aspects of the representative's approach were most helpful to the customer?
"""
),
)
q9 = QuestionFreeText(
question_name="inadequate_explanation",
question_text=textwrap.dedent(
"""\
Based on this transcript:
{{ scenario.transcript }}
Were any features or details not adequately explained?
"""
),
)
q10 = QuestionFreeText(
question_name="improvements",
question_text=textwrap.dedent(
"""\
Based on this transcript:
{{ scenario.transcript }}
How could the representative have improved their explanation of the products?
"""
),
)
q11 = QuestionFreeText(
question_name="confusing",
question_text=textwrap.dedent(
"""\
Based on this transcript:
{{ scenario.transcript }}
Was there anything about the conversation that seemed unclear or confusing?
"""
),
)
q12 = QuestionFreeText(
question_name="confident",
question_text=textwrap.dedent(
"""\
Based on this transcript:
{{ scenario.transcript }}
What additional information could have helped the customer feel more confident in the representative's offerings?
"""
),
)
# Combine questions into a survey
evaluation_survey = Survey([q1, q2, q3, q4, q5, q6, q7, q8, q9, q10, q11, q12])
# Create the agent with expert persona
agent = Agent(
traits={
"persona": "You are an expert business development representative with many years of experience at diverse companies."
}
)
# Create jobs object
jobs_object = evaluation_survey.by(agent)
# Create output formatters
# Summary table with ratings
ratings_formatter = (
OutputFormatter(description="Ratings Summary", output_type="markdown")
.select(
"answer.understanding",
"answer.explain_features",
"answer.address_concerns",
"answer.product_knowledge",
"answer.attentive",
"answer.likely_sale",
"answer.next_steps",
)
.rename(
{
"answer.understanding": "Understanding of Customer Needs",
"answer.explain_features": "Feature Explanation Quality",
"answer.address_concerns": "Addressing Concerns",
"answer.product_knowledge": "Product Knowledge",
"answer.attentive": "Attentiveness",
"answer.likely_sale": "Likelihood of Sale (1-10)",
"answer.next_steps": "Next Steps Clarity",
}
)
.table()
)
# .flip()
# .to_string()
#)
# Detailed feedback
feedback_formatter = (
OutputFormatter(description="Detailed Feedback", output_type="markdown")
.select(
"answer.helpful_approaches",
"answer.inadequate_explanation",
"answer.improvements",
"answer.confusing",
"answer.confident",
)
.rename(
{
"answer.helpful_approaches": "Most Helpful Aspects",
"answer.inadequate_explanation": "Inadequately Explained Features",
"answer.improvements": "Improvement Suggestions",
"answer.confusing": "Unclear or Confusing Elements",
"answer.confident": "Additional Info Needed for Confidence",
}
)
.table(tablefmt="github")
.flip()
.to_string()
)
# Complete report combining both
complete_report_formatter = (
OutputFormatter(description="Complete Report", output_type="markdown")
.select(
"answer.understanding",
"answer.explain_features",
"answer.address_concerns",
"answer.product_knowledge",
"answer.attentive",
"answer.likely_sale",
"answer.next_steps",
"answer.helpful_approaches",
"answer.inadequate_explanation",
"answer.improvements",
"answer.confusing",
"answer.confident",
)
.rename(
{
"answer.understanding": "Understanding of Customer Needs",
"answer.explain_features": "Feature Explanation Quality",
"answer.address_concerns": "Addressing Concerns",
"answer.product_knowledge": "Product Knowledge",
"answer.attentive": "Attentiveness",
"answer.likely_sale": "Likelihood of Sale (1-10)",
"answer.next_steps": "Next Steps Clarity",
"answer.helpful_approaches": "Most Helpful Aspects",
"answer.inadequate_explanation": "Inadequately Explained Features",
"answer.improvements": "Improvement Suggestions",
"answer.confusing": "Unclear or Confusing Elements",
"answer.confident": "Additional Info Needed for Confidence",
}
)
.table(tablefmt="github")
.flip()
.to_string()
)
# Create the macro
macro = Macro(
application_name="analyze_customer_call",
display_name="Customer Call Analyzer",
short_description="Analyze and provide feedback on customer call transcripts.",
long_description=textwrap.dedent(
"""\
This application analyzes transcripts of customer calls (e.g., business development, sales, support)
and provides comprehensive feedback on the representative's performance.
The analysis covers multiple dimensions including:
- Understanding of customer needs
- Quality of feature explanations
- Effectiveness in addressing concerns
- Product knowledge demonstration
- Attentiveness to customer needs
- Likelihood of successful sale
- Clarity of next steps
It also provides detailed qualitative feedback on:
- What approaches were most helpful
- What was inadequately explained
- How the representative could improve
- What was unclear or confusing
- What additional information would build confidence
The reviewer can be customized with different personas (e.g., sales expert, technical expert, customer service expert).
"""
),
initial_survey=initial_survey,
jobs_object=jobs_object,
output_formatters={
"ratings": ratings_formatter,
"feedback": feedback_formatter,
"complete": complete_report_formatter,
},
default_formatter_name="complete",
)
if __name__ == "__main__":
# Example usage with a sample transcript
sample_transcript = """
Alex (Quick Representative):
Hi, Jamie! Thanks so much for taking the time to chat today. How's everything going with your website?
Jamie (Customer):
Hi, Alex. It's going okay, I think. We're getting some users, but honestly, I'm just trying to figure out the best way to manage payments. It's all new to me.
Alex:
Got it, no worries! Quick can really help simplify things for you. Our platform allows you to accept payments easily and has a subscription option, which I think you mentioned you were interested in, right?
Jamie:
Yeah, we're thinking about offering different subscription levels for our software, but I'm not sure how to set it all up. And we have some international users, so that's been a bit confusing too.
Alex:
Right, right. So, with Quick, you can definitely do subscriptions, and it handles multiple currencies, too. For example, if you have a customer in Europe, Quick can automatically handle the conversion. It's designed to make that part easy, so you don't need to worry too much about different currencies.
Jamie:
That sounds helpful. But I'm a bit concerned about the setup. I'm not a developer, so I'm worried this might be too complicated.
Alex:
Oh, yeah, I totally understand! Quick's setup is meant to be as easy as possible. We have plugins and a lot of guides to walk you through it. I'd say that most people get it up and running without too much trouble. And if you do need help, our support team is available.
Jamie:
Okay, that's a relief. I've heard some stories about people getting stuck for weeks with payment systems. I don't want that to happen.
Alex:
I get that completely. We try to make it as straightforward as possible. Also, if you're worried about fraud or security, Quick has a feature called Shield that helps detect fraud. It's built in, so it's automatically protecting you from day one.
Jamie:
Oh, that sounds good. I don't know much about fraud detection. Is it something I'd have to set up?
Alex:
Nope! Shield is on by default, so you don't have to configure anything special unless you want to. It uses machine learning to detect unusual activity based on data from many transactions, which helps catch fraudulent transactions without much work on your end.
Jamie:
That's nice to know. What about fees? I'd like to have a clear idea of what this will cost.
Alex:
Absolutely. So, Quick charges 2.9% plus 30 cents per transaction. For subscriptions, there's no extra fee beyond the normal transaction cost. Also, if you start processing a lot of payments, we do offer some discounts, but those kick in at a higher volume.
Jamie:
Alright, that makes sense. And what about invoicing? A few customers have asked about getting invoices instead of just a credit card charge.
Alex:
Yes, we can do that too. With Quick Invoicing, you can send out one-time or recurring invoices, which is nice if you have larger clients who prefer an invoice. It's all within the Quick system, so it integrates well.
Jamie:
Good to know. I think this covers most of my questions. It sounds like Quick could be a good fit. I'd just need to make sure I'm able to actually set it up without a ton of back-and-forth.
Alex:
I totally understand, Jamie. I'll send over some guides and set you up with a sandbox account to test things out. Let's reconnect in a couple of weeks to go over any questions you might have.
Jamie:
Sounds good, thanks, Alex. Looking forward to trying it out.
Alex:
Great! Thanks for your time, Jamie. I'll follow up soon. Have a good one!
"""
output = macro.output({"transcript": sample_transcript})
print(output)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment