1+ class AIPromptInput extends HTMLElement {
2+ constructor ( playbackEngine , sendResponseAsEvent = false , sinceLastCommentPrompt = 'Describe how the code has changed.' , allTimePrompt = 'Describe this code.' ) {
3+ super ( ) ;
4+
5+ this . playbackEngine = playbackEngine ;
6+ this . sendResponseAsEvent = sendResponseAsEvent ;
7+ this . sinceLastCommentPrompt = sinceLastCommentPrompt ;
8+ this . allTimePrompt = allTimePrompt ;
9+
10+ this . attachShadow ( { mode : 'open' } ) ;
11+ this . shadowRoot . innerHTML = `
12+ <style>
13+ :host {
14+ }
15+
16+ hr {
17+ border: none;
18+ border-top: 1px solid darkgray;
19+ }
20+
21+ #submitChatButton {
22+ background-color: lightgrey;
23+ color: black;
24+ border: 1px solid lightgrey;
25+ border-radius: .25rem;
26+ padding: 5px;
27+ margin: 5px;
28+ width: 70%;
29+ display: block;
30+ margin-left: auto;
31+ margin-right: auto;
32+
33+ transition: color .15s ease-in-out, background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out;
34+ }
35+
36+ #inputText {
37+ min-height: 100px;
38+ padding: 5px;
39+ color: lightgrey;
40+ outline: none;
41+ border: 1px solid grey;
42+ overflow-y: scroll;
43+ word-wrap: break-word;
44+ scrollbar-width: thin;
45+ resize: vertical;
46+ }
47+
48+ .questionText {
49+ font-style: italic;
50+ }
51+
52+ .responseText {
53+ margin: 10px;
54+ }
55+ </style>
56+ <div>
57+ <input type="checkbox" id="sinceLastCommentOnly" name="sinceLastCommentOnly" checked>
58+ <label for="sinceLastCommentOnly">Since the last comment only</label>
59+ <div id="inputText" contenteditable="true">${ this . sinceLastCommentPrompt } </div>
60+ <button id="submitChatButton">Submit Your Question</button>
61+ <div class="aiResponse"></div>
62+ </div>
63+ ` ;
64+ }
65+
66+ connectedCallback ( ) {
67+ const submitChatButton = this . shadowRoot . querySelector ( '#submitChatButton' ) ;
68+ submitChatButton . addEventListener ( 'click' , this . submitText ) ;
69+
70+ const checkbox = this . shadowRoot . querySelector ( '#sinceLastCommentOnly' ) ;
71+ checkbox . addEventListener ( 'change' , this . toggleLastComment ) ;
72+
73+ const inputText = this . shadowRoot . querySelector ( '#inputText' ) ;
74+ inputText . addEventListener ( 'keydown' , this . ignoreKeyboardControls ) ;
75+ }
76+
77+ disconnectedCallback ( ) {
78+ const submitChatButton = this . shadowRoot . querySelector ( '#submitChatButton' ) ;
79+ submitChatButton . removeEventListener ( 'click' , this . submitText ) ;
80+
81+ const checkbox = this . shadowRoot . querySelector ( '#sinceLastCommentOnly' ) ;
82+ checkbox . removeEventListener ( 'change' , this . toggleLastComment ) ;
83+
84+ const inputText = this . shadowRoot . querySelector ( '#inputText' ) ;
85+ inputText . removeEventListener ( 'keydown' , this . ignoreKeyboardControls ) ;
86+ }
87+
88+ toggleLastComment = ( event ) => {
89+ const checkbox = this . shadowRoot . querySelector ( '#sinceLastCommentOnly' ) ;
90+ const inputText = this . shadowRoot . querySelector ( '#inputText' ) ;
91+ if ( checkbox . checked ) {
92+ //if other default is set or the box is empty
93+ if ( inputText . textContent . trim ( ) === this . allTimePrompt || inputText . textContent . trim ( ) === "" ) {
94+ //set the default prompt
95+ inputText . textContent = this . sinceLastCommentPrompt ;
96+ } //else- user has something typed in, keep it
97+ } else {
98+ //if other default is set or the box is empty
99+ if ( inputText . textContent . trim ( ) === this . sinceLastCommentPrompt || inputText . textContent . trim ( ) === "" ) {
100+ //set the default prompt
101+ inputText . textContent = this . allTimePrompt ;
102+ } //else- user has something typed in, keep it
103+ }
104+ }
105+
106+ ignoreKeyboardControls = ( event ) => {
107+ //consume keyboad events while typing the question
108+ event . stopImmediatePropagation ( ) ;
109+ }
110+
111+ submitText = async ( ) => {
112+ const inputText = this . shadowRoot . querySelector ( '#inputText' ) ;
113+ const sinceLastCommentCheckbox = this . shadowRoot . querySelector ( '#sinceLastCommentOnly' ) ;
114+ const submitChatButton = this . shadowRoot . querySelector ( '#submitChatButton' ) ;
115+
116+ let codeFromPlayback = this . playbackEngine . getMostRecentFileEdits ( sinceLastCommentCheckbox . checked ) ;
117+
118+ //add prompt from user
119+ const promptWithCode = `${ codeFromPlayback } \n\nBriefly respond to this prompt.\n\n${ inputText . innerText } ` ;
120+
121+ let promptObject = {
122+ requestType : "Ask" ,
123+ prompt : promptWithCode ,
124+ playbackViewId : document . body . dataset . playbackViewId ? document . body . dataset . playbackViewId : null
125+ } ;
126+
127+ submitChatButton . textContent = 'Generating response...' ;
128+ //make the submitChatButton disabled
129+ submitChatButton . setAttribute ( 'disabled' , 'true' ) ;
130+ inputText . setAttribute ( 'contenteditable' , 'false' ) ;
131+ sinceLastCommentCheckbox . setAttribute ( 'disabled' , 'true' ) ;
132+
133+ //send the formatted one to the server
134+ const serverProxy = new ServerProxy ( ) ;
135+ const responseObject = await serverProxy . sendAIPromptToServer ( promptObject ) ;
136+
137+ submitChatButton . textContent = 'Submit Another Question' ;
138+ submitChatButton . removeAttribute ( 'disabled' ) ;
139+ inputText . setAttribute ( 'contenteditable' , 'true' ) ;
140+ inputText . focus ( ) ;
141+ sinceLastCommentCheckbox . removeAttribute ( 'disabled' ) ;
142+
143+ if ( responseObject . error ) {
144+ const aiResponse = this . shadowRoot . querySelector ( '.aiResponse' ) ;
145+ aiResponse . textContent = responseObject . response ;
146+ } else {
147+ const md = markdownit ( ) ;
148+
149+ if ( this . sendResponseAsEvent ) {
150+ const event = new CustomEvent ( 'ai-prompt-response' , {
151+ detail : {
152+ prompt : inputText . innerText ,
153+ response : md . render ( responseObject . response )
154+ } ,
155+ bubbles : true ,
156+ composed : true
157+ } ) ;
158+ this . dispatchEvent ( event ) ;
159+ } else {
160+ const answeredQuestion = document . createElement ( 'div' ) ;
161+ answeredQuestion . appendChild ( document . createElement ( 'hr' ) ) ;
162+
163+ const questionElement = document . createElement ( 'div' ) ;
164+ questionElement . classList . add ( 'questionText' ) ;
165+ questionElement . textContent = inputText . innerText ;
166+ answeredQuestion . appendChild ( questionElement ) ;
167+
168+ const responseElement = document . createElement ( 'div' ) ;
169+ responseElement . classList . add ( 'responseText' ) ;
170+ responseElement . innerHTML = md . render ( responseObject . response ) ;
171+ answeredQuestion . appendChild ( responseElement ) ;
172+
173+ const aiResponse = this . shadowRoot . querySelector ( '.aiResponse' ) ;
174+ aiResponse . prepend ( answeredQuestion ) ;
175+ }
176+ }
177+ }
178+ }
179+
180+ window . customElements . define ( 'st-ai-prompt-input' , AIPromptInput ) ;
0 commit comments