Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Response Bot using GPT and Webpage Sources #7518

Merged
merged 41 commits into from
Jul 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
3cbbc3a
poc: Search support articles via OpenAI embeddings
sojan-official May 22, 2023
fe86e78
Merge branch 'develop' into spike/CW-1690-embeddings-for-articles
sojan-official May 29, 2023
3e0a71d
Chore: basic prototype
sojan-official Mar 20, 2023
8fbfe44
chore: GPT bot with article recommendations
sojan-official May 29, 2023
44a24bb
Merge branch 'develop' into spike/CW-1690-embeddings-for-articles
sojan-official May 29, 2023
cdaa40b
chore: minor formatting
sojan-official May 29, 2023
a728bb2
Merge branch 'develop' into spike/CW-1690-embeddings-for-articles
sojan-official Jun 21, 2023
f26649a
Merge branch 'develop' into spike/CW-1690-embeddings-for-articles
sojan-official Jul 5, 2023
c921aec
chore: Response Sources
sojan-official Jul 10, 2023
ce872de
Merge branch 'spike/CW-1690-embeddings-for-articles' into chore/respo…
sojan-official Jul 10, 2023
870d2e6
chore: fi
sojan-official Jul 13, 2023
41a7a25
chore: clean up
sojan-official Jul 13, 2023
a732ec1
chore: clean up
sojan-official Jul 13, 2023
78814eb
Merge branch 'develop' into chore/response-sources-with-embeddings
sojan-official Jul 13, 2023
bf6d69a
chore: fix
sojan-official Jul 13, 2023
dc01127
chore: endpoint to create sources
sojan-official Jul 13, 2023
590cff4
chor: fixes
sojan-official Jul 13, 2023
11a16a8
chore: The bot
sojan-official Jul 13, 2023
6510886
chore: reoder gemfile
sojan-official Jul 13, 2023
cc61674
chore: fix
sojan-official Jul 13, 2023
b7c7b09
chore: APIs for add and remove documents
sojan-official Jul 14, 2023
ada6c9c
Chore: clean up
sojan-official Jul 14, 2023
3729a9f
Merge branch 'develop' into chore/response-sources-with-embeddings
sojan-official Jul 14, 2023
dfa9b27
chore: fixes
sojan-official Jul 17, 2023
fce44b7
Merge branch 'develop' into chore/response-sources-with-embeddings
sojan-official Jul 17, 2023
c459f42
chore: clean up
sojan-official Jul 17, 2023
98e3ae0
chore: clean up
sojan-official Jul 17, 2023
f63feff
chore: refactor
sojan-official Jul 17, 2023
fec1e8a
Merge branch 'develop' into chore/response-sources-with-embeddings
pranavrajs Jul 19, 2023
30a2009
Merge branch 'develop' into chore/response-sources-with-embeddings
pranavrajs Jul 19, 2023
3ca3f9d
chore: add feature lock
sojan-official Jul 20, 2023
4538d35
chore: clean up
sojan-official Jul 20, 2023
1db6b2a
chore: fix specs
sojan-official Jul 20, 2023
e99a8ee
Merge branch 'develop' into chore/response-sources-with-embeddings
sojan-official Jul 21, 2023
4b05257
chore: fix code climate
sojan-official Jul 21, 2023
45a2754
chore: fix specs
sojan-official Jul 21, 2023
455df91
chore: test latest postgres
sojan-official Jul 21, 2023
ede19fe
chore: tests
sojan-official Jul 21, 2023
441da57
chore: update
sojan-official Jul 21, 2023
fe86348
Empty-Commit
sojan-official Jul 21, 2023
acf5b66
chore: clean up
sojan-official Jul 21, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ defaults: &defaults
# Specify service dependencies here if necessary
# CircleCI maintains a library of pre-built images
# documented at https://circleci.com/docs/2.0/circleci-images/
- image: cimg/postgres:14.1
- image: cimg/postgres:15.3
- image: cimg/redis:6.2.6
environment:
- RAILS_LOG_TO_STDOUT: false
Expand Down
5 changes: 5 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -231,5 +231,10 @@ AZURE_APP_SECRET=
# control the concurrency setting of sidekiq
# SIDEKIQ_CONCURRENCY=10


# AI powered features
## OpenAI key
# OPENAI_API_KEY=

# Sentiment analysis model file path
SENTIMENT_FILE_PATH=
3 changes: 2 additions & 1 deletion .github/workflows/run_foss_spec.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,12 @@ jobs:
runs-on: ubuntu-20.04
services:
postgres:
image: postgres:10.8
image: postgres:15.3
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: ""
POSTGRES_DB: postgres
POSTGRES_HOST_AUTH_METHOD: trust
ports:
- 5432:5432
# needed because the postgres container does not provide a healthcheck
Expand Down
78 changes: 78 additions & 0 deletions .github/workflows/run_response_bot_spec.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# #
# # This workflow will run specs related to response bot
# # This can only be activated in installations Where vector extension is available.
# #

name: Run Response Bot spec
on:
push:
branches:
- develop
- master
pull_request:
workflow_dispatch:

jobs:
test:
runs-on: ubuntu-20.04
services:
postgres:
image: ankane/pgvector
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: ""
POSTGRES_DB: postgres
POSTGRES_HOST_AUTH_METHOD: trust
ports:
- 5432:5432
# needed because the postgres container does not provide a healthcheck
# tmpfs makes DB faster by using RAM
options: >-
--mount type=tmpfs,destination=/var/lib/postgresql/data
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
redis:
image: redis
ports:
- 6379:6379
options: --entrypoint redis-server

steps:
- uses: actions/checkout@v3
with:
ref: ${{ github.event.pull_request.head.ref }}
repository: ${{ github.event.pull_request.head.repo.full_name }}

- uses: ruby/setup-ruby@v1
with:
bundler-cache: true # runs 'bundle install' and caches installed gems automatically

- uses: actions/setup-node@v3
with:
node-version: 16

- name: yarn
run: yarn install

- name: Create database
run: bundle exec rake db:create

- name: Seed database
run: bundle exec rake db:schema:load

- name: Enable ResponseBotService in installation
run: RAILS_ENV=test bundle exec rails runner "Features::ResponseBotService.new.enable_in_installation"

# Run Response Bot specs
- name: Run backend tests
run: |
bundle exec rspec spec/enterprise/controllers/api/v1/accounts/response_sources_controller_spec.rb spec/enterprise/controllers/enterprise/api/v1/accounts/inboxes_controller_spec.rb:47 --profile=10 --format documentation

- name: Upload rails log folder
uses: actions/upload-artifact@v3
if: always()
with:
name: rails-log-folder
path: log
1 change: 1 addition & 0 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ Style/ClassAndModuleChildren:
EnforcedStyle: compact
Exclude:
- 'config/application.rb'
- 'config/initializers/monkey_patches/*'
Style/MapToHash:
Enabled: false
Style/HashSyntax:
Expand Down
7 changes: 7 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,13 @@ gem 'omniauth'
gem 'omniauth-google-oauth2'
gem 'omniauth-rails_csrf_protection', '~> 1.0'

## Gems for reponse bot
# adds cosine similarity to postgres using vector extension
gem 'neighbor'
gem 'pgvector'
# Convert Website HTML to Markdown
gem 'reverse_markdown'

# Sentiment analysis
gem 'informers'

Expand Down
8 changes: 8 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,8 @@ GEM
multi_json (1.15.0)
multi_xml (0.6.0)
multipart-post (2.3.0)
neighbor (0.2.3)
activerecord (>= 5.2)
net-http-persistent (4.0.2)
connection_pool (~> 2.2)
net-imap (0.3.6)
Expand Down Expand Up @@ -532,6 +534,7 @@ GEM
pg_search (2.3.6)
activerecord (>= 5.2)
activesupport (>= 5.2)
pgvector (0.1.1)
procore-sift (1.0.0)
activerecord (>= 6.1)
pry (0.14.2)
Expand Down Expand Up @@ -617,6 +620,8 @@ GEM
mime-types (>= 1.16, < 4.0)
netrc (~> 0.8)
retriable (3.1.2)
reverse_markdown (2.1.1)
nokogiri
rexml (3.2.5)
rspec-core (3.12.2)
rspec-support (~> 3.12.0)
Expand Down Expand Up @@ -884,6 +889,7 @@ DEPENDENCIES
lograge (~> 0.12.0)
maxminddb
mock_redis
neighbor
newrelic-sidekiq-metrics
newrelic_rpm
omniauth
Expand All @@ -892,6 +898,7 @@ DEPENDENCIES
omniauth-rails_csrf_protection (~> 1.0)
pg
pg_search
pgvector
procore-sift
pry-rails
puma
Expand All @@ -905,6 +912,7 @@ DEPENDENCIES
redis-namespace
responders
rest-client
reverse_markdown
rspec-rails
rspec_junit_formatter
rubocop
Expand Down
2 changes: 1 addition & 1 deletion app/models/account.rb
Original file line number Diff line number Diff line change
Expand Up @@ -151,5 +151,5 @@ def remove_account_sequences
end

Account.prepend_mod_with('Account')
Account.include_mod_with('EnterpriseAccountConcern')
Account.include_mod_with('Concerns::Account')
Account.include_mod_with('Audit::Account')
1 change: 1 addition & 0 deletions app/models/inbox.rb
Original file line number Diff line number Diff line change
Expand Up @@ -172,3 +172,4 @@ def check_channel_type?

Inbox.prepend_mod_with('Inbox')
Inbox.include_mod_with('Audit::Inbox')
Inbox.include_mod_with('Concerns::Inbox')
4 changes: 4 additions & 0 deletions app/policies/inbox_policy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ def campaigns?
@account_user.administrator?
end

def response_sources?
@account_user.administrator?
end

def create?
@account_user.administrator?
end
Expand Down
17 changes: 17 additions & 0 deletions app/policies/response_source_policy.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
class ResponseSourcePolicy < ApplicationPolicy
def parse?
@account_user.administrator?
end

def create?
@account_user.administrator?
end

def add_document?
@account_user.administrator?
end

def remove_document?
@account_user.administrator?
end
end
1 change: 1 addition & 0 deletions app/services/message_templates/hook_execution_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,4 @@ def should_send_csat_survey?
true
end
end
MessageTemplates::HookExecutionService.prepend_mod_with('MessageTemplates::HookExecutionService')
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
json.array! @response_sources do |response_source|
json.partial! 'api/v1/models/response_source', formats: [:json], resource: response_source
end
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
json.partial! 'api/v1/models/response_source', formats: [:json], resource: @response_source
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
json.partial! 'api/v1/models/response_source', formats: [:json], resource: @response_source
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
json.partial! 'api/v1/models/response_source', formats: [:json], resource: @response_source
16 changes: 16 additions & 0 deletions app/views/api/v1/models/_response_source.json.jbuilder
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
json.id resource.id
json.name resource.name
json.source_link resource.source_link
json.source_type resource.source_type
json.inbox_id resource.inbox_id
json.account_id resource.account_id
json.created_at resource.created_at.to_i
json.updated_at resource.updated_at.to_i
json.response_documents do
json.array! resource.response_documents do |response_document|
json.id response_document.id
json.document_link response_document.document_link
json.created_at response_document.created_at.to_i
json.updated_at response_document.updated_at.to_i
end
end
2 changes: 2 additions & 0 deletions config/features.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,5 @@
enabled: false
- name: audit_logs
enabled: false
- name: response_bot
enabled: false
35 changes: 35 additions & 0 deletions config/initializers/monkey_patches/schema_dumper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# When working with experimental extensions, which doesn't have support on all providers
# This monkey patch will help us to ignore the extensions when dumping the schema
# Additionally we will also ignore the tables associated with those features and exentions

# Once the feature stabilizes, we can remove the tables/extension from the ignore list
# Ensure you write appropriate migrations when you do that.

module ActiveRecord
module ConnectionAdapters
module PostgreSQL
class SchemaDumper < ConnectionAdapters::SchemaDumper
cattr_accessor :ignore_extentions, default: []

private

def extensions(stream)
extensions = @connection.extensions
return unless extensions.any?

stream.puts ' # These are extensions that must be enabled in order to support this database'
extensions.sort.each do |extension|
stream.puts " enable_extension #{extension.inspect}" unless ignore_extentions.include?(extension)
end
stream.puts
end
end
end
end
end

## Extentions / Tables to be ignored
ActiveRecord::ConnectionAdapters::PostgreSQL::SchemaDumper.ignore_extentions << 'vector'
ActiveRecord::SchemaDumper.ignore_tables << 'responses'
ActiveRecord::SchemaDumper.ignore_tables << 'response_sources'
ActiveRecord::SchemaDumper.ignore_tables << 'response_documents'
10 changes: 10 additions & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@
resources :inboxes, only: [:index, :show, :create, :update, :destroy] do
get :assignable_agents, on: :member
get :campaigns, on: :member
get :response_sources, on: :member
get :agent_bot, on: :member
post :set_agent_bot, on: :member
delete :avatar, on: :member
Expand All @@ -151,6 +152,15 @@
end
end
resources :labels, only: [:index, :show, :create, :update, :destroy]
resources :response_sources, only: [:create] do
collection do
post :parse
end
member do
post :add_document
post :remove_document
end
end

resources :notifications, only: [:index, :update] do
collection do
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
class Api::V1::Accounts::ResponseSourcesController < Api::V1::Accounts::BaseController
before_action :current_account
before_action :check_authorization
before_action :find_response_source, only: [:add_document, :remove_document]

def parse
links = PageCrawlerService.new(params[:link]).page_links
render json: { links: links }
end

def create
@response_source = Current.account.response_sources.new(response_source_params)
@response_source.save!
end

def add_document
@response_source.response_documents.create!(document_link: params[:document_link])
end

def remove_document
@response_source.response_documents.find(params[:document_id]).destroy!
end

private

def find_response_source
@response_source = Current.account.response_sources.find(params[:id])
end

def response_source_params
params.require(:response_source).permit(:name, :source_link, :inbox_id,
response_documents_attributes: [:document_link])
end
end
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
module Enterprise::Api::V1::Accounts::InboxesController
def response_sources
@response_sources = @inbox.response_sources
end

def inbox_attributes
super + ee_inbox_attributes
end
Expand Down
7 changes: 7 additions & 0 deletions enterprise/app/jobs/response_bot_job.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
class ResponseBotJob < ApplicationJob
queue_as :medium

def perform(conversation)
::Enterprise::MessageTemplates::ResponseBotService.new(conversation: conversation).perform
end
end
Loading