107 lines
3.2 KiB
Ruby
107 lines
3.2 KiB
Ruby
class Captain::FollowUpService < Captain::BaseTaskService
|
|
pattr_initialize [:account!, :follow_up_context!, :user_message!, { conversation_display_id: nil }]
|
|
|
|
ALLOWED_EVENT_NAMES = %w[
|
|
professional
|
|
casual
|
|
friendly
|
|
confident
|
|
straightforward
|
|
fix_spelling_grammar
|
|
improve
|
|
summarize
|
|
reply_suggestion
|
|
label_suggestion
|
|
].freeze
|
|
|
|
def perform
|
|
return { error: 'Follow-up context missing', error_code: 400 } unless valid_follow_up_context?
|
|
|
|
# Build context-aware system prompt
|
|
system_prompt = build_follow_up_system_prompt(follow_up_context)
|
|
|
|
# Build full message array (convert history from string keys to symbol keys)
|
|
history = follow_up_context['conversation_history'].to_a.map do |msg|
|
|
{ role: msg['role'], content: msg['content'] }
|
|
end
|
|
|
|
messages = [
|
|
{ role: 'system', content: system_prompt },
|
|
{ role: 'user', content: follow_up_context['original_context'] },
|
|
{ role: 'assistant', content: follow_up_context['last_response'] },
|
|
*history,
|
|
{ role: 'user', content: user_message }
|
|
]
|
|
|
|
response = make_api_call(model: GPT_MODEL, messages: messages)
|
|
return response if response[:error]
|
|
|
|
response.merge(follow_up_context: update_follow_up_context(user_message, response[:message]))
|
|
end
|
|
|
|
private
|
|
|
|
def build_follow_up_system_prompt(session_data)
|
|
action_context = describe_previous_action(session_data['event_name'])
|
|
|
|
<<~PROMPT
|
|
You just performed a #{action_context} action for a customer support agent.
|
|
Your job now is to help them refine the result based on their feedback.
|
|
Be concise and focused on their specific request.
|
|
Output only the reply, no preamble, tags, or explanation.
|
|
PROMPT
|
|
end
|
|
|
|
def describe_previous_action(event_name)
|
|
case event_name
|
|
when 'professional', 'casual', 'friendly', 'confident', 'straightforward'
|
|
"tone rewrite (#{event_name})"
|
|
when 'fix_spelling_grammar'
|
|
'spelling and grammar correction'
|
|
when 'improve'
|
|
'message improvement'
|
|
when 'summarize'
|
|
'conversation summary'
|
|
when 'reply_suggestion'
|
|
'reply suggestion'
|
|
when 'label_suggestion'
|
|
'label suggestion'
|
|
else
|
|
event_name
|
|
end
|
|
end
|
|
|
|
def valid_follow_up_context?
|
|
return false unless follow_up_context.is_a?(Hash)
|
|
return false unless ALLOWED_EVENT_NAMES.include?(follow_up_context['event_name'])
|
|
|
|
required_keys = %w[event_name original_context last_response]
|
|
required_keys.all? { |key| follow_up_context[key].present? }
|
|
end
|
|
|
|
def update_follow_up_context(user_msg, assistant_msg)
|
|
updated_history = follow_up_context['conversation_history'].to_a + [
|
|
{ 'role' => 'user', 'content' => user_msg },
|
|
{ 'role' => 'assistant', 'content' => assistant_msg }
|
|
]
|
|
|
|
{
|
|
'event_name' => follow_up_context['event_name'],
|
|
'original_context' => follow_up_context['original_context'],
|
|
'last_response' => assistant_msg,
|
|
'conversation_history' => updated_history,
|
|
'channel_type' => follow_up_context['channel_type']
|
|
}
|
|
end
|
|
|
|
def instrumentation_metadata
|
|
{
|
|
channel_type: conversation&.inbox&.channel_type || follow_up_context['channel_type']
|
|
}.compact
|
|
end
|
|
|
|
def event_name
|
|
'follow_up'
|
|
end
|
|
end
|