Compare commits

..
1 Commits
Author SHA1 Message Date
Sam Saffron 7912b5e8be this code should no longer need 2025-05-23 22:05:17 +10:00
61 changed files with 76 additions and 425 deletions
@@ -18,16 +18,14 @@ import DiffStreamer from "../../lib/diff-streamer";
import SmoothStreamer from "../../lib/smooth-streamer";
import AiIndicatorWave from "../ai-indicator-wave";
const CHANNEL = "/discourse-ai/ai-helper/stream_composer_suggestion";
export default class ModalDiffModal extends Component {
@service currentUser;
@service messageBus;
@tracked loading = false;
@tracked finalResult = "";
@tracked escapedSelectedText = escapeExpression(this.args.model.selectedText);
@tracked diffStreamer = new DiffStreamer(this.args.model.selectedText);
@tracked selectedText = escapeExpression(this.args.model.selectedText);
@tracked diffStreamer = new DiffStreamer(this.selectedText);
@tracked suggestion = "";
@tracked
smoothStreamer = new SmoothStreamer(
@@ -47,13 +45,11 @@ export default class ModalDiffModal extends Component {
// Prevents flash by showing the
// original text when the diff is empty
return this.escapedSelectedText;
return this.selectedText;
}
get isStreaming() {
// diffStreamer stops Streaming when it is finished with a chunk, looking at isDone is safe
// it starts off not done
return !this.diffStreamer.isDone || this.smoothStreamer.isStreaming;
return this.diffStreamer.isStreaming || this.smoothStreamer.isStreaming;
}
get primaryBtnLabel() {
@@ -68,23 +64,25 @@ export default class ModalDiffModal extends Component {
@bind
subscribe() {
this.messageBus.subscribe(CHANNEL, this.updateResult);
const channel = "/discourse-ai/ai-helper/stream_composer_suggestion";
this.messageBus.subscribe(channel, this.updateResult);
}
@bind
cleanup() {
// stop all callbacks so it does not end up streaming pointlessly
this.smoothStreamer.resetStreaming();
this.diffStreamer.reset();
this.messageBus.unsubscribe(CHANNEL, this.updateResult);
unsubscribe() {
const channel = "/discourse-ai/ai-helper/stream_composer_suggestion";
this.messageBus.subscribe(channel, this.updateResult);
}
@action
updateResult(result) {
async updateResult(result) {
this.loading = false;
if (result.done) {
this.finalResult = result.result;
}
if (result.done) {
this.loading = false;
}
@@ -107,7 +105,7 @@ export default class ModalDiffModal extends Component {
data: {
location: "composer",
mode: this.args.model.mode,
text: this.args.model.selectedText,
text: this.selectedText,
custom_prompt: this.args.model.customPromptValue,
force_default_locale: true,
client_id: this.messageBus.clientId,
@@ -124,7 +122,7 @@ export default class ModalDiffModal extends Component {
if (this.suggestion) {
this.args.model.toolbarEvent.replaceText(
this.args.model.selectedText,
this.selectedText,
this.suggestion
);
}
@@ -133,12 +131,8 @@ export default class ModalDiffModal extends Component {
this.finalResult?.length > 0
? this.finalResult
: this.diffStreamer.suggestion;
if (this.args.model.showResultAsDiff && finalResult) {
this.args.model.toolbarEvent.replaceText(
this.args.model.selectedText,
finalResult
);
this.args.model.toolbarEvent.replaceText(this.selectedText, finalResult);
}
}
@@ -151,7 +145,7 @@ export default class ModalDiffModal extends Component {
<:body>
<div
{{didInsert this.subscribe}}
{{willDestroy this.cleanup}}
{{willDestroy this.unsubscribe}}
class="text-preview"
>
{{#if this.loading}}
@@ -19,6 +19,7 @@ export default class AiPostHelperTrigger extends Component {
@tracked menuState = this.MENU_STATES.triggers;
@tracked showMainButtons = true;
@tracked showAiButtons = true;
@tracked originalPostHTML = null;
@tracked postHighlighted = false;
@tracked currentMenu = this.menu.getByIdentifier(
"post-text-selection-toolbar"
@@ -44,6 +45,7 @@ export default class AiPostHelperTrigger extends Component {
return;
}
this.originalPostHTML = postElement.innerHTML;
this.selectedText = this.args.outletArgs.data.quoteState.buffer;
const selection = window.getSelection();
@@ -119,15 +121,7 @@ export default class AiPostHelperTrigger extends Component {
return;
}
const highlightedSpans = postElement.querySelectorAll(
"span.ai-helper-highlighted-selection"
);
highlightedSpans.forEach((span) => {
const textNode = document.createTextNode(span.textContent);
span.parentNode.replaceChild(textNode, span);
});
postElement.innerHTML = this.originalPostHTML;
this.postHighlighted = false;
}
@@ -18,8 +18,8 @@ export default class AiConversationInvite extends Component {
get participants() {
const participants = [
...(this.header.topicInfo.details?.allowed_users ?? []),
...(this.header.topicInfo.details?.allowed_groups ?? []),
...this.header.topicInfo.details.allowed_users,
...this.header.topicInfo.details.allowed_groups,
];
return participants;
}
@@ -2,9 +2,8 @@ import { tracked } from "@glimmer/tracking";
import { cancel, later } from "@ember/runloop";
import loadJSDiff from "discourse/lib/load-js-diff";
import { parseAsync } from "discourse/lib/text";
import { escapeExpression } from "discourse/lib/utilities";
const DEFAULT_CHAR_TYPING_DELAY = 10;
const DEFAULT_CHAR_TYPING_DELAY = 30;
const STREAMING_DIFF_TRUNCATE_THRESHOLD = 0.1;
const STREAMING_DIFF_TRUNCATE_BUFFER = 10;
@@ -52,7 +51,7 @@ export default class DiffStreamer {
const originalDiff = this.jsDiff.diffWordsWithSpace(
this.selectedText,
newText
this.suggestion
);
this.diff = this.#formatDiffWithTags(originalDiff, false);
return;
@@ -100,7 +99,6 @@ export default class DiffStreamer {
this.currentWordIndex = 0;
this.currentCharIndex = 0;
this.isStreaming = false;
this.isDone = false;
if (this.typingTimer) {
cancel(this.typingTimer);
this.typingTimer = null;
@@ -174,10 +172,6 @@ export default class DiffStreamer {
}
async #streamNextChar() {
if (!this.isStreaming || this.isDone) {
return;
}
if (this.currentWordIndex < this.words.length) {
const currentToken = this.words[this.currentWordIndex];
@@ -202,19 +196,6 @@ export default class DiffStreamer {
}
this.typingTimer = later(this, this.#streamNextChar, this.typingDelay);
} else {
if (!this.suggestion || !this.selectedText || !this.jsDiff) {
return;
}
const originalDiff = this.jsDiff.diffWordsWithSpace(
this.selectedText,
this.suggestion
);
this.typingTimer = null;
this.diff = this.#formatDiffWithTags(originalDiff, false);
this.isStreaming = false;
}
}
@@ -258,7 +239,6 @@ export default class DiffStreamer {
return `<span>${text}</span>`;
}
// returns an HTML safe diff (escaping all internals)
#formatDiffWithTags(diffArray, highlightLastWord = true) {
const wordsWithType = [];
const output = [];
@@ -287,8 +267,7 @@ export default class DiffStreamer {
}
for (let i = 0; i <= lastWordIndex; i++) {
let { text, type } = wordsWithType[i];
text = escapeExpression(text);
const { text, type } = wordsWithType[i];
if (/^\s+$/.test(text)) {
output.push(text);
@@ -318,7 +297,6 @@ export default class DiffStreamer {
i++;
}
chunkText = escapeExpression(chunkText);
output.push(this.#wrapChunk(chunkText, chunkType));
}
}
@@ -39,22 +39,25 @@ body.has-ai-conversations-sidebar {
.sidebar-section-link.date-heading {
pointer-events: none;
cursor: default;
color: var(--d-sidebar-header-color);
color: var(--primary-medium);
opacity: 0.8;
font-weight: 700;
margin-top: 1em;
font-weight: bold;
font-size: var(--font-down-2-rem);
text-transform: uppercase;
letter-spacing: 0.05rem;
font-size: var(--font-down-2);
}
.sidebar-section-link {
height: unset;
padding-block: 0.65em;
font-size: var(--font-down-1);
letter-spacing: 0.35px;
border-radius: 0 var(--border-radius) var(--border-radius) 0;
.sidebar-section-link-content-text {
white-space: normal;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
-webkit-line-clamp: 2;
overflow: hidden;
}
}
@@ -1,5 +1,3 @@
@use "lib/viewport";
.composer-ai-helper-modal {
.text-preview,
.inline-diff {
@@ -181,7 +179,7 @@
@keyframes dot-falling {
0% {
box-shadow: 9999px -15px 0 0 rgb(152, 128, 255, 0);
box-shadow: 9999px -15px 0 0 rgba(152, 128, 255, 0);
}
25%,
@@ -191,13 +189,13 @@
}
100% {
box-shadow: 9999px 15px 0 0 rgb(152, 128, 255, 0);
box-shadow: 9999px 15px 0 0 rgba(152, 128, 255, 0);
}
}
@keyframes dot-falling-before {
0% {
box-shadow: 9984px -15px 0 0 rgb(152, 128, 255, 0);
box-shadow: 9984px -15px 0 0 rgba(152, 128, 255, 0);
}
25%,
@@ -207,13 +205,13 @@
}
100% {
box-shadow: 9984px 15px 0 0 rgb(152, 128, 255, 0);
box-shadow: 9984px 15px 0 0 rgba(152, 128, 255, 0);
}
}
@keyframes dot-falling-after {
0% {
box-shadow: 10014px -15px 0 0 rgb(152, 128, 255, 0);
box-shadow: 10014px -15px 0 0 rgba(152, 128, 255, 0);
}
25%,
@@ -223,7 +221,7 @@
}
100% {
box-shadow: 10014px 15px 0 0 rgb(152, 128, 255, 0);
box-shadow: 10014px 15px 0 0 rgba(152, 128, 255, 0);
}
}
@@ -234,6 +232,19 @@
input:focus {
z-index: 1;
}
input {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
}
.category-chooser,
.mini-tag-chooser {
.select-kit-header {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
}
#edit-title {
@@ -628,7 +639,7 @@
height: 7em;
min-width: var(--ai-caption-popup-min-width);
@include viewport.until(md) {
@include breakpoint(tablet) {
width: 100%;
max-width: unset;
min-width: unset;
-2
View File
@@ -603,8 +603,6 @@ ar:
share_ai_conversation:
name: "مشاركة محادثة الذكاء الاصطناعي"
title: "مشاركة هذه المحادثة بشكلٍ علني"
invite_ai_conversation:
button: "دعوة"
ai_label: "الذكاء الاصطناعي"
ai_title: "المحادثة مع الذكاء الاصطناعي"
share_modal:
-2
View File
@@ -134,8 +134,6 @@ bg:
request: "Заявка"
next_log: "Напред"
previous_log: "Предишни"
invite_ai_conversation:
button: "Покана"
share_modal:
copy: "Копирай"
conversations:
-2
View File
@@ -128,8 +128,6 @@ bs_BA:
response: "Odgovor"
next_log: "Iduće"
previous_log: "Previous"
invite_ai_conversation:
button: "Invite"
share_modal:
copy: "Copy"
conversations:
-2
View File
@@ -133,8 +133,6 @@ ca:
response: "Reacció"
next_log: "Següent"
previous_log: "Previ"
invite_ai_conversation:
button: "Convida"
share_modal:
copy: "Còpia"
conversations:
-45
View File
@@ -211,69 +211,24 @@ cs:
ai_artifact:
collapse_view_label: "Ukončení celé obrazovky (ESC nebo tlačítko Zpět)"
ai_bot:
pm_warning: "Zprávy chatbotů s umělou inteligencí jsou pravidelně monitorovány moderátory."
cancel_streaming: "Zastavit odpověď"
default_pm_prefix: "[Nepojmenovaná SZ od AI bota]"
shortcut_title: "Začněte SZ s AI botem"
share: "Kopírovat konverzaci s AI"
conversation_shared: "Konverzace zkopírována"
debug_ai: "Zobrazit nezpracovaný požadavek a odpověď umělé inteligence"
sidebar_empty: "Zde se zobrazí historie konverzace s botem."
debug_ai_modal:
title: "Zobrazit interakci s umělou inteligencí"
copy_request: "Kopírovat požadavek"
copy_response: "Kopírovat odpověď"
request_tokens: "Tokeny požadavku:"
response_tokens: "Tokeny odpovědi:"
request: "Požadavek"
response: "Odpověď"
next_log: "Další"
previous_log: "Předchozí"
share_full_topic_modal:
title: "Veřejně sdílet konverzaci"
share: "Sdílet a kopírovat odkaz"
update: "Aktualizovat a zkopírovat odkaz"
delete: "Odstranit sdílení"
share_ai_conversation:
name: "Sdílet konverzaci s AI"
title: "Sdílejte veřejně tuto konverzaci s umělou inteligencí"
invite_ai_conversation:
button: "Pozvat"
title: "Pozvat do konverzace s AI"
ai_title: "Konverzace s AI"
share_modal:
title: "Kopírovat konverzaci s AI"
copy: "Kopírovat"
context: "Interakce ke sdílení:"
share_tip: "Můžete také sdílet celou konverzaci."
bot_names:
fake: "Falešný testovací bot"
claude-3-opus: "Claude 3 Opus"
claude-3-sonnet: "Claude 3 Sonet"
claude-3-haiku: "Haiku Claude 3"
cohere-command-r-plus: "Cohere Command R Plus"
gpt-4: "GPT-4"
gpt-4-turbo: "GPT-4 Turbo"
gpt-4o: "GPT-4 Omni"
gpt-3:
5-turbo: "GPT-3.5"
claude-2: "Claude 2"
gemini-1:
5-pro: "Gemini"
mixtral-8x7B-Instruct-V0:
"1": "Mixtral-8x7B V0.1"
conversations:
header: "S čím mohu pomoci?"
submit: "Odeslat otázku"
disclaimer: "Generativní umělá inteligence může dělat chyby. Ověřte si důležité informace."
placeholder: "Zeptejte se..."
new: "Nová otázka"
min_input_length_message:
one: "Zpráva musí mít 1 nebo více znaků"
few: "Zpráva musí mít %{count} nebo více znaků"
many: "Zpráva musí mít %{count} nebo více znaků"
other: "Zpráva musí mít %{count} nebo více znaků"
messages_sidebar_title: "Konverzace"
today: "Dnes"
last_7_days: "Posledních 7 dní"
last_30_days: "Posledních 30 dní"
-2
View File
@@ -147,8 +147,6 @@ da:
response: "Svar"
next_log: "Næste"
previous_log: "Forrige"
invite_ai_conversation:
button: "Invitér"
share_modal:
copy: "Kopier"
conversations:
+1 -8
View File
@@ -328,11 +328,9 @@ de:
key_title: "Schlüssel"
examples:
title: Beispiele
examples_help: Simuliere frühere Interaktionen mit dem LLM und erde es, um bessere Ergebnisse zu erzielen.
new: Neues Beispiel
remove: Beispiel löschen
collapsable_title: "Beispiel #%{number}"
user: "Nachricht des Benutzers"
model: "Antwort des Modells"
list:
enabled: "KI-Bot?"
@@ -524,8 +522,7 @@ de:
provider_quantizations: "Reihenfolge der Provider-Quantisierungen (kommagetrennte Liste, z. B.: fp16,fp8)"
disable_streaming: "Streaming-Vervollständigung deaktivieren (Streaming-Anfragen in Nicht-Streaming-Anfragen umwandeln)"
reasoning_effort: "Argumentationsaufwand (gilt nur für Argumentationsmodelle)"
enable_reasoning: "Argumentation aktivieren (nur für Argumentationsmodelle anwendbar)"
enable_thinking: "Denken aktivieren (nur bei entsprechenden Modellen, z.B.: Flash 2.5)"
enable_reasoning: "Argumentation aktivieren (gilt nur für Sonnet 3.7)"
thinking_tokens: "Anzahl der zum Denken verwendeten Token"
reasoning_tokens: "Anzahl der für die Argumentation verwendeten Token"
disable_temperature: "Temperatur deaktivieren (einige Denkmodelle unterstützen keine Temperatur)"
@@ -667,7 +664,6 @@ de:
share: "KI-Unterhaltung kopieren"
conversation_shared: "Unterhaltung kopiert"
debug_ai: "Rohdaten der KI-Anfrage und -Antwort anzeigen"
sidebar_empty: "Der Verlauf der Bot-Konversation wird hier angezeigt."
debug_ai_modal:
title: "KI-Interaktion ansehen"
copy_request: "Anfrage kopieren"
@@ -686,9 +682,6 @@ de:
share_ai_conversation:
name: "KI-Unterhaltung teilen"
title: "Diese KI-Unterhaltung öffentlich teilen"
invite_ai_conversation:
button: "Einladen"
title: "Zur KI-Konversation einladen"
ai_label: "KI"
ai_title: "Unterhaltung mit KI"
share_modal:
-2
View File
@@ -142,8 +142,6 @@ el:
response: "Απάντηση"
next_log: "Επόμενο"
previous_log: "Προηγούμενο"
invite_ai_conversation:
button: "Πρόσκληση"
share_modal:
copy: "Αντιγραφή"
conversations:
+1 -1
View File
@@ -540,7 +540,7 @@ en:
provider_quantizations: "Order of provider quantizations (comma delimited list eg: fp16,fp8)"
disable_streaming: "Disable streaming completions (convert streaming to non streaming requests)"
reasoning_effort: "Reasoning effort (only applicable to reasoning models)"
enable_reasoning: "Enable reasoning (only applicable to reasoning models)"
enable_reasoning: "Enable reasoning (only applicable to Sonnet 3.7)"
enable_thinking: "Enable thinking (only on applicable models eg: flash 2.5)"
thinking_tokens: "Number of tokens used for thinking"
reasoning_tokens: "Number of tokens used for reasoning"
-2
View File
@@ -591,8 +591,6 @@ es:
share_ai_conversation:
name: "Compartir conversación de IA"
title: "Compartir esta conversación de IA públicamente"
invite_ai_conversation:
button: "Invitar"
ai_label: "IA"
ai_title: "Conversación con IA"
share_modal:
-2
View File
@@ -130,8 +130,6 @@ et:
response: "Vastus"
next_log: "Järgmine"
previous_log: "Eelmine"
invite_ai_conversation:
button: "Kutsu"
share_modal:
copy: "Kopeeri"
conversations:
-2
View File
@@ -187,8 +187,6 @@ fa_IR:
response: "پاسخ"
next_log: "بعدی"
previous_log: "پیشین"
invite_ai_conversation:
button: "دعوت"
ai_label: "هوش مصنوعی"
share_modal:
copy: "کپی"
-2
View File
@@ -591,8 +591,6 @@ fi:
share_ai_conversation:
name: "Jaa tekoälykeskustelu"
title: "Jaa tämä tekoälykeskustelu julkisesti"
invite_ai_conversation:
button: "Kutsu"
ai_label: "Tekoäly"
ai_title: "Keskustelu tekoälyn kanssa"
share_modal:
-2
View File
@@ -591,8 +591,6 @@ fr:
share_ai_conversation:
name: "Partager une conversation IA"
title: "Partager publiquement cette conversation avec l'IA"
invite_ai_conversation:
button: "Inviter"
ai_label: "IA"
ai_title: "Conversation avec l'IA"
share_modal:
-2
View File
@@ -140,8 +140,6 @@ gl:
response: "Resposta"
next_log: "Seguinte"
previous_log: "Anterior"
invite_ai_conversation:
button: "Convidar"
share_modal:
copy: "Copiar"
conversations:
+1 -7
View File
@@ -497,8 +497,7 @@ he:
disable_native_tools: "השבתת תמיכה בבלי מובנה (להשתמש בכלים מבוססי XML)"
provider_order: "סדר ספקים (רשימה מופרדת בפסיקים)"
provider_quantizations: "סדר כימות הספקים (רשימה מופרדת בפסיקים, למשל: fp16,fp8)"
reasoning_effort: "מאמץ נימוק (תקף רק על מודלים של נימוק)"
enable_thinking: "הפעלת חשיבה (רק במודלים תקפים לדוגמה: flash 2.5)"
enable_reasoning: "הפעלת נימוק (תקף רק על Sonnet 3.7)"
reasoning_tokens: "כמות אסימונים המשמשים לנימוק"
related_topics:
title: "נושאים קשורים"
@@ -632,7 +631,6 @@ he:
share: "העתקת דיון עם בינה מלאכותית"
conversation_shared: "הדיון הועתק"
debug_ai: "הצגת בקשה ותגובה גולמיות לבינה המלאכותית"
sidebar_empty: "היסטוריית השיחה עם הבוט תופיע כאן."
debug_ai_modal:
title: "הצגת התכתובת מול הבינה המלאכותית"
copy_request: "העתקת הבקשה"
@@ -651,9 +649,6 @@ he:
share_ai_conversation:
name: "שיתוף דיון עם בינה מלאכותית"
title: "שיתוף שיחת בינה מלאכותית באופן ציבורי"
invite_ai_conversation:
button: "להזמין"
title: "הזמנה לשיחה עם בינה מלאכותית"
ai_label: "בינה מלאכותית"
ai_title: "דיון עם בינה מלאכותית"
share_modal:
@@ -680,7 +675,6 @@ he:
conversations:
header: "איך אפשר לעזור?"
submit: "הגשת שאלה"
disclaimer: "בינה מלאכותית מחוללת עלולה לשגות. כדאי לאמת פרטים חשובים."
placeholder: "הגשת שאלה…"
new: "שאלה חדשה"
messages_sidebar_title: "שיחות"
-2
View File
@@ -147,8 +147,6 @@ hr:
response: "Odgovor"
next_log: "Sljedeći"
previous_log: "Predhodno"
invite_ai_conversation:
button: "Pozovite"
share_modal:
copy: "Kopija"
conversations:
-2
View File
@@ -150,8 +150,6 @@ hu:
response: "Válasz"
next_log: "Tovább"
previous_log: "Vissza"
invite_ai_conversation:
button: "Meghívás"
share_modal:
copy: "Másolás"
conversations:
-2
View File
@@ -133,8 +133,6 @@ hy:
response: "Արձագանք"
next_log: "Հաջորդը"
previous_log: "Նախորդը"
invite_ai_conversation:
button: "Հրավիրել"
share_modal:
copy: "Կրկնօրինակել"
conversations:
-2
View File
@@ -234,8 +234,6 @@ id:
share_ai_conversation:
name: "Bagikan percakapan AI"
title: "Bagikan percakapan AI ini secara publik"
invite_ai_conversation:
button: "Undang"
ai_label: "AI"
ai_title: "Percakapan dengan AI"
share_modal:
-2
View File
@@ -591,8 +591,6 @@ it:
share_ai_conversation:
name: "Condividi la conversazione con IA"
title: "Condividi pubblicamente questa conversazione IA"
invite_ai_conversation:
button: "Invita"
ai_label: "IA"
ai_title: "Conversazione con IA"
share_modal:
-2
View File
@@ -586,8 +586,6 @@ ja:
share_ai_conversation:
name: "AI の会話を共有"
title: "この AI の会話を公開共有する"
invite_ai_conversation:
button: "招待"
ai_label: "AI"
ai_title: "AI との会話"
share_modal:
-2
View File
@@ -148,8 +148,6 @@ ko:
response: "응답"
next_log: "다음"
previous_log: "이전값"
invite_ai_conversation:
button: "초대"
share_modal:
copy: "복사"
conversations:
-2
View File
@@ -187,8 +187,6 @@ lt:
response: "Atsakymas"
next_log: "Kitas"
previous_log: "Buvęs"
invite_ai_conversation:
button: "Kviesti"
ai_label: "AI"
share_modal:
copy: "Kopijuoti"

Some files were not shown because too many files have changed in this diff Show More