appchat 0.0.3 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
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