appchat 0.0.3 → 0.0.5
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/lib/generators/appchat/appchat_generator.rb +29 -6
- data/lib/generators/appchat/templates/assets/appchat.tailwind.css +76 -0
- data/lib/generators/appchat/templates/chats/chat.html.erb +3 -3
- data/lib/generators/appchat/templates/chats/index.html.erb +18 -15
- data/lib/generators/appchat/templates/chats_controller.rb +1 -1
- data/lib/generators/appchat/templates/javascript/speech_to_text_controller.js +65 -0
- data/lib/generators/appchat/templates/messages/_typing_bubbles.html.erb +5 -0
- data/lib/generators/appchat/templates/messages/message.html.erb +5 -1
- data/lib/generators/appchat/templates/messages/new.html.erb +35 -12
- metadata +6 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3071421a8c3c49e11f5c5186b9f17a00bd37d45229d0d95a3b466ae9b9032fee
|
4
|
+
data.tar.gz: 79284185b56a3efaeb60e1ec1ad144ada532fd499e686b4604db7a29aabccd16
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9e642582fe817de68a171c14b272a0b0ceb2257b96021ae9a51e630c5ef562ed982c452fdc9694c2d6e6c81378720f636e0e8218f51d1704134d383602cf2df7
|
7
|
+
data.tar.gz: a71996c59642154416cb3178b9406d44242b5626ab7069aeb6341a15e1062d6c297131dfd19de2455c7e59be0cbf8af8c43e6daa0879afb269c001a88723f0a3
|
@@ -23,21 +23,38 @@ class AppchatGenerator < Rails::Generators::Base
|
|
23
23
|
run 'rails tailwindcss:install'
|
24
24
|
end
|
25
25
|
|
26
|
-
def
|
27
|
-
generate "model", "Chat context:text"
|
26
|
+
def set_routes
|
28
27
|
route "resources :chats"
|
29
|
-
|
28
|
+
route "resources :messages"
|
30
29
|
end
|
31
30
|
|
32
|
-
def
|
31
|
+
def generate_models
|
32
|
+
generate "model", "Chat context:text"
|
33
|
+
generate "model", "Message chat:references content:text role:integer"
|
34
|
+
end
|
35
|
+
|
36
|
+
def create_controllers
|
33
37
|
copy_file "chats_controller.rb", "app/controllers/chats_controller.rb"
|
38
|
+
copy_file "messages_controller.rb", "app/controllers/messages_controller.rb", force: true
|
39
|
+
end
|
40
|
+
|
41
|
+
def create_views
|
34
42
|
copy_file "chats/chat.html.erb", "app/views/chats/_chat.html.erb", force: true
|
35
43
|
copy_file "chats/index.html.erb", "app/views/chats/index.html.erb", force: true
|
36
44
|
copy_file "chats/show.html.erb", "app/views/chats/show.html.erb", force: true
|
37
45
|
copy_file "messages/index.html.erb", "app/views/messages/index.html.erb", force: true
|
38
46
|
copy_file "messages/new.html.erb", "app/views/messages/new.html.erb", force: true
|
39
47
|
copy_file "messages/message.html.erb", "app/views/messages/_message.html.erb", force: true
|
48
|
+
copy_file "messages/_typing_bubbles.html.erb", "app/views/messages/_typing_bubbles.html.erb", force: true
|
49
|
+
end
|
50
|
+
|
51
|
+
def create_stylesheets
|
52
|
+
copy_file "assets/appchat.tailwind.css", "app/assets/stylesheets/appchat.tailwind.css", force: true
|
53
|
+
end
|
54
|
+
|
55
|
+
def create_stimulus_controllers
|
40
56
|
copy_file "javascript/chat_message_controller.js", "app/javascript/controllers/chat_message_controller.js"
|
57
|
+
copy_file "javascript/speech_to_text_controller.js", "app/javascript/controllers/speech_to_text_controller.js"
|
41
58
|
end
|
42
59
|
|
43
60
|
def copy_models
|
@@ -61,8 +78,14 @@ class AppchatGenerator < Rails::Generators::Base
|
|
61
78
|
copy_file "get_ai_response_job.rb", "app/jobs/get_ai_response_job.rb"
|
62
79
|
end
|
63
80
|
|
64
|
-
def
|
65
|
-
|
81
|
+
def swap_class_in_layout
|
82
|
+
layout_file = "app/views/layouts/application.html.erb"
|
83
|
+
|
84
|
+
if File.exist?(layout_file)
|
85
|
+
gsub_file layout_file, /\bmt-28\b/, "mt-10"
|
86
|
+
else
|
87
|
+
say "Layout file not found. No changes were made.", :red
|
88
|
+
end
|
66
89
|
end
|
67
90
|
|
68
91
|
def show_art
|
@@ -0,0 +1,76 @@
|
|
1
|
+
@tailwind base;
|
2
|
+
@tailwind components;
|
3
|
+
@tailwind utilities;
|
4
|
+
|
5
|
+
|
6
|
+
|
7
|
+
@layer components {
|
8
|
+
|
9
|
+
.typing {
|
10
|
+
background-color: #e0e0e0;
|
11
|
+
display: block;
|
12
|
+
width: 60px;
|
13
|
+
height: 40px;
|
14
|
+
border-radius: 20px;
|
15
|
+
margin: 0 1rem;
|
16
|
+
display: flex;
|
17
|
+
justify-content: center;
|
18
|
+
align-items: center;
|
19
|
+
}
|
20
|
+
|
21
|
+
.circle {
|
22
|
+
display: block;
|
23
|
+
height: 10px;
|
24
|
+
width: 10px;
|
25
|
+
border-radius: 50%;
|
26
|
+
background-color: #8d8d8d;
|
27
|
+
margin: 3px;
|
28
|
+
}
|
29
|
+
|
30
|
+
.circle.scaling {
|
31
|
+
animation: typing 1000ms ease-in-out infinite;
|
32
|
+
animation-delay: 3600ms;
|
33
|
+
}
|
34
|
+
|
35
|
+
.circle:nth-child(1) {
|
36
|
+
animation-delay: 0ms;
|
37
|
+
}
|
38
|
+
|
39
|
+
.circle:nth-child(2) {
|
40
|
+
animation-delay: 333ms;
|
41
|
+
}
|
42
|
+
|
43
|
+
.circle:nth-child(3) {
|
44
|
+
animation-delay: 666ms;
|
45
|
+
}
|
46
|
+
|
47
|
+
@keyframes typing {
|
48
|
+
0% {
|
49
|
+
transform: scale(1);
|
50
|
+
}
|
51
|
+
33% {
|
52
|
+
transform: scale(1);
|
53
|
+
}
|
54
|
+
50% {
|
55
|
+
transform: scale(1.4);
|
56
|
+
}
|
57
|
+
100% {
|
58
|
+
transform: scale(1);
|
59
|
+
}
|
60
|
+
}
|
61
|
+
|
62
|
+
#microphone-button.recording {
|
63
|
+
animation: flash 1s infinite;
|
64
|
+
}
|
65
|
+
|
66
|
+
@keyframes flash {
|
67
|
+
0%, 100% {
|
68
|
+
opacity: 80;
|
69
|
+
background-color: #EE4B2B; /* Ensure the color remains during the flash */
|
70
|
+
}
|
71
|
+
50% {
|
72
|
+
opacity: 0.5;
|
73
|
+
background-color: #EE4B2B; /* Ensure the color remains during the flash */
|
74
|
+
}
|
75
|
+
}
|
76
|
+
}
|
@@ -1,5 +1,5 @@
|
|
1
1
|
<%= link_to chat, data: { turbo_frame: :chat } do %>
|
2
|
-
<div class="w-full text-gray-100 hover:text-green-500">
|
3
|
-
|
4
|
-
</div>
|
2
|
+
<div class="w-full text-gray-100 hover:text-green-500">
|
3
|
+
<%= chat&.messages&.first&.content&.truncate(45) || "New AI chat conversation" %>
|
4
|
+
</div>
|
5
5
|
<% end %>
|
@@ -3,20 +3,23 @@
|
|
3
3
|
background-color: black;
|
4
4
|
}
|
5
5
|
</style>
|
6
|
+
|
6
7
|
<div class="flex w-full">
|
7
|
-
<%= turbo_stream_from :chats %>
|
8
|
-
<div class="max-w-sm w-full h-full flex flex-col gap-4 p-2 w-full flex-shrink-0 bg-[#2e2e2e] rounded-lg" id="chats">
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
8
|
+
<%= turbo_stream_from :chats %>
|
9
|
+
<div class="max-w-sm w-full h-full flex flex-col gap-4 p-2 w-full flex-shrink-0 bg-[#2e2e2e] rounded-lg" id="chats">
|
10
|
+
<%= link_to chats_path, data: { turbo_method: :post, turbo_frame: :chat }, class: "flex gap-2 justify-center items-center bg-gray-500 text-gray-100 rounded-lg p-2 text-center mr-auto" do %>
|
11
|
+
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6">
|
12
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M12 4.5v15m7.5-7.5h-15" />
|
13
|
+
</svg>
|
14
|
+
<span> Create Chat </span>
|
15
|
+
<% end %>
|
16
|
+
<div class="h-[70vh] overflow-y-hidden overflow-y-scroll">
|
17
|
+
<% @chats.each do |chat| %>
|
18
|
+
<%= render "chat", chat: chat %>
|
19
|
+
<% end %>
|
20
|
+
</div>
|
21
|
+
</div>
|
22
|
+
<div class="w-full ml-4">
|
23
|
+
<%= turbo_frame_tag :chat, src: ( chat_path(@chats.first) if @chats.any? ) %>
|
24
|
+
</div>
|
22
25
|
</div>
|
@@ -0,0 +1,65 @@
|
|
1
|
+
import { Controller } from "@hotwired/stimulus";
|
2
|
+
|
3
|
+
// Connects to data-controller="speech-to-text"
|
4
|
+
export default class extends Controller {
|
5
|
+
static targets = ["microphoneButton", "chatInput"]
|
6
|
+
|
7
|
+
connect() {
|
8
|
+
const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
|
9
|
+
if (SpeechRecognition) {
|
10
|
+
this.microphoneButtonTarget.classList.remove("hidden")
|
11
|
+
} else {
|
12
|
+
return
|
13
|
+
}
|
14
|
+
|
15
|
+
this.recognition = new SpeechRecognition();
|
16
|
+
this.recognition.continuous = false;
|
17
|
+
this.recognition.lang = 'en-US';
|
18
|
+
this.recognition.interimResults = false;
|
19
|
+
this.recognition.maxAlternatives = 1;
|
20
|
+
|
21
|
+
this.recognition.onresult = this.handleResult.bind(this);
|
22
|
+
this.recognition.onerror = this.handleError.bind(this);
|
23
|
+
this.recognition.onstart = this.handleStart.bind(this);
|
24
|
+
this.recognition.onend = this.handleEnd.bind(this);
|
25
|
+
|
26
|
+
this.isRecognizing = false; // Track if recognition is active
|
27
|
+
}
|
28
|
+
|
29
|
+
startRecognition(event) {
|
30
|
+
event.preventDefault();
|
31
|
+
if (this.isRecognizing) {
|
32
|
+
console.log("Recognition already started");
|
33
|
+
return;
|
34
|
+
}
|
35
|
+
|
36
|
+
try {
|
37
|
+
this.recognition.start();
|
38
|
+
this.isRecognizing = true;
|
39
|
+
} catch (error) {
|
40
|
+
console.error("Recognition start failed:", error);
|
41
|
+
this.isRecognizing = false;
|
42
|
+
}
|
43
|
+
}
|
44
|
+
|
45
|
+
handleStart() {
|
46
|
+
this.microphoneButtonTarget.classList.add("recording");
|
47
|
+
}
|
48
|
+
|
49
|
+
handleEnd() {
|
50
|
+
this.microphoneButtonTarget.classList.remove("recording");
|
51
|
+
this.isRecognizing = false;
|
52
|
+
}
|
53
|
+
|
54
|
+
handleResult(event) {
|
55
|
+
const transcript = event.results[0][0].transcript;
|
56
|
+
this.chatInputTarget.value += ` ${transcript}`;
|
57
|
+
this.recognition.stop();
|
58
|
+
}
|
59
|
+
|
60
|
+
handleError(event) {
|
61
|
+
console.error(`Error occurred in recognition: ${event.error}`);
|
62
|
+
this.isRecognizing = false;
|
63
|
+
alert(`Speech recognition error: ${event.error}`);
|
64
|
+
}
|
65
|
+
}
|
@@ -1,3 +1,7 @@
|
|
1
1
|
<div data-chat-message-target="message" id="<%= dom_id(message) %>" class="bg-gray-200 text-gray-900 shadow-lg p-4 rounded-lg">
|
2
|
-
|
2
|
+
<% if message.content? %>
|
3
|
+
<%= message.content %>
|
4
|
+
<% else %>
|
5
|
+
<%= render 'messages/typing_bubbles' %>
|
6
|
+
<% end %>
|
3
7
|
</div>
|
@@ -1,16 +1,39 @@
|
|
1
1
|
<%= turbo_frame_tag :new_message do %>
|
2
2
|
<%= form_with model: @chat.messages.new, url: messages_path(chat_id: @chat.id) do |f| %>
|
3
|
-
<div class="w-full flex items-center gap-2">
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
3
|
+
<div class="w-full flex items-center gap-2 mt-4">
|
4
|
+
<div class="flex flex-col w-full" data-controller="speech-to-text">
|
5
|
+
<div class="relative w-full">
|
6
|
+
<%= f.text_area :content, class: "w-full pr-32 rounded-lg", "data-speech-to-text-target":"chatInput" %>
|
7
|
+
<button id="microphone-button"
|
8
|
+
data-speech-to-text-target="microphoneButton"
|
9
|
+
data-speech-to-text-recording-class="recording"
|
10
|
+
data-action="click->speech-to-text#startRecognition"
|
11
|
+
class="absolute right-14 top-1/2 transform -translate-y-1/2 p-1 mr-2 bg-gray-200 rounded-full hidden">
|
12
|
+
<svg
|
13
|
+
fill="#000000"
|
14
|
+
height="40px"
|
15
|
+
width="40px"
|
16
|
+
version="1.1"
|
17
|
+
xmlns="http://www.w3.org/2000/svg"
|
18
|
+
viewBox="0 0 512 512"
|
19
|
+
xmlns:xlink="http://www.w3.org/1999/xlink"
|
20
|
+
enable-background="new 0 0 512 512">
|
21
|
+
<g>
|
22
|
+
<g>
|
23
|
+
<path d="m439.5,236c0-11.3-9.1-20.4-20.4-20.4s-20.4,9.1-20.4,20.4c0,70-64,126.9-142.7,126.9-78.7,0-142.7-56.9-142.7-126.9 0-11.3-9.1-20.4-20.4-20.4s-20.4,9.1-20.4,20.4c0,86.2 71.5,157.4 163.1,166.7v57.5h-23.6c-11.3,0-20.4,9.1-20.4,20.4 0,11.3 9.1,20.4 20.4,20.4h88c11.3,0 20.4-9.1 20.4-20.4 0-11.3-9.1-20.4-20.4-20.4h-23.6v-57.5c91.6-9.3 163.1-80.5 163.1-166.7z"/>
|
24
|
+
<path d="m256,323.5c51,0 92.3-41.3 92.3-92.3v-127.9c0-51-41.3-92.3-92.3-92.3s-92.3,41.3-92.3,92.3v127.9c0,51 41.3,92.3 92.3,92.3zm-52.3-220.2c0-28.8 23.5-52.3 52.3-52.3s52.3,23.5 52.3,52.3v127.9c0,28.8-23.5,52.3-52.3,52.3s-52.3-23.5-52.3-52.3v-127.9z"/>
|
25
|
+
</g>
|
26
|
+
</g>
|
27
|
+
</svg>
|
28
|
+
</button>
|
29
|
+
<%= button_tag class: "absolute top-1 right-0 flex p-2 rounded-lg text-gray-900 font-semibold" do %>
|
30
|
+
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-10">
|
31
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M6 12 3.269 3.125A59.769 59.769 0 0 1 21.485 12 59.768 59.768 0 0 1 3.27 20.875L5.999 12Zm0 0h7.5" />
|
32
|
+
</svg>
|
33
|
+
<% end %>
|
34
|
+
</div>
|
35
|
+
</div>
|
36
|
+
|
37
|
+
</div>
|
15
38
|
<% end %>
|
16
39
|
<% end %>
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: appchat
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- hackliteracy
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-08-
|
11
|
+
date: 2024-08-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -73,12 +73,15 @@ extensions: []
|
|
73
73
|
extra_rdoc_files: []
|
74
74
|
files:
|
75
75
|
- lib/generators/appchat/appchat_generator.rb
|
76
|
+
- lib/generators/appchat/templates/assets/appchat.tailwind.css
|
76
77
|
- lib/generators/appchat/templates/chats/chat.html.erb
|
77
78
|
- lib/generators/appchat/templates/chats/index.html.erb
|
78
79
|
- lib/generators/appchat/templates/chats/show.html.erb
|
79
80
|
- lib/generators/appchat/templates/chats_controller.rb
|
80
81
|
- lib/generators/appchat/templates/get_ai_response_job.rb
|
81
82
|
- lib/generators/appchat/templates/javascript/chat_message_controller.js
|
83
|
+
- lib/generators/appchat/templates/javascript/speech_to_text_controller.js
|
84
|
+
- lib/generators/appchat/templates/messages/_typing_bubbles.html.erb
|
82
85
|
- lib/generators/appchat/templates/messages/index.html.erb
|
83
86
|
- lib/generators/appchat/templates/messages/message.html.erb
|
84
87
|
- lib/generators/appchat/templates/messages/new.html.erb
|
@@ -105,7 +108,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
105
108
|
- !ruby/object:Gem::Version
|
106
109
|
version: '0'
|
107
110
|
requirements: []
|
108
|
-
rubygems_version: 3.5.
|
111
|
+
rubygems_version: 3.5.17
|
109
112
|
signing_key:
|
110
113
|
specification_version: 4
|
111
114
|
summary: Appchat makes it easy to add a chat to your app
|