polylingo_chat 0.1.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +383 -22
- data/lib/generators/polylingo_chat/install/README +72 -0
- data/lib/generators/polylingo_chat/install/install_generator.rb +44 -16
- data/lib/generators/polylingo_chat/install/templates/channels/polylingo_chat_channel.rb +1 -1
- data/lib/generators/polylingo_chat/install/templates/controllers/polylingo_chat/conversations_controller.rb +127 -0
- data/lib/generators/polylingo_chat/install/templates/controllers/polylingo_chat/messages_controller.rb +113 -0
- data/lib/generators/polylingo_chat/install/templates/create_conversations.rb +2 -2
- data/lib/generators/polylingo_chat/install/templates/create_message_translations.rb +13 -0
- data/lib/generators/polylingo_chat/install/templates/create_messages.rb +8 -4
- data/lib/generators/polylingo_chat/install/templates/create_participants.rb +8 -5
- data/lib/generators/polylingo_chat/install/templates/javascript/chat.js +5 -5
- data/lib/generators/polylingo_chat/install/templates/jobs/translate_job.rb +93 -0
- data/lib/generators/polylingo_chat/install/templates/models/conversation.rb +34 -5
- data/lib/generators/polylingo_chat/install/templates/models/message.rb +16 -8
- data/lib/generators/polylingo_chat/install/templates/models/participant.rb +19 -4
- data/lib/generators/polylingo_chat/install/templates/views/polylingo_chat/conversations/index.html.erb +56 -0
- data/lib/generators/polylingo_chat/install/templates/views/polylingo_chat/conversations/show.html.erb +141 -0
- data/lib/polylingo_chat/translator/anthropic_client.rb +2 -2
- data/lib/polylingo_chat/translator/gemini_client.rb +2 -2
- data/lib/polylingo_chat/translator/openai_client.rb +2 -2
- data/lib/polylingo_chat/version.rb +1 -1
- data/lib/polylingo_chat.rb +0 -1
- metadata +17 -29
- data/lib/generators/polylingo_chat/install_generator.rb +0 -38
- data/lib/generators/polylingo_chat/templates/INSTALL_README.md +0 -124
- data/lib/generators/polylingo_chat/templates/chat_channel_example.js +0 -18
- data/lib/generators/polylingo_chat/templates/create_polyglot_conversations.rb +0 -9
- data/lib/generators/polylingo_chat/templates/create_polyglot_messages.rb +0 -13
- data/lib/generators/polylingo_chat/templates/create_polyglot_participants.rb +0 -12
- data/lib/generators/polylingo_chat/templates/models/conversation.rb +0 -7
- data/lib/generators/polylingo_chat/templates/models/message.rb +0 -14
- data/lib/generators/polylingo_chat/templates/models/participant.rb +0 -6
- data/lib/generators/polylingo_chat/templates/polyglot.rb +0 -53
- data/lib/generators/polylingo_chat/templates/polylingo_chat_channel.rb +0 -19
- data/lib/polylingo_chat/translate_job.rb +0 -63
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
<div class="polylingo-conversation-show">
|
|
2
|
+
<h1><%%= @conversation.title || "Conversation ##{@conversation.id}" %></h1>
|
|
3
|
+
|
|
4
|
+
<div class="conversation-info">
|
|
5
|
+
<p>
|
|
6
|
+
<strong>Participants:</strong>
|
|
7
|
+
<%%= @conversation.participantables.map { |p| p.try(:name) || p.try(:email) }.join(', ') %>
|
|
8
|
+
</p>
|
|
9
|
+
</div>
|
|
10
|
+
|
|
11
|
+
<div id="messages" class="messages-container">
|
|
12
|
+
<%% @conversation.messages.order(created_at: :asc).each do |message| %>
|
|
13
|
+
<div class="message <%%= message.sender == current_user ? 'sent' : 'received' %>" data-message-id="<%%= message.id %>">
|
|
14
|
+
<div class="message-sender"><%%= message.sender_name %></div>
|
|
15
|
+
<div class="message-body"><%%= message.translated_body || message.body %></div>
|
|
16
|
+
<div class="message-time"><%%= time_ago_in_words(message.created_at) %> ago</div>
|
|
17
|
+
</div>
|
|
18
|
+
<%% end %>
|
|
19
|
+
</div>
|
|
20
|
+
|
|
21
|
+
<!-- Message input form -->
|
|
22
|
+
<div class="message-form">
|
|
23
|
+
<%%= form_with url: polylingo_chat_conversation_messages_path(@conversation), method: :post, local: true, class: "new-message-form" do |f| %>
|
|
24
|
+
<div class="form-group">
|
|
25
|
+
<%%= text_area_tag "message[body]", nil, placeholder: "Type your message...", class: "message-input", rows: 3 %>
|
|
26
|
+
<%%= hidden_field_tag :sender_type, current_user.class.name %>
|
|
27
|
+
<%%= hidden_field_tag :sender_id, current_user.id %>
|
|
28
|
+
</div>
|
|
29
|
+
<%%= f.submit "Send", class: "btn-send" %>
|
|
30
|
+
<%% end %>
|
|
31
|
+
</div>
|
|
32
|
+
|
|
33
|
+
<p>
|
|
34
|
+
<%%= link_to "← Back to Conversations", polylingo_chat_conversations_path, class: "btn-back" %>
|
|
35
|
+
</p>
|
|
36
|
+
</div>
|
|
37
|
+
|
|
38
|
+
<script>
|
|
39
|
+
// Set up for real-time chat via ActionCable
|
|
40
|
+
window.conversationId = <%%= @conversation.id %>;
|
|
41
|
+
window.currentUserId = <%%= current_user&.id || 'null' %>;
|
|
42
|
+
</script>
|
|
43
|
+
|
|
44
|
+
<style>
|
|
45
|
+
.polylingo-conversation-show {
|
|
46
|
+
max-width: 800px;
|
|
47
|
+
margin: 0 auto;
|
|
48
|
+
padding: 20px;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.conversation-info {
|
|
52
|
+
padding: 10px;
|
|
53
|
+
background: #f0f0f0;
|
|
54
|
+
border-radius: 5px;
|
|
55
|
+
margin-bottom: 20px;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.messages-container {
|
|
59
|
+
min-height: 400px;
|
|
60
|
+
max-height: 600px;
|
|
61
|
+
overflow-y: auto;
|
|
62
|
+
padding: 20px;
|
|
63
|
+
border: 1px solid #ddd;
|
|
64
|
+
border-radius: 8px;
|
|
65
|
+
background: #fff;
|
|
66
|
+
margin-bottom: 20px;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.message {
|
|
70
|
+
margin-bottom: 15px;
|
|
71
|
+
padding: 10px;
|
|
72
|
+
border-radius: 8px;
|
|
73
|
+
max-width: 70%;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.message.sent {
|
|
77
|
+
margin-left: auto;
|
|
78
|
+
background: #007bff;
|
|
79
|
+
color: white;
|
|
80
|
+
text-align: right;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.message.received {
|
|
84
|
+
background: #f1f1f1;
|
|
85
|
+
color: #333;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.message-sender {
|
|
89
|
+
font-weight: bold;
|
|
90
|
+
font-size: 0.9em;
|
|
91
|
+
margin-bottom: 5px;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.message-body {
|
|
95
|
+
margin-bottom: 5px;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.message-time {
|
|
99
|
+
font-size: 0.8em;
|
|
100
|
+
opacity: 0.7;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
.message-form {
|
|
104
|
+
background: #f9f9f9;
|
|
105
|
+
padding: 15px;
|
|
106
|
+
border-radius: 8px;
|
|
107
|
+
margin-bottom: 20px;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.message-input {
|
|
111
|
+
width: 100%;
|
|
112
|
+
padding: 10px;
|
|
113
|
+
border: 1px solid #ddd;
|
|
114
|
+
border-radius: 5px;
|
|
115
|
+
margin-bottom: 10px;
|
|
116
|
+
font-family: inherit;
|
|
117
|
+
resize: vertical;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
.btn-send {
|
|
121
|
+
background: #007bff;
|
|
122
|
+
color: white;
|
|
123
|
+
padding: 10px 20px;
|
|
124
|
+
border: none;
|
|
125
|
+
border-radius: 5px;
|
|
126
|
+
cursor: pointer;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.btn-send:hover {
|
|
130
|
+
background: #0056b3;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
.btn-back {
|
|
134
|
+
color: #007bff;
|
|
135
|
+
text-decoration: none;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.btn-back:hover {
|
|
139
|
+
text-decoration: underline;
|
|
140
|
+
}
|
|
141
|
+
</style>
|
|
@@ -21,7 +21,7 @@ module PolylingoChat
|
|
|
21
21
|
# caching
|
|
22
22
|
cache_key = "polylingo_chat:#{Digest::SHA1.hexdigest([text, from, to, context].join(':'))}"
|
|
23
23
|
if (cache = PolylingoChat.config.cache_store)
|
|
24
|
-
cached = cache.get(cache_key) rescue nil
|
|
24
|
+
cached = cache.get(cache_key) rescue StandardError; nil
|
|
25
25
|
return JSON.parse(cached)['translated'] if cached
|
|
26
26
|
end
|
|
27
27
|
|
|
@@ -31,7 +31,7 @@ module PolylingoChat
|
|
|
31
31
|
if (cache = PolylingoChat.config.cache_store)
|
|
32
32
|
begin
|
|
33
33
|
cache.set(cache_key, { translated: translated }.to_json)
|
|
34
|
-
rescue => e
|
|
34
|
+
rescue StandardError => e
|
|
35
35
|
# ignore cache failures
|
|
36
36
|
end
|
|
37
37
|
end
|
|
@@ -21,7 +21,7 @@ module PolylingoChat
|
|
|
21
21
|
# caching
|
|
22
22
|
cache_key = "polylingo_chat:#{Digest::SHA1.hexdigest([text, from, to, context].join(':'))}"
|
|
23
23
|
if (cache = PolylingoChat.config.cache_store)
|
|
24
|
-
cached = cache.get(cache_key) rescue nil
|
|
24
|
+
cached = cache.get(cache_key) rescue StandardError; nil
|
|
25
25
|
return JSON.parse(cached)['translated'] if cached
|
|
26
26
|
end
|
|
27
27
|
|
|
@@ -31,7 +31,7 @@ module PolylingoChat
|
|
|
31
31
|
if (cache = PolylingoChat.config.cache_store)
|
|
32
32
|
begin
|
|
33
33
|
cache.set(cache_key, { translated: translated }.to_json)
|
|
34
|
-
rescue => e
|
|
34
|
+
rescue StandardError => e
|
|
35
35
|
# ignore cache failures
|
|
36
36
|
end
|
|
37
37
|
end
|
|
@@ -23,7 +23,7 @@ module PolylingoChat
|
|
|
23
23
|
# caching
|
|
24
24
|
cache_key = "polylingo_chat:#{Digest::SHA1.hexdigest([text, from, to, context].join(':'))}"
|
|
25
25
|
if (cache = PolylingoChat.config.cache_store)
|
|
26
|
-
cached = cache.get(cache_key) rescue nil
|
|
26
|
+
cached = cache.get(cache_key) rescue StandardError; nil
|
|
27
27
|
return JSON.parse(cached)['translated'] if cached
|
|
28
28
|
end
|
|
29
29
|
|
|
@@ -33,7 +33,7 @@ module PolylingoChat
|
|
|
33
33
|
if (cache = PolylingoChat.config.cache_store)
|
|
34
34
|
begin
|
|
35
35
|
cache.set(cache_key, { translated: translated }.to_json)
|
|
36
|
-
rescue => e
|
|
36
|
+
rescue StandardError => e
|
|
37
37
|
# ignore cache failures
|
|
38
38
|
end
|
|
39
39
|
end
|
data/lib/polylingo_chat.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: polylingo_chat
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.4.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Shoaib Malik
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2025-11-
|
|
11
|
+
date: 2025-11-18 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rails
|
|
@@ -17,6 +17,9 @@ dependencies:
|
|
|
17
17
|
- - ">="
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
19
|
version: '6.0'
|
|
20
|
+
- - "<"
|
|
21
|
+
- !ruby/object:Gem::Version
|
|
22
|
+
version: '9'
|
|
20
23
|
type: :runtime
|
|
21
24
|
prerelease: false
|
|
22
25
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -24,6 +27,9 @@ dependencies:
|
|
|
24
27
|
- - ">="
|
|
25
28
|
- !ruby/object:Gem::Version
|
|
26
29
|
version: '6.0'
|
|
30
|
+
- - "<"
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '9'
|
|
27
33
|
- !ruby/object:Gem::Dependency
|
|
28
34
|
name: faraday
|
|
29
35
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -52,20 +58,6 @@ dependencies:
|
|
|
52
58
|
- - "~>"
|
|
53
59
|
- !ruby/object:Gem::Version
|
|
54
60
|
version: '1.2'
|
|
55
|
-
- !ruby/object:Gem::Dependency
|
|
56
|
-
name: json
|
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
|
58
|
-
requirements:
|
|
59
|
-
- - ">="
|
|
60
|
-
- !ruby/object:Gem::Version
|
|
61
|
-
version: '0'
|
|
62
|
-
type: :runtime
|
|
63
|
-
prerelease: false
|
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
-
requirements:
|
|
66
|
-
- - ">="
|
|
67
|
-
- !ruby/object:Gem::Version
|
|
68
|
-
version: '0'
|
|
69
61
|
description:
|
|
70
62
|
email:
|
|
71
63
|
- shoaib2109@gmail.com
|
|
@@ -74,38 +66,33 @@ extensions: []
|
|
|
74
66
|
extra_rdoc_files: []
|
|
75
67
|
files:
|
|
76
68
|
- README.md
|
|
69
|
+
- lib/generators/polylingo_chat/install/README
|
|
77
70
|
- lib/generators/polylingo_chat/install/install_generator.rb
|
|
78
71
|
- lib/generators/polylingo_chat/install/templates/README
|
|
79
72
|
- lib/generators/polylingo_chat/install/templates/channels/application_cable/channel.rb
|
|
80
73
|
- lib/generators/polylingo_chat/install/templates/channels/application_cable/connection.rb
|
|
81
74
|
- lib/generators/polylingo_chat/install/templates/channels/polylingo_chat_channel.rb
|
|
75
|
+
- lib/generators/polylingo_chat/install/templates/controllers/polylingo_chat/conversations_controller.rb
|
|
76
|
+
- lib/generators/polylingo_chat/install/templates/controllers/polylingo_chat/messages_controller.rb
|
|
82
77
|
- lib/generators/polylingo_chat/install/templates/create_conversations.rb
|
|
78
|
+
- lib/generators/polylingo_chat/install/templates/create_message_translations.rb
|
|
83
79
|
- lib/generators/polylingo_chat/install/templates/create_messages.rb
|
|
84
80
|
- lib/generators/polylingo_chat/install/templates/create_participants.rb
|
|
85
81
|
- lib/generators/polylingo_chat/install/templates/initializer.rb
|
|
86
82
|
- lib/generators/polylingo_chat/install/templates/javascript/channels/consumer.js
|
|
87
83
|
- lib/generators/polylingo_chat/install/templates/javascript/channels/index.js
|
|
88
84
|
- lib/generators/polylingo_chat/install/templates/javascript/chat.js
|
|
85
|
+
- lib/generators/polylingo_chat/install/templates/jobs/translate_job.rb
|
|
89
86
|
- lib/generators/polylingo_chat/install/templates/models/conversation.rb
|
|
90
87
|
- lib/generators/polylingo_chat/install/templates/models/message.rb
|
|
91
88
|
- lib/generators/polylingo_chat/install/templates/models/participant.rb
|
|
92
|
-
- lib/generators/polylingo_chat/
|
|
93
|
-
- lib/generators/polylingo_chat/templates/
|
|
94
|
-
- lib/generators/polylingo_chat/templates/chat_channel_example.js
|
|
95
|
-
- lib/generators/polylingo_chat/templates/create_polyglot_conversations.rb
|
|
96
|
-
- lib/generators/polylingo_chat/templates/create_polyglot_messages.rb
|
|
97
|
-
- lib/generators/polylingo_chat/templates/create_polyglot_participants.rb
|
|
98
|
-
- lib/generators/polylingo_chat/templates/models/conversation.rb
|
|
99
|
-
- lib/generators/polylingo_chat/templates/models/message.rb
|
|
100
|
-
- lib/generators/polylingo_chat/templates/models/participant.rb
|
|
101
|
-
- lib/generators/polylingo_chat/templates/polyglot.rb
|
|
102
|
-
- lib/generators/polylingo_chat/templates/polylingo_chat_channel.rb
|
|
89
|
+
- lib/generators/polylingo_chat/install/templates/views/polylingo_chat/conversations/index.html.erb
|
|
90
|
+
- lib/generators/polylingo_chat/install/templates/views/polylingo_chat/conversations/show.html.erb
|
|
103
91
|
- lib/polylingo_chat.rb
|
|
104
92
|
- lib/polylingo_chat/config.rb
|
|
105
93
|
- lib/polylingo_chat/engine.rb
|
|
106
94
|
- lib/polylingo_chat/railtie.rb
|
|
107
95
|
- lib/polylingo_chat/realtime.rb
|
|
108
|
-
- lib/polylingo_chat/translate_job.rb
|
|
109
96
|
- lib/polylingo_chat/translator.rb
|
|
110
97
|
- lib/polylingo_chat/translator/anthropic_client.rb
|
|
111
98
|
- lib/polylingo_chat/translator/base.rb
|
|
@@ -134,5 +121,6 @@ requirements: []
|
|
|
134
121
|
rubygems_version: 3.4.10
|
|
135
122
|
signing_key:
|
|
136
123
|
specification_version: 4
|
|
137
|
-
summary: Realtime chat with automatic AI translation for Ruby/Rails apps
|
|
124
|
+
summary: Realtime chat with automatic AI translation for Ruby/Rails apps - supports
|
|
125
|
+
API-only mode and polymorphic associations
|
|
138
126
|
test_files: []
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
require 'rails/generators'
|
|
2
|
-
module PolylingoChat
|
|
3
|
-
module Generators
|
|
4
|
-
class InstallGenerator < Rails::Generators::Base
|
|
5
|
-
source_root File.expand_path('templates', __dir__)
|
|
6
|
-
|
|
7
|
-
def copy_initializer
|
|
8
|
-
template 'polylingo_chat.rb', 'config/initializers/polylingo_chat.rb'
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
def copy_channel
|
|
12
|
-
template 'polylingo_chat_chat_channel.rb', 'app/channels/polylingo_chat_chat_channel.rb'
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
def copy_js_example
|
|
16
|
-
template 'chat_channel_example.js', 'app/javascript/channels/polylingo_chat_chat_channel.js'
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def copy_models
|
|
20
|
-
template 'models/conversation.rb', 'app/models/conversation.rb'
|
|
21
|
-
template 'models/participant.rb', 'app/models/participant.rb'
|
|
22
|
-
template 'models/message.rb', 'app/models/message.rb'
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def copy_migrations
|
|
26
|
-
migration_template 'create_polylingo_chat_conversations.rb', 'db/migrate/create_polylingo_chat_conversations.rb'
|
|
27
|
-
migration_template 'create_polylingo_chat_participants.rb', 'db/migrate/create_polylingo_chat_participants.rb'
|
|
28
|
-
migration_template 'create_polylingo_chat_messages.rb', 'db/migrate/create_polylingo_chat_messages.rb'
|
|
29
|
-
rescue => e
|
|
30
|
-
say_status('warning', 'Skipping migrations: ensure you add your own Message/Conversation models or run generator again with --migrate', :yellow)
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
def show_readme
|
|
34
|
-
readme 'INSTALL_README.md' if behavior == :invoke
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
end
|
|
38
|
-
end
|
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
## PolylingoChat Installation Complete!
|
|
2
|
-
|
|
3
|
-
### Next Steps:
|
|
4
|
-
|
|
5
|
-
**PolylingoChat can work in TWO modes:**
|
|
6
|
-
1. **Chat-Only Mode:** Real-time chat without translation (no API key needed)
|
|
7
|
-
2. **With Translation:** AI-powered translation (API key required)
|
|
8
|
-
|
|
9
|
-
---
|
|
10
|
-
|
|
11
|
-
### 1. Run migrations
|
|
12
|
-
```bash
|
|
13
|
-
bin/rails db:migrate
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
### 2. Configure ActiveJob
|
|
17
|
-
|
|
18
|
-
```ruby
|
|
19
|
-
# config/application.rb or config/environments/production.rb
|
|
20
|
-
config.active_job.queue_adapter = :sidekiq # or :solid_queue, :delayed_job, :async
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
### 3. Install your background job processor
|
|
24
|
-
|
|
25
|
-
**Sidekiq:**
|
|
26
|
-
```ruby
|
|
27
|
-
# Gemfile
|
|
28
|
-
gem 'sidekiq'
|
|
29
|
-
```
|
|
30
|
-
Then: `bundle install && bundle exec sidekiq`
|
|
31
|
-
|
|
32
|
-
**Solid Queue:**
|
|
33
|
-
```ruby
|
|
34
|
-
# Gemfile
|
|
35
|
-
gem 'solid_queue'
|
|
36
|
-
```
|
|
37
|
-
Then: `bundle install && bin/rails solid_queue:install && bin/rails db:migrate && bin/rails solid_queue:start`
|
|
38
|
-
|
|
39
|
-
**Delayed Job:**
|
|
40
|
-
```ruby
|
|
41
|
-
# Gemfile
|
|
42
|
-
gem 'delayed_job_active_record'
|
|
43
|
-
```
|
|
44
|
-
Then: `bundle install && bin/rails generate delayed_job:active_record && bin/rails db:migrate && bin/rails jobs:work`
|
|
45
|
-
|
|
46
|
-
---
|
|
47
|
-
|
|
48
|
-
### 4. Configure PolylingoChat
|
|
49
|
-
|
|
50
|
-
Edit `config/initializers/polylingo_chat.rb`:
|
|
51
|
-
|
|
52
|
-
**Option A: Chat-Only (No Translation)**
|
|
53
|
-
```ruby
|
|
54
|
-
PolylingoChat.configure do |config|
|
|
55
|
-
# Leave api_key as nil for chat-only mode
|
|
56
|
-
config.api_key = nil
|
|
57
|
-
config.queue_adapter = :sidekiq
|
|
58
|
-
config.async = true
|
|
59
|
-
end
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
**Option B: With AI Translation**
|
|
63
|
-
```ruby
|
|
64
|
-
PolylingoChat.configure do |config|
|
|
65
|
-
# Enable translation
|
|
66
|
-
config.provider = :openai # or :anthropic, :gemini
|
|
67
|
-
config.api_key = ENV['POLYGLOT_API_KEY']
|
|
68
|
-
config.model = 'gpt-4o-mini'
|
|
69
|
-
|
|
70
|
-
config.queue_adapter = :sidekiq
|
|
71
|
-
config.default_language = 'en'
|
|
72
|
-
config.cache_store = Rails.cache
|
|
73
|
-
end
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
---
|
|
77
|
-
|
|
78
|
-
### 5. (Optional) Add preferred_language to User
|
|
79
|
-
|
|
80
|
-
**Only needed if using translation:**
|
|
81
|
-
```bash
|
|
82
|
-
bin/rails generate migration AddPreferredLanguageToUsers preferred_language:string
|
|
83
|
-
bin/rails db:migrate
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
---
|
|
87
|
-
|
|
88
|
-
### 6. Get API Key (Optional)
|
|
89
|
-
|
|
90
|
-
**Only if you want translation:**
|
|
91
|
-
- OpenAI: https://platform.openai.com/api-keys
|
|
92
|
-
- Anthropic: https://console.anthropic.com/
|
|
93
|
-
- Gemini: https://ai.google.dev/
|
|
94
|
-
|
|
95
|
-
```bash
|
|
96
|
-
# .env
|
|
97
|
-
POLYGLOT_API_KEY=your-key-here
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
---
|
|
101
|
-
|
|
102
|
-
### Testing
|
|
103
|
-
|
|
104
|
-
```ruby
|
|
105
|
-
conversation = Conversation.create!(title: "Test")
|
|
106
|
-
Participant.create!(conversation: conversation, user: user1)
|
|
107
|
-
Participant.create!(conversation: conversation, user: user2)
|
|
108
|
-
|
|
109
|
-
Message.create!(
|
|
110
|
-
conversation: conversation,
|
|
111
|
-
sender: user1,
|
|
112
|
-
body: "Hello!"
|
|
113
|
-
)
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
- **Without API key:** Message sent as-is
|
|
117
|
-
- **With API key:** Message translated to each user's language
|
|
118
|
-
|
|
119
|
-
---
|
|
120
|
-
|
|
121
|
-
### Need Help?
|
|
122
|
-
|
|
123
|
-
- 📖 Documentation: https://github.com/shoaibmalik786/polylingo_chat
|
|
124
|
-
- 🐛 Issues: https://github.com/shoaibmalik786/polylingo_chat/issues
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import consumer from "@rails/actioncable"
|
|
2
|
-
|
|
3
|
-
const cable = consumer.createConsumer();
|
|
4
|
-
|
|
5
|
-
export default function subscribe(conversationId, handleReceive) {
|
|
6
|
-
const subscription = cable.subscriptions.create({ channel: 'PolylinguoChatChannel', conversation_id: conversationId }, {
|
|
7
|
-
connected() {},
|
|
8
|
-
disconnected() {},
|
|
9
|
-
received(data) {
|
|
10
|
-
handleReceive(data)
|
|
11
|
-
},
|
|
12
|
-
sendMessage(text, conversationId) {
|
|
13
|
-
this.perform('receive', { message: text, conversation_id: conversationId });
|
|
14
|
-
}
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
return subscription;
|
|
18
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
class CreatePolylingoChatMessages < ActiveRecord::Migration[6.0]
|
|
2
|
-
def change
|
|
3
|
-
create_table :messages do |t|
|
|
4
|
-
t.references :sender, null: false, foreign_key: { to_table: :users }
|
|
5
|
-
t.references :conversation, null: false, foreign_key: true
|
|
6
|
-
t.text :body
|
|
7
|
-
t.string :language
|
|
8
|
-
t.text :translated_body
|
|
9
|
-
t.boolean :translated, default: false
|
|
10
|
-
t.timestamps
|
|
11
|
-
end
|
|
12
|
-
end
|
|
13
|
-
end
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
class CreatePolylingoChatParticipants < ActiveRecord::Migration[6.0]
|
|
2
|
-
def change
|
|
3
|
-
create_table :participants do |t|
|
|
4
|
-
t.references :user, null: false, foreign_key: true
|
|
5
|
-
t.references :conversation, null: false, foreign_key: true
|
|
6
|
-
t.string :role
|
|
7
|
-
t.timestamps
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
add_index :participants, [:user_id, :conversation_id], unique: true
|
|
11
|
-
end
|
|
12
|
-
end
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
class Message < ApplicationRecord
|
|
2
|
-
belongs_to :conversation
|
|
3
|
-
belongs_to :sender, class_name: 'User', foreign_key: 'sender_id'
|
|
4
|
-
|
|
5
|
-
validates :body, presence: true
|
|
6
|
-
|
|
7
|
-
after_create_commit :enqueue_translation_job
|
|
8
|
-
|
|
9
|
-
private
|
|
10
|
-
|
|
11
|
-
def enqueue_translation_job
|
|
12
|
-
PolylingoChat::TranslateJob.perform_later(id) if PolylingoChat.config.async
|
|
13
|
-
end
|
|
14
|
-
end
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
# PolylingoChat Configuration
|
|
2
|
-
# For more information, see: https://github.com/shoaibmalik786/polylingo_chat
|
|
3
|
-
|
|
4
|
-
PolylingoChat.configure do |config|
|
|
5
|
-
# ========================================
|
|
6
|
-
# AI Provider Configuration (OPTIONAL)
|
|
7
|
-
# ========================================
|
|
8
|
-
|
|
9
|
-
# Translation is OPTIONAL! If you don't set an API key, PolylingoChat works as a
|
|
10
|
-
# real-time chat engine without translation (messages sent as-is).
|
|
11
|
-
|
|
12
|
-
# To enable translation, choose your AI provider: :openai, :anthropic, or :gemini
|
|
13
|
-
config.provider = :openai
|
|
14
|
-
|
|
15
|
-
# Set your API key (leave nil to use chat-only mode without translation)
|
|
16
|
-
config.api_key = ENV['POLYGLOT_API_KEY'] # or set to nil for chat-only mode
|
|
17
|
-
|
|
18
|
-
# Choose your model based on provider:
|
|
19
|
-
# OpenAI: 'gpt-4o-mini', 'gpt-4o', 'gpt-3.5-turbo'
|
|
20
|
-
# Anthropic: 'claude-3-5-sonnet-20241022', 'claude-3-5-haiku-20241022', 'claude-3-opus-20240229'
|
|
21
|
-
# Gemini: 'gemini-1.5-flash', 'gemini-1.5-pro'
|
|
22
|
-
config.model = 'gpt-4o-mini'
|
|
23
|
-
|
|
24
|
-
# ========================================
|
|
25
|
-
# Background Job Configuration
|
|
26
|
-
# ========================================
|
|
27
|
-
|
|
28
|
-
# Specify which ActiveJob adapter you're using (OPTIONAL, for documentation purposes)
|
|
29
|
-
# You still need to configure ActiveJob in your Rails app as normal
|
|
30
|
-
# Options: :sidekiq, :solid_queue, :delayed_job, :async, :inline, etc.
|
|
31
|
-
#
|
|
32
|
-
# Example ActiveJob configuration (in config/application.rb or config/environments/*.rb):
|
|
33
|
-
# config.active_job.queue_adapter = :sidekiq
|
|
34
|
-
#
|
|
35
|
-
# Then tell PolylingoChat which adapter you're using:
|
|
36
|
-
config.queue_adapter = :sidekiq # Change this to match your ActiveJob setup
|
|
37
|
-
|
|
38
|
-
# Enable/disable async processing
|
|
39
|
-
config.async = true
|
|
40
|
-
|
|
41
|
-
# ========================================
|
|
42
|
-
# Translation Configuration
|
|
43
|
-
# ========================================
|
|
44
|
-
|
|
45
|
-
# Default language for translations (ISO 639-1 code)
|
|
46
|
-
config.default_language = 'en'
|
|
47
|
-
|
|
48
|
-
# Enable caching for translations (recommended for production)
|
|
49
|
-
config.cache_store = Rails.cache
|
|
50
|
-
|
|
51
|
-
# Request timeout in seconds
|
|
52
|
-
config.timeout = 15
|
|
53
|
-
end
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
class PolylinguoChatChannel < ApplicationCable::Channel
|
|
2
|
-
def subscribed
|
|
3
|
-
# stream for the current user
|
|
4
|
-
stream_from "polylingo_chat_recipient_#{current_user.id}"
|
|
5
|
-
end
|
|
6
|
-
|
|
7
|
-
def receive(data)
|
|
8
|
-
# data: { message: 'Hola', conversation_id: 1 }
|
|
9
|
-
message_text = data['message']
|
|
10
|
-
conversation = Conversation.find(data['conversation_id'])
|
|
11
|
-
|
|
12
|
-
msg = Message.create!(conversation: conversation, sender: current_user, body: message_text, language: current_user.preferred_language)
|
|
13
|
-
# enqueue translation job
|
|
14
|
-
PolylingoChat::TranslateJob.perform_async(msg.id)
|
|
15
|
-
|
|
16
|
-
# broadcast original to sender's stream if you want
|
|
17
|
-
ActionCable.server.broadcast("polylingo_chat_recipient_#{current_user.id}", { message: message_text, original: message_text, sender_id: current_user.id, message_id: msg.id, original:true })
|
|
18
|
-
end
|
|
19
|
-
end
|