94 lines
2.4 KiB
Ruby
94 lines
2.4 KiB
Ruby
class Captain::LabelSuggestionService < Captain::BaseTaskService
|
|
pattr_initialize [:account!, :conversation_display_id!]
|
|
|
|
def perform
|
|
# Check cache first
|
|
cached_response = read_from_cache
|
|
return cached_response if cached_response.present?
|
|
|
|
# Build content
|
|
content = labels_with_messages
|
|
return nil if content.blank?
|
|
|
|
# Make API call
|
|
response = make_api_call(
|
|
model: GPT_MODEL, # TODO: Use separate model for label suggestion
|
|
messages: [
|
|
{ role: 'system', content: prompt_from_file('label_suggestion') },
|
|
{ role: 'user', content: content }
|
|
]
|
|
)
|
|
return response if response[:error].present?
|
|
|
|
# Clean up response
|
|
result = { message: response[:message] ? response[:message].gsub(/^(label|labels):/i, '') : '' }
|
|
|
|
# Cache successful result
|
|
write_to_cache(result)
|
|
|
|
result
|
|
end
|
|
|
|
private
|
|
|
|
def cache_key
|
|
return nil unless conversation
|
|
|
|
format(
|
|
::Redis::Alfred::OPENAI_CONVERSATION_KEY,
|
|
event_name: 'label_suggestion',
|
|
conversation_id: conversation.id,
|
|
updated_at: conversation.last_activity_at.to_i
|
|
)
|
|
end
|
|
|
|
def read_from_cache
|
|
return nil unless cache_key
|
|
|
|
cached = Redis::Alfred.get(cache_key)
|
|
JSON.parse(cached, symbolize_names: true) if cached.present?
|
|
rescue JSON::ParserError
|
|
nil
|
|
end
|
|
|
|
def write_to_cache(response)
|
|
Redis::Alfred.setex(cache_key, response.to_json) if cache_key
|
|
end
|
|
|
|
def labels_with_messages
|
|
return nil unless valid_conversation?(conversation)
|
|
|
|
labels = account.labels.pluck(:title).join(', ')
|
|
messages = format_messages_as_string(start_from: labels.length)
|
|
|
|
return nil if messages.blank? || labels.blank?
|
|
|
|
"Messages:\n#{messages}\nLabels:\n#{labels}"
|
|
end
|
|
|
|
def format_messages_as_string(start_from: 0)
|
|
messages = conversation_messages(start_from: start_from)
|
|
messages.map do |msg|
|
|
sender_type = msg[:role] == 'user' ? 'Customer' : 'Agent'
|
|
"#{sender_type}: #{msg[:content]}\n"
|
|
end.join
|
|
end
|
|
|
|
def valid_conversation?(conversation)
|
|
return false if conversation.nil?
|
|
return false if conversation.messages.incoming.count < 3
|
|
return false if conversation.messages.count > 100
|
|
return false if conversation.messages.count > 20 && !conversation.messages.last.incoming?
|
|
|
|
true
|
|
end
|
|
|
|
def event_name
|
|
'label_suggestion'
|
|
end
|
|
|
|
def build_follow_up_context?
|
|
false
|
|
end
|
|
end
|