Compare commits

..
Author SHA1 Message Date
Keegan George 3ce8d943a7 DEV: First version
showing message bus error, but it kinda works? wip on a fix.
2024-11-12 20:42:19 -08:00
673 changed files with 10697 additions and 880064 deletions
-3
View File
@@ -1,6 +1,3 @@
< 3.5.0.beta1-dev: bdef136080074a993e7c4f5ca562edc31a8ba756
< 3.4.0.beta4-dev: a53719ab8eb071459f215227421b3ea4987e5f87
< 3.4.0.beta4-dev: 20612fde52d3f740cad64823ef8aadb0748b567f
< 3.4.0.beta3-dev: decf1bb49d737ea15308400f22f89d1d1e71d13d < 3.4.0.beta3-dev: decf1bb49d737ea15308400f22f89d1d1e71d13d
< 3.4.0.beta1-dev: 9d887ad4ace8e33c3fe7dbb39237e882c08b4f0b < 3.4.0.beta1-dev: 9d887ad4ace8e33c3fe7dbb39237e882c08b4f0b
< 3.3.0.beta5-dev: 4d8090002f6dcd8e34d41033606bf131fa221475 < 3.3.0.beta5-dev: 4d8090002f6dcd8e34d41033606bf131fa221475
+1
View File
@@ -0,0 +1 @@
module.exports = require("@discourse/lint-configs/eslint");
-3
View File
@@ -2,6 +2,3 @@ node_modules
/gems /gems
/auto_generated /auto_generated
.env .env
evals/log
evals/cases
config/eval-llms.local.yml
-3
View File
@@ -2,6 +2,3 @@ inherit_gem:
rubocop-discourse: stree-compat.yml rubocop-discourse: stree-compat.yml
RSpec/NamedSubject: RSpec/NamedSubject:
Enabled: false Enabled: false
Style/GlobalVars:
AllowedVariables: [$prometheus_client]
+45 -59
View File
@@ -1,93 +1,79 @@
GEM GEM
remote: https://rubygems.org/ remote: https://rubygems.org/
specs: specs:
activesupport (8.0.2) activesupport (7.1.3.4)
base64 base64
benchmark (>= 0.3)
bigdecimal bigdecimal
concurrent-ruby (~> 1.0, >= 1.3.1) concurrent-ruby (~> 1.0, >= 1.0.2)
connection_pool (>= 2.2.5) connection_pool (>= 2.2.5)
drb drb
i18n (>= 1.6, < 2) i18n (>= 1.6, < 2)
logger (>= 1.4.2)
minitest (>= 5.1) minitest (>= 5.1)
securerandom (>= 0.3) mutex_m
tzinfo (~> 2.0, >= 2.0.5) tzinfo (~> 2.0)
uri (>= 0.13.1)
ast (2.4.2) ast (2.4.2)
base64 (0.2.0) base64 (0.2.0)
benchmark (0.4.0) bigdecimal (3.1.8)
bigdecimal (3.1.9) concurrent-ruby (1.3.3)
concurrent-ruby (1.3.5) connection_pool (2.4.1)
connection_pool (2.5.0)
drb (2.2.1) drb (2.2.1)
i18n (1.14.7) i18n (1.14.5)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
json (2.10.2) json (2.7.2)
language_server-protocol (3.17.0.4) language_server-protocol (3.17.0.3)
lint_roller (1.1.0) minitest (5.24.1)
logger (1.6.6) mutex_m (0.2.0)
minitest (5.25.5) parallel (1.25.1)
parallel (1.26.3) parser (3.3.3.0)
parser (3.3.7.1)
ast (~> 2.4.1) ast (~> 2.4.1)
racc racc
prettier_print (1.2.1) prettier_print (1.2.1)
racc (1.8.1) racc (1.8.0)
rack (3.1.12) rack (3.1.6)
rainbow (3.1.1) rainbow (3.1.1)
regexp_parser (2.10.0) regexp_parser (2.9.2)
rubocop (1.74.0) rexml (3.3.9)
rubocop (1.64.1)
json (~> 2.3) json (~> 2.3)
language_server-protocol (~> 3.17.0.2) language_server-protocol (>= 3.17.0)
lint_roller (~> 1.1.0)
parallel (~> 1.10) parallel (~> 1.10)
parser (>= 3.3.0.2) parser (>= 3.3.0.2)
rainbow (>= 2.2.2, < 4.0) rainbow (>= 2.2.2, < 4.0)
regexp_parser (>= 2.9.3, < 3.0) regexp_parser (>= 1.8, < 3.0)
rubocop-ast (>= 1.38.0, < 2.0) rexml (>= 3.2.5, < 4.0)
rubocop-ast (>= 1.31.1, < 2.0)
ruby-progressbar (~> 1.7) ruby-progressbar (~> 1.7)
unicode-display_width (>= 2.4.0, < 4.0) unicode-display_width (>= 2.4.0, < 3.0)
rubocop-ast (1.38.1) rubocop-ast (1.31.3)
parser (>= 3.3.1.0) parser (>= 3.3.1.0)
rubocop-capybara (2.22.1) rubocop-capybara (2.21.0)
lint_roller (~> 1.1) rubocop (~> 1.41)
rubocop (~> 1.72, >= 1.72.1) rubocop-discourse (3.8.1)
rubocop-discourse (3.12.1)
activesupport (>= 6.1) activesupport (>= 6.1)
lint_roller (>= 1.1.0) rubocop (>= 1.59.0)
rubocop (>= 1.73.2) rubocop-capybara (>= 2.0.0)
rubocop-capybara (>= 2.22.0) rubocop-factory_bot (>= 2.0.0)
rubocop-factory_bot (>= 2.27.0) rubocop-rails (>= 2.25.0)
rubocop-rails (>= 2.30.3)
rubocop-rspec (>= 3.0.1) rubocop-rspec (>= 3.0.1)
rubocop-rspec_rails (>= 2.31.0) rubocop-rspec_rails (>= 2.30.0)
rubocop-factory_bot (2.27.1) rubocop-factory_bot (2.26.1)
lint_roller (~> 1.1) rubocop (~> 1.61)
rubocop (~> 1.72, >= 1.72.1) rubocop-rails (2.25.1)
rubocop-rails (2.30.3)
activesupport (>= 4.2.0) activesupport (>= 4.2.0)
lint_roller (~> 1.1)
rack (>= 1.1) rack (>= 1.1)
rubocop (>= 1.72.1, < 2.0) rubocop (>= 1.33.0, < 2.0)
rubocop-ast (>= 1.38.0, < 2.0) rubocop-ast (>= 1.31.1, < 2.0)
rubocop-rspec (3.5.0) rubocop-rspec (3.0.2)
lint_roller (~> 1.1) rubocop (~> 1.61)
rubocop (~> 1.72, >= 1.72.1) rubocop-rspec_rails (2.30.0)
rubocop-rspec_rails (2.31.0) rubocop (~> 1.61)
lint_roller (~> 1.1) rubocop-rspec (~> 3, >= 3.0.1)
rubocop (~> 1.72, >= 1.72.1)
rubocop-rspec (~> 3.5)
ruby-progressbar (1.13.0) ruby-progressbar (1.13.0)
securerandom (0.4.1)
syntax_tree (6.2.0) syntax_tree (6.2.0)
prettier_print (>= 1.2.0) prettier_print (>= 1.2.0)
tzinfo (2.0.6) tzinfo (2.0.6)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
unicode-display_width (3.1.4) unicode-display_width (2.5.0)
unicode-emoji (~> 4.0, >= 4.0.4)
unicode-emoji (4.0.4)
uri (1.0.3)
PLATFORMS PLATFORMS
ruby ruby
@@ -97,4 +83,4 @@ DEPENDENCIES
syntax_tree syntax_tree
BUNDLED WITH BUNDLED WITH
2.6.6 2.5.10
+1 -1
View File
@@ -1,6 +1,6 @@
The MIT License (MIT) The MIT License (MIT)
Copyright (c) Civilized Discourse Construction Kit, Inc. Copyright (c) 2021 Civilized Discourse Construction Kit
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
-24
View File
@@ -3,27 +3,3 @@
**Plugin Summary** **Plugin Summary**
For more information, please see: https://meta.discourse.org/t/discourse-ai/259214?u=falco For more information, please see: https://meta.discourse.org/t/discourse-ai/259214?u=falco
### Evals
The directory `evals` contains AI evals for the Discourse AI plugin.
You may create a local config by copying `config/eval-llms.yml` to `config/eval-llms.local.yml` and modifying the values.
To run them use:
cd evals
./run --help
```
Usage: evals/run [options]
-e, --eval NAME Name of the evaluation to run
--list-models List models
-m, --model NAME Model to evaluate (will eval all models if not specified)
-l, --list List evals
```
To run evals you will need to configure API keys in your environment:
OPENAI_API_KEY=your_openai_api_key
ANTHROPIC_API_KEY=your_anthropic_api_key
GEMINI_API_KEY=your_gemini_api_key
-7
View File
@@ -1,7 +0,0 @@
{
"tests": {
"requiredPlugins": [
"https://github.com/discourse/discourse-prometheus"
]
}
}
@@ -1,21 +0,0 @@
import DiscourseRoute from "discourse/routes/discourse";
export default class AdminPluginsShowDiscourseAiEmbeddingsEdit extends DiscourseRoute {
async model(params) {
const allEmbeddings = this.modelFor(
"adminPlugins.show.discourse-ai-embeddings"
);
const id = parseInt(params.id, 10);
const record = allEmbeddings.findBy("id", id);
record.provider_params = record.provider_params || {};
return record;
}
setupController(controller, model) {
super.setupController(controller, model);
controller.set(
"allEmbeddings",
this.modelFor("adminPlugins.show.discourse-ai-embeddings")
);
}
}
@@ -1,17 +0,0 @@
import DiscourseRoute from "discourse/routes/discourse";
export default class AdminPluginsShowDiscourseAiEmbeddingsNew extends DiscourseRoute {
async model() {
const record = this.store.createRecord("ai-embedding");
record.provider_params = {};
return record;
}
setupController(controller, model) {
super.setupController(controller, model);
controller.set(
"allEmbeddings",
this.modelFor("adminPlugins.show.discourse-ai-embeddings")
);
}
}
@@ -1,7 +0,0 @@
import DiscourseRoute from "discourse/routes/discourse";
export default class DiscourseAiAiEmbeddingsRoute extends DiscourseRoute {
model() {
return this.store.findAll("ai-embedding");
}
}
@@ -1,18 +1,18 @@
import DiscourseRoute from "discourse/routes/discourse"; import DiscourseRoute from "discourse/routes/discourse";
export default class AdminPluginsShowDiscourseAiLlmsNew extends DiscourseRoute { export default DiscourseRoute.extend({
queryParams = { queryParams: {
llmTemplate: { refreshModel: true }, llmTemplate: { refreshModel: true },
}; },
async model() { async model() {
const record = this.store.createRecord("ai-llm"); const record = this.store.createRecord("ai-llm");
record.provider_params = {}; record.provider_params = {};
return record; return record;
} },
setupController(controller, model) { setupController(controller, model) {
super.setupController(controller, model); this._super(controller, model);
controller.set( controller.set(
"allLlms", "allLlms",
this.modelFor("adminPlugins.show.discourse-ai-llms") this.modelFor("adminPlugins.show.discourse-ai-llms")
@@ -21,5 +21,5 @@ export default class AdminPluginsShowDiscourseAiLlmsNew extends DiscourseRoute {
"llmTemplate", "llmTemplate",
this.paramsFor(this.routeName).llmTemplate || null this.paramsFor(this.routeName).llmTemplate || null
); );
} },
} });
@@ -1,19 +1,19 @@
import DiscourseRoute from "discourse/routes/discourse"; import DiscourseRoute from "discourse/routes/discourse";
export default class AdminPluginsShowDiscourseAiLlmsEdit extends DiscourseRoute { export default DiscourseRoute.extend({
async model(params) { async model(params) {
const allLlms = this.modelFor("adminPlugins.show.discourse-ai-llms"); const allLlms = this.modelFor("adminPlugins.show.discourse-ai-llms");
const id = parseInt(params.id, 10); const id = parseInt(params.id, 10);
const record = allLlms.findBy("id", id); const record = allLlms.findBy("id", id);
record.provider_params = record.provider_params || {}; record.provider_params = record.provider_params || {};
return record; return record;
} },
setupController(controller, model) { setupController(controller, model) {
super.setupController(controller, model); this._super(controller, model);
controller.set( controller.set(
"allLlms", "allLlms",
this.modelFor("adminPlugins.show.discourse-ai-llms") this.modelFor("adminPlugins.show.discourse-ai-llms")
); );
} },
} });
@@ -1,7 +1,7 @@
import { AUTO_GROUPS } from "discourse/lib/constants"; import { AUTO_GROUPS } from "discourse/lib/constants";
import DiscourseRoute from "discourse/routes/discourse"; import DiscourseRoute from "discourse/routes/discourse";
export default class AdminPluginsShowDiscourseAiPersonasNew extends DiscourseRoute { export default DiscourseRoute.extend({
async model() { async model() {
const record = this.store.createRecord("ai-persona"); const record = this.store.createRecord("ai-persona");
record.set("allowed_group_ids", [AUTO_GROUPS.trust_level_0.id]); record.set("allowed_group_ids", [AUTO_GROUPS.trust_level_0.id]);
@@ -13,13 +13,13 @@ export default class AdminPluginsShowDiscourseAiPersonasNew extends DiscourseRou
record.set("allow_personal_messages", true); record.set("allow_personal_messages", true);
record.set("tool_details", false); record.set("tool_details", false);
return record; return record;
} },
setupController(controller, model) { setupController(controller, model) {
super.setupController(controller, model); this._super(controller, model);
controller.set( controller.set(
"allPersonas", "allPersonas",
this.modelFor("adminPlugins.show.discourse-ai-personas") this.modelFor("adminPlugins.show.discourse-ai-personas")
); );
} },
} });
@@ -1,19 +1,19 @@
import DiscourseRoute from "discourse/routes/discourse"; import DiscourseRoute from "discourse/routes/discourse";
export default class AdminPluginsShowDiscourseAiPersonasEdit extends DiscourseRoute { export default DiscourseRoute.extend({
async model(params) { async model(params) {
const allPersonas = this.modelFor( const allPersonas = this.modelFor(
"adminPlugins.show.discourse-ai-personas" "adminPlugins.show.discourse-ai-personas"
); );
const id = parseInt(params.id, 10); const id = parseInt(params.id, 10);
return allPersonas.findBy("id", id); return allPersonas.findBy("id", id);
} },
setupController(controller, model) { setupController(controller, model) {
super.setupController(controller, model); this._super(controller, model);
controller.set( controller.set(
"allPersonas", "allPersonas",
this.modelFor("adminPlugins.show.discourse-ai-personas") this.modelFor("adminPlugins.show.discourse-ai-personas")
); );
} },
} });
@@ -1,11 +0,0 @@
import { service } from "@ember/service";
import { ajax } from "discourse/lib/ajax";
import DiscourseRoute from "discourse/routes/discourse";
export default class DiscourseAiSpamRoute extends DiscourseRoute {
@service store;
model() {
return ajax("/admin/plugins/discourse-ai/ai-spam.json");
}
}
@@ -1,10 +1,6 @@
import DiscourseRoute from "discourse/routes/discourse"; import DiscourseRoute from "discourse/routes/discourse";
export default class DiscourseAiToolsNewRoute extends DiscourseRoute { export default class DiscourseAiToolsNewRoute extends DiscourseRoute {
beforeModel(transition) {
this.preset = transition.to.queryParams.presetId || "empty_tool";
}
async model() { async model() {
return this.store.createRecord("ai-tool"); return this.store.createRecord("ai-tool");
} }
@@ -12,10 +8,8 @@ export default class DiscourseAiToolsNewRoute extends DiscourseRoute {
setupController(controller) { setupController(controller) {
super.setupController(...arguments); super.setupController(...arguments);
const toolsModel = this.modelFor("adminPlugins.show.discourse-ai-tools"); const toolsModel = this.modelFor("adminPlugins.show.discourse-ai-tools");
controller.set("allTools", toolsModel); controller.set("allTools", toolsModel);
controller.set("presets", toolsModel.resultSetMeta.presets); controller.set("presets", toolsModel.resultSetMeta.presets);
controller.set("llms", toolsModel.resultSetMeta.llms);
controller.set("settings", toolsModel.resultSetMeta.settings);
controller.set("selectedPreset", this.preset);
} }
} }
@@ -1,6 +1,6 @@
import DiscourseRoute from "discourse/routes/discourse"; import DiscourseRoute from "discourse/routes/discourse";
export default class DiscourseAiToolsEditRoute extends DiscourseRoute { export default class DiscourseAiToolsShowRoute extends DiscourseRoute {
async model(params) { async model(params) {
const allTools = this.modelFor("adminPlugins.show.discourse-ai-tools"); const allTools = this.modelFor("adminPlugins.show.discourse-ai-tools");
const id = parseInt(params.id, 10); const id = parseInt(params.id, 10);
@@ -14,7 +14,5 @@ export default class DiscourseAiToolsEditRoute extends DiscourseRoute {
controller.set("allTools", toolsModel); controller.set("allTools", toolsModel);
controller.set("presets", toolsModel.resultSetMeta.presets); controller.set("presets", toolsModel.resultSetMeta.presets);
controller.set("llms", toolsModel.resultSetMeta.llms);
controller.set("settings", toolsModel.resultSetMeta.settings);
} }
} }
@@ -1,11 +0,0 @@
import { service } from "@ember/service";
import { ajax } from "discourse/lib/ajax";
import DiscourseRoute from "discourse/routes/discourse";
export default class DiscourseAiUsageRoute extends DiscourseRoute {
@service store;
model() {
return ajax("/admin/plugins/discourse-ai/ai-usage.json");
}
}
@@ -1,4 +0,0 @@
<AiEmbeddingsListEditor
@embeddings={{this.allEmbeddings}}
@currentEmbedding={{this.model}}
/>
@@ -1 +0,0 @@
<AiEmbeddingsListEditor @embeddings={{this.model}} />
@@ -1,4 +0,0 @@
<AiEmbeddingsListEditor
@embeddings={{this.allEmbeddings}}
@currentEmbedding={{this.model}}
/>
@@ -1 +0,0 @@
<AiSpam @model={{this.model}} />
@@ -1,9 +0,0 @@
<section class="ai-persona-tool-editor__current admin-detail pull-left">
<AiToolEditor
@tools={{this.allTools}}
@model={{this.model}}
@presets={{this.presets}}
@llms={{this.llms}}
@settings={{this.settings}}
/>
</section>
@@ -1,10 +1,5 @@
<section class="ai-persona-tool-editor__current admin-detail pull-left"> <AiToolEditor
<AiToolEditor @tools={{this.allTools}}
@tools={{this.allTools}} @model={{this.model}}
@model={{this.model}} @presets={{this.presets}}
@presets={{this.presets}} />
@llms={{this.llms}}
@settings={{this.settings}}
@selectedPreset={{this.selectedPreset}}
/>
</section>
@@ -0,0 +1,5 @@
<AiToolEditor
@tools={{this.allTools}}
@model={{this.model}}
@presets={{this.presets}}
/>
@@ -1 +0,0 @@
<AiUsage @model={{this.model}} />
@@ -1,133 +0,0 @@
# frozen_string_literal: true
module DiscourseAi
module Admin
class AiEmbeddingsController < ::Admin::AdminController
requires_plugin ::DiscourseAi::PLUGIN_NAME
def index
embedding_defs = EmbeddingDefinition.all.order(:display_name)
render json: {
ai_embeddings:
ActiveModel::ArraySerializer.new(
embedding_defs,
each_serializer: AiEmbeddingDefinitionSerializer,
root: false,
).as_json,
meta: {
provider_params: EmbeddingDefinition.provider_params,
providers: EmbeddingDefinition.provider_names,
distance_functions: EmbeddingDefinition.distance_functions,
tokenizers:
EmbeddingDefinition.tokenizer_names.map { |tn|
{ id: tn, name: tn.split("::").last }
},
presets: EmbeddingDefinition.presets,
},
}
end
def new
end
def edit
embedding_def = EmbeddingDefinition.find(params[:id])
render json: AiEmbeddingDefinitionSerializer.new(embedding_def)
end
def create
embedding_def = EmbeddingDefinition.new(ai_embeddings_params)
if embedding_def.save
render json: AiEmbeddingDefinitionSerializer.new(embedding_def), status: :created
else
render_json_error embedding_def
end
end
def update
embedding_def = EmbeddingDefinition.find(params[:id])
if embedding_def.seeded?
return(
render_json_error(I18n.t("discourse_ai.embeddings.cannot_edit_builtin"), status: 403)
)
end
if embedding_def.update(ai_embeddings_params.except(:dimensions))
render json: AiEmbeddingDefinitionSerializer.new(embedding_def)
else
render_json_error embedding_def
end
end
def destroy
embedding_def = EmbeddingDefinition.find(params[:id])
if embedding_def.seeded?
return(
render_json_error(I18n.t("discourse_ai.embeddings.cannot_edit_builtin"), status: 403)
)
end
if embedding_def.id == SiteSetting.ai_embeddings_selected_model.to_i
return render_json_error(I18n.t("discourse_ai.embeddings.delete_failed"), status: 409)
end
if embedding_def.destroy
head :no_content
else
render_json_error embedding_def
end
end
def test
RateLimiter.new(
current_user,
"ai_embeddings_test_#{current_user.id}",
3,
1.minute,
).performed!
embedding_def = EmbeddingDefinition.new(ai_embeddings_params)
DiscourseAi::Embeddings::Vector.new(embedding_def).vector_from("this is a test")
render json: { success: true }
rescue Net::HTTPBadResponse => e
render json: { success: false, error: e.message }
end
private
def ai_embeddings_params
permitted =
params.require(:ai_embedding).permit(
:display_name,
:dimensions,
:max_sequence_length,
:pg_function,
:provider,
:url,
:api_key,
:tokenizer_class,
:embed_prompt,
:search_prompt,
:matryoshka_dimensions,
)
extra_field_names = EmbeddingDefinition.provider_params.dig(permitted[:provider]&.to_sym)
if extra_field_names.present?
received_prov_params =
params.dig(:ai_embedding, :provider_params)&.slice(*extra_field_names.keys)
if received_prov_params.present?
permitted[:provider_params] = received_prov_params.permit!
end
end
permitted
end
end
end
end

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