bridgetown-ai-chatbot 1.0.0
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 +7 -0
- data/LICENSE +21 -0
- data/README.md +81 -0
- data/lib/bridgetown-ai-chatbot/core.rb +111 -0
- data/lib/bridgetown-ai-chatbot/version.rb +5 -0
- data/lib/bridgetown-ai-chatbot.rb +22 -0
- metadata +72 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: ec8a22027dea0a642f58f72dc9f1ea495fc7ba4e424eb6139445f2e78755d048
|
|
4
|
+
data.tar.gz: f742004f93f182466e5435c286b665730f3e9b92d724979cce44bace1a8898e7
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 067652eae23aedca9679dcec2a24902d7407dc440b2e3d1a671a87f2c5f14fc1645288e12bbf616c78dc79ff1ae76b9dbe6806f7f4e75687e80f061ddc56fd88
|
|
7
|
+
data.tar.gz: 0ed08586920bb6c31e0cfccc1c12478c1aec91ebaeabab5cdc25a44a1fe65488f04ece64bc44a977c2425a14b55b0de2de463cb493745a50511ab41180815e7a
|
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Asyntai
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# bridgetown-ai-chatbot
|
|
2
|
+
|
|
3
|
+
Add the [Asyntai](https://asyntai.com) AI chat assistant to your Bridgetown
|
|
4
|
+
site. It answers visitor questions from your own content, in more than 80
|
|
5
|
+
languages.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
bundle add bridgetown-ai-chatbot
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Then add the plugin in `config/initializers.rb`:
|
|
14
|
+
|
|
15
|
+
```ruby
|
|
16
|
+
Bridgetown.configure do |config|
|
|
17
|
+
init :"bridgetown-ai-chatbot", widget_id: "asyntai_1a2b3c4d5e6f"
|
|
18
|
+
end
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Build the site. The chat bubble is on every page.
|
|
22
|
+
|
|
23
|
+
## Where the widget ID comes from
|
|
24
|
+
|
|
25
|
+
Open the Install page in your [Asyntai dashboard](https://asyntai.com/dashboard).
|
|
26
|
+
The widget ID is the value of `data-asyntai-id` in the snippet shown there. It
|
|
27
|
+
starts with `asyntai_`.
|
|
28
|
+
|
|
29
|
+
Creating an account is free, and the Free plan is enough to try the widget.
|
|
30
|
+
|
|
31
|
+
## Options
|
|
32
|
+
|
|
33
|
+
| Option | Type | Default | What it does |
|
|
34
|
+
| --- | --- | --- | --- |
|
|
35
|
+
| `widget_id` | string | required | Your Asyntai widget ID |
|
|
36
|
+
| `enable_in_development` | boolean | `true` | Set to `false` to keep the widget off the site while `BRIDGETOWN_ENV` is `development` |
|
|
37
|
+
| `script_url` | string | the Asyntai CDN | Advanced. Load the widget from another URL |
|
|
38
|
+
|
|
39
|
+
You can also use the block form:
|
|
40
|
+
|
|
41
|
+
```ruby
|
|
42
|
+
init :"bridgetown-ai-chatbot" do
|
|
43
|
+
widget_id "asyntai_1a2b3c4d5e6f"
|
|
44
|
+
enable_in_development false
|
|
45
|
+
end
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
A missing or malformed `widget_id` stops the build with a message that says how
|
|
49
|
+
to fix it.
|
|
50
|
+
|
|
51
|
+
## What the plugin does
|
|
52
|
+
|
|
53
|
+
- It adds the Asyntai loader to every HTML page, just before `</body>`.
|
|
54
|
+
That includes pages from collections, posts and pagination.
|
|
55
|
+
- The loader waits for the page's `load` event, so your own content always
|
|
56
|
+
renders first.
|
|
57
|
+
- Feeds, JSON and other non-HTML files stay as they are.
|
|
58
|
+
- A page that already has the Asyntai snippet keeps it and gets no second one.
|
|
59
|
+
|
|
60
|
+
It works with every template engine: ERB, Serbea and Liquid.
|
|
61
|
+
|
|
62
|
+
Tested with Bridgetown 1.3 and 2.2.
|
|
63
|
+
|
|
64
|
+
## Answering from your content
|
|
65
|
+
|
|
66
|
+
Asyntai reads your published pages. Add your site URL in the dashboard, and the
|
|
67
|
+
assistant answers from the same pages the widget sits on. You can also add extra
|
|
68
|
+
documents and question and answer pairs.
|
|
69
|
+
|
|
70
|
+
## Removing it
|
|
71
|
+
|
|
72
|
+
Delete the `init` line and build again. The widget is gone.
|
|
73
|
+
|
|
74
|
+
## Support
|
|
75
|
+
|
|
76
|
+
Email [hello@asyntai.com](mailto:hello@asyntai.com), or read the
|
|
77
|
+
[Bridgetown guide](https://asyntai.com/documentation/integrations/bridgetown/).
|
|
78
|
+
|
|
79
|
+
## Licence
|
|
80
|
+
|
|
81
|
+
MIT. See [LICENSE](LICENSE).
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Asyntai AI chatbot for Bridgetown: the logic, without the initializer, so
|
|
4
|
+
# it can be tested outside a Bridgetown build.
|
|
5
|
+
#
|
|
6
|
+
# Adds the Asyntai chat widget to every HTML page the site builds. The plugin
|
|
7
|
+
# hooks into rendering: after a page is rendered, it puts the ordinary embed
|
|
8
|
+
# loader just before </body> and changes nothing else about the page.
|
|
9
|
+
|
|
10
|
+
require "json"
|
|
11
|
+
require "bridgetown"
|
|
12
|
+
require "bridgetown-ai-chatbot/version"
|
|
13
|
+
|
|
14
|
+
module BridgetownAiChatbot
|
|
15
|
+
DEFAULT_SCRIPT_URL = "https://widget.asyntai.com/static/js/chat-widget.js"
|
|
16
|
+
WIDGET_ID_PATTERN = /\Aasyntai_[A-Za-z0-9]+\z/
|
|
17
|
+
NAME = "bridgetown-ai-chatbot"
|
|
18
|
+
|
|
19
|
+
class ConfigurationError < StandardError; end
|
|
20
|
+
|
|
21
|
+
Settings = Struct.new(:widget_id, :script_url, :enable_in_development, keyword_init: true)
|
|
22
|
+
|
|
23
|
+
module_function
|
|
24
|
+
|
|
25
|
+
# Bridgetown runs the initializer before it builds anything, so a wrong option
|
|
26
|
+
# stops the build with a clear message instead of producing a site with no chat.
|
|
27
|
+
def validate_options(options)
|
|
28
|
+
opts = (options || {}).to_h.transform_keys(&:to_sym)
|
|
29
|
+
widget_id = opts[:widget_id].is_a?(String) ? opts[:widget_id].strip : ""
|
|
30
|
+
|
|
31
|
+
if widget_id.empty?
|
|
32
|
+
raise ConfigurationError,
|
|
33
|
+
"#{NAME}: \"widget_id\" is required. Copy it from the Install page of your " \
|
|
34
|
+
"Asyntai dashboard, for example asyntai_1a2b3c4d5e6f."
|
|
35
|
+
end
|
|
36
|
+
unless WIDGET_ID_PATTERN.match?(widget_id)
|
|
37
|
+
raise ConfigurationError,
|
|
38
|
+
"#{NAME}: \"#{widget_id}\" does not look like a widget ID. It starts with " \
|
|
39
|
+
"asyntai_, for example asyntai_1a2b3c4d5e6f."
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
script_url = opts[:script_url].is_a?(String) && !opts[:script_url].strip.empty? ?
|
|
43
|
+
opts[:script_url].strip : DEFAULT_SCRIPT_URL
|
|
44
|
+
|
|
45
|
+
Settings.new(
|
|
46
|
+
widget_id: widget_id,
|
|
47
|
+
script_url: script_url,
|
|
48
|
+
# Set to false to keep the widget off the site while BRIDGETOWN_ENV is development.
|
|
49
|
+
enable_in_development: opts[:enable_in_development] != false
|
|
50
|
+
)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# JSON string, safe inside an HTML <script> element.
|
|
54
|
+
def js_string(value)
|
|
55
|
+
JSON.generate(value.to_s).gsub("<", "\\u003c")
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# The loader waits for the page's load event before it fetches the widget.
|
|
59
|
+
# An ordinary `<script async src>` holds the load event open until its own
|
|
60
|
+
# fetch finishes, so an unreachable server would delay the host page. This
|
|
61
|
+
# pattern cannot.
|
|
62
|
+
def build_loader(widget_id, script_url)
|
|
63
|
+
"(function(){var l=function(){" \
|
|
64
|
+
"if(document.querySelector(\"script[data-asyntai-id]\"))return;" \
|
|
65
|
+
"var s=document.createElement(\"script\");" \
|
|
66
|
+
"s.src=#{js_string(script_url)};s.async=true;" \
|
|
67
|
+
"s.setAttribute(\"data-asyntai-id\",#{js_string(widget_id)});" \
|
|
68
|
+
"document.head.appendChild(s)};" \
|
|
69
|
+
"if(document.readyState===\"complete\"){l()}" \
|
|
70
|
+
"else{window.addEventListener(\"load\",l)}})();"
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def build_tag(settings)
|
|
74
|
+
"<script data-asyntai-loader>#{build_loader(settings.widget_id, settings.script_url)}</script>"
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Puts the tag before the last </body>, or before </html> when the page has no
|
|
78
|
+
# body tag. A fragment with neither is left alone: it is not a whole page.
|
|
79
|
+
# A page that already carries an Asyntai snippet is left alone too.
|
|
80
|
+
def inject_into_html(html, tag)
|
|
81
|
+
return html unless html.is_a?(String)
|
|
82
|
+
return html if html.include?("data-asyntai-id")
|
|
83
|
+
|
|
84
|
+
lower = html.downcase
|
|
85
|
+
at = lower.rindex("</body>") || lower.rindex("</html>")
|
|
86
|
+
return html if at.nil?
|
|
87
|
+
|
|
88
|
+
html[0...at] + tag + html[at..]
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# Only pages that are written to disk as .html get the widget. Feeds, JSON,
|
|
92
|
+
# CSS and pages with `permalink: false` stay as they are.
|
|
93
|
+
def html_output?(document)
|
|
94
|
+
if document.respond_to?(:write?)
|
|
95
|
+
return false unless document.write?
|
|
96
|
+
end
|
|
97
|
+
ext = document.respond_to?(:output_ext) ? document.output_ext.to_s.downcase : ""
|
|
98
|
+
[".html", ".htm"].include?(ext)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def development?
|
|
102
|
+
Bridgetown.environment.to_s == "development"
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def apply(document, settings, tag)
|
|
106
|
+
return if !settings.enable_in_development && development?
|
|
107
|
+
return unless html_output?(document)
|
|
108
|
+
|
|
109
|
+
document.output = inject_into_html(document.output, tag)
|
|
110
|
+
end
|
|
111
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Asyntai AI chatbot for Bridgetown.
|
|
4
|
+
#
|
|
5
|
+
# In config/initializers.rb:
|
|
6
|
+
#
|
|
7
|
+
# init :"bridgetown-ai-chatbot", widget_id: "asyntai_1a2b3c4d5e6f"
|
|
8
|
+
|
|
9
|
+
require "bridgetown-ai-chatbot/core"
|
|
10
|
+
|
|
11
|
+
Bridgetown.initializer :"bridgetown-ai-chatbot" do |config, **options|
|
|
12
|
+
settings = BridgetownAiChatbot.validate_options(options)
|
|
13
|
+
tag = BridgetownAiChatbot.build_tag(settings)
|
|
14
|
+
|
|
15
|
+
# Low priority, so the widget goes in after other plugins change the page.
|
|
16
|
+
config.hook :resources, :post_render, priority: :low do |resource|
|
|
17
|
+
BridgetownAiChatbot.apply(resource, settings, tag)
|
|
18
|
+
end
|
|
19
|
+
config.hook :generated_pages, :post_render, priority: :low do |page|
|
|
20
|
+
BridgetownAiChatbot.apply(page, settings, tag)
|
|
21
|
+
end
|
|
22
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: bridgetown-ai-chatbot
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Asyntai
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2026-10-15 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: bridgetown
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - ">="
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '1.2'
|
|
20
|
+
- - "<"
|
|
21
|
+
- !ruby/object:Gem::Version
|
|
22
|
+
version: '3.0'
|
|
23
|
+
type: :runtime
|
|
24
|
+
prerelease: false
|
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
26
|
+
requirements:
|
|
27
|
+
- - ">="
|
|
28
|
+
- !ruby/object:Gem::Version
|
|
29
|
+
version: '1.2'
|
|
30
|
+
- - "<"
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '3.0'
|
|
33
|
+
description: Adds the Asyntai AI chatbot to every page of your Bridgetown site. It
|
|
34
|
+
answers visitor questions from your own content, in 80+ languages.
|
|
35
|
+
email: hello@asyntai.com
|
|
36
|
+
executables: []
|
|
37
|
+
extensions: []
|
|
38
|
+
extra_rdoc_files: []
|
|
39
|
+
files:
|
|
40
|
+
- LICENSE
|
|
41
|
+
- README.md
|
|
42
|
+
- lib/bridgetown-ai-chatbot.rb
|
|
43
|
+
- lib/bridgetown-ai-chatbot/core.rb
|
|
44
|
+
- lib/bridgetown-ai-chatbot/version.rb
|
|
45
|
+
homepage: https://asyntai.com/documentation/integrations/bridgetown/
|
|
46
|
+
licenses:
|
|
47
|
+
- MIT
|
|
48
|
+
metadata:
|
|
49
|
+
homepage_uri: https://asyntai.com/documentation/integrations/bridgetown/
|
|
50
|
+
source_code_uri: https://github.com/asyntai/bridgetown-ai-chatbot
|
|
51
|
+
bug_tracker_uri: https://github.com/asyntai/bridgetown-ai-chatbot/issues
|
|
52
|
+
rubygems_mfa_required: 'true'
|
|
53
|
+
post_install_message:
|
|
54
|
+
rdoc_options: []
|
|
55
|
+
require_paths:
|
|
56
|
+
- lib
|
|
57
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - ">="
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '2.7'
|
|
62
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
63
|
+
requirements:
|
|
64
|
+
- - ">="
|
|
65
|
+
- !ruby/object:Gem::Version
|
|
66
|
+
version: '0'
|
|
67
|
+
requirements: []
|
|
68
|
+
rubygems_version: 3.5.22
|
|
69
|
+
signing_key:
|
|
70
|
+
specification_version: 4
|
|
71
|
+
summary: Add the Asyntai AI chat assistant to your Bridgetown site.
|
|
72
|
+
test_files: []
|