Skip to content

Commit

Permalink
feat: update follow up questions for DI
Browse files Browse the repository at this point in the history
  • Loading branch information
Shibani Basava authored and Shibani Basava committed Feb 13, 2024
1 parent a7840b3 commit 628065d
Show file tree
Hide file tree
Showing 7 changed files with 93 additions and 48 deletions.
9 changes: 7 additions & 2 deletions packages/chat-component/src/components/chat-component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,11 @@ export class ChatComponent extends LitElement {
@lazyMultiInject(ControllerType.ChatSection)
chatSectionControllers: ChatSectionController[] | undefined;

public constructor() {
super();
this.setQuestionInputValue = this.setQuestionInputValue.bind(this);
}

// Lifecycle method that runs when the component is first connected to the DOM
override connectedCallback(): void {
super.connectedCallback();
Expand Down Expand Up @@ -328,7 +333,7 @@ export class ChatComponent extends LitElement {
.svgIcon="${iconLogo}"
.context="${this.chatContext}"
@on-citation-click="${this.handleCitationClick}"
@on-followup-click="${this.handleInput}"
@on-input="${this.handleInput}"
>
</chat-thread-component>`;
}
Expand All @@ -338,7 +343,7 @@ export class ChatComponent extends LitElement {
? ''
: this.chatInputComponents
.filter((component) => component.position === position)
.map((component) => component.render(this.handleInput));
.map((component) => component.render(this.setQuestionInputValue));
}

// Render the chat component as a web component
Expand Down
65 changes: 25 additions & 40 deletions packages/chat-component/src/components/chat-thread-component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ import { customElement, property, query, state } from 'lit/decorators.js';
import { styles } from '../styles/chat-thread-component.js';

import { globalConfig } from '../config/global-config.js';
import { unsafeSVG } from 'lit/directives/unsafe-svg.js';
import { unsafeHTML } from 'lit/directives/unsafe-html.js';

import iconQuestion from '../../public/svg/bubblequestion-icon.svg?raw';

import { type ChatActionButton } from './chat-action-button.js';
import { type ChatEntryActionController, ControllerType, lazyMultiInject } from './composable.js';
import {
type ChatEntryActionController,
type ChatEntryInlineInputController,
ControllerType,
lazyMultiInject,
} from './composable.js';
import { type ChatContextController } from './chat-context.js';

@customElement('chat-thread-component')
Expand Down Expand Up @@ -41,13 +43,27 @@ export class ChatThreadComponent extends LitElement {
@lazyMultiInject(ControllerType.ChatEntryAction)
actionCompontents: ChatEntryActionController[] | undefined;

@lazyMultiInject(ControllerType.ChatEntryInlineInput)
inlineInputComponents: ChatEntryInlineInputController[] | undefined;

public constructor() {
super();
this.handleInput = this.handleInput.bind(this);
}

connectedCallback() {
super.connectedCallback();
if (this.actionCompontents) {
for (const component of this.actionCompontents) {
component.attach(this, this.context);
}
}

if (this.inlineInputComponents) {
for (const component of this.inlineInputComponents) {
component.attach(this, this.context);
}
}
}

actionButtonClicked(actionButton: ChatActionButton, entry: ChatThreadEntry, event: Event) {
Expand Down Expand Up @@ -75,12 +91,10 @@ export class ChatThreadComponent extends LitElement {
}, 500);
}

handleFollowupQuestionClick(question: string, entry: ChatThreadEntry, event: Event) {
event.preventDefault();
const followUpClickEvent = new CustomEvent('on-followup-click', {
handleInput(input: string) {
const followUpClickEvent = new CustomEvent('on-input', {
detail: {
value: question,
chatThreadEntry: entry,
value: input,
},
bubbles: true,
composed: true,
Expand Down Expand Up @@ -150,36 +164,6 @@ export class ChatThreadComponent extends LitElement {
return '';
}

renderFollowupQuestions(entry: ChatThreadEntry) {
const followupQuestions = entry.followupQuestions;
// render followup questions
// need to fix first after decoupling of teaserlist
if (followupQuestions && followupQuestions.length > 0) {
return html`
<div class="items__listWrapper">
${unsafeSVG(iconQuestion)}
<ul class="items__list followup">
${followupQuestions.map(
(followupQuestion) => html`
<li class="items__listItem--followup">
<a
class="items__link"
href="#"
data-testid="followUpQuestion"
@click="${(event) => this.handleFollowupQuestionClick(followupQuestion, entry, event)}"
>${followupQuestion}</a
>
</li>
`,
)}
</ul>
</div>
`;
}

return '';
}

renderError(error: { message: string }) {
return html`<p class="chat__txt error">${error.message}</p>`;
}
Expand All @@ -193,7 +177,8 @@ export class ChatThreadComponent extends LitElement {
<div class="chat__txt ${message.isUserMessage ? 'user-message' : ''}">
${message.isUserMessage ? '' : this.renderResponseActions(message)}
${message.text.map((textEntry) => this.renderTextEntry(textEntry))} ${this.renderCitation(message)}
${this.renderFollowupQuestions(message)} ${message.error ? this.renderError(message.error) : ''}
${this.inlineInputComponents?.map((component) => component.render(message, this.handleInput))}
${message.error ? this.renderError(message.error) : ''}
</div>
<p class="chat__txt--info">
<span class="timestamp">${message.timestamp}</span>,
Expand Down
10 changes: 8 additions & 2 deletions packages/chat-component/src/components/composable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export const ControllerType = {
ChatSection: Symbol.for('ChatSectionController'),
ChatEntryAction: Symbol.for('ChatEntryActionController'),
Citation: Symbol.for('CitationController'),
ChatEntryInlineInput: Symbol.for('ChatEntryInlineInputController'),
};

export interface ComposableReactiveController extends ReactiveController {
Expand All @@ -24,7 +25,7 @@ export abstract class ComposableReactiveControllerBase implements ComposableReac
protected context: ChatContextController;

attach(host: ReactiveControllerHost, context: ChatContextController) {
this.host = host;
(this.host = host).addController(this);
this.context = context;
}

Expand All @@ -34,7 +35,7 @@ export abstract class ComposableReactiveControllerBase implements ComposableReac

export interface ChatInputController extends ComposableReactiveController {
position: 'left' | 'right' | 'top';
render: (handleInput: (event: CustomEvent<InputValue>) => void) => TemplateResult;
render: (handleInput: (input: string) => void) => TemplateResult;
}

export interface ChatInputFooterController extends ComposableReactiveController {
Expand All @@ -51,6 +52,10 @@ export interface ChatEntryActionController extends ComposableReactiveController
render: (entry: ChatThreadEntry, isDisabled: boolean) => TemplateResult;
}

export interface ChatEntryInlineInputController extends ComposableReactiveController {
render: (entry: ChatThreadEntry, handleInput: (event: CustomEvent<InputValue>) => void) => TemplateResult;
}

export interface CitationController extends ComposableReactiveController {
render: (citation: Citation, url: string) => TemplateResult;
}
Expand Down Expand Up @@ -80,3 +85,4 @@ container.bind<ChatInputFooterController>(ControllerType.ChatInputFooter).to(Def
container.bind<ChatSectionController>(ControllerType.ChatSection).to(DefaultChatSectionController);
container.bind<ChatEntryActionController>(ControllerType.ChatEntryAction).to(DefaultController);
container.bind<CitationController>(ControllerType.Citation).to(DefaultController);
container.bind<ChatEntryInlineInputController>(ControllerType.ChatEntryInlineInput).to(DefaultController);
4 changes: 2 additions & 2 deletions packages/chat-component/src/components/default-questions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@ import { html } from 'lit';
export class DefaultQuestionsInputController extends ComposableReactiveControllerBase implements ChatInputController {
position = 'top';

render(handleInput: (event: CustomEvent<InputValue>) => void) {
render(handleInput: (input: string) => void) {
const promptTemplate = html`
<teaser-list-component
.heading="${this.context.interactionModel === 'chat'
? teaserListTexts.HEADING_CHAT
: teaserListTexts.HEADING_ASK}"
.clickable="${true}"
.actionLabel="${teaserListTexts.TEASER_CTA_LABEL}"
@teaser-click="${handleInput}"
@teaser-click="${(event) => handleInput(event?.detail?.value)}"
.teasers="${teaserListTexts.DEFAULT_PROMPTS}"
></teaser-list-component>
`;
Expand Down
1 change: 1 addition & 0 deletions packages/chat-component/src/components/features.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ import './teaser-list-component.js';
import './document-previewer.js';
import './citation-previewer.js';

import './follow-up-questions.js';
// [COMPOSE COMPONENTS END]
48 changes: 48 additions & 0 deletions packages/chat-component/src/components/follow-up-questions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { injectable } from 'inversify';
import {
container,
type ChatEntryInlineInputController,
ControllerType,
ComposableReactiveControllerBase,
} from './composable.js';
import { html } from 'lit';
import { unsafeSVG } from 'lit/directives/unsafe-svg.js';
import iconQuestion from '../../public/svg/bubblequestion-icon.svg?raw';

@injectable()
export class FollowupQuestionsController
extends ComposableReactiveControllerBase
implements ChatEntryInlineInputController
{
render(entry: ChatThreadEntry, handleInput: (input: string) => void) {
const followupQuestions = entry.followupQuestions;
// render followup questions
// need to fix first after decoupling of teaserlist
if (followupQuestions && followupQuestions.length > 0) {
return html`
<div class="items__listWrapper">
${unsafeSVG(iconQuestion)}
<ul class="items__list followup">
${followupQuestions.map(
(followupQuestion) => html`
<li class="items__listItem--followup">
<a
class="items__link"
href="#"
data-testid="followUpQuestion"
@click="${() => handleInput(followupQuestion)}"
>${followupQuestion}</a
>
</li>
`,
)}
</ul>
</div>
`;
}

return '';
}
}

container.bind<ChatEntryInlineInputController>(ControllerType.ChatEntryInlineInput).to(FollowupQuestionsController);
4 changes: 2 additions & 2 deletions packages/chat-component/src/components/voice-input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import { html } from 'lit';
export class VoiceInputController extends ComposableReactiveControllerBase implements ChatInputController {
position = 'right';

render(handleInput: (event: CustomEvent<InputValue>) => void) {
return html`<voice-input-button @on-voice-input="${handleInput}" />`;
render(handleInput: (input: string) => void) {
return html`<voice-input-button @on-voice-input="${(event) => handleInput(event?.detail?.value)}" />`;
}
}

Expand Down

0 comments on commit 628065d

Please sign in to comment.