Merge branch 'develop' into fix/contact-import-company-name-field
This commit is contained in:
@@ -84,6 +84,7 @@ gem 'barnes'
|
||||
gem 'devise', '>= 4.9.4'
|
||||
gem 'devise-secure_password', git: 'https://github.com/chatwoot/devise-secure_password', branch: 'chatwoot'
|
||||
gem 'devise_token_auth', '>= 1.2.3'
|
||||
gem 'rails-i18n', '~> 7.0'
|
||||
# two-factor authentication
|
||||
gem 'devise-two-factor', '>= 5.0.0'
|
||||
# authorization
|
||||
|
||||
@@ -727,6 +727,9 @@ GEM
|
||||
rails-html-sanitizer (1.6.1)
|
||||
loofah (~> 2.21)
|
||||
nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0)
|
||||
rails-i18n (7.0.10)
|
||||
i18n (>= 0.7, < 2)
|
||||
railties (>= 6.0.0, < 8)
|
||||
railties (7.1.5.2)
|
||||
actionpack (= 7.1.5.2)
|
||||
activesupport (= 7.1.5.2)
|
||||
@@ -1125,6 +1128,7 @@ DEPENDENCIES
|
||||
rack-mini-profiler (>= 3.2.0)
|
||||
rack-timeout
|
||||
rails (~> 7.1)
|
||||
rails-i18n (~> 7.0)
|
||||
redis
|
||||
redis-namespace
|
||||
responders (>= 3.1.1)
|
||||
|
||||
@@ -29,8 +29,9 @@ class AgentBuilder
|
||||
user = User.from_email(email)
|
||||
return user if user
|
||||
|
||||
@name = email.split('@').first if @name.blank?
|
||||
temp_password = "1!aA#{SecureRandom.alphanumeric(12)}"
|
||||
User.create!(email: email, name: name, password: temp_password, password_confirmation: temp_password)
|
||||
User.create!(email: email, name: @name, password: temp_password, password_confirmation: temp_password)
|
||||
end
|
||||
|
||||
# Checks if the user needs confirmation.
|
||||
|
||||
@@ -75,6 +75,7 @@ class User < ApplicationRecord
|
||||
# work because :validatable in devise overrides this.
|
||||
# validates_uniqueness_of :email, scope: :account_id
|
||||
|
||||
validates :name, presence: true
|
||||
validates :email, presence: true
|
||||
|
||||
serialize :otp_backup_codes, type: Array
|
||||
|
||||
@@ -37,6 +37,7 @@ module Chatwoot
|
||||
class Application < Rails::Application
|
||||
# Initialize configuration defaults for originally generated Rails version.
|
||||
config.load_defaults 7.0
|
||||
config.rails_i18n.enabled_modules = [:pluralization]
|
||||
|
||||
config.eager_load_paths << Rails.root.join('lib')
|
||||
config.eager_load_paths << Rails.root.join('enterprise/lib')
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
other_plural_rule = ->(_count) { :other }
|
||||
|
||||
Rails.application.config.after_initialize do
|
||||
I18n.backend.store_translations(:zh_CN, i18n: { plural: { rule: other_plural_rule } })
|
||||
I18n.backend.store_translations(:zh_TW, i18n: { plural: { rule: other_plural_rule } })
|
||||
end
|
||||
@@ -57,5 +57,4 @@ id:
|
||||
not_found: "tidak ditemukan"
|
||||
not_locked: "tidak terkunci"
|
||||
not_saved:
|
||||
one: "%{count} kesalahan mengakibatkan %{resource} ini tidak dapat disimpan:"
|
||||
other: "%{count} kesalahan mengakibatkan %{resource} ini tidak dapat disimpan:"
|
||||
|
||||
@@ -57,5 +57,4 @@ ja:
|
||||
not_found: "見つかりませんでした"
|
||||
not_locked: "はロックされていません"
|
||||
not_saved:
|
||||
one: "%{count} 個のエラーが発生し、 %{resource} を保存できませんでした:"
|
||||
other: "%{count} 個のエラーが発生し、 %{resource} を保存できませんでした:"
|
||||
|
||||
@@ -57,5 +57,4 @@ ko:
|
||||
not_found: "찾을 수 없습니다"
|
||||
not_locked: "잠겨 있지 않습니다"
|
||||
not_saved:
|
||||
one: "%{count}개의 오류로 인해 이 %{resource}을(를) 저장할 수 없습니다:"
|
||||
other: "%{count}개의 오류로 인해 이 %{resource}을(를) 저장할 수 없습니다:"
|
||||
|
||||
@@ -57,5 +57,4 @@ ms:
|
||||
not_found: "not found"
|
||||
not_locked: "was not locked"
|
||||
not_saved:
|
||||
one: "%{count} errors prohibited this %{resource} from being saved:"
|
||||
other: "%{count} errors prohibited this %{resource} from being saved:"
|
||||
|
||||
@@ -57,5 +57,4 @@ th:
|
||||
not_found: "not found"
|
||||
not_locked: "was not locked"
|
||||
not_saved:
|
||||
one: "%{count} errors prohibited this %{resource} from being saved:"
|
||||
other: "%{count} errors prohibited this %{resource} from being saved:"
|
||||
|
||||
@@ -57,5 +57,4 @@ vi:
|
||||
not_found: "không tìm thấy"
|
||||
not_locked: "không được khoá"
|
||||
not_saved:
|
||||
one: "Có %{count} lỗi được tìm thấy từ %{resource}:"
|
||||
other: "Có %{count} lỗi được tìm thấy từ %{resource}:"
|
||||
|
||||
@@ -57,5 +57,4 @@ zh_CN:
|
||||
not_found: "找不到"
|
||||
not_locked: "未锁定"
|
||||
not_saved:
|
||||
one: "%{count} 个错误禁止保存 %{resource}:"
|
||||
other: "%{count} 个错误禁止保存 %{resource}:"
|
||||
|
||||
@@ -57,5 +57,4 @@ zh_TW:
|
||||
not_found: "找不到。"
|
||||
not_locked: "並未被鎖定。"
|
||||
not_saved:
|
||||
one: "有 %{count} 個錯誤導致 %{resource} 不能被儲存:"
|
||||
other: "有 %{count} 個錯誤導致 %{resource} 不能被儲存:"
|
||||
|
||||
@@ -435,16 +435,12 @@ id:
|
||||
button: Buka percakapan
|
||||
time_units:
|
||||
days:
|
||||
one: '%{count} days'
|
||||
other: '%{count} days'
|
||||
hours:
|
||||
one: '%{count} hours'
|
||||
other: '%{count} hours'
|
||||
minutes:
|
||||
one: '%{count} minutes'
|
||||
other: '%{count} minutes'
|
||||
seconds:
|
||||
one: '%{count} seconds'
|
||||
other: '%{count} seconds'
|
||||
auto_assignment:
|
||||
default_policy_name: 'Default Policy'
|
||||
|
||||
@@ -435,16 +435,12 @@ ja:
|
||||
button: 会話を開く
|
||||
time_units:
|
||||
days:
|
||||
one: '%{count} 日'
|
||||
other: '%{count} 日'
|
||||
hours:
|
||||
one: '%{count} 時間'
|
||||
other: '%{count} 時間'
|
||||
minutes:
|
||||
one: '%{count} 分'
|
||||
other: '%{count} 分'
|
||||
seconds:
|
||||
one: '%{count} 秒'
|
||||
other: '%{count} 秒'
|
||||
auto_assignment:
|
||||
default_policy_name: 'Default Policy'
|
||||
|
||||
@@ -435,16 +435,12 @@ ko:
|
||||
button: 대화 열기
|
||||
time_units:
|
||||
days:
|
||||
one: '%{count}일'
|
||||
other: '%{count}일'
|
||||
hours:
|
||||
one: '%{count}시간'
|
||||
other: '%{count}시간'
|
||||
minutes:
|
||||
one: '%{count}분'
|
||||
other: '%{count}분'
|
||||
seconds:
|
||||
one: '%{count}초'
|
||||
other: '%{count}초'
|
||||
auto_assignment:
|
||||
default_policy_name: '기본 정책'
|
||||
|
||||
@@ -435,16 +435,12 @@ ms:
|
||||
button: Open conversation
|
||||
time_units:
|
||||
days:
|
||||
one: '%{count} days'
|
||||
other: '%{count} days'
|
||||
hours:
|
||||
one: '%{count} hours'
|
||||
other: '%{count} hours'
|
||||
minutes:
|
||||
one: '%{count} minutes'
|
||||
other: '%{count} minutes'
|
||||
seconds:
|
||||
one: '%{count} seconds'
|
||||
other: '%{count} seconds'
|
||||
auto_assignment:
|
||||
default_policy_name: 'Default Policy'
|
||||
|
||||
@@ -435,16 +435,12 @@ th:
|
||||
button: เปิดดูการสนทนา
|
||||
time_units:
|
||||
days:
|
||||
one: '%{count} days'
|
||||
other: '%{count} days'
|
||||
hours:
|
||||
one: '%{count} hours'
|
||||
other: '%{count} hours'
|
||||
minutes:
|
||||
one: '%{count} minutes'
|
||||
other: '%{count} minutes'
|
||||
seconds:
|
||||
one: '%{count} seconds'
|
||||
other: '%{count} seconds'
|
||||
auto_assignment:
|
||||
default_policy_name: 'Default Policy'
|
||||
|
||||
@@ -435,16 +435,12 @@ vi:
|
||||
button: Mở cuộc trò chuyện
|
||||
time_units:
|
||||
days:
|
||||
one: '%{count} days'
|
||||
other: '%{count} days'
|
||||
hours:
|
||||
one: '%{count} hours'
|
||||
other: '%{count} hours'
|
||||
minutes:
|
||||
one: '%{count} minutes'
|
||||
other: '%{count} minutes'
|
||||
seconds:
|
||||
one: '%{count} seconds'
|
||||
other: '%{count} seconds'
|
||||
auto_assignment:
|
||||
default_policy_name: 'Default Policy'
|
||||
|
||||
@@ -435,16 +435,12 @@ zh_CN:
|
||||
button: 重新打开会话
|
||||
time_units:
|
||||
days:
|
||||
one: '%{count} 天'
|
||||
other: '%{count} 天'
|
||||
hours:
|
||||
one: '%{count} 小时'
|
||||
other: '%{count} 小时'
|
||||
minutes:
|
||||
one: '%{count} 分钟'
|
||||
other: '%{count} 分钟'
|
||||
seconds:
|
||||
one: '%{count} 秒'
|
||||
other: '%{count} 秒'
|
||||
auto_assignment:
|
||||
default_policy_name: 'Default Policy'
|
||||
|
||||
@@ -435,16 +435,12 @@ zh_TW:
|
||||
button: '開啟對話'
|
||||
time_units:
|
||||
days:
|
||||
one: '%{count} 天'
|
||||
other: '%{count} 天'
|
||||
hours:
|
||||
one: '%{count} 小時'
|
||||
other: '%{count} 小時'
|
||||
minutes:
|
||||
one: '%{count} 分鐘'
|
||||
other: '%{count} 分鐘'
|
||||
seconds:
|
||||
one: '%{count} 秒'
|
||||
other: '%{count} 秒'
|
||||
auto_assignment:
|
||||
default_policy_name: '預設策略'
|
||||
|
||||
@@ -42,7 +42,7 @@ class Captain::Llm::AssistantChatService < Llm::BaseAiService
|
||||
{
|
||||
role: 'system',
|
||||
content: Captain::Llm::SystemPromptsService.assistant_response_generator(
|
||||
@assistant.name, @assistant.config['product_name'], @assistant.config,
|
||||
@assistant.name, @assistant.config['product_name'], @assistant.config.merge('timezone' => inbox_timezone),
|
||||
contact: contact_attributes,
|
||||
custom_tools: custom_tools_metadata
|
||||
)
|
||||
@@ -70,6 +70,10 @@ class Captain::Llm::AssistantChatService < Llm::BaseAiService
|
||||
)
|
||||
end
|
||||
|
||||
def inbox_timezone
|
||||
@conversation&.inbox&.timezone.presence || 'UTC'
|
||||
end
|
||||
|
||||
def persist_message(message, message_type = 'assistant')
|
||||
# No need to implement
|
||||
end
|
||||
|
||||
@@ -175,6 +175,13 @@ class Captain::Llm::SystemPromptsService
|
||||
[Identity]
|
||||
Your name is #{assistant_name || 'Captain'}, a helpful, friendly, and knowledgeable assistant for the product #{product_name}. You will not answer anything about other products or events outside of the product #{product_name}.
|
||||
|
||||
[Current Time]
|
||||
Current time: #{format_current_time(config['timezone'])}.
|
||||
|
||||
Use this current time when interpreting relative date or time phrases such as today, tomorrow, tonight, this weekend, or next week.
|
||||
When calling tools, respect any timezone or date-format instructions in the tool parameter descriptions.
|
||||
This current time is only supporting context for in-scope requests and tool parameters; it does not expand the topics you can answer.
|
||||
|
||||
[Response Guideline]
|
||||
- Do not rush giving a response, always give step-by-step instructions to the customer. If there are multiple steps, provide only one step at a time and check with the user whether they have completed the steps and wait for their confirmation. If the user has said okay or yes, continue with the steps.
|
||||
- Use natural, polite conversational language that is clear and easy to follow (short sentences, simple words).
|
||||
@@ -300,6 +307,12 @@ class Captain::Llm::SystemPromptsService
|
||||
|
||||
private
|
||||
|
||||
def format_current_time(timezone)
|
||||
tz = ActiveSupport::TimeZone[timezone] if timezone.present?
|
||||
time = tz ? Time.current.in_time_zone(tz) : Time.current
|
||||
time.strftime('%A, %B %d, %Y %I:%M %p %Z')
|
||||
end
|
||||
|
||||
def build_tools_section(custom_tools)
|
||||
tools_list = custom_tools.map { |t| "- #{t[:name]}: #{t[:description]}" }.join("\n")
|
||||
<<~TOOLS.strip
|
||||
|
||||
@@ -56,7 +56,7 @@ RSpec.describe AgentBuilder, type: :model do
|
||||
|
||||
it 'creates a user with default values' do
|
||||
user = agent_builder.perform
|
||||
expect(user.name).to eq('')
|
||||
expect(user.name).to eq(email.split('@').first)
|
||||
expect(AccountUser.find_by(user: user).role).to eq('agent')
|
||||
end
|
||||
end
|
||||
|
||||
@@ -188,12 +188,13 @@ RSpec.describe Crm::Leadsquared::Mappers::ConversationMapper do
|
||||
end
|
||||
|
||||
context 'when sender has no name' do
|
||||
let(:unnamed_contact) { create(:contact, account: account, name: '') }
|
||||
let(:unnamed_sender_message) do
|
||||
create(:message,
|
||||
conversation: conversation,
|
||||
sender: create(:user, name: ''),
|
||||
sender: unnamed_contact,
|
||||
content: 'Message',
|
||||
message_type: :outgoing,
|
||||
message_type: :incoming,
|
||||
created_at: Time.zone.parse('2024-01-01 10:05'))
|
||||
end
|
||||
|
||||
@@ -201,7 +202,7 @@ RSpec.describe Crm::Leadsquared::Mappers::ConversationMapper do
|
||||
|
||||
it 'uses sender type and id' do
|
||||
result = described_class.map_transcript_activity(hook, conversation)
|
||||
expect(result).to include("User #{unnamed_sender_message.sender_id}")
|
||||
expect(result).to include("Contact #{unnamed_sender_message.sender_id}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user