appchat 0.0.4 → 0.0.6
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 +56 -16
- 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/get_ai_response_job.rb +27 -5
- data/lib/generators/appchat/templates/javascript/speech_to_text_controller.js +65 -0
- data/lib/generators/appchat/templates/messages/message.html.erb +3 -1
- data/lib/generators/appchat/templates/messages/new.html.erb +35 -12
- data/lib/generators/appchat/templates/models/appchat_function.rb +18 -0
- data/lib/generators/appchat/templates/services/appchat_function_service.rb +47 -0
- data/lib/generators/appchat/templates/services/web_search_service.rb +23 -0
- data/lib/generators/appchat/templates/tasks/create_appchat_function.rake +13 -0
- metadata +9 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4aca406ace060a7c7b9af445e20d5be1f3605614109320792523cba09b7f92fe
|
4
|
+
data.tar.gz: 8c1e290b46dfca74c66c94748d305386d67703291e455c066aed1df0d1dc5cc8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5aaa00c36101e08cb562924a7a3a0cca7da5ef49680eb6f9f202a8d17ebe0cbbe852fe86ef4481cb65ef8c2811d9933731074363875930ccb916e92d9fdd66d4
|
7
|
+
data.tar.gz: 876249a02dbec15d9d3ee4c9dbabcfbcc843970f8d85d7b4e9fad563a97af8a86c1a3600c7383ef3dea9fc2bfffef4c19f3fef70cb7009f0fc0a12401efbb462
|
@@ -9,28 +9,45 @@ class AppchatGenerator < Rails::Generators::Base
|
|
9
9
|
source_root File.expand_path('templates', __dir__)
|
10
10
|
|
11
11
|
def add_gems
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
12
|
+
gems = %w(
|
13
|
+
ollama-ai
|
14
|
+
tailwindcss-rails
|
15
|
+
watir
|
16
|
+
)
|
17
|
+
|
18
|
+
gems.each do |gem|
|
19
|
+
unless gem_exists?(gem)
|
20
|
+
append_to_file 'Gemfile', "\ngem '#{gem}'\n"
|
21
|
+
end
|
18
22
|
end
|
19
23
|
|
20
24
|
Bundler.with_unbundled_env do
|
21
25
|
run 'bundle install'
|
22
26
|
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def install_tailwind
|
23
30
|
run 'rails tailwindcss:install'
|
24
31
|
end
|
25
32
|
|
26
|
-
def
|
27
|
-
generate "model", "Chat context:text"
|
33
|
+
def set_routes
|
28
34
|
route "resources :chats"
|
29
|
-
|
35
|
+
route "resources :messages"
|
30
36
|
end
|
31
37
|
|
32
|
-
def
|
38
|
+
def generate_models
|
39
|
+
generate "model", "Chat context:text"
|
40
|
+
generate "model", "Message chat:references content:text role:integer status:string"
|
41
|
+
generate "model", "AppchatFunction name:string description:text class_name:string"
|
42
|
+
generate "model", "FunctionParameter appchat_function:references name:string example_value:string"
|
43
|
+
end
|
44
|
+
|
45
|
+
def create_controllers
|
33
46
|
copy_file "chats_controller.rb", "app/controllers/chats_controller.rb"
|
47
|
+
copy_file "messages_controller.rb", "app/controllers/messages_controller.rb", force: true
|
48
|
+
end
|
49
|
+
|
50
|
+
def create_views
|
34
51
|
copy_file "chats/chat.html.erb", "app/views/chats/_chat.html.erb", force: true
|
35
52
|
copy_file "chats/index.html.erb", "app/views/chats/index.html.erb", force: true
|
36
53
|
copy_file "chats/show.html.erb", "app/views/chats/show.html.erb", force: true
|
@@ -38,21 +55,30 @@ class AppchatGenerator < Rails::Generators::Base
|
|
38
55
|
copy_file "messages/new.html.erb", "app/views/messages/new.html.erb", force: true
|
39
56
|
copy_file "messages/message.html.erb", "app/views/messages/_message.html.erb", force: true
|
40
57
|
copy_file "messages/_typing_bubbles.html.erb", "app/views/messages/_typing_bubbles.html.erb", force: true
|
58
|
+
end
|
59
|
+
|
60
|
+
def create_stylesheets
|
41
61
|
copy_file "assets/appchat.tailwind.css", "app/assets/stylesheets/appchat.tailwind.css", force: true
|
62
|
+
end
|
63
|
+
|
64
|
+
def create_stimulus_controllers
|
42
65
|
copy_file "javascript/chat_message_controller.js", "app/javascript/controllers/chat_message_controller.js"
|
66
|
+
copy_file "javascript/speech_to_text_controller.js", "app/javascript/controllers/speech_to_text_controller.js"
|
43
67
|
end
|
44
68
|
|
45
69
|
def copy_models
|
46
70
|
copy_file "models/message.rb", "app/models/message.rb", force: true
|
47
71
|
copy_file "models/chat.rb", "app/models/chat.rb", force: true
|
72
|
+
copy_file "models/appchat_function.rb", "app/models/appchat_function.rb", force: true
|
48
73
|
end
|
49
74
|
|
50
|
-
def
|
51
|
-
|
75
|
+
def copy_services
|
76
|
+
copy_file "services/appchat_function_service.rb", "app/services/appchat_function_service.rb", force: true
|
77
|
+
copy_file "services/web_search_service.rb", "app/services/web_search_service.rb", force: true
|
52
78
|
end
|
53
79
|
|
54
|
-
def
|
55
|
-
inject_into_class 'app/models/chat.rb', 'Chat', "
|
80
|
+
def serialize_context
|
81
|
+
inject_into_class 'app/models/chat.rb', 'Chat', "serialize :context, coder:JSON, type: Array\n"
|
56
82
|
end
|
57
83
|
|
58
84
|
def run_migrations
|
@@ -63,8 +89,22 @@ class AppchatGenerator < Rails::Generators::Base
|
|
63
89
|
copy_file "get_ai_response_job.rb", "app/jobs/get_ai_response_job.rb"
|
64
90
|
end
|
65
91
|
|
66
|
-
def
|
67
|
-
|
92
|
+
def swap_class_in_layout
|
93
|
+
layout_file = "app/views/layouts/application.html.erb"
|
94
|
+
|
95
|
+
if File.exist?(layout_file)
|
96
|
+
gsub_file layout_file, /\bmt-28\b/, "mt-10"
|
97
|
+
else
|
98
|
+
say "Layout file not found. No changes were made.", :red
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def copy_rake_tasks
|
103
|
+
copy_file "tasks/create_appchat_function.rake", "lib/tasks/create_appchat_function.rake"
|
104
|
+
end
|
105
|
+
|
106
|
+
def create_functions
|
107
|
+
rake "appchat_function:create_web_search"
|
68
108
|
end
|
69
109
|
|
70
110
|
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>
|
@@ -1,27 +1,33 @@
|
|
1
1
|
class GetAiResponseJob < ApplicationJob
|
2
2
|
queue_as :default
|
3
3
|
|
4
|
-
attr_reader :chat, :user_prompt
|
4
|
+
attr_reader :client, :chat, :user_prompt, :informed_prompt, :message
|
5
5
|
|
6
6
|
def perform(chat_id, user_prompt)
|
7
|
+
@client = new_client
|
7
8
|
@chat = Chat.find(chat_id)
|
8
9
|
@user_prompt = user_prompt
|
10
|
+
@message = chat.messages.create(role: 'assistant')
|
11
|
+
appchat_functions
|
9
12
|
call_ollama
|
10
13
|
end
|
11
14
|
|
12
15
|
private
|
13
16
|
|
14
|
-
def
|
15
|
-
|
17
|
+
def new_client
|
18
|
+
Ollama.new(
|
16
19
|
credentials: { address: 'http://localhost:11434' },
|
17
20
|
options: { server_sent_events: true }
|
18
21
|
)
|
19
|
-
|
22
|
+
end
|
23
|
+
|
24
|
+
def call_ollama
|
25
|
+
prompt = informed_prompt || user_prompt
|
20
26
|
|
21
27
|
response = client.generate(
|
22
28
|
{
|
23
29
|
model: 'llama3.1',
|
24
|
-
prompt:
|
30
|
+
prompt: prompt,
|
25
31
|
context: chat.context,
|
26
32
|
stream: true,
|
27
33
|
}
|
@@ -35,4 +41,20 @@ class GetAiResponseJob < ApplicationJob
|
|
35
41
|
end
|
36
42
|
chat.update(context: response.last["context"])
|
37
43
|
end
|
44
|
+
|
45
|
+
def appchat_functions
|
46
|
+
appchat_function_service = AppchatFunctionService.new(chat.id, user_prompt).run
|
47
|
+
if appchat_function_service["match"] == "true" && appchat_function_service["appchat_function"].in?(AppchatFunction.pluck(:class_name))
|
48
|
+
puts "Function Match Found! --> #{appchat_function_service}"
|
49
|
+
function_class = appchat_function_service["appchat_function"].constantize
|
50
|
+
function_response = function_class.new(appchat_function_service["parameters"]).run do |status|
|
51
|
+
message.update(status: status)
|
52
|
+
end
|
53
|
+
|
54
|
+
return if function_response.nil?
|
55
|
+
@informed_prompt = "#{ user_prompt }, base your response on this data:
|
56
|
+
#{ appchat_function_service["name"] } responded with: #{ function_response },
|
57
|
+
:current_time => #{Date.current}"
|
58
|
+
end
|
59
|
+
end
|
38
60
|
end
|
@@ -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,5 +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
|
-
<% if message.content? %>
|
2
|
+
<% if message.status? && !message.content? %>
|
3
|
+
<%= message.status %>
|
4
|
+
<% elsif message.content? %>
|
3
5
|
<%= message.content %>
|
4
6
|
<% else %>
|
5
7
|
<%= render 'messages/typing_bubbles' %>
|
@@ -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 %>
|
@@ -0,0 +1,18 @@
|
|
1
|
+
class AppchatFunction < ApplicationRecord
|
2
|
+
has_many :function_parameters, dependent: :destroy
|
3
|
+
|
4
|
+
def to_prompt_hash
|
5
|
+
{
|
6
|
+
name: name,
|
7
|
+
description: description,
|
8
|
+
class_name: class_name,
|
9
|
+
parameters: function_parameters.each_with_object({}) do |param, hash|
|
10
|
+
hash[param.name] = param.example_value
|
11
|
+
end
|
12
|
+
}
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.all_to_prompt_json
|
16
|
+
all.includes(:function_parameters).map(&:to_prompt_hash).to_json
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
class AppchatFunctionService
|
2
|
+
attr_reader :chat, :user_prompt, :response_json
|
3
|
+
|
4
|
+
def initialize(chat_id, user_prompt)
|
5
|
+
@chat = Chat.find(chat_id)
|
6
|
+
@user_prompt = user_prompt
|
7
|
+
end
|
8
|
+
|
9
|
+
def run
|
10
|
+
call_ollama
|
11
|
+
response_json
|
12
|
+
end
|
13
|
+
|
14
|
+
def call_ollama
|
15
|
+
client = Ollama.new(
|
16
|
+
credentials: { address: 'http://localhost:11434' },
|
17
|
+
options: { server_sent_events: true }
|
18
|
+
)
|
19
|
+
response = client.generate(
|
20
|
+
{
|
21
|
+
model: 'llama3.1',
|
22
|
+
prompt: prompt,
|
23
|
+
context: chat.context,
|
24
|
+
"format": "json"
|
25
|
+
}
|
26
|
+
)
|
27
|
+
@response_json = JSON.parse(response.map { |r| r["response"] }.join)
|
28
|
+
end
|
29
|
+
def prompt
|
30
|
+
<<-PROMPT
|
31
|
+
Evaluate the following user prompt in chat context.
|
32
|
+
Your goal is to determine whether the user prompt is requesting or requires additional information from any of the available services.
|
33
|
+
- If the prompt is a general greeting, casual remark, or something that can be answered without further information, respond with JSON { 'match' => 'false' }.
|
34
|
+
- If the prompt asks for specific information, requires a search, or needs a service to generate the correct response, then respond with JSON like this example:
|
35
|
+
{
|
36
|
+
'match' => 'true',
|
37
|
+
'appchat_function' => 'WebSearchService',
|
38
|
+
'parameters' => {
|
39
|
+
'query' => 'a query based on the prompt and context'
|
40
|
+
}
|
41
|
+
}
|
42
|
+
|
43
|
+
Here is the user's prompt: #{user_prompt}
|
44
|
+
Here are the Available Services: #{ AppchatFunction.all_to_prompt_json }
|
45
|
+
PROMPT
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'watir'
|
2
|
+
require 'cgi'
|
3
|
+
|
4
|
+
class WebSearchService
|
5
|
+
attr_reader :query
|
6
|
+
|
7
|
+
def initialize(args)
|
8
|
+
@query = args["query"]
|
9
|
+
end
|
10
|
+
|
11
|
+
def run
|
12
|
+
yield("Searching Google for #{@query}") if block_given?
|
13
|
+
|
14
|
+
browser = Watir::Browser.new :chrome, headless: true
|
15
|
+
search_url = "https://www.google.com/search?q=#{CGI.escape(query)}"
|
16
|
+
browser.goto(search_url)
|
17
|
+
response = "browser_text: #{browser.text} browser_links: #{browser.links}"
|
18
|
+
browser.close
|
19
|
+
response
|
20
|
+
rescue Selenium::WebDriver::Error::UnknownError => e
|
21
|
+
"Error: #{e.message}"
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# lib/tasks/create_appchat_function.rake
|
2
|
+
namespace :appchat_function do
|
3
|
+
desc "Create an AppchatFunction with name 'Web Search', class name 'WebSearchService', and a description"
|
4
|
+
task create_web_search: :environment do
|
5
|
+
af = AppchatFunction.create!(
|
6
|
+
name: "Web Search",
|
7
|
+
class_name: "WebSearchService",
|
8
|
+
description: "Searches Google with a user's query and returns the page text and links"
|
9
|
+
)
|
10
|
+
puts "AppchatFunction 'Web Search' created successfully."
|
11
|
+
af.function_parameters.create(name: 'query', example_value: 'Dog friendly vegan resturants in Austin, TX')
|
12
|
+
end
|
13
|
+
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.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- hackliteracy
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-09-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -66,7 +66,7 @@ dependencies:
|
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: 1.3.0
|
69
|
-
description: The best and easiest framework for adding chats
|
69
|
+
description: The best and easiest framework for adding AI chats
|
70
70
|
email: hackliteracy@gmail.com
|
71
71
|
executables: []
|
72
72
|
extensions: []
|
@@ -80,13 +80,18 @@ 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
|
86
87
|
- lib/generators/appchat/templates/messages/new.html.erb
|
87
88
|
- lib/generators/appchat/templates/messages_controller.rb
|
89
|
+
- lib/generators/appchat/templates/models/appchat_function.rb
|
88
90
|
- lib/generators/appchat/templates/models/chat.rb
|
89
91
|
- lib/generators/appchat/templates/models/message.rb
|
92
|
+
- lib/generators/appchat/templates/services/appchat_function_service.rb
|
93
|
+
- lib/generators/appchat/templates/services/web_search_service.rb
|
94
|
+
- lib/generators/appchat/templates/tasks/create_appchat_function.rake
|
90
95
|
homepage: https://rubygems.org/gems/appchat
|
91
96
|
licenses:
|
92
97
|
- MIT
|
@@ -110,5 +115,5 @@ requirements: []
|
|
110
115
|
rubygems_version: 3.5.17
|
111
116
|
signing_key:
|
112
117
|
specification_version: 4
|
113
|
-
summary: Appchat makes it easy to add
|
118
|
+
summary: Appchat makes it easy to add an AI chat to your app
|
114
119
|
test_files: []
|