{"id":16480,"date":"2024-10-22T11:50:11","date_gmt":"2024-10-22T18:50:11","guid":{"rendered":"https:\/\/www.couchbase.com\/blog\/?p=16480"},"modified":"2025-06-13T16:36:37","modified_gmt":"2025-06-13T23:36:37","slug":"part2-ai-in-action-enhancing-and-not-replacing-jobs","status":"publish","type":"post","link":"https:\/\/www.couchbase.com\/blog\/pt\/part2-ai-in-action-enhancing-and-not-replacing-jobs\/","title":{"rendered":"Parte 2 - IA em a\u00e7\u00e3o: Aprimorando e n\u00e3o substituindo empregos"},"content":{"rendered":"<p><span style=\"font-weight: 400;\">Bem-vindo de volta \u00e0 segunda parte de nossa s\u00e9rie de duas partes sobre a cria\u00e7\u00e3o de um aplicativo interativo de suporte ao atendimento ao cliente que capacita os agentes de suporte com a ajuda da IA. O objetivo \u00e9 aprimorar o importante trabalho deles, aproveitando respostas resolvidas anteriormente para perguntas abertas atuais de forma r\u00e1pida e intuitiva usando a pesquisa vetorial.<\/span><\/p>\n<p><b><i>tl;dr Caso queira pular direto para a implementa\u00e7\u00e3o, voc\u00ea pode encontrar um exemplo totalmente funcional desse aplicativo em <\/i><\/b><a href=\"https:\/\/github.com\/hummusonrails\/whatsapp_support_app\"><b><i>GitHub<\/i><\/b><\/a><b><i> juntamente com instru\u00e7\u00f5es detalhadas do README.<\/i><\/b><\/p>\n<p><span style=\"font-weight: 400;\"><a href=\"https:\/\/www.couchbase.com\/blog\/pt\/ai-in-action-enhancing-and-not-replacing-jobs\/\">Na primeira parte,<\/a> configuramos todos os servi\u00e7os necess\u00e1rios para nosso aplicativo, incluindo:<\/span><\/p>\n<ul>\n<li style=\"list-style-type: none;\">\n<ul>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Couchbase Capella<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">API de mensagens da Vonage<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">API de incorpora\u00e7\u00e3o da OpenAI<\/span><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<blockquote class=\"wp-embedded-content\" data-secret=\"FgkBWZlmbu\"><p><a href=\"https:\/\/www.couchbase.com\/blog\/pt\/ai-in-action-enhancing-and-not-replacing-jobs\/\">IA em a\u00e7\u00e3o: Aprimorando e n\u00e3o substituindo empregos<\/a><\/p><\/blockquote>\n<p><iframe loading=\"lazy\" class=\"wp-embedded-content\" sandbox=\"allow-scripts\" security=\"restricted\" style=\"position: absolute; visibility: hidden;\" title=\"&quot;IA em a\u00e7\u00e3o: Aprimorando e n\u00e3o substituindo empregos&quot; - The Couchbase Blog\" src=\"https:\/\/www.couchbase.com\/blog\/ai-in-action-enhancing-and-not-replacing-jobs\/embed\/#?secret=sCe5GHoTyn#?secret=FgkBWZlmbu\" data-secret=\"FgkBWZlmbu\" width=\"600\" height=\"338\" frameborder=\"0\" marginwidth=\"0\" marginheight=\"0\" scrolling=\"no\"><\/iframe><\/p>\n<p><span style=\"font-weight: 400;\">Tamb\u00e9m montamos o back-end do nosso aplicativo com o Ruby on Rails. Agora, vamos escrever o c\u00f3digo que conectar\u00e1 esses tr\u00eas servi\u00e7os e os reunir\u00e1 para dar suporte ao trabalho dos agentes de atendimento ao cliente que respondem \u00e0s consultas dos usu\u00e1rios via WhatsApp.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Primeiro, vamos definir a l\u00f3gica comercial do nosso aplicativo.<\/span><\/p>\n<h2><span style=\"font-weight: 400;\">Defini\u00e7\u00e3o da l\u00f3gica comercial do aplicativo<\/span><\/h2>\n<p><span style=\"font-weight: 400;\">Uma das coisas boas do Ruby on Rails \u00e9 sua no\u00e7\u00e3o de conven\u00e7\u00e3o sobre configura\u00e7\u00e3o. Isso significa que n\u00e3o precisamos reinventar a roda para saber onde colocar a l\u00f3gica comercial do nosso aplicativo. O que criaremos agora ser\u00e1 uma vers\u00e3o simplificada. Todo o c\u00f3digo do aplicativo n\u00e3o ser\u00e1 mostrado neste tutorial, mas, conforme mencionado no in\u00edcio, toda a base de c\u00f3digo est\u00e1 dispon\u00edvel para clonagem localmente em <\/span><a href=\"https:\/\/github.com\/hummusonrails\/whatsapp_support_app\"><span style=\"font-weight: 400;\">GitHub<\/span><\/a><span style=\"font-weight: 400;\">.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Em resumo, definiremos nossa l\u00f3gica nos arquivos de modelo e controlador.\u00a0<\/span><\/p>\n<p><span style=\"font-weight: 400;\">O aplicativo ter\u00e1 tr\u00eas modelos:<\/span><\/p>\n<ul>\n<li style=\"list-style-type: none;\">\n<ul>\n<li aria-level=\"1\"><b>Bilhete<\/b><\/li>\n<li aria-level=\"1\"><b>Usu\u00e1rio<\/b><\/li>\n<li aria-level=\"1\"><b>Agente<\/b><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p><span style=\"font-weight: 400;\">O aplicativo tamb\u00e9m ter\u00e1 dois controladores:<\/span><\/p>\n<ul>\n<li style=\"list-style-type: none;\">\n<ul>\n<li aria-level=\"1\"><b>Controlador de mensagens<\/b><\/li>\n<li aria-level=\"1\"><b>Controlador do painel<\/b><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p><span style=\"font-weight: 400;\">Outras partes do aplicativo que precisar\u00e3o ser configuradas incluem os inicializadores Vonage, OpenAI e Couchbase em <\/span><b><code>config\/initializadores<\/code><\/b><span style=\"font-weight: 400;\">e as rotas para o aplicativo em <\/span><b><code>config\/routes.rb<\/code><\/b><span style=\"font-weight: 400;\">. Todos eles podem ser visualizados no GitHub e copiados diretamente de l\u00e1 para sua pr\u00f3pria base de c\u00f3digo.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Vamos come\u00e7ar com os modelos.<\/span><\/p>\n<h3><span style=\"font-weight: 400;\">Criar modelos<\/span><\/h3>\n<p><span style=\"font-weight: 400;\">\u00c9 verdade que, classicamente, o Rails trabalha com bancos de dados SQL imediatamente. E se voc\u00ea quiser combinar o melhor do Rails com o melhor de um banco de dados de documentos JSON como o Couchbase? Agora \u00e9 poss\u00edvel fazer isso de forma simplificada gra\u00e7as ao Couchbase Ruby ORM, que disponibiliza muitas das funcionalidades do ActiveRecord no Rails para trabalhar com o Couchbase. Cada um de nossos modelos herdar\u00e1 de <\/span><i><span style=\"font-weight: 400;\"><code>CouchbaseOrm::Base<\/code><\/span><\/i><span style=\"font-weight: 400;\"> para tornar os m\u00e9todos do ORM dispon\u00edveis para ele.<\/span><\/p>\n<h4><span style=\"font-weight: 400;\">O modelo Ticket<\/span><\/h4>\n<p><span style=\"font-weight: 400;\">Um t\u00edquete no aplicativo precisa conter informa\u00e7\u00f5es sobre a consulta, seu status atual, quem a solicitou, o resumo da eventual resolu\u00e7\u00e3o e a incorpora\u00e7\u00e3o vetorial dessa resolu\u00e7\u00e3o. Podemos definir cada uma dessas informa\u00e7\u00f5es como atributos:<\/span><\/p>\n<pre class=\"nums:false lang:default decode:true\">OPEN = 'aberto'\r\nRESOLVED = 'resolvido'\r\n\r\npertence a: usu\u00e1rio\r\nbelongs_to :agent, opcional: true\r\n\r\natributo :query, :string\r\natributo :status, :string, padr\u00e3o: OPEN\r\natributo :summary, :string\r\natributo :embedding, :array, tipo: :float, padr\u00e3o: []\r\natributo :created_at, :datetime, padr\u00e3o: -&gt; { Time.now }\r\natributo :updated_at, :datetime, padr\u00e3o: -&gt; { Time.now }<\/pre>\n<p><span style=\"font-weight: 400;\">Como voc\u00ea pode ver acima, tamb\u00e9m definimos duas constantes, <\/span><b>ABERTO<\/b><span style=\"font-weight: 400;\"> e <\/span><b>RESOLVIDO, <\/b><span style=\"font-weight: 400;\">que s\u00e3o os dois estados de status poss\u00edveis em que um ticket pode estar. Tamb\u00e9m criamos o relacionamento de um ticket com um usu\u00e1rio e com um agente, opcionalmente.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Al\u00e9m de definir os atributos, tamb\u00e9m queremos criar alguns m\u00e9todos no t\u00edquete que possam ser acessados em nosso aplicativo. Queremos criar m\u00e9todos auxiliares que possam ser usados para verificar o status de um t\u00edquete como este:<\/span><\/p>\n<pre class=\"nums:false lang:default decode:true\">  def self.open_tickets\r\n    where(status: OPEN).to_a\r\n  final\r\n\r\n  def self.resolved_tickets\r\n    where(status: RESOLVED).to_a\r\n  end\r\n\r\n  def open?\r\n    status == OPEN\r\n  end\r\n\r\n  def resolved?\r\n    status == RESOLVED\r\n  end\r\n\r\n  def mark_as_resolved!\r\n    update!(status: RESOLVED)\r\n  end<\/pre>\n<p><span style=\"font-weight: 400;\">Em conjunto, o modelo de ticket ter\u00e1 a seguinte apar\u00eancia, incluindo valida\u00e7\u00f5es adicionais:<\/span><\/p>\n<pre class=\"nums:false lang:default decode:true\">class Ticket  { Time.now }\r\n  atributo :updated_at, :datetime, padr\u00e3o: -&gt; { Time.now }\r\n\r\n  ensure_design_document!\r\n\r\n  valida :query, presen\u00e7a: true\r\n\r\n  before_save :set_timestamps\r\n  def self.open_tickets\r\n    where(status: OPEN).to_a\r\n  final\r\n\r\n  def self.resolved_tickets\r\n    where(status: RESOLVED).to_a\r\n  end\r\n\r\n  def open?\r\n    status == OPEN\r\n  end\r\n\r\n  def resolved?\r\n    status == RESOLVED\r\n  end\r\n\r\n  def mark_as_resolved!\r\n    update!(status: RESOLVED)\r\n  end\r\n\r\n  privado\r\n\r\n  def set_timestamps\r\n    self.updated_at = Time.now\r\n  end\r\nend<\/pre>\n<p><span style=\"font-weight: 400;\">Vamos seguir um caminho semelhante para o modelo de usu\u00e1rio.<\/span><\/p>\n<h4><span style=\"font-weight: 400;\">O modelo do usu\u00e1rio<\/span><\/h4>\n<p><span style=\"font-weight: 400;\">Um usu\u00e1rio no aplicativo precisa ter muitos t\u00edquetes, pois \u00e9 poss\u00edvel que um cliente esteja lidando com v\u00e1rios problemas para os quais est\u00e1 buscando suporte.\u00a0<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Tamb\u00e9m queremos garantir que possamos encontrar facilmente um usu\u00e1rio pelo n\u00famero do WhatsApp, portanto, criaremos um m\u00e9todo auxiliar no modelo para isso tamb\u00e9m. Nesse m\u00e9todo auxiliar, um usu\u00e1rio ser\u00e1 encontrado pelo n\u00famero ou, caso contr\u00e1rio, um novo usu\u00e1rio ser\u00e1 criado e uma parte do n\u00famero ser\u00e1 usada para preencher o campo de nome.<\/span><\/p>\n<pre class=\"nums:false lang:default decode:true\">classe Usu\u00e1rio  { Time.now }\r\n  atributo :updated_at, :datetime, default: -&gt; { Time.now }\r\n\r\n  valida :whatsapp_number, presen\u00e7a: true\r\n  valida :name, presen\u00e7a: true\r\n\r\n  before_save :set_timestamps\r\n\r\n  private\r\n\r\n  def set_timestamps\r\n    self.updated_at = Time.now\r\n  final\r\n\r\n  def self.find_or_create_user_by_whatsapp_number(whatsapp_number)\r\n    user = User.find_by(whatsapp_number: whatsapp_number)\r\n    unless user\r\n      user = User.create!(whatsapp_number: whatsapp_number, name: \"User #{whatsapp_number[-4..-1]}\")\r\n    fim\r\n    usu\u00e1rio\r\n  end\r\nend<\/pre>\n<p><span style=\"font-weight: 400;\">O \u00faltimo modelo que criaremos \u00e9 o modelo Agent, vamos fazer isso.<\/span><\/p>\n<h4><span style=\"font-weight: 400;\">O modelo de agente<\/span><\/h4>\n<p><span style=\"font-weight: 400;\">De muitas maneiras, o modelo de agente \u00e9 semelhante ao modelo de usu\u00e1rio, pois ambos t\u00eam muitos t\u00edquetes. Uma distin\u00e7\u00e3o importante \u00e9 que o agente n\u00e3o usa seu pr\u00f3prio n\u00famero do WhatsApp para se comunicar no aplicativo. Em vez disso, ele se comunica com os usu\u00e1rios por meio do painel do aplicativo e a API Vonage Messages envia programaticamente suas mensagens para a caixa de entrada do WhatsApp do usu\u00e1rio.<\/span><\/p>\n<pre class=\"nums:false lang:default decode:true\">requerer 'couchbase-orm'\r\n\r\nclasse Agent  { Time.now }\r\n  attribute :updated_at, :datetime, default: -&gt; { Time.now }\r\n\r\n  valida :email, presen\u00e7a: true, exclusividade: true\r\n  valida :name, presen\u00e7a: true\r\n\r\n  before_save :set_timestamps\r\n\r\n  private\r\n\r\n  def set_timestamps\r\n    self.updated_at = Time.now\r\n  end\r\nend<\/pre>\n<p><span style=\"font-weight: 400;\">Neste ponto, j\u00e1 criamos nossos modelos. N\u00e3o \u00e9 hora de definir os controladores.<\/span><\/p>\n<h3><span style=\"font-weight: 400;\">Criar controladores<\/span><\/h3>\n<p><span style=\"font-weight: 400;\">O aplicativo ter\u00e1 dois controladores que definem o que acontece em cada rota do site. Ou seja, um <\/span><i><span style=\"font-weight: 400;\"><code>controlador de painel<\/code><\/span><\/i><span style=\"font-weight: 400;\"> que supervisiona a funcionalidade do Dashboard, e um <\/span><i><span style=\"font-weight: 400;\"><code>controlador_de_mensagens<\/code><\/span><\/i> <span style=\"font-weight: 400;\">que supervisiona a funcionalidade de mensagens.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Come\u00e7aremos com o Dashboard primeiro.<\/span><\/p>\n<h4><span style=\"font-weight: 400;\">O controlador Dashboard<\/span><\/h4>\n<p><span style=\"font-weight: 400;\">O <\/span><b>\u00edndice<\/b><span style=\"font-weight: 400;\"> e <\/span><b>show<\/b><span style=\"font-weight: 400;\"> ser\u00e3o definidas no controlador do painel, juntamente com m\u00e9todos auxiliares para buscar a similaridade vetorial de tickets resolvidos anteriormente para os agentes de suporte em seu trabalho com os tickets atuais.\u00a0<\/span><\/p>\n<p><span style=\"font-weight: 400;\">O Couchbase Ruby SDK inclui muitas abstra\u00e7\u00f5es \u00fateis para tornar a intera\u00e7\u00e3o com a funcionalidade do Couchbase mais simplificada. Isso inclui a cria\u00e7\u00e3o de uma nova pesquisa vetorial usando <\/span><b><code>Couchbase::VectorSearch.new<\/code><\/b><span style=\"font-weight: 400;\"> definindo os argumentos dentro da instancia\u00e7\u00e3o de um novo <\/span><b><code>VectorSearch<\/code> <\/b><span style=\"font-weight: 400;\">objeto como esse:<\/span><\/p>\n<pre class=\"nums:false lang:default decode:true\">  \u00a0 request = Couchbase::SearchRequest.new(\r\n      Couchbase::VectorSearch.new(\r\n        [\r\n          Couchbase::VectorQuery.new('embedding', embedding) do |q|\r\n            q.num_candidates = 2\r\n            q.boost = 0,3\r\n          end\r\n        ],\r\n        Couchbase::Options::VectorSearch.new(vector_query_combination: :and)\r\n      )\r\n    )<\/pre>\n<p><span style=\"font-weight: 400;\">Primeiro, o <\/span><b><code>VectorSearch<\/code><\/b><span style=\"font-weight: 400;\"> \u00e9 agrupado em uma nova inst\u00e2ncia de <\/span><b><code>Couchbase::SearchRequest<\/code><\/b><span style=\"font-weight: 400;\">, como o <\/span><b><code>VectorSearch<\/code><\/b><span style=\"font-weight: 400;\"> \u00e9 um tipo de solicita\u00e7\u00e3o de pesquisa. Em seguida, uma nova <\/span><b><code>Couchbase::VectorQuery<\/code><\/b><span style=\"font-weight: 400;\"> \u00e9 passada para a inst\u00e2ncia <\/span><b><code>VectorSearch<\/code> <\/b><span style=\"font-weight: 400;\">especificando o campo a ser pesquisado (ou seja, o objeto <\/span><i><span style=\"font-weight: 400;\">incorpora\u00e7\u00e3o<\/span><\/i><span style=\"font-weight: 400;\">) e a consulta do cliente convertida em sua pr\u00f3pria incorpora\u00e7\u00e3o como o segundo argumento.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Tendo isso em mente sobre como criar uma pesquisa vetorial usando o Ruby SDK, vamos dar uma olhada no c\u00f3digo completo do controlador do painel:<\/span><\/p>\n<pre class=\"nums:false lang:default decode:true\">classe DashboardController &lt; ApplicationController\r\n  def index\r\n    @open_tickets = Ticket.where(status: &#039;open&#039;).to_a.sort_by { |ticket| ticket.created_at }.reverse\r\n    @resolved_tickets = Ticket.all.to_a.select { |ticket| ticket.status == Ticket::RESOLVED }.to_a.sort_by { |ticket| ticket.updated_at }.reverse\r\n  final\r\n\r\n  def show\r\n    @ticket = find_ticket\r\n    @user = find_user\r\n    @suggestions = find_suggestions\r\n  fim\r\n\r\n  private\r\n  def find_ticket\r\n    Ticket.find(params[:id])\r\n  end\r\n\r\n  def find_user\r\n    find_ticket.user\r\n  end\r\n\r\n  def find_suggestions\r\n    search_similar_tickets(find_ticket.query)\r\n  end\r\n\r\n  def search_similar_tickets(query)\r\n    embedding = OPENAI_CLIENT.embeddings(\r\n      parameters: {\r\n        model: &quot;text-embedding-ada-002&quot;,\r\n        input: query\r\n      }\r\n    )[&#039;data&#039;][0][&#039;embedding&#039;]\r\n\r\n    cluster = Couchbase::Cluster.connect(\r\n      ENV[&#039;COUCHBASE_CONNECTION_STRING&#039;],\r\n      ENV[&#039;COUCHBASE_USERNAME&#039;],\r\n      ENV[&#039;COUCHBASE_PASSWORD&#039;]\r\n    )\r\n\r\n    bucket = cluster.bucket(ENV[&#039;COUCHBASE_BUCKET&#039;])\r\n\r\n    escopo = bucket.scope(&#039;_default&#039;)\r\n\r\n    request = Couchbase::SearchRequest.new(\r\n      Couchbase::VectorSearch.new(\r\n        [\r\n          Couchbase::VectorQuery.new(&#039;embedding&#039;, embedding) do |q|\r\n            q.num_candidates = 2\r\n            q.boost = 0,3\r\n          end\r\n        ],\r\n        Couchbase::Options::VectorSearch.new(vector_query_combination: :and)\r\n      )\r\n    )\r\n\r\n    result = scope.search(&#039;whatsapp_support_index&#039;, request)\r\n\r\n    result.rows.map do |row|\r\n      document = bucket.default_collection.get(row.id)\r\n      {\r\n        id: row.id,\r\n        pontua\u00e7\u00e3o: row.score,\r\n        summary: document.content[&#039;summary&#039;]\r\n      }\r\n    end\r\n  end\r\nend<\/pre>\n<p><span style=\"font-weight: 400;\">Com esse c\u00f3digo, definimos a l\u00f3gica funcional tanto para a visualiza\u00e7\u00e3o do painel principal quanto para a visualiza\u00e7\u00e3o de cada t\u00edquete individual no painel.\u00a0<\/span><\/p>\n<p><span style=\"font-weight: 400;\">O c\u00f3digo de front-end pode ser encontrado em <\/span><a href=\"https:\/\/github.com\/hummusonrails\/whatsapp_support_app\/tree\/main\/app\/views\/dashboard\"><span style=\"font-weight: 400;\">GitHub<\/span><\/a><span style=\"font-weight: 400;\"> para essas duas visualiza\u00e7\u00f5es e podem ser copiadas diretamente para sua base de c\u00f3digo ou editadas de acordo com suas necessidades espec\u00edficas.<\/span><\/p>\n<p><a href=\"https:\/\/github.com\/hummusonrails\/whatsapp_support_app\/tree\/main\/app\/views\/dashboard\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-16482 size-large\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/10\/Screenshot-2024-10-22-at-12.33.05\u202fPM-1024x652.png\" alt=\"\" width=\"900\" height=\"573\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/10\/Screenshot-2024-10-22-at-12.33.05\u202fPM-1024x652.png 1024w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/10\/Screenshot-2024-10-22-at-12.33.05\u202fPM-300x191.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/10\/Screenshot-2024-10-22-at-12.33.05\u202fPM-768x489.png 768w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/10\/Screenshot-2024-10-22-at-12.33.05\u202fPM-1536x978.png 1536w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/10\/Screenshot-2024-10-22-at-12.33.05\u202fPM-2048x1304.png 2048w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/10\/Screenshot-2024-10-22-at-12.33.05\u202fPM-1320x841.png 1320w\" sizes=\"auto, (max-width: 900px) 100vw, 900px\" \/><\/a><\/p>\n<h4><span style=\"font-weight: 400;\">O controlador de mensagens<\/span><\/h4>\n<p><span style=\"font-weight: 400;\">Agora precisamos definir a l\u00f3gica de todas as mensagens que ser\u00e3o recebidas e enviadas pelo aplicativo via WhatsApp. O controlador de mensagens tamb\u00e9m ser\u00e1 respons\u00e1vel por garantir que novos t\u00edquetes e usu\u00e1rios sejam criados quando um usu\u00e1rio enviar uma mensagem pela primeira vez.\u00a0<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00c9 poss\u00edvel que, em uma itera\u00e7\u00e3o posterior do aplicativo, algumas dessas funcionalidades possam ser movidas e separadas em diferentes \u00e1reas da base de c\u00f3digo, mas, para simplificar, manteremos tudo no controlador de mensagens por enquanto.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Um dos grandes aspectos do Rails \u00e9 a capacidade de injetar dinamicamente novo conte\u00fado na janela do navegador sem a necessidade de usar JavaScript. Isso \u00e9 feito com o <\/span><a href=\"https:\/\/api.rubyonrails.org\/v7.1.3.4\/classes\/ActionCable\/Server\/Broadcasting.html\"><span style=\"font-weight: 400;\">ActionCable<\/span><\/a><span style=\"font-weight: 400;\">um recurso essencial do Rails. Tamb\u00e9m usaremos o ActionCable para atualizar a exibi\u00e7\u00e3o de t\u00edquete individual do painel com as mensagens mais recentes enviadas e recebidas com a API de mensagens da Vonage.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Conforme mencionado no <\/span><a href=\"https:\/\/www.couchbase.com\/blog\/pt\/ai-in-action-enhancing-and-not-replacing-jobs\/\"><em><span style=\"font-weight: 400;\">Usando a API de mensagens da Vonage <\/span><\/em><\/a><span style=\"font-weight: 400;\">se\u00e7\u00e3o, para fins de desenvolvimento, estamos construindo com a sandbox da API, portanto, como resultado, nossa chamada de API para enviar mensagens ser\u00e1 constru\u00edda manualmente como uma solicita\u00e7\u00e3o HTTP POST. Depois de concluir as etapas necess\u00e1rias descritas na documenta\u00e7\u00e3o da Vonage para obter uma conta comercial do Meta WhatsApp, voc\u00ea poder\u00e1 usar o Ruby SDK da Vonage para abstrair essas solicita\u00e7\u00f5es HTTP para voc\u00ea.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Aqui est\u00e1 o c\u00f3digo do controlador:<\/span><\/p>\n<pre class=\"nums:false lang:default decode:true\">class MessagesController &lt; ApplicationController\r\n  skip_before_action :verify_authenticity_token\r\n\r\n  def inbound\r\n    whatsapp_number = params[:from]\r\n    text = params[:text]\r\n    @reply = { sender: &#039;User&#039;, body: text, created_at: Time.current }\r\n    @user = User.find_by(whatsapp_number: whatsapp_number)\r\n\r\n    se @user\r\n      open_ticket = Ticket.find_by(user_id: @user.id, status: Ticket::OPEN)\r\n\r\n      if open_ticket.nil?\r\n        Ticket.create!(user_id: @user.id, query: &quot;Aguardando consulta&quot;, status: Ticket::OPEN)\r\n        send_message(to: whatsapp_number, text: &quot;Obrigado por sua mensagem. Por favor, descreva sua consulta de suporte.&quot;)\r\n      elsif open_ticket.query == &quot;Aguardando consulta&quot;\r\n        open_ticket.update!(query: text)\r\n        ActionCable.server.broadcast &quot;messages_#{@user.id}&quot;, { reply: @reply, ticket: open_ticket }\r\n      else\r\n        ActionCable.server.broadcast &quot;messages_#{@user.id}&quot;, { reply: @reply, ticket: open_ticket }\r\n      end\r\n    else\r\n      @user = User.create!(whatsapp_number: whatsapp_number, name: &quot;User #{whatsapp_number[-4..-1]}&quot;)\r\n      send_message(to: whatsapp_number, text: &quot;Obrigado por sua mensagem. Descreva sua consulta de suporte.&quot;)\r\n      Ticket.create!(user_id: @user.id, query: &quot;Aguardando consulta&quot;, status: Ticket::OPEN)\r\n    fim\r\n\r\n    respond_to do |format|\r\n      format.turbo_stream { render turbo_stream: turbo_stream.append(&quot;messages_#{@user.id}&quot;, partial: &quot;messages\/reply&quot;, locals: { reply: @reply }) }\r\n    end\r\n  fim\r\n\r\n  def reply\r\n    @ticket_id = params[:ticket_id]\r\n    @message = params[:message]\r\n    @resolved = params[:mark_as_resolved] == &quot;1&quot;\r\n\r\n    @ticket = Ticket.find(@ticket_id)\r\n    @user = @ticket.user\r\n\r\n    @reply = { sender: &#039;Agent&#039;, body: @message, created_at: Time.current }\r\n\r\n    ActionCable.server.broadcast &quot;messages_#{@user.id}&quot;, { reply: @reply, ticket: @ticket }\r\n\r\n    if @resolved\r\n      embedding = OPENAI_CLIENT.embeddings(\r\n        parameters: {\r\n          model: &quot;text-embedding-ada-002&quot;,\r\n          input: @message\r\n        }\r\n      )[&#039;data&#039;][0][&#039;embedding&#039;]\r\n\r\n      @ticket.update!(summary: @message, status: Ticket::RESOLVED, embedding: embedding)\r\n\r\n      send_message(\r\n        to: @user.whatsapp_number,\r\n        text: @message\r\n      )\r\n\r\n      respond_to do |format|\r\n        format.html { redirect_to request.referrer, notice: &quot;Ticket marcado como resolvido&quot;. }\r\n      end\r\n    else\r\n      send_message(\r\n        to: @user.whatsapp_number,\r\n        text: @message\r\n      )\r\n\r\n      respond_to do |format|\r\n        format.turbo_stream { render turbo_stream: turbo_stream.append(&quot;messages_#{@user.id}&quot;, partial: &quot;messages\/reply&quot;, locals: { reply: @reply }) }\r\n      end\r\n    fim\r\n  fim\r\n\r\n  def status\r\n    head :ok\r\n  end\r\n\r\n  privado\r\n\r\n  def send_message(to:, text:)\r\n    require &#039;net\/http&#039;\r\n    require &#039;uri&#039;\r\n    requer &#039;json&#039;\r\n\r\n    uri = URI.parse(&quot;https:\/\/messages-sandbox.nexmo.com\/v1\/messages&quot;)\r\n\r\n    request = Net::HTTP::Post.new(uri)\r\n    request.basic_auth(ENV[&#039;VONAGE_API_KEY&#039;], ENV[&#039;VONAGE_API_SECRET&#039;])\r\n    request.content_type = &#039;application\/json&#039;\r\n    request[&#039;Accept&#039;] = &#039;application\/json&#039;\r\n\r\n    request.body = {\r\n      from: ENV[&#039;VONAGE_FROM_NUMBER&#039;],\r\n      to: to,\r\n      message_type: &#039;text&#039;,\r\n      text: text,\r\n      channel: &#039;whatsapp&#039;\r\n    }.to_json\r\n\r\n    http = Net::HTTP.new(uri.host, uri.port)\r\n    http.use_ssl = true\r\n\r\n    resposta = http.request(request)\r\n\r\n    coloca &quot;C\u00f3digo de resposta: #{response.code}&quot;\r\n    puts &quot;Corpo da resposta: #{response.body}&quot;\r\n  end\r\nfim<\/pre>\n<p><span style=\"font-weight: 400;\">Com a cria\u00e7\u00e3o do controlador de mensagens, definimos praticamente toda a funcionalidade de que precisamos em nosso aplicativo.\u00a0<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Qualquer coisa que voc\u00ea ainda esteja tentando descobrir est\u00e1 prontamente dispon\u00edvel no aplicativo de exemplo totalmente completo e funcional em <\/span><a href=\"https:\/\/github.com\/hummusonrails\/whatsapp_support_app\/tree\/main\"><span style=\"font-weight: 400;\">GitHub<\/span><\/a><span style=\"font-weight: 400;\">.<\/span><\/p>\n<p><a href=\"https:\/\/github.com\/hummusonrails\/whatsapp_support_app\/tree\/main\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-large wp-image-16483\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/10\/Screenshot-2024-10-22-at-12.39.14\u202fPM-1024x618.png\" alt=\"\" width=\"900\" height=\"543\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/10\/Screenshot-2024-10-22-at-12.39.14\u202fPM-1024x618.png 1024w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/10\/Screenshot-2024-10-22-at-12.39.14\u202fPM-300x181.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/10\/Screenshot-2024-10-22-at-12.39.14\u202fPM-768x464.png 768w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/10\/Screenshot-2024-10-22-at-12.39.14\u202fPM-1536x927.png 1536w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/10\/Screenshot-2024-10-22-at-12.39.14\u202fPM-2048x1236.png 2048w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/10\/Screenshot-2024-10-22-at-12.39.14\u202fPM-1320x797.png 1320w\" sizes=\"auto, (max-width: 900px) 100vw, 900px\" \/><\/a><\/p>\n<p><span style=\"font-weight: 400;\">Tudo o que falta fazer agora \u00e9 executar nosso aplicativo!\u00a0<\/span><\/p>\n<h2><span style=\"font-weight: 400;\">Executar o aplicativo<\/span><\/h2>\n<p><span style=\"font-weight: 400;\">Para usar o aplicativo, abra uma janela de terminal e execute <\/span><i><span style=\"font-weight: 400;\"><code>bin\/dev<\/code><\/span><\/i><span style=\"font-weight: 400;\"> dentro da pasta do aplicativo. Isso iniciar\u00e1 um ambiente de desenvolvimento do aplicativo. Agora, em uma janela de terminal separada, inicie o ngrok, se estiver usando o ngrok conforme descrito acima para tornar seu ambiente localhost acess\u00edvel externamente, executando <\/span><i><span style=\"font-weight: 400;\"><code>ngrok http 3000<\/code><\/span><\/i><span style=\"font-weight: 400;\">.\u00a0<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Depois de executar os dois comandos, voc\u00ea poder\u00e1 abrir no navegador <\/span><a href=\"https:\/\/localhost:3000\/\">https:\/\/localhost:3000<\/a><span style=\"font-weight: 400;\">. Voc\u00ea ver\u00e1 um painel vazio, sem tickets. Isso \u00e9 porque voc\u00ea ainda n\u00e3o criou um!<\/span><\/p>\n<p><span style=\"font-weight: 400;\">V\u00e1 em frente e envie uma mensagem para o n\u00famero do WhatsApp fornecido a voc\u00ea na sandbox da API do Vonage Messages. O aplicativo responder\u00e1 pedindo que voc\u00ea explique sua pergunta de suporte. Depois disso, o painel em seu navegador ser\u00e1 preenchido com o novo t\u00edquete. Voc\u00ea pode ent\u00e3o abrir o t\u00edquete clicando em <\/span><b>Ver<\/b><span style=\"font-weight: 400;\"> e come\u00e7ar a interagir com ele.<\/span><\/p>\n<p><a href=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/10\/image6-2.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-large wp-image-16481\" style=\"border: 1px black solid;\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/10\/image6-2-1024x618.png\" alt=\"\" width=\"900\" height=\"543\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/10\/image6-2-1024x618.png 1024w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/10\/image6-2-300x181.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/10\/image6-2-768x463.png 768w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/10\/image6-2-1536x927.png 1536w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/10\/image6-2-1320x796.png 1320w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/10\/image6-2.png 1999w\" sizes=\"auto, (max-width: 900px) 100vw, 900px\" \/><\/a><\/p>\n<p><span style=\"font-weight: 400;\">Quando voc\u00ea come\u00e7ar a ter tickets marcados como resolvidos, os tickets futuros ser\u00e3o preenchidos com um <\/span><b>Solu\u00e7\u00f5es sugeridas<\/b><span style=\"font-weight: 400;\"> como pode ser visto na captura de tela acima. Cada solu\u00e7\u00e3o sugerida ser\u00e1 classificada por sua similaridade com a pergunta de suporte atual.\u00a0<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Dessa forma, criamos um aplicativo utilizando IA que capacita os membros da equipe em seu trabalho e n\u00e3o busca substitu\u00ed-los em suas fun\u00e7\u00f5es.<\/span><\/p>\n<h2><span style=\"font-weight: 400;\">Concluindo<\/span><\/h2>\n<p><span style=\"font-weight: 400;\">Ao integrar Couchbase, Vonage e OpenAI, criamos um aplicativo que capacita os agentes com acesso r\u00e1pido a informa\u00e7\u00f5es relevantes, melhorando sua efici\u00eancia e permitindo que eles se concentrem em oferecer um excelente atendimento ao cliente. Esse projeto mostra como a tecnologia pode ser aproveitada para apoiar e elevar as fun\u00e7\u00f5es humanas no local de trabalho, levando a melhores resultados para funcion\u00e1rios e clientes. Agora que voc\u00ea j\u00e1 viu o potencial, \u00e9 hora de aplicar esses conceitos em seus pr\u00f3prios projetos e continuar inovando.<\/span><\/p>\n<ul>\n<li style=\"list-style-type: none;\">\n<ul>\n<li>Parte 1 - <a class=\"row-title\" href=\"https:\/\/www.couchbase.com\/blog\/wp-admin\/post.php?post=16427&amp;action=edit\" aria-label=\"&quot;IA em a\u00e7\u00e3o: Aprimorando e n\u00e3o substituindo empregos&quot; (Editar)\">IA em a\u00e7\u00e3o: Aprimorando e n\u00e3o substituindo empregos<\/a><\/li>\n<li>Comece a usar o Couchbase Capella hoje mesmo, <a href=\"https:\/\/cloud.couchbase.com\/sign-up?ref=blog\">Registre-se gratuitamente<\/a><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p><a href=\"https:\/\/cloud.couchbase.com\/sign-up?ref=blog\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-16409 size-large\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/10\/capella-cloud-dbaas-couchbase-signup-free-1024x835.png\" alt=\"\" width=\"900\" height=\"734\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/10\/capella-cloud-dbaas-couchbase-signup-free-1024x835.png 1024w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/10\/capella-cloud-dbaas-couchbase-signup-free-300x245.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/10\/capella-cloud-dbaas-couchbase-signup-free-768x626.png 768w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/10\/capella-cloud-dbaas-couchbase-signup-free-1536x1252.png 1536w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/10\/capella-cloud-dbaas-couchbase-signup-free-2048x1670.png 2048w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/10\/capella-cloud-dbaas-couchbase-signup-free-1320x1076.png 1320w\" sizes=\"auto, (max-width: 900px) 100vw, 900px\" \/><\/a><\/p>\n<p><br style=\"font-weight: 400;\" \/><br style=\"font-weight: 400;\" \/><\/p>","protected":false},"excerpt":{"rendered":"<p>Welcome back to the second part of our two-part series on building an interactive customer service support application that empowers support agents with the help of AI. The goal is to enhance their important work by leveraging previously resolved answers [&hellip;]<\/p>","protected":false},"author":85356,"featured_media":16484,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[10122,1815,2225,9973,9407,2389,9937],"tags":[9560,9974,9964,10039,10044],"ppma_author":[9985],"class_list":["post-16480","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-artificial-intelligence-ai","category-best-practices-and-tutorials","category-cloud","category-generative-ai-genai","category-ruby","category-solutions","category-vector-search","tag-customer-service","tag-genai","tag-openai","tag-vonage","tag-whatsapp"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v26.1 (Yoast SEO v26.1.1) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Part 2 - AI in Action: Enhancing and Not Replacing Jobs - The Couchbase Blog<\/title>\n<meta name=\"description\" content=\"Couchbase, Vonage, and OpenAI to build an AI-driven customer support app. Part 2 covers coding the business logic and connecting the services.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.couchbase.com\/blog\/pt\/part2-ai-in-action-enhancing-and-not-replacing-jobs\/\" \/>\n<meta property=\"og:locale\" content=\"pt_BR\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Part 2 - AI in Action: Enhancing and Not Replacing Jobs\" \/>\n<meta property=\"og:description\" content=\"Couchbase, Vonage, and OpenAI to build an AI-driven customer support app. Part 2 covers coding the business logic and connecting the services.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.couchbase.com\/blog\/pt\/part2-ai-in-action-enhancing-and-not-replacing-jobs\/\" \/>\n<meta property=\"og:site_name\" content=\"The Couchbase Blog\" \/>\n<meta property=\"article:published_time\" content=\"2024-10-22T18:50:11+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-06-13T23:36:37+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/10\/blog-vonage-openai-part2.png\" \/>\n\t<meta property=\"og:image:width\" content=\"2400\" \/>\n\t<meta property=\"og:image:height\" content=\"1256\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Ben Greenberg, Senior Developer Evangelist\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Ben Greenberg, Senior Developer Evangelist\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"8 minutos\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/part2-ai-in-action-enhancing-and-not-replacing-jobs\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/part2-ai-in-action-enhancing-and-not-replacing-jobs\/\"},\"author\":{\"name\":\"Ben Greenberg, Senior Developer Evangelist\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/48efa1524aec97312d92f65a270c255d\"},\"headline\":\"Part 2 &#8211; AI in Action: Enhancing and Not Replacing Jobs\",\"datePublished\":\"2024-10-22T18:50:11+00:00\",\"dateModified\":\"2025-06-13T23:36:37+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/part2-ai-in-action-enhancing-and-not-replacing-jobs\/\"},\"wordCount\":1614,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/part2-ai-in-action-enhancing-and-not-replacing-jobs\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/10\/blog-vonage-openai-part2.png\",\"keywords\":[\"customer service\",\"GenAI\",\"openai\",\"vonage\",\"WhatsApp\"],\"articleSection\":[\"Artificial Intelligence (AI)\",\"Best Practices and Tutorials\",\"Couchbase Capella\",\"Generative AI (GenAI)\",\"Ruby\",\"Solutions\",\"Vector Search\"],\"inLanguage\":\"pt-BR\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/part2-ai-in-action-enhancing-and-not-replacing-jobs\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/part2-ai-in-action-enhancing-and-not-replacing-jobs\/\",\"url\":\"https:\/\/www.couchbase.com\/blog\/part2-ai-in-action-enhancing-and-not-replacing-jobs\/\",\"name\":\"Part 2 - AI in Action: Enhancing and Not Replacing Jobs - The Couchbase Blog\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/part2-ai-in-action-enhancing-and-not-replacing-jobs\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/part2-ai-in-action-enhancing-and-not-replacing-jobs\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/10\/blog-vonage-openai-part2.png\",\"datePublished\":\"2024-10-22T18:50:11+00:00\",\"dateModified\":\"2025-06-13T23:36:37+00:00\",\"description\":\"Couchbase, Vonage, and OpenAI to build an AI-driven customer support app. Part 2 covers coding the business logic and connecting the services.\",\"breadcrumb\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/part2-ai-in-action-enhancing-and-not-replacing-jobs\/#breadcrumb\"},\"inLanguage\":\"pt-BR\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/part2-ai-in-action-enhancing-and-not-replacing-jobs\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"pt-BR\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/part2-ai-in-action-enhancing-and-not-replacing-jobs\/#primaryimage\",\"url\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/10\/blog-vonage-openai-part2.png\",\"contentUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/10\/blog-vonage-openai-part2.png\",\"width\":2400,\"height\":1256},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/part2-ai-in-action-enhancing-and-not-replacing-jobs\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.couchbase.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Part 2 &#8211; AI in Action: Enhancing and Not Replacing Jobs\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#website\",\"url\":\"https:\/\/www.couchbase.com\/blog\/\",\"name\":\"The Couchbase Blog\",\"description\":\"Couchbase, the NoSQL Database\",\"publisher\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.couchbase.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"pt-BR\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\",\"name\":\"The Couchbase Blog\",\"url\":\"https:\/\/www.couchbase.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"pt-BR\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png\",\"contentUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png\",\"width\":218,\"height\":34,\"caption\":\"The Couchbase Blog\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/48efa1524aec97312d92f65a270c255d\",\"name\":\"Ben Greenberg, Senior Developer Evangelist\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"pt-BR\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/c9bda12524045d12a5878a2ef3fbe0de\",\"url\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/06\/T024FJS4M-U075H3NTJUR-b4c321d902e2-512.jpeg\",\"contentUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/06\/T024FJS4M-U075H3NTJUR-b4c321d902e2-512.jpeg\",\"caption\":\"Ben Greenberg, Senior Developer Evangelist\"},\"url\":\"https:\/\/www.couchbase.com\/blog\/pt\/author\/bengreenberg\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Part 2 - AI in Action: Enhancing and Not Replacing Jobs - The Couchbase Blog","description":"Couchbase, Vonage e OpenAI para criar um aplicativo de suporte ao cliente orientado por IA. A Parte 2 aborda a codifica\u00e7\u00e3o da l\u00f3gica comercial e a conex\u00e3o dos servi\u00e7os.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.couchbase.com\/blog\/pt\/part2-ai-in-action-enhancing-and-not-replacing-jobs\/","og_locale":"pt_BR","og_type":"article","og_title":"Part 2 - AI in Action: Enhancing and Not Replacing Jobs","og_description":"Couchbase, Vonage, and OpenAI to build an AI-driven customer support app. Part 2 covers coding the business logic and connecting the services.","og_url":"https:\/\/www.couchbase.com\/blog\/pt\/part2-ai-in-action-enhancing-and-not-replacing-jobs\/","og_site_name":"The Couchbase Blog","article_published_time":"2024-10-22T18:50:11+00:00","article_modified_time":"2025-06-13T23:36:37+00:00","og_image":[{"width":2400,"height":1256,"url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/10\/blog-vonage-openai-part2.png","type":"image\/png"}],"author":"Ben Greenberg, Senior Developer Evangelist","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Ben Greenberg, Senior Developer Evangelist","Est. reading time":"8 minutos"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.couchbase.com\/blog\/part2-ai-in-action-enhancing-and-not-replacing-jobs\/#article","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/part2-ai-in-action-enhancing-and-not-replacing-jobs\/"},"author":{"name":"Ben Greenberg, Senior Developer Evangelist","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/48efa1524aec97312d92f65a270c255d"},"headline":"Part 2 &#8211; AI in Action: Enhancing and Not Replacing Jobs","datePublished":"2024-10-22T18:50:11+00:00","dateModified":"2025-06-13T23:36:37+00:00","mainEntityOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/part2-ai-in-action-enhancing-and-not-replacing-jobs\/"},"wordCount":1614,"commentCount":0,"publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/part2-ai-in-action-enhancing-and-not-replacing-jobs\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/10\/blog-vonage-openai-part2.png","keywords":["customer service","GenAI","openai","vonage","WhatsApp"],"articleSection":["Artificial Intelligence (AI)","Best Practices and Tutorials","Couchbase Capella","Generative AI (GenAI)","Ruby","Solutions","Vector Search"],"inLanguage":"pt-BR","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.couchbase.com\/blog\/part2-ai-in-action-enhancing-and-not-replacing-jobs\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.couchbase.com\/blog\/part2-ai-in-action-enhancing-and-not-replacing-jobs\/","url":"https:\/\/www.couchbase.com\/blog\/part2-ai-in-action-enhancing-and-not-replacing-jobs\/","name":"Part 2 - AI in Action: Enhancing and Not Replacing Jobs - The Couchbase Blog","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/part2-ai-in-action-enhancing-and-not-replacing-jobs\/#primaryimage"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/part2-ai-in-action-enhancing-and-not-replacing-jobs\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/10\/blog-vonage-openai-part2.png","datePublished":"2024-10-22T18:50:11+00:00","dateModified":"2025-06-13T23:36:37+00:00","description":"Couchbase, Vonage e OpenAI para criar um aplicativo de suporte ao cliente orientado por IA. A Parte 2 aborda a codifica\u00e7\u00e3o da l\u00f3gica comercial e a conex\u00e3o dos servi\u00e7os.","breadcrumb":{"@id":"https:\/\/www.couchbase.com\/blog\/part2-ai-in-action-enhancing-and-not-replacing-jobs\/#breadcrumb"},"inLanguage":"pt-BR","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.couchbase.com\/blog\/part2-ai-in-action-enhancing-and-not-replacing-jobs\/"]}]},{"@type":"ImageObject","inLanguage":"pt-BR","@id":"https:\/\/www.couchbase.com\/blog\/part2-ai-in-action-enhancing-and-not-replacing-jobs\/#primaryimage","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/10\/blog-vonage-openai-part2.png","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/10\/blog-vonage-openai-part2.png","width":2400,"height":1256},{"@type":"BreadcrumbList","@id":"https:\/\/www.couchbase.com\/blog\/part2-ai-in-action-enhancing-and-not-replacing-jobs\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.couchbase.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Part 2 &#8211; AI in Action: Enhancing and Not Replacing Jobs"}]},{"@type":"WebSite","@id":"https:\/\/www.couchbase.com\/blog\/#website","url":"https:\/\/www.couchbase.com\/blog\/","name":"Blog do Couchbase","description":"Couchbase, o banco de dados NoSQL","publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.couchbase.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"pt-BR"},{"@type":"Organization","@id":"https:\/\/www.couchbase.com\/blog\/#organization","name":"Blog do Couchbase","url":"https:\/\/www.couchbase.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"pt-BR","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png","width":218,"height":34,"caption":"The Couchbase Blog"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/48efa1524aec97312d92f65a270c255d","name":"Ben Greenberg, desenvolvedor s\u00eanior evangelista","image":{"@type":"ImageObject","inLanguage":"pt-BR","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/c9bda12524045d12a5878a2ef3fbe0de","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/06\/T024FJS4M-U075H3NTJUR-b4c321d902e2-512.jpeg","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/06\/T024FJS4M-U075H3NTJUR-b4c321d902e2-512.jpeg","caption":"Ben Greenberg, Senior Developer Evangelist"},"url":"https:\/\/www.couchbase.com\/blog\/pt\/author\/bengreenberg\/"}]}},"authors":[{"term_id":9985,"user_id":85356,"is_guest":0,"slug":"bengreenberg","display_name":"Ben Greenberg, Senior Developer Evangelist","avatar_url":{"url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/06\/T024FJS4M-U075H3NTJUR-b4c321d902e2-512.jpeg","url2x":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/06\/T024FJS4M-U075H3NTJUR-b4c321d902e2-512.jpeg"},"author_category":"","last_name":"Greenberg, Senior Developer Evangelist","first_name":"Ben","job_title":"Senior Developer Evangelist","user_url":"","description":""}],"_links":{"self":[{"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/posts\/16480","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/users\/85356"}],"replies":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/comments?post=16480"}],"version-history":[{"count":0,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/posts\/16480\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/media\/16484"}],"wp:attachment":[{"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/media?parent=16480"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/categories?post=16480"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/tags?post=16480"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/ppma_author?post=16480"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}