mirror of
https://github.com/lingble/chatwoot.git
synced 2025-10-29 18:22:53 +00:00
This commit introduces the ability to associate response sources to an inbox, allowing external webpages to be parsed by Chatwoot. The parsed data is converted into embeddings for use with GPT models when managing customer queries. The implementation relies on the `pgvector` extension for PostgreSQL. Database migrations related to this feature are handled separately by `Features::ResponseBotService`. A future update will integrate these migrations into the default rails migrations, once compatibility with Postgres extensions across all self-hosted installation options is confirmed. Additionally, a new GitHub action has been added to the CI pipeline to ensure the execution of specs related to this feature.
156 lines
5.7 KiB
Ruby
156 lines
5.7 KiB
Ruby
# == Schema Information
|
|
#
|
|
# Table name: accounts
|
|
#
|
|
# id :integer not null, primary key
|
|
# auto_resolve_duration :integer
|
|
# custom_attributes :jsonb
|
|
# domain :string(100)
|
|
# feature_flags :integer default(0), not null
|
|
# limits :jsonb
|
|
# locale :integer default("en")
|
|
# name :string not null
|
|
# status :integer default("active")
|
|
# support_email :string(100)
|
|
# created_at :datetime not null
|
|
# updated_at :datetime not null
|
|
#
|
|
# Indexes
|
|
#
|
|
# index_accounts_on_status (status)
|
|
#
|
|
|
|
class Account < ApplicationRecord
|
|
# used for single column multi flags
|
|
include FlagShihTzu
|
|
include Reportable
|
|
include Featurable
|
|
include CacheKeys
|
|
|
|
DEFAULT_QUERY_SETTING = {
|
|
flag_query_mode: :bit_operator,
|
|
check_for_column: false
|
|
}.freeze
|
|
|
|
validates :name, presence: true
|
|
validates :auto_resolve_duration, numericality: { greater_than_or_equal_to: 1, less_than_or_equal_to: 999, allow_nil: true }
|
|
validates :domain, length: { maximum: 100 }
|
|
|
|
has_many :account_users, dependent: :destroy_async
|
|
has_many :agent_bot_inboxes, dependent: :destroy_async
|
|
has_many :agent_bots, dependent: :destroy_async
|
|
has_many :api_channels, dependent: :destroy_async, class_name: '::Channel::Api'
|
|
has_many :articles, dependent: :destroy_async, class_name: '::Article'
|
|
has_many :automation_rules, dependent: :destroy_async
|
|
has_many :macros, dependent: :destroy_async
|
|
has_many :campaigns, dependent: :destroy_async
|
|
has_many :canned_responses, dependent: :destroy_async
|
|
has_many :categories, dependent: :destroy_async, class_name: '::Category'
|
|
has_many :contacts, dependent: :destroy_async
|
|
has_many :conversations, dependent: :destroy_async
|
|
has_many :csat_survey_responses, dependent: :destroy_async
|
|
has_many :custom_attribute_definitions, dependent: :destroy_async
|
|
has_many :custom_filters, dependent: :destroy_async
|
|
has_many :dashboard_apps, dependent: :destroy_async
|
|
has_many :data_imports, dependent: :destroy_async
|
|
has_many :email_channels, dependent: :destroy_async, class_name: '::Channel::Email'
|
|
has_many :facebook_pages, dependent: :destroy_async, class_name: '::Channel::FacebookPage'
|
|
has_many :hooks, dependent: :destroy_async, class_name: 'Integrations::Hook'
|
|
has_many :inboxes, dependent: :destroy_async
|
|
has_many :labels, dependent: :destroy_async
|
|
has_many :line_channels, dependent: :destroy_async, class_name: '::Channel::Line'
|
|
has_many :mentions, dependent: :destroy_async
|
|
has_many :messages, dependent: :destroy_async
|
|
has_many :notes, dependent: :destroy_async
|
|
has_many :notification_settings, dependent: :destroy_async
|
|
has_many :notifications, dependent: :destroy_async
|
|
has_many :portals, dependent: :destroy_async, class_name: '::Portal'
|
|
has_many :sms_channels, dependent: :destroy_async, class_name: '::Channel::Sms'
|
|
has_many :teams, dependent: :destroy_async
|
|
has_many :telegram_bots, dependent: :destroy_async
|
|
has_many :telegram_channels, dependent: :destroy_async, class_name: '::Channel::Telegram'
|
|
has_many :twilio_sms, dependent: :destroy_async, class_name: '::Channel::TwilioSms'
|
|
has_many :twitter_profiles, dependent: :destroy_async, class_name: '::Channel::TwitterProfile'
|
|
has_many :users, through: :account_users
|
|
has_many :web_widgets, dependent: :destroy_async, class_name: '::Channel::WebWidget'
|
|
has_many :webhooks, dependent: :destroy_async
|
|
has_many :whatsapp_channels, dependent: :destroy_async, class_name: '::Channel::Whatsapp'
|
|
has_many :working_hours, dependent: :destroy_async
|
|
|
|
has_one_attached :contacts_export
|
|
|
|
enum locale: LANGUAGES_CONFIG.map { |key, val| [val[:iso_639_1_code], key] }.to_h
|
|
enum status: { active: 0, suspended: 1 }
|
|
|
|
before_validation :validate_limit_keys
|
|
after_create_commit :notify_creation
|
|
after_destroy :remove_account_sequences
|
|
|
|
def agents
|
|
users.where(account_users: { role: :agent })
|
|
end
|
|
|
|
def administrators
|
|
users.where(account_users: { role: :administrator })
|
|
end
|
|
|
|
def all_conversation_tags
|
|
# returns array of tags
|
|
conversation_ids = conversations.pluck(:id)
|
|
ActsAsTaggableOn::Tagging.includes(:tag)
|
|
.where(context: 'labels',
|
|
taggable_type: 'Conversation',
|
|
taggable_id: conversation_ids)
|
|
.map { |_| _.tag.name }
|
|
end
|
|
|
|
def webhook_data
|
|
{
|
|
id: id,
|
|
name: name
|
|
}
|
|
end
|
|
|
|
def inbound_email_domain
|
|
domain || GlobalConfig.get('MAILER_INBOUND_EMAIL_DOMAIN')['MAILER_INBOUND_EMAIL_DOMAIN'] || ENV.fetch('MAILER_INBOUND_EMAIL_DOMAIN', false)
|
|
end
|
|
|
|
def support_email
|
|
super || ENV.fetch('MAILER_SENDER_EMAIL') { GlobalConfig.get('MAILER_SUPPORT_EMAIL')['MAILER_SUPPORT_EMAIL'] }
|
|
end
|
|
|
|
def usage_limits
|
|
{
|
|
agents: ChatwootApp.max_limit.to_i,
|
|
inboxes: ChatwootApp.max_limit.to_i
|
|
}
|
|
end
|
|
|
|
private
|
|
|
|
def notify_creation
|
|
Rails.configuration.dispatcher.dispatch(ACCOUNT_CREATED, Time.zone.now, account: self)
|
|
end
|
|
|
|
trigger.after(:insert).for_each(:row) do
|
|
"execute format('create sequence IF NOT EXISTS conv_dpid_seq_%s', NEW.id);"
|
|
end
|
|
|
|
trigger.name('camp_dpid_before_insert').after(:insert).for_each(:row) do
|
|
"execute format('create sequence IF NOT EXISTS camp_dpid_seq_%s', NEW.id);"
|
|
end
|
|
|
|
def validate_limit_keys
|
|
# method overridden in enterprise module
|
|
end
|
|
|
|
def remove_account_sequences
|
|
ActiveRecord::Base.connection.exec_query("drop sequence IF EXISTS camp_dpid_seq_#{id}")
|
|
ActiveRecord::Base.connection.exec_query("drop sequence IF EXISTS conv_dpid_seq_#{id}")
|
|
end
|
|
end
|
|
|
|
Account.prepend_mod_with('Account')
|
|
Account.include_mod_with('Concerns::Account')
|
|
Account.include_mod_with('Audit::Account')
|