diff --git a/assets/javascripts/initializers/ai-bot-replies.js b/assets/javascripts/initializers/ai-bot-replies.js
index ff6551d1..774fdf37 100644
--- a/assets/javascripts/initializers/ai-bot-replies.js
+++ b/assets/javascripts/initializers/ai-bot-replies.js
@@ -1,3 +1,4 @@
+import { later } from "@ember/runloop";
import { hbs } from "ember-cli-htmlbars";
import { ajax } from "discourse/lib/ajax";
import { popupAjaxError } from "discourse/lib/ajax-error";
@@ -94,15 +95,41 @@ function initializeAIBotReplies(api) {
onAIBotStreamedReply: function (data) {
const post = this.model.postStream.findLoadedPost(data.post_id);
+ // it may take us a few seconds to load the post
+ // we need to requeue the event
+ if (!post && !data.done) {
+ const refresh = this.onAIBotStreamedReply.bind(this);
+ data.retries = data.retries || 5;
+ data.retries -= 1;
+ data.skipIfStreaming = true;
+ if (data.retries > 0) {
+ later(() => {
+ refresh(data);
+ }, 1000);
+ }
+ }
+
if (post) {
if (data.raw) {
+ const postElement = document.querySelector(
+ `#post_${data.post_number}`
+ );
+
+ if (
+ data.skipIfStreaming &&
+ postElement.classList.contains("streaming")
+ ) {
+ return;
+ }
+
cook(data.raw).then((cooked) => {
post.set("raw", data.raw);
post.set("cooked", cooked);
- document
- .querySelector(`#post_${data.post_number}`)
- .classList.add("streaming");
+ // resets animation
+ postElement.classList.remove("streaming");
+ void postElement.offsetWidth;
+ postElement.classList.add("streaming");
const cookedElement = document.createElement("div");
cookedElement.innerHTML = cooked;
@@ -131,9 +158,12 @@ function initializeAIBotReplies(api) {
this.model.details.allowed_users &&
this.model.details.allowed_users.filter(isGPTBot).length >= 1
) {
+ // we attempt to recover the last message in the bus
+ // so we subscribe at -2
this.messageBus.subscribe(
`discourse-ai/ai-bot/topic/${this.model.id}`,
- this.onAIBotStreamedReply.bind(this)
+ this.onAIBotStreamedReply.bind(this),
+ -2
);
}
},
diff --git a/assets/stylesheets/modules/ai-bot/common/bot-replies.scss b/assets/stylesheets/modules/ai-bot/common/bot-replies.scss
index 2a8ba805..eeefb0ea 100644
--- a/assets/stylesheets/modules/ai-bot/common/bot-replies.scss
+++ b/assets/stylesheets/modules/ai-bot/common/bot-replies.scss
@@ -47,6 +47,35 @@ article.streaming nav.post-controls .actions button.cancel-streaming {
display: inline-block;
}
+@keyframes flashing {
+ 0%,
+ 100% {
+ opacity: 0;
+ }
+ 50% {
+ opacity: 1;
+ }
+}
+
+article.streaming .cooked > {
+ :not(ol):not(ul):not(pre):last-child::after,
+ ol:last-child li:last-child p:last-child::after,
+ ol:last-child li:last-child:not(:has(p))::after,
+ ul:last-child li:last-child p:last-child::after,
+ ul:last-child li:last-child:not(:has(p))::after,
+ pre:last-child code::after {
+ content: "\25CF";
+ font-family: Söhne Circle, system-ui, -apple-system, Segoe UI, Roboto,
+ Ubuntu, Cantarell, Noto Sans, sans-serif;
+ line-height: normal;
+ margin-left: 0.25rem;
+ vertical-align: baseline;
+
+ animation: flashing 1.5s 3s infinite;
+ display: inline-block;
+ }
+}
+
.ai-bot-available-bot-options {
.ai-bot-available-bot-content {
color: var(--primary-high);
diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml
index ce4d3aec..9d3dffd6 100644
--- a/config/locales/server.en.yml
+++ b/config/locales/server.en.yml
@@ -130,13 +130,11 @@ en:
explain: "Explain"
illustrate_post: "Illustrate Post"
painter:
- attribution:
+ attribution:
stable_diffusion_xl: "Image by Stable Diffusion XL"
dall_e_3: "Image by DALL-E 3"
ai_bot:
- placeholder_reply: "I will reply shortly..."
-
personas:
cannot_delete_system_persona: "System personas cannot be deleted, please disable it instead"
cannot_edit_system_persona: "System personas can only be renamed, you may not edit commands or system prompt, instead disable and make a copy"
diff --git a/lib/ai_bot/bot.rb b/lib/ai_bot/bot.rb
index c67880e5..661ee8d4 100644
--- a/lib/ai_bot/bot.rb
+++ b/lib/ai_bot/bot.rb
@@ -152,10 +152,17 @@ module DiscourseAi
#{details}
- HTML - placeholder << custom_raw if custom_raw + if custom_raw + placeholder << "\n" + placeholder << custom_raw + else + # we need this for cursor placeholder to work + # doing this in CSS is very hard + # if changing test with a custom tool such as search + placeholder << "\n\n" + end placeholder end diff --git a/lib/ai_bot/playground.rb b/lib/ai_bot/playground.rb index 293c0fbe..2bb6940a 100644 --- a/lib/ai_bot/playground.rb +++ b/lib/ai_bot/playground.rb @@ -107,10 +107,12 @@ module DiscourseAi PostCreator.create!( bot.bot_user, topic_id: post.topic_id, - raw: I18n.t("discourse_ai.ai_bot.placeholder_reply"), + raw: "", skip_validations: true, ) + publish_update(reply_post, raw: "") + redis_stream_key = "gpt_cancel:#{reply_post.id}" Discourse.redis.setex(redis_stream_key, 60, 1) diff --git a/lib/ai_bot/tools/dall_e.rb b/lib/ai_bot/tools/dall_e.rb index 85621056..96548f6b 100644 --- a/lib/ai_bot/tools/dall_e.rb +++ b/lib/ai_bot/tools/dall_e.rb @@ -36,7 +36,7 @@ module DiscourseAi def invoke(bot_user, _llm) # max 4 prompts max_prompts = prompts.take(4) - progress = +"" + progress = prompts.first yield(progress) @@ -70,11 +70,7 @@ module DiscourseAi end end - while true - progress << "." - yield(progress) - break if threads.all? { |t| t.join(2) } - end + break if threads.all? { |t| t.join(2) } while true results = threads.filter_map(&:value) diff --git a/lib/ai_bot/tools/image.rb b/lib/ai_bot/tools/image.rb index e9d47fa3..92f3a3d4 100644 --- a/lib/ai_bot/tools/image.rb +++ b/lib/ai_bot/tools/image.rb @@ -51,7 +51,7 @@ module DiscourseAi selected_prompts = prompts.take(4) seeds = seeds.take(4) if seeds - progress = +"" + progress = prompts.first yield(progress) results = nil @@ -85,11 +85,7 @@ module DiscourseAi end end - while true - progress << "." - yield(progress) - break if threads.all? { |t| t.join(2) } - end + break if threads.all? { |t| t.join(2) } while true results = threads.map(&:value).compact @@ -115,7 +111,7 @@ module DiscourseAi end @custom_raw = <<~RAW - + [grid] #{ uploads diff --git a/spec/lib/modules/ai_bot/bot_spec.rb b/spec/lib/modules/ai_bot/bot_spec.rb index a5ac0185..b3ab4506 100644 --- a/spec/lib/modules/ai_bot/bot_spec.rb +++ b/spec/lib/modules/ai_bot/bot_spec.rb @@ -45,6 +45,7 @@ RSpec.describe DiscourseAi::AiBot::Bot do