Compare commits

..
Author SHA1 Message Date
Roman Rizzi 822594f3e3 Update db/migrate/20250716005855_copy_ai_image_caption_model_to_persona_default.rb 2025-07-21 18:00:01 -03:00
Keegan George 7dee59c97f DEV: Remove no longer needed seeded model check 2025-07-21 08:08:20 -07:00
Keegan George fbbe01e576 DEV: Hide seeded LLMs in the enumerator for now 2025-07-21 07:45:27 -07:00
Keegan George f420261196 DEV: Apply feedback from review 2025-07-18 12:17:08 -07:00
Keegan George eb93e1736b Final spec fix 🤞 2025-07-17 14:46:15 -07:00
Keegan George cc34882074 FIX: rest of specs 2025-07-17 14:34:29 -07:00
Keegan George 4b03cdcc96 FIX: LLM controller spec 2025-07-17 13:31:26 -07:00
Keegan George d9b53b4a3d FIX: semantic search 2025-07-17 12:23:38 -07:00
Keegan George a927fd2270 fix 2025-07-17 12:00:05 -07:00
Keegan George f077d58abf FIX: automation spec 2025-07-17 11:48:28 -07:00
Keegan George 08d2f3ddf9 FIX: spam 2025-07-17 11:36:19 -07:00
Keegan George 273a1fa618 FIX: occurrences of old model setting 2025-07-17 09:43:45 -07:00
Keegan George 7af3ce820d DEV: Remove references to translation model 2025-07-17 09:27:08 -07:00
Keegan George 5841543bd9 FIX: validator 2025-07-16 14:51:32 -07:00
Keegan George 5ae80645bb Merge branch 'main' into default-llm-model 2025-07-16 12:07:10 -07:00
Keegan George b675c4c39b DEV: Remove custom prefix in specs 2025-07-16 11:39:55 -07:00
Keegan George 0fadf1da1a DEV: update enumerator 2025-07-16 10:56:18 -07:00
Keegan George c26d604072 FIX: dependency validator should depend on default LLM setting 2025-07-16 07:08:29 -07:00
Keegan George 7ae61ce877 DEV: update automation to remove custom: prefix 2025-07-15 18:08:41 -07:00
Keegan George f593ab6e1e DEV: remove custom: prefix
and update migrations for translations
2025-07-15 18:07:05 -07:00
Keegan George b58f198ee8 FIX: don't run_test in testing env 2025-07-15 11:08:39 -07:00
Keegan George 88811f97bf fixes 2025-07-15 10:23:58 -07:00
Keegan George 2377b286dd DEV: rely on default llm model in spec 2025-07-15 09:56:24 -07:00
Keegan George 8da4318021 DEV: assign_fake_provider 2025-07-11 12:32:36 -07:00
Keegan George b6a88ff03e spec 2025-07-11 12:02:50 -07:00
Keegan George f366ded03b DEV: Force default to be set if it was found not to be set! 2025-07-11 08:19:30 -07:00
Keegan George 87c42145d4 DEV: hide hyde model setting 2025-07-10 15:07:12 -07:00
Keegan George c49f1df2ba DEV: migrate hyde model to content creator persona 2025-07-10 15:00:34 -07:00
Keegan George b46940fc66 DEV: hide reset button
It resets it to default before the migration
2025-07-10 14:46:02 -07:00
Keegan George 249aab100c DEV: Use a simple validator
- no need for seeding checks or module dependant checks
2025-07-10 14:44:02 -07:00
Keegan George 5a29074799 DEV: Use default LLM model 2025-07-10 11:54:35 -07:00
Keegan George 29d415755a fix 2025-07-09 15:42:44 -07:00
Keegan George 5a590fddc1 DEV: updates... 2025-07-09 15:36:34 -07:00
Keegan George cad39c1aa4 DEV: client side 2025-07-09 15:29:50 -07:00
Keegan George 2592be65ff FEATURE: configure a default LLM model for all features
This update adds a setting to the configure a default LLM model to be used for all features (unless overridden).
2025-07-09 15:29:24 -07:00
139 changed files with 823 additions and 564 deletions
-1
View File
@@ -1,4 +1,3 @@
< 3.5.0.beta8-dev: 5d80a34589d63e381d80273828072badc18955b1
< 3.5.0.beta7-dev: cd14b0c0bee0cf63c59b64b6f7213e31a37f11a7
< 3.5.0.beta6-dev: 3e74eea1e5e3143888d67a8d8a11206df214dc24
< 3.5.0.beta3-dev: 09a68414804a1447f52e5d60691ba59742cda9ec
+1 -1
View File
@@ -40,7 +40,7 @@ module Jobs
return if locales.blank?
locales.each do |locale|
next if LocaleNormalizer.is_same?(locale, detected_locale)
next if DiscourseAi::Translation::LocaleNormalizer.is_same?(locale, detected_locale)
regionless_locale = locale.split("_").first
next if post.post_localizations.where("locale LIKE ?", "#{regionless_locale}%").exists?
+1 -1
View File
@@ -38,7 +38,7 @@ module Jobs
return if locales.blank?
locales.each do |locale|
next if LocaleNormalizer.is_same?(locale, detected_locale)
next if DiscourseAi::Translation::LocaleNormalizer.is_same?(locale, detected_locale)
regionless_locale = locale.split("_").first
next if topic.topic_localizations.where("locale LIKE ?", "#{regionless_locale}%").exists?
+1 -1
View File
@@ -29,7 +29,7 @@ module Jobs
missing_locales = locales - existing_locales - [category.locale]
missing_locales.each do |locale|
break if remaining_limit <= 0
next if LocaleNormalizer.is_same?(locale, category.locale)
next if DiscourseAi::Translation::LocaleNormalizer.is_same?(locale, category.locale)
begin
DiscourseAi::Translation::CategoryLocalizer.localize(category, locale)
-12
View File
@@ -12,7 +12,6 @@ class AiPersona < ActiveRecord::Base
validates :system_prompt, presence: true, length: { maximum: 10_000_000 }
validate :system_persona_unchangeable, on: :update, if: :system
validate :chat_preconditions
validate :allowed_seeded_model, if: :default_llm_id
validate :well_formated_examples
validates :max_context_posts, numericality: { greater_than: 0 }, allow_nil: true
# leaves some room for growth but sets a maximum to avoid memory issues
@@ -365,17 +364,6 @@ class AiPersona < ActiveRecord::Base
end
end
def allowed_seeded_model
return if default_llm_id.blank?
return if default_llm.nil?
return if !default_llm.seeded?
return if SiteSetting.ai_bot_allowed_seeded_models_map.include?(default_llm.id.to_s)
errors.add(:default_llm, I18n.t("discourse_ai.llm.configuration.invalid_seeded_model"))
end
def well_formated_examples
return if examples.blank?
+1 -1
View File
@@ -99,7 +99,7 @@ class LlmModel < ActiveRecord::Base
end
def identifier
"custom:#{id}"
"#{id}"
end
def toggle_companion_user
@@ -0,0 +1,46 @@
import Component from "@glimmer/component";
import { tracked } from "@glimmer/tracking";
import { ajax } from "discourse/lib/ajax";
import { i18n } from "discourse-i18n";
import SiteSettingComponent from "admin/components/site-setting";
import SiteSetting from "admin/models/site-setting";
export default class AiDefaultLlmSelector extends Component {
@tracked defaultLlmSetting = null;
constructor() {
super(...arguments);
this.#loadDefaultLlmSetting();
}
async #loadDefaultLlmSetting() {
const { site_settings } = await ajax("/admin/config/site_settings.json", {
data: {
plugin: "discourse-ai",
category: "discourse_ai",
},
});
const defaultLlmSetting = site_settings.find(
(setting) => setting.setting === "ai_default_llm_model"
);
this.defaultLlmSetting = SiteSetting.create(defaultLlmSetting);
}
<template>
<div class="ai-configure-default-llm">
<div class="ai-configure-default-llm__header">
<h3>{{i18n "discourse_ai.default_llm.title"}}</h3>
<p>{{i18n "discourse_ai.default_llm.description"}}</p>
</div>
{{#if this.defaultLlmSetting}}
<SiteSettingComponent
@setting={{this.defaultLlmSetting}}
class="ai-configure-default-llm__setting"
/>
{{/if}}
</div>
</template>
}
@@ -9,6 +9,7 @@ import DPageSubheader from "discourse/components/d-page-subheader";
import DSelect from "discourse/components/d-select";
import FilterInput from "discourse/components/filter-input";
import { i18n } from "discourse-i18n";
import AiDefaultLlmSelector from "./ai-default-llm-selector";
import AiFeaturesList from "./ai-features-list";
const ALL = "all";
@@ -202,6 +203,8 @@ export default class AiFeatures extends Component {
/>
</div>
<AiDefaultLlmSelector />
{{#if this.filteredFeatures.length}}
<AiFeaturesList @modules={{this.filteredFeatures}} />
{{else}}
@@ -9,6 +9,7 @@ import I18n, { i18n } from "discourse-i18n";
import AdminSectionLandingItem from "admin/components/admin-section-landing-item";
import AdminSectionLandingWrapper from "admin/components/admin-section-landing-wrapper";
import DTooltip from "float-kit/components/d-tooltip";
import AiDefaultLlmSelector from "./ai-default-llm-selector";
import AiLlmEditor from "./ai-llm-editor";
function isPreseeded(llm) {
@@ -137,6 +138,9 @@ export default class AiLlmsListEditor extends Component {
}}
@learnMoreUrl="https://meta.discourse.org/t/discourse-ai-large-language-model-llm-settings-page/319903"
/>
<AiDefaultLlmSelector />
{{#if this.hasLlmElements}}
<section class="ai-llms-list-editor__configured">
<DPageSubheader
@@ -90,7 +90,7 @@ export default class AiSpam extends Component {
this.isEnabled = model.is_enabled;
if (model.llm_id) {
this.selectedLLM = "custom:" + model.llm_id;
this.selectedLLM = model.llm_id;
} else {
if (this.availableLLMs.length) {
this.selectedLLM = this.availableLLMs[0].id;
@@ -127,7 +127,7 @@ export default class AiSpam extends Component {
}
get llmId() {
return this.selectedLLM.toString().split(":")[1];
return this.selectedLLM;
}
@action
@@ -158,3 +158,51 @@
.ai-expanded-list__toggle-button {
padding: 0;
}
.ai-configure-default-llm {
display: flex;
align-items: center;
gap: var(--space-2);
background: var(--primary-very-low);
padding: 1rem;
margin-block: 1rem;
border-radius: var(--d-border-radius);
&__header {
flex: 3;
}
&__setting {
flex: 2;
display: flex;
gap: var(--space-2);
align-items: center;
justify-content: center;
.setting-controls__undo {
display: none;
}
}
h3 {
color: var(--primary);
font-size: var(--font-0);
margin-bottom: 0;
}
p {
margin-top: 0;
font-size: var(--font-down-1);
color: var(--primary-high-or-secondary-low);
}
.select-kit,
.btn {
font-size: var(--font-down-1);
}
.setting-label,
.desc {
display: none;
}
}
-7
View File
@@ -110,9 +110,6 @@ de:
top_p:
label: "Top P"
description: "Top P für die LLM, erhöhen, um die Zufälligkeit zu erhöhen (leer lassen, um das Standardmodell zu verwenden)"
persona_id:
label: "Persona"
description: "KI Persona zur Berichtserstellung"
llm_tool_triage:
fields:
model:
@@ -182,9 +179,6 @@ de:
temperature:
label: "Temperatur"
description: "Temperatur, die für das LLM verwendet werden soll. Erhöhen, um die Zufälligkeit zu erhöhen (leer lassen, um das Standardmodell zu verwenden)"
max_output_tokens:
label: "Maximale Ausgabetoken"
description: "Wenn angegeben, wird eine Obergrenze für die maximale Anzahl von Token festgelegt, die das Modell erzeugen kann. Beachtet die Obergrenze für die Anzahl der ausgegebenen Token des LLM"
discourse_ai:
title: "KI"
features:
@@ -842,7 +836,6 @@ de:
last_7_days: "Letzte 7 Tage"
last_30_days: "Letzte 30 Tage"
upload_files: "Dateien hochladen"
uploads_in_progress: "Absenden nicht möglich, solange Uploads nicht abgeschlossen sind"
sentiments:
dashboard:
title: "Stimmung"
+5 -4
View File
@@ -180,13 +180,14 @@ en:
temperature:
label: "Temperature"
description: "Temperature to use for the LLM. Increase to increase randomness (leave empty to use model default)"
max_output_tokens:
label: "Max output tokens"
description: "When specified, sets an upper bound to the maximum number of tokens the model can generate. Respects LLM's max output tokens limit"
discourse_ai:
title: "AI"
default_llm:
title: "Default LLM model"
description: "The default LLM model to use for all AI features. This will be used if no LLM is specified in the feature configuration or persona. If no default LLM is specified, the last created LLM will be used."
features:
short_title: "Features"
description: "These are the AI features available to visitors on your site. These can be configured to use specific personas and LLMs, and can be access controlled by groups."
@@ -569,7 +570,7 @@ en:
max_usages_required: "Must be set if max tokens is not set"
usage:
ai_bot: "AI bot"
ai_helper: "Helper"
ai_helper: "Helper (%{persona})"
ai_helper_image_caption: "Image caption"
ai_persona: "Persona (%{persona})"
ai_summarization: "Summarize"
-6
View File
@@ -109,9 +109,6 @@ he:
top_p:
label: "ה־P המובילים"
description: "ה־P המוביל לשימוש למודל השפה הגדול (LLM), הגדלה תגדיל את האקראיות (להשאיר ריק כדי להשתמש בברירת המחדל של הדגם)"
persona_id:
label: "דמות"
description: "דמות בינה מלאכותית לשימוש להפקת דוחות"
llm_tool_triage:
fields:
model:
@@ -170,8 +167,6 @@ he:
temperature:
label: "טמפרטורה"
description: "טמפרטורה לשימוש למודל השפה הגדול (LLM), הגדלה תגדיל את האקראיות (להשאיר ריק כדי להשתמש בברירת המחדל של הדגם)"
max_output_tokens:
label: "כמות אסימוני פלט מרבית"
discourse_ai:
title: "בינה מלאכותית"
features:
@@ -778,7 +773,6 @@ he:
last_7_days: "7 הימים האחרונים"
last_30_days: "30 הימים האחרונים"
upload_files: "העלאת קבצים"
uploads_in_progress: "לא ניתן להגיש תוך כדי שמתבצעות העלאות"
sentiments:
dashboard:
title: "רגש"
-2
View File
@@ -110,8 +110,6 @@ lt:
top_p:
label: "Viršutinė P"
description: "Viršutinė P, naudojama LLM, padidinkite, kad padidėtų atsitiktinumas (palikite tuščią, jei norite naudoti numatytuosius modelio parametrus)"
persona_id:
label: "Persona"
llm_tool_triage:
fields:
model:
-2
View File
@@ -88,8 +88,6 @@ pl_PL:
temperature:
label: "Temperatura"
description: "Temperatura używana dla LLM. Zwiększ, aby zwiększyć losowość (pozostaw puste, aby użyć domyślnego modelu)."
persona_id:
label: "Osobowość"
llm_tool_triage:
fields:
model:
-2
View File
@@ -94,8 +94,6 @@ zh_CN:
top_p:
label: "Top P"
description: "用于 LLM 的 Top P 值,增加该值会提高生成内容的随机性(留空则使用模型默认值)"
persona_id:
label: "角色模型"
llm_tool_triage:
fields:
model:
-3
View File
@@ -384,9 +384,6 @@ de:
content_creator:
name: "Inhaltsersteller"
description: "Standard-Persona für die HyDE-Suche"
report_runner:
name: "Berichtsausführer"
description: "Standard-Persona, die im Automatisierungsskript für Berichte verwendet wird."
topic_not_found: "Zusammenfassung nicht verfügbar, Thema nicht gefunden!"
summarizing: "Thema zusammenfassen"
searching: "Suche nach: „%{query}“"
+2 -1
View File
@@ -25,6 +25,7 @@ en:
description: "Periodic report based on a large language model"
site_settings:
discourse_ai_enabled: "Enable the discourse AI plugin."
ai_default_llm_model: "The default LLM model to use for all AI features"
ai_artifact_security: "The AI artifact system generates IFRAMEs with runnable code. Strict mode forces an extra click to run code. Lax mode runs code immediately. Hybrid mode allows user to supply data-ai-artifact-autorun to show right away. Disabled mode disables the artifact system."
ai_toxicity_enabled: "Enable the toxicity module."
ai_toxicity_inference_service_api_endpoint: "URL where the API is running for the toxicity module"
@@ -582,7 +583,7 @@ en:
llm:
configuration:
create_llm: "You need to setup an LLM before enabling this feature"
disable_module_first: "You have to disable %{setting} first."
disable_modules_first: "You must disable these modules first: %{settings}"
set_llm_first: "Set %{setting} first"
model_unreachable: "We couldn't get a response from this model. Check your settings first."
invalid_seeded_model: "You can't use this model with this feature"
-3
View File
@@ -302,9 +302,6 @@ he:
name: "בקשה מותאמת אישית"
smart_dates:
name: "תאריכים חכמים"
report_runner:
name: "אצן דוחות"
description: "דמות ברירת המחדל שסקריפט אוטומציית הדוחות משתמש בה"
topic_not_found: "תקציר לא זמין, לא נמצא נושא!"
summarizing: "הנושא מסוכם"
searching: "חיפוש אחר: ‚%{query}’"
+12 -10
View File
@@ -11,6 +11,12 @@ discourse_ai:
- "lax"
- "hybrid"
- "strict"
ai_default_llm_model:
default: ""
type: enum
allow_any: false
enum: "DiscourseAi::Configuration::LlmEnumerator"
validator: "DiscourseAi::Configuration::LlmValidator"
ai_sentiment_enabled:
default: false
@@ -103,7 +109,7 @@ discourse_ai:
default: false
client: true
area: "ai-features/ai_helper"
ai_helper_model:
ai_helper_model: # Deprecated. TODO(keegan): Remove 2025-09-01
default: ""
allow_any: false
type: enum
@@ -149,7 +155,7 @@ discourse_ai:
- "context_menu"
- "image_caption"
area: "ai-features/ai_helper"
ai_helper_image_caption_model:
ai_helper_image_caption_model: # Deprecated. TODO(keegan): Remove 2025-09-01
default: ""
type: enum
enum: "DiscourseAi::Configuration::LlmVisionEnumerator"
@@ -260,12 +266,12 @@ discourse_ai:
client: true
validator: "DiscourseAi::Configuration::LlmDependencyValidator"
area: "ai-features/embeddings"
ai_embeddings_semantic_search_hyde_model:
ai_embeddings_semantic_search_hyde_model: # Deprecated. TODO(keegan): Remove 2025-09-01
hidden: true
default: ""
type: enum
allow_any: false
enum: "DiscourseAi::Configuration::LlmEnumerator"
validator: "DiscourseAi::Configuration::LlmValidator"
area: "ai-features/embeddings"
ai_embeddings_semantic_search_hyde_model_allowed_seeded_models:
default: ""
@@ -316,12 +322,11 @@ discourse_ai:
client: true
validator: "DiscourseAi::Configuration::LlmDependencyValidator"
area: "ai-features/summarization"
ai_summarization_model:
ai_summarization_model: # Deprecated. TODO(keegan): Remove 2025-09-01
default: ""
allow_any: false
type: enum
enum: "DiscourseAi::Configuration::LlmEnumerator"
validator: "DiscourseAi::Configuration::LlmValidator"
hidden: true
ai_summarization_persona:
default: "-11"
@@ -483,12 +488,11 @@ discourse_ai:
client: true
validator: "DiscourseAi::Configuration::LlmDependencyValidator"
area: "ai-features/translation"
ai_translation_model:
ai_translation_model: # Deprecated. TODO(keegan): Remove 2025-09-01
default: ""
type: enum
allow_any: false
enum: "DiscourseAi::Configuration::LlmEnumerator"
validator: "DiscourseAi::Configuration::LlmValidator"
area: "ai-features/translation"
ai_translation_locale_detector_persona:
default: "-27"
@@ -527,8 +531,6 @@ discourse_ai:
area: "ai-features/translation"
ai_translation_backfill_max_age_days:
default: 5
min: 0
max: 20000
client: false
area: "ai-features/translation"
ai_translation_verbose_logs:
@@ -0,0 +1,16 @@
# frozen_string_literal: true
class SeedAiDefaultLlmModel < ActiveRecord::Migration[7.2]
def up
return if DB.query_single("SELECT 1 FROM llm_models LIMIT 1").empty?
last_model_id = DB.query_single("SELECT id FROM llm_models ORDER BY id DESC LIMIT 1").first
if last_model_id.present?
execute "UPDATE site_settings SET value = '#{last_model_id}' WHERE name = 'ai_default_llm_model' AND (value IS NULL OR value = '');"
end
end
def down
raise ActiveRecord::IrreversibleMigration
end
end
@@ -0,0 +1,33 @@
# frozen_string_literal: true
class CopyAiSummarizationModelToPersonaDefault < ActiveRecord::Migration[7.2]
def up
ai_summarization_model =
DB.query_single("SELECT value FROM site_settings WHERE name = 'ai_summarization_model'").first
if ai_summarization_model.present? && ai_summarization_model.start_with?("custom:")
# Extract the model ID from the setting value (e.g., "custom:-5" -> "-5")
model_id = ai_summarization_model.split(":").last
persona_settings = %w[ai_summarization_persona ai_summary_gists_persona]
default_persona_ids = [-11, -12]
persona_ids_query =
persona_settings
.map { |setting| "SELECT value FROM site_settings WHERE name = '#{setting}'" }
.join(" UNION ")
persona_ids = DB.query_single(persona_ids_query).compact
all_persona_ids = (default_persona_ids + persona_ids).map(&:to_i).uniq.join(",")
# Update the summarization personas with the extracted model ID
execute(<<~SQL)
UPDATE ai_personas
SET default_llm_id = #{model_id}
WHERE id IN (#{all_persona_ids}) AND default_llm_id IS NULL
SQL
end
end
def down
raise ActiveRecord::IrreversibleMigration
end
end
@@ -0,0 +1,43 @@
# frozen_string_literal: true
class CopyAiHelperModelToPersonaDefault < ActiveRecord::Migration[7.2]
def up
ai_helper_model =
DB.query_single("SELECT value FROM site_settings WHERE name = 'ai_helper_model'").first
if ai_helper_model.present? && ai_helper_model.start_with?("custom:")
# Extract the model ID from the setting value (e.g., "custom:1" -> "1")
model_id = ai_helper_model.split(":").last
# Get persona IDs from site settings
persona_settings = %w[
ai_helper_proofreader_persona
ai_helper_title_suggestions_persona
ai_helper_explain_persona
ai_helper_smart_dates_persona
ai_helper_translator_persona
ai_helper_markdown_tables_persona
ai_helper_custom_prompt_persona
]
default_persona_ids = [-18, -19, -20, -22, -23, -24, -25]
persona_ids_query =
persona_settings
.map { |setting| "SELECT value FROM site_settings WHERE name = '#{setting}'" }
.join(" UNION ")
persona_ids = DB.query_single(persona_ids_query).compact
all_persona_ids = (default_persona_ids + persona_ids).map(&:to_i).uniq.join(",")
# Update the helper personas with the extracted model ID
execute(<<~SQL)
UPDATE ai_personas
SET default_llm_id = #{model_id}
WHERE id IN (#{all_persona_ids}) AND default_llm_id IS NULL
SQL
end
end
def down
raise ActiveRecord::IrreversibleMigration
end
end
@@ -0,0 +1,35 @@
# frozen_string_literal: true
class CopyHydeModelToPersona < ActiveRecord::Migration[7.2]
def up
hyde_model =
DB.query_single(
"SELECT value FROM site_settings WHERE name = 'ai_embeddings_semantic_search_hyde_model'",
).first
if hyde_model.present? && hyde_model.start_with?("custom:")
# Extract the model ID from the setting value (e.g., "custom:1" -> "1")
model_id = hyde_model.split(":").last
persona_settings = %w[ai_embeddings_semantic_search_hyde_persona]
default_persona_ids = [-32]
persona_ids_query =
persona_settings
.map { |setting| "SELECT value FROM site_settings WHERE name = '#{setting}'" }
.join(" UNION ")
persona_ids = DB.query_single(persona_ids_query).compact
all_persona_ids = (default_persona_ids + persona_ids).map(&:to_i).uniq.join(",")
# Update the hyde persona with the extracted model ID
execute(<<~SQL)
UPDATE ai_personas
SET default_llm_id = #{model_id}
WHERE id IN (#{all_persona_ids}) AND default_llm_id IS NULL
SQL
end
end
def down
raise ActiveRecord::IrreversibleMigration
end
end
@@ -0,0 +1,39 @@
# frozen_string_literal: true
class CopyTranslationModelToPersona < ActiveRecord::Migration[7.2]
def up
ai_translation_model =
DB.query_single("SELECT value FROM site_settings WHERE name = 'ai_translation_model'").first
if ai_translation_model.present? && ai_translation_model.start_with?("custom:")
# Extract the model ID from the setting value (e.g., "custom:-5" -> "-5")
model_id = ai_translation_model.split(":").last
persona_settings = %w[
ai_translation_locale_detector_persona
ai_translation_post_raw_translator_persona
ai_translation_topic_title_translator_persona
ai_translation_short_text_translator_persona
]
default_persona_ids = [-27, -28, -29, -30]
persona_ids_query =
persona_settings
.map { |setting| "SELECT value FROM site_settings WHERE name = '#{setting}'" }
.join(" UNION ")
persona_ids = DB.query_single(persona_ids_query).compact
all_persona_ids = (default_persona_ids + persona_ids).map(&:to_i).uniq.join(",")
# Update the translation personas (IDs -27, -28, -29, -30) with the extracted model ID
execute(<<~SQL)
UPDATE ai_personas
SET default_llm_id = #{model_id}
WHERE id IN (#{all_persona_ids}) AND default_llm_id IS NULL
SQL
end
end
def down
raise ActiveRecord::IrreversibleMigration
end
end
@@ -0,0 +1,37 @@
# frozen_string_literal: true
class CopyAiImageCaptionModelToPersonaDefault < ActiveRecord::Migration[7.2]
def up
ai_helper_image_caption_model =
DB.query_single(
"SELECT value FROM site_settings WHERE name = 'ai_helper_image_caption_model'",
).first
if ai_helper_image_caption_model.present? &&
ai_helper_image_caption_model.start_with?("custom:")
# Extract the model ID from the setting value (e.g., "custom:1" -> "1")
model_id = ai_helper_image_caption_model.split(":").last
persona_settings = %w[ai_helper_post_illustrator_persona ai_helper_image_caption_persona]
default_persona_ids = [-21, -26]
persona_ids_query =
persona_settings
.map { |setting| "SELECT value FROM site_settings WHERE name = '#{setting}'" }
.join(" UNION ")
persona_ids = DB.query_single(persona_ids_query).compact
all_persona_ids = (default_persona_ids + persona_ids).map(&:to_i).uniq.join(",")
# Update the helper personas with the extracted model ID
execute(<<~SQL)
UPDATE ai_personas
SET default_llm_id = #{model_id}
WHERE id IN (#{all_persona_ids}) AND default_llm_id IS NULL
SQL
end
end
def down
raise ActiveRecord::IrreversibleMigration
end
end
@@ -1,22 +0,0 @@
# frozen_string_literal: true
class SetTranslationBackfillMaxAge < ActiveRecord::Migration[7.2]
def up
execute <<~SQL
UPDATE site_settings
SET value = '20000'
WHERE name = 'ai_translation_backfill_max_age_days'
AND value::integer > 20000;
SQL
execute <<~SQL
UPDATE site_settings
SET value = '0'
WHERE name = 'ai_translation_backfill_max_age_days'
AND value::integer < 0;
SQL
end
def down
raise ActiveRecord::IrreversibleMigration
end
end
@@ -1,11 +0,0 @@
# frozen_string_literal: true
class AddIndexToAiTopicsEmbeddings < ActiveRecord::Migration[7.2]
def up
add_index :ai_topics_embeddings, %i[topic_id model_id]
end
def down
raise ActiveRecord::IrreversibleMigration
end
end
-5
View File
@@ -24,7 +24,6 @@ if defined?(DiscourseAutomation)
field :max_post_tokens, component: :text
field :stop_sequences, component: :text_list, required: false
field :temperature, component: :text
field :max_output_tokens, component: :text
# Actions
field :category, component: :category
@@ -86,9 +85,6 @@ if defined?(DiscourseAutomation)
temperature = temperature.to_f
end
max_output_tokens = fields.dig("max_output_tokens", "value").to_i
max_output_tokens = nil if max_output_tokens <= 0
max_post_tokens = nil if max_post_tokens <= 0
stop_sequences = fields.dig("stop_sequences", "value")
@@ -126,7 +122,6 @@ if defined?(DiscourseAutomation)
stop_sequences: stop_sequences,
automation: self.automation,
temperature: temperature,
max_output_tokens: max_output_tokens,
action: context["action"],
)
rescue => e

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