Compare commits

..
11 Commits
Author SHA1 Message Date
Jordan Vidrine 5b012a15b8 lint 2025-05-27 16:24:13 -05:00
Jordan Vidrine 051ac3ea49 more 2025-05-27 15:49:55 -05:00
Jordan Vidrine d993b02975 bring sidebar styles closer to core 2025-05-27 15:19:35 -05:00
Discourse Translator Bot 39653aed22 Update translations (#1371) 2025-05-27 22:11:32 +02:00
Sam 6781ecd02e DEV: cleanup diff streaming (#1370)
This simplifies some of the internal logic and ensures it is a
bit more robust
2025-05-27 18:12:02 +10:00
Keegan George e264572597 FIX: Closing AI menu stops post audio from playing (#1369)
## 🔍 Overview
When you have a post with audio being played and you open and close the AI post helper menu, it re-renders the entire post DOM, causing the audio to be interrupted and stop playing.

The reason for this is because we highlight the selected text when opening the AI post helper menu and we replace the entire post back with the original post HTML when closing the menu. This fix ensures that we do not re-render the entire post DOM and instead only remove the highlighted section that was added.

## 🔗 Context
https://meta.discourse.org/t/ai-helper-interrupting-uploaded-mp3-audio-stream/366817?u=keegan
2025-05-26 10:24:06 -07:00
Sam 70b0db2871 FIX: improve researcher tool - fix topic filters (#1368)
* Small fix, reasoning is now available on Claude 4 models

* fix invalid filters should raise, topic filter not working

* fix spec so we are consistent
2025-05-26 16:00:44 +10:00
Sam 2d6ec5e1e6 FIX: apply diffs more consistently (#1367)
* FIX: apply diffs more consistently

1. Do escaping direct in diff streamer, that way HTML tags and other unsafe chars can be displayed and fixed
2. Add safeguard to ensure streaming always stops when it was terminated elsewhere

* lint

* bug unsubscribe should unsubscribe
2025-05-24 15:19:48 +10:00
Mark VanLandingham cead887480 FIX: Don't error when navigating from AI Bot topic to regular (#1366)
We were getting an error in this logic causing Ember to fail to render the non-bot-topic that we navigate to.

I believe this is because the getter of participants is re-calculating (due to this.header.topicInfo being updated) before the args to this connector changes. Adding some safe navigation here fixes the issue.
2025-05-23 13:30:08 -05:00
Jordan Vidrine adc92e1e75 UX: Allow rounded corners (#1365) 2025-05-23 10:42:55 -05:00
Roman Rizzi 0ce17a122f FIX: Correctly pass tool_choice when using Claude models. (#1364)
The `ClaudePrompt` object couldn't access the original prompt's tool_choice attribute, affecting both Anthropic and Bedrock.
2025-05-23 10:36:52 -03:00
61 changed files with 425 additions and 76 deletions
@@ -18,14 +18,16 @@ 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 selectedText = escapeExpression(this.args.model.selectedText);
@tracked diffStreamer = new DiffStreamer(this.selectedText);
@tracked escapedSelectedText = escapeExpression(this.args.model.selectedText);
@tracked diffStreamer = new DiffStreamer(this.args.model.selectedText);
@tracked suggestion = "";
@tracked
smoothStreamer = new SmoothStreamer(
@@ -45,11 +47,13 @@ export default class ModalDiffModal extends Component {
// Prevents flash by showing the
// original text when the diff is empty
return this.selectedText;
return this.escapedSelectedText;
}
get isStreaming() {
return this.diffStreamer.isStreaming || this.smoothStreamer.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;
}
get primaryBtnLabel() {
@@ -64,25 +68,23 @@ export default class ModalDiffModal extends Component {
@bind
subscribe() {
const channel = "/discourse-ai/ai-helper/stream_composer_suggestion";
this.messageBus.subscribe(channel, this.updateResult);
this.messageBus.subscribe(CHANNEL, this.updateResult);
}
@bind
unsubscribe() {
const channel = "/discourse-ai/ai-helper/stream_composer_suggestion";
this.messageBus.subscribe(channel, this.updateResult);
cleanup() {
// stop all callbacks so it does not end up streaming pointlessly
this.smoothStreamer.resetStreaming();
this.diffStreamer.reset();
this.messageBus.unsubscribe(CHANNEL, this.updateResult);
}
@action
async updateResult(result) {
updateResult(result) {
this.loading = false;
if (result.done) {
this.finalResult = result.result;
}
if (result.done) {
this.loading = false;
}
@@ -105,7 +107,7 @@ export default class ModalDiffModal extends Component {
data: {
location: "composer",
mode: this.args.model.mode,
text: this.selectedText,
text: this.args.model.selectedText,
custom_prompt: this.args.model.customPromptValue,
force_default_locale: true,
client_id: this.messageBus.clientId,
@@ -122,7 +124,7 @@ export default class ModalDiffModal extends Component {
if (this.suggestion) {
this.args.model.toolbarEvent.replaceText(
this.selectedText,
this.args.model.selectedText,
this.suggestion
);
}
@@ -131,8 +133,12 @@ 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.selectedText, finalResult);
this.args.model.toolbarEvent.replaceText(
this.args.model.selectedText,
finalResult
);
}
}
@@ -145,7 +151,7 @@ export default class ModalDiffModal extends Component {
<:body>
<div
{{didInsert this.subscribe}}
{{willDestroy this.unsubscribe}}
{{willDestroy this.cleanup}}
class="text-preview"
>
{{#if this.loading}}
@@ -19,7 +19,6 @@ 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"
@@ -45,7 +44,6 @@ export default class AiPostHelperTrigger extends Component {
return;
}
this.originalPostHTML = postElement.innerHTML;
this.selectedText = this.args.outletArgs.data.quoteState.buffer;
const selection = window.getSelection();
@@ -121,7 +119,15 @@ export default class AiPostHelperTrigger extends Component {
return;
}
postElement.innerHTML = this.originalPostHTML;
const highlightedSpans = postElement.querySelectorAll(
"span.ai-helper-highlighted-selection"
);
highlightedSpans.forEach((span) => {
const textNode = document.createTextNode(span.textContent);
span.parentNode.replaceChild(textNode, span);
});
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,8 +2,9 @@ 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 = 30;
const DEFAULT_CHAR_TYPING_DELAY = 10;
const STREAMING_DIFF_TRUNCATE_THRESHOLD = 0.1;
const STREAMING_DIFF_TRUNCATE_BUFFER = 10;
@@ -51,7 +52,7 @@ export default class DiffStreamer {
const originalDiff = this.jsDiff.diffWordsWithSpace(
this.selectedText,
this.suggestion
newText
);
this.diff = this.#formatDiffWithTags(originalDiff, false);
return;
@@ -99,6 +100,7 @@ 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;
@@ -172,6 +174,10 @@ export default class DiffStreamer {
}
async #streamNextChar() {
if (!this.isStreaming || this.isDone) {
return;
}
if (this.currentWordIndex < this.words.length) {
const currentToken = this.words[this.currentWordIndex];
@@ -196,6 +202,19 @@ 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;
}
}
@@ -239,6 +258,7 @@ export default class DiffStreamer {
return `<span>${text}</span>`;
}
// returns an HTML safe diff (escaping all internals)
#formatDiffWithTags(diffArray, highlightLastWord = true) {
const wordsWithType = [];
const output = [];
@@ -267,7 +287,8 @@ export default class DiffStreamer {
}
for (let i = 0; i <= lastWordIndex; i++) {
const { text, type } = wordsWithType[i];
let { text, type } = wordsWithType[i];
text = escapeExpression(text);
if (/^\s+$/.test(text)) {
output.push(text);
@@ -297,6 +318,7 @@ export default class DiffStreamer {
i++;
}
chunkText = escapeExpression(chunkText);
output.push(this.#wrapChunk(chunkText, chunkType));
}
}
@@ -39,25 +39,22 @@ body.has-ai-conversations-sidebar {
.sidebar-section-link.date-heading {
pointer-events: none;
cursor: default;
color: var(--primary-medium);
opacity: 0.8;
font-weight: 700;
color: var(--d-sidebar-header-color);
margin-top: 1em;
font-size: var(--font-down-2);
font-weight: bold;
font-size: var(--font-down-2-rem);
text-transform: uppercase;
letter-spacing: 0.05rem;
}
.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: 2;
-webkit-line-clamp: 1;
overflow: hidden;
}
}
@@ -1,3 +1,5 @@
@use "lib/viewport";
.composer-ai-helper-modal {
.text-preview,
.inline-diff {
@@ -179,7 +181,7 @@
@keyframes dot-falling {
0% {
box-shadow: 9999px -15px 0 0 rgba(152, 128, 255, 0);
box-shadow: 9999px -15px 0 0 rgb(152, 128, 255, 0);
}
25%,
@@ -189,13 +191,13 @@
}
100% {
box-shadow: 9999px 15px 0 0 rgba(152, 128, 255, 0);
box-shadow: 9999px 15px 0 0 rgb(152, 128, 255, 0);
}
}
@keyframes dot-falling-before {
0% {
box-shadow: 9984px -15px 0 0 rgba(152, 128, 255, 0);
box-shadow: 9984px -15px 0 0 rgb(152, 128, 255, 0);
}
25%,
@@ -205,13 +207,13 @@
}
100% {
box-shadow: 9984px 15px 0 0 rgba(152, 128, 255, 0);
box-shadow: 9984px 15px 0 0 rgb(152, 128, 255, 0);
}
}
@keyframes dot-falling-after {
0% {
box-shadow: 10014px -15px 0 0 rgba(152, 128, 255, 0);
box-shadow: 10014px -15px 0 0 rgb(152, 128, 255, 0);
}
25%,
@@ -221,7 +223,7 @@
}
100% {
box-shadow: 10014px 15px 0 0 rgba(152, 128, 255, 0);
box-shadow: 10014px 15px 0 0 rgb(152, 128, 255, 0);
}
}
@@ -232,19 +234,6 @@
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 {
@@ -639,7 +628,7 @@
height: 7em;
min-width: var(--ai-caption-popup-min-width);
@include breakpoint(tablet) {
@include viewport.until(md) {
width: 100%;
max-width: unset;
min-width: unset;
+2
View File
@@ -603,6 +603,8 @@ ar:
share_ai_conversation:
name: "مشاركة محادثة الذكاء الاصطناعي"
title: "مشاركة هذه المحادثة بشكلٍ علني"
invite_ai_conversation:
button: "دعوة"
ai_label: "الذكاء الاصطناعي"
ai_title: "المحادثة مع الذكاء الاصطناعي"
share_modal:
+2
View File
@@ -134,6 +134,8 @@ bg:
request: "Заявка"
next_log: "Напред"
previous_log: "Предишни"
invite_ai_conversation:
button: "Покана"
share_modal:
copy: "Копирай"
conversations:
+2
View File
@@ -128,6 +128,8 @@ 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,6 +133,8 @@ 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,24 +211,69 @@ 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,6 +147,8 @@ da:
response: "Svar"
next_log: "Næste"
previous_log: "Forrige"
invite_ai_conversation:
button: "Invitér"
share_modal:
copy: "Kopier"
conversations:
+8 -1
View File
@@ -328,9 +328,11 @@ 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?"
@@ -522,7 +524,8 @@ 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 (gilt nur für Sonnet 3.7)"
enable_reasoning: "Argumentation aktivieren (nur für Argumentationsmodelle anwendbar)"
enable_thinking: "Denken aktivieren (nur bei entsprechenden Modellen, z.B.: Flash 2.5)"
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)"
@@ -664,6 +667,7 @@ 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"
@@ -682,6 +686,9 @@ 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,6 +142,8 @@ 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 Sonnet 3.7)"
enable_reasoning: "Enable reasoning (only applicable to reasoning models)"
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,6 +591,8 @@ 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,6 +130,8 @@ et:
response: "Vastus"
next_log: "Järgmine"
previous_log: "Eelmine"
invite_ai_conversation:
button: "Kutsu"
share_modal:
copy: "Kopeeri"
conversations:
+2
View File
@@ -187,6 +187,8 @@ fa_IR:
response: "پاسخ"
next_log: "بعدی"
previous_log: "پیشین"
invite_ai_conversation:
button: "دعوت"
ai_label: "هوش مصنوعی"
share_modal:
copy: "کپی"
+2
View File
@@ -591,6 +591,8 @@ 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,6 +591,8 @@ 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,6 +140,8 @@ gl:
response: "Resposta"
next_log: "Seguinte"
previous_log: "Anterior"
invite_ai_conversation:
button: "Convidar"
share_modal:
copy: "Copiar"
conversations:
+7 -1
View File
@@ -497,7 +497,8 @@ he:
disable_native_tools: "השבתת תמיכה בבלי מובנה (להשתמש בכלים מבוססי XML)"
provider_order: "סדר ספקים (רשימה מופרדת בפסיקים)"
provider_quantizations: "סדר כימות הספקים (רשימה מופרדת בפסיקים, למשל: fp16,fp8)"
enable_reasoning: "הפעלת נימוק (תקף רק על Sonnet 3.7)"
reasoning_effort: "מאמץ נימוק (תקף רק על מודלים של נימוק)"
enable_thinking: "הפעלת חשיבה (רק במודלים תקפים לדוגמה: flash 2.5)"
reasoning_tokens: "כמות אסימונים המשמשים לנימוק"
related_topics:
title: "נושאים קשורים"
@@ -631,6 +632,7 @@ he:
share: "העתקת דיון עם בינה מלאכותית"
conversation_shared: "הדיון הועתק"
debug_ai: "הצגת בקשה ותגובה גולמיות לבינה המלאכותית"
sidebar_empty: "היסטוריית השיחה עם הבוט תופיע כאן."
debug_ai_modal:
title: "הצגת התכתובת מול הבינה המלאכותית"
copy_request: "העתקת הבקשה"
@@ -649,6 +651,9 @@ he:
share_ai_conversation:
name: "שיתוף דיון עם בינה מלאכותית"
title: "שיתוף שיחת בינה מלאכותית באופן ציבורי"
invite_ai_conversation:
button: "להזמין"
title: "הזמנה לשיחה עם בינה מלאכותית"
ai_label: "בינה מלאכותית"
ai_title: "דיון עם בינה מלאכותית"
share_modal:
@@ -675,6 +680,7 @@ he:
conversations:
header: "איך אפשר לעזור?"
submit: "הגשת שאלה"
disclaimer: "בינה מלאכותית מחוללת עלולה לשגות. כדאי לאמת פרטים חשובים."
placeholder: "הגשת שאלה…"
new: "שאלה חדשה"
messages_sidebar_title: "שיחות"
+2
View File
@@ -147,6 +147,8 @@ hr:
response: "Odgovor"
next_log: "Sljedeći"
previous_log: "Predhodno"
invite_ai_conversation:
button: "Pozovite"
share_modal:
copy: "Kopija"
conversations:
+2
View File
@@ -150,6 +150,8 @@ 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,6 +133,8 @@ hy:
response: "Արձագանք"
next_log: "Հաջորդը"
previous_log: "Նախորդը"
invite_ai_conversation:
button: "Հրավիրել"
share_modal:
copy: "Կրկնօրինակել"
conversations:
+2
View File
@@ -234,6 +234,8 @@ 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,6 +591,8 @@ 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,6 +586,8 @@ ja:
share_ai_conversation:
name: "AI の会話を共有"
title: "この AI の会話を公開共有する"
invite_ai_conversation:
button: "招待"
ai_label: "AI"
ai_title: "AI との会話"
share_modal:
+2
View File
@@ -148,6 +148,8 @@ ko:
response: "응답"
next_log: "다음"
previous_log: "이전값"
invite_ai_conversation:
button: "초대"
share_modal:
copy: "복사"
conversations:
+2
View File
@@ -187,6 +187,8 @@ 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