This repository was archived by the owner on Jul 22, 2025. It is now read-only.
File tree Expand file tree Collapse file tree 11 files changed +367
-0
lines changed
controllers/discourse_ai/ai_bot
stylesheets/modules/ai-bot/common Expand file tree Collapse file tree 11 files changed +367
-0
lines changed Original file line number Diff line number Diff line change 1+ # frozen_string_literal: true
2+
3+ module DiscourseAi
4+ module AiBot
5+ class ArtifactsController < ApplicationController
6+
7+ requires_plugin DiscourseAi ::PLUGIN_NAME
8+
9+ skip_before_action :preload_json , :check_xhr , only : %i[ show ]
10+
11+ def show
12+ artifact = AiArtifact . find ( params [ :id ] )
13+
14+ post = Post . find_by ( id : artifact . post_id )
15+ raise Discourse ::NotFound unless post && guardian . can_see? ( post )
16+
17+ # Prepare the HTML document
18+ html = <<~HTML
19+ <!DOCTYPE html>
20+ < html >
21+ < head >
22+ < meta charset ="UTF-8 ">
23+ < title > #{ ERB ::Util . html_escape ( artifact . name ) } </ title>
24+ < style >
25+ #{ artifact . css }
26+ </ style>
27+ </ head>
28+ < body >
29+ #{ artifact . html }
30+ < script >
31+ #{ artifact . js }
32+ </ script>
33+ </ body>
34+ </ html>
35+ HTML
36+
37+ response . headers . delete ( "X-Frame-Options" )
38+ response . headers . delete ( "Content-Security-Policy" )
39+
40+ # Render the content
41+ render html : html . html_safe , layout : false , content_type : "text/html"
42+ end
43+ end
44+ end
45+ end
Original file line number Diff line number Diff line change 1+ # frozen_string_literal: true
2+
3+ class AiArtifact < ActiveRecord ::Base
4+ belongs_to :user
5+ belongs_to :post
6+ end
7+
8+ # == Schema Information
9+ #
10+ # Table name: ai_artifacts
11+ #
12+ # id :bigint not null, primary key
13+ # user_id :integer not null
14+ # post_id :integer not null
15+ # name :string(255) not null
16+ # html :string(65535)
17+ # css :string(65535)
18+ # js :string(65535)
19+ # metadata :jsonb
20+ # created_at :datetime not null
21+ # updated_at :datetime not null
22+ #
Original file line number Diff line number Diff line change 1+ import { withPluginApi } from "discourse/lib/plugin-api" ;
2+
3+ function initializeAiArtifactTabs ( api ) {
4+ api . decorateCooked (
5+ ( $element ) => {
6+ const element = $element [ 0 ] ;
7+ const artifacts = element . querySelectorAll ( ".ai-artifact" ) ;
8+ if ( ! artifacts . length ) {
9+ return ;
10+ }
11+
12+ artifacts . forEach ( ( artifact ) => {
13+ const tabs = artifact . querySelectorAll ( ".ai-artifact-tab" ) ;
14+ const panels = artifact . querySelectorAll ( ".ai-artifact-panel" ) ;
15+
16+ tabs . forEach ( ( tab ) => {
17+ tab . addEventListener ( "click" , ( e ) => {
18+ e . preventDefault ( ) ;
19+
20+ if ( tab . hasAttribute ( "data-selected" ) ) {
21+ return ;
22+ }
23+
24+ const tabType = Object . keys ( tab . dataset ) . find (
25+ ( key ) => key !== "selected"
26+ ) ;
27+
28+ tabs . forEach ( ( t ) => t . removeAttribute ( "data-selected" ) ) ;
29+ panels . forEach ( ( p ) => p . removeAttribute ( "data-selected" ) ) ;
30+
31+ tab . setAttribute ( "data-selected" , "" ) ;
32+ const targetPanel = artifact . querySelector (
33+ `.ai-artifact-panel[data-${ tabType } ]`
34+ ) ;
35+ if ( targetPanel ) {
36+ targetPanel . setAttribute ( "data-selected" , "" ) ;
37+ }
38+ } ) ;
39+ } ) ;
40+ } ) ;
41+ } ,
42+ {
43+ id : "ai-artifact-tabs" ,
44+ onlyStream : false ,
45+ }
46+ ) ;
47+ }
48+
49+ export default {
50+ name : "ai-artifact-tabs" ,
51+ initialize ( ) {
52+ withPluginApi ( "0.8.7" , initializeAiArtifactTabs ) ;
53+ } ,
54+ } ;
Original file line number Diff line number Diff line change 11export function setup ( helper ) {
22 helper . allowList ( [ "details[class=ai-quote]" ] ) ;
3+ helper . allowList ( [ "div[class=ai-artifact]" ] ) ;
4+ helper . allowList ( [ "div[class=ai-artifact-tab]" ] ) ;
5+ helper . allowList ( [ "div[class=ai-artifact-tabs]" ] ) ;
6+ helper . allowList ( [ "div[class=ai-artifact-panels]" ] ) ;
7+ helper . allowList ( [ "div[class=ai-artifact-panel]" ] ) ;
38}
Original file line number Diff line number Diff line change 1+ .ai-artifact {
2+ margin : 1em 0 ;
3+
4+ .ai-artifact-tabs {
5+ display : flex ;
6+ gap : 0.20em ;
7+ border-bottom : 2px solid var (--primary-low );
8+ padding : 0 0.2em ;
9+
10+ .ai-artifact-tab {
11+ margin-bottom : -2px ;
12+
13+ & [data-selected ] {
14+ a {
15+ color : var (--tertiary );
16+ font-weight : 500 ;
17+ border-bottom : 2px solid var (--tertiary );
18+ }
19+ }
20+
21+ & :hover:not ([data-selected ]) {
22+ a {
23+ color : var (--primary );
24+ background : var (--primary-very-low );
25+ }
26+ }
27+
28+ a {
29+ display : block ;
30+ padding : 0.5em 1em ;
31+ color : var (--primary-medium );
32+ text-decoration : none ;
33+ cursor : pointer ;
34+ border-bottom : 2px solid transparent ;
35+ }
36+ }
37+ }
38+
39+ .ai-artifact-panels {
40+ padding : 1em 0 0 0 ;
41+ background : var (--blend-primary-secondary-5 );
42+
43+ .ai-artifact-panel {
44+ display : none ;
45+ min-height : 400px ;
46+
47+ & [data-selected ] {
48+ display : block ;
49+ }
50+
51+ pre {
52+ margin : 0 ;
53+ }
54+ }
55+ }
56+ }
Original file line number Diff line number Diff line change 220220 name : " Base Search Query"
221221 description : " Base query to use when searching. Example: '#urgent' will prepend '#urgent' to the search query and only include topics with the urgent category or tag."
222222 tool_summary :
223+ create_artifact : " Create web artifact"
223224 web_browser : " Browse Web"
224225 github_search_files : " GitHub search files"
225226 github_search_code : " GitHub code search"
241242 search_meta_discourse : " Search Meta Discourse"
242243 javascript_evaluator : " Evaluate JavaScript"
243244 tool_help :
245+ create_artifact : " Create a web artifact using the AI Bot"
244246 web_browser : " Browse web page using the AI Bot"
245247 github_search_code : " Search for code in a GitHub repository"
246248 github_search_files : " Search for files in a GitHub repository"
262264 search_meta_discourse : " Search Meta Discourse"
263265 javascript_evaluator : " Evaluate JavaScript"
264266 tool_description :
267+ create_artifact : " Created a web artifact using the AI Bot"
265268 web_browser : " Reading <a href='%{url}'>%{url}</a>"
266269 github_search_files : " Searched for '%{keywords}' in %{repo}/%{branch}"
267270 github_search_code : " Searched for '%{query}' in %{repo}"
Original file line number Diff line number Diff line change 3232 get "/preview/:topic_id" => "shared_ai_conversations#preview"
3333 end
3434
35+ scope module : :ai_bot , path : "/ai-bot/artifacts" do
36+ get "/:id" => "artifacts#show"
37+ end
38+
3539 scope module : :summarization , path : "/summarization" , defaults : { format : :json } do
3640 get "/t/:topic_id" => "summary#show" , :constraints => { topic_id : /\d +/ }
3741 get "/channels/:channel_id" => "chat_summary#show"
Original file line number Diff line number Diff line change 1+ # frozen_string_literal: true
2+ class AddAiArtifacts < ActiveRecord ::Migration [ 7.1 ]
3+ def change
4+ create_table :ai_artifacts do |t |
5+ t . integer :user_id , null : false
6+ t . integer :post_id , null : false
7+ t . string :name , null : false , limit : 255
8+ t . string :html , limit : 65535 # ~64KB limit
9+ t . string :css , limit : 65535 # ~64KB limit
10+ t . string :js , limit : 65535 # ~64KB limit
11+ t . jsonb :metadata # For any additional properties
12+
13+ t . timestamps
14+ end
15+ end
16+ end
Original file line number Diff line number Diff line change @@ -96,6 +96,7 @@ def all_available_tools
9696 Tools ::GithubSearchFiles ,
9797 Tools ::WebBrowser ,
9898 Tools ::JavascriptEvaluator ,
99+ Tools ::CreateArtifact ,
99100 ]
100101
101102 tools << Tools ::GithubSearchCode if SiteSetting . ai_bot_github_access_token . present?
You can’t perform that action at this time.
0 commit comments