appchat 0.0.4 → 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 +27 -6
- data/lib/generators/appchat/templates/assets/appchat.tailwind.css +14 -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/new.html.erb +35 -12
- metadata +3 -2
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,14 +23,22 @@ 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
|
@@ -38,8 +46,15 @@ class AppchatGenerator < Rails::Generators::Base
|
|
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
|
40
48
|
copy_file "messages/_typing_bubbles.html.erb", "app/views/messages/_typing_bubbles.html.erb", force: true
|
49
|
+
end
|
50
|
+
|
51
|
+
def create_stylesheets
|
41
52
|
copy_file "assets/appchat.tailwind.css", "app/assets/stylesheets/appchat.tailwind.css", force: true
|
53
|
+
end
|
54
|
+
|
55
|
+
def create_stimulus_controllers
|
42
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"
|
43
58
|
end
|
44
59
|
|
45
60
|
def copy_models
|
@@ -63,8 +78,14 @@ class AppchatGenerator < Rails::Generators::Base
|
|
63
78
|
copy_file "get_ai_response_job.rb", "app/jobs/get_ai_response_job.rb"
|
64
79
|
end
|
65
80
|
|
66
|
-
def
|
67
|
-
|
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
|
68
89
|
end
|
69
90
|
|
70
91
|
def show_art
|
@@ -59,4 +59,18 @@
|
|
59
59
|
}
|
60
60
|
}
|
61
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
|
+
}
|
62
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,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
|
@@ -80,6 +80,7 @@ files:
|
|
80
80
|
- lib/generators/appchat/templates/chats_controller.rb
|
81
81
|
- lib/generators/appchat/templates/get_ai_response_job.rb
|
82
82
|
- lib/generators/appchat/templates/javascript/chat_message_controller.js
|
83
|
+
- lib/generators/appchat/templates/javascript/speech_to_text_controller.js
|
83
84
|
- lib/generators/appchat/templates/messages/_typing_bubbles.html.erb
|
84
85
|
- lib/generators/appchat/templates/messages/index.html.erb
|
85
86
|
- lib/generators/appchat/templates/messages/message.html.erb
|