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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f9bb854d39e8d17f65dcc5ff09269f488e63a50fe080e1c7ae104d9326d8d8b9
4
- data.tar.gz: 50c75e1d61f287bd89d865b9dffbd24bd77c5448cc13c6407788117a0c49140f
3
+ metadata.gz: 3071421a8c3c49e11f5c5186b9f17a00bd37d45229d0d95a3b466ae9b9032fee
4
+ data.tar.gz: 79284185b56a3efaeb60e1ec1ad144ada532fd499e686b4604db7a29aabccd16
5
5
  SHA512:
6
- metadata.gz: ddecc383090bcb31337e1fab220b510fe62afe86d2763cbd95a837b2ae87c52f7aef7d08130411b02e443c76c5392a70d1481cc1556e4928a29aefbe30c1c91a
7
- data.tar.gz: a04b84d8eab498add64fb2e4111a8fd491e6dec1af3a984957dfc713c26c4f55d90acff6a16ca83a0d9806087efb26db87b06ec4f861e77bc6ff338e4ac227d2
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 generate_scaffolds
27
- generate "model", "Chat context:text"
26
+ def set_routes
28
27
  route "resources :chats"
29
- generate "scaffold", "Message chat:references content:text role:integer"
28
+ route "resources :messages"
30
29
  end
31
30
 
32
- def create_views
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 create_messages_controller
65
- copy_file "messages_controller.rb", "app/controllers/messages_controller.rb", force: true
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
- <%= chat&.messages&.first&.content || "New AI chat conversation" %>
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
- <%= 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 %>
10
- <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6">
11
- <path stroke-linecap="round" stroke-linejoin="round" d="M12 4.5v15m7.5-7.5h-15" />
12
- </svg>
13
- <span> Create Chat </span>
14
- <% end %>
15
- <% @chats.each do |chat| %>
16
- <%= render "chat", chat: chat %>
17
- <% end %>
18
- </div>
19
- <div class="w-full ml-4">
20
- <%= turbo_frame_tag :chat, src: ( chat_path(@chats.first) if @chats.any? ) %>
21
- </div>
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>
@@ -3,7 +3,7 @@ class ChatsController < ApplicationController
3
3
  @chat = Chat.find(params[:id])
4
4
  end
5
5
  def index
6
- @chats = Chat.all
6
+ @chats = Chat.all.reverse
7
7
  end
8
8
  def create
9
9
  @chat = Chat.create
@@ -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
+ }
@@ -0,0 +1,5 @@
1
+ <div class="typing">
2
+ <span class="circle scaling"></span>
3
+ <span class="circle scaling"></span>
4
+ <span class="circle scaling"></span>
5
+ </div>
@@ -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
- <%= message.content %>
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
- <div class="flex flex-col w-full">
5
- <%= f.label :content, "What do you want to ask?" %>
6
- <%= f.text_area :content, class: "w-full" %>
7
- </div>
8
- <%= button_tag class: "mt-4 flex p-2 rounded-lg bg-gradient-to-r from-indigo-500 to-blue-500 text-blue-100 font-semibold" do %>
9
- Send Message
10
- <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6">
11
- <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" />
12
- </svg>
13
- <% end %>
14
- </div>
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.3
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-10 00:00:00.000000000 Z
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.11
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