Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Update feedback dialog form
Browse files Browse the repository at this point in the history
ajbozarth committed Nov 1, 2024

Verified

This commit was signed with the committer’s verified signature.
merlinran Merlin Ran
1 parent 7b0202b commit 021b361
Showing 3 changed files with 132 additions and 34 deletions.
144 changes: 110 additions & 34 deletions src/service/feedback.tsx
Original file line number Diff line number Diff line change
@@ -16,16 +16,25 @@

import React from 'react';

import { InputDialog, Notification } from '@jupyterlab/apputils';
import { Dialog, Notification } from '@jupyterlab/apputils';
import { ReactWidget } from '@jupyterlab/ui-components';

import { postFeedback } from './api';
import { getCurrentModel } from './modelHandler';
import { lastPrompt } from '../QiskitCompletionProvider';
import { feedbackIcon } from '../utils/icons';
import { IFeedbackResponse } from '../utils/schema';
import { IFeedbackForm, IFeedbackResponse } from '../utils/schema';

const DIALOG_TITLE = 'Qiskit Code Assistant Feedback';
const toBool = (bool?: string): boolean | undefined => {
switch (bool) {
case 'true':
return true;
case 'false':
return false;
default:
return undefined;
}
};

export function getFeedbackStatusBarWidget() {
const feedbackButton = ReactWidget.create(
@@ -49,39 +58,106 @@ export function getFeedbackStatusBarWidget() {
}

export function getFeedback(prompt: boolean = true) {
return InputDialog.getText({
title: DIALOG_TITLE,
label: prompt ? lastPrompt?.items[0] : undefined
}).then(result => {
// send feedback
if (result.button.accept) {
sendFeedback(
getCurrentModel()?._id,
prompt ? lastPrompt?.prompt_id : undefined,
undefined,
result.value || undefined
);
}
const model_id = getCurrentModel()?._id;
const prompt_id = prompt ? lastPrompt?.prompt_id : undefined;
const prompt_text = prompt ? lastPrompt?.items[0] : undefined;

const dialog = new Dialog({
title: 'Qiskit Code Assistant Feedback',
body: getFeedbackBodyWidget(prompt_text),
buttons: [Dialog.cancelButton(), Dialog.okButton({ label: 'Submit' })],
focusNodeSelector: '.jp-qiskit-code-assistant-feedback-form textarea'
});
}

function sendFeedback(
model_id?: string,
prompt_id?: string,
positive_feedback?: boolean,
comment?: string
) {
console.log(
`model_id: ${model_id}`,
`prompt_id: ${prompt_id}`,
`positive_feedback: ${positive_feedback}`,
`comment: ${comment}`
);
postFeedback(model_id, prompt_id, positive_feedback, comment).then(
(response: IFeedbackResponse) => {
Notification.info(`Qiskit Code Assistant:\n${response['message']}`, {
autoClose: false
const dialogHandleEvent = dialog.handleEvent;
dialog.handleEvent = (event: Event) => {
if (
event.type === 'keydown' &&
(event as KeyboardEvent).code === 'Enter' &&
document.activeElement instanceof HTMLTextAreaElement
) {
return;
}
dialogHandleEvent.call(dialog, event);
};

return dialog.launch().then(result => {
if (
result.button.accept &&
(result.value?.positive_feedback || result.value?.comment)
) {
postFeedback(
model_id,
prompt_id,
toBool(result.value?.positive_feedback),
result.value?.comment
).then((response: IFeedbackResponse) => {
Notification.info(`Qiskit Code Assistant:\n${response['message']}`, {
autoClose: 5000
});
});
}
);
});
}

function getFeedbackBodyWidget(
prompt?: string
): Dialog.IBodyWidget<IFeedbackForm> {
const bodyWidget = ReactWidget.create(
<>
{!!prompt && (
<>
<b>Completion</b>
<pre>{prompt.trim()}</pre>
</>
)}
<form>
{!!prompt && (
<p>
How helpful was this completion? &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<label>
<input type="radio" name="positive_feedback" value="true" />
<span className="positive-feedback">&#128077;</span>
</label>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<label>
<input type="radio" name="positive_feedback" value="false" />
<span className="positive-feedback">&#128078;</span>
</label>
</p>
)}
<p>
<label>
<p>
{prompt
? 'Additional feedback (Optional)'
: 'Please share your experience with Qiskit Code Assistant'}
</p>
<textarea name="comment"></textarea>
</label>
</p>
</form>
</>
) as Dialog.IBodyWidget<IFeedbackForm>;

bodyWidget.addClass('jp-qiskit-code-assistant-feedback-form');
if (prompt) {
bodyWidget.addClass('jp-qiskit-code-assistant-feedback-prompt');
} else {
bodyWidget.addClass('jp-qiskit-code-assistant-feedback-general');
}

bodyWidget.getValue = (): IFeedbackForm => {
const form = bodyWidget.node.querySelector('form');
const formData = new FormData(form ? form : undefined);
const positive_feedback = formData.get('positive_feedback') as string;
const comment = formData.get('comment') as string;

return {
positive_feedback: positive_feedback ? positive_feedback : undefined,
comment: comment ? comment : undefined
};
};

return bodyWidget;
}
5 changes: 5 additions & 0 deletions src/utils/schema.ts
Original file line number Diff line number Diff line change
@@ -89,3 +89,8 @@ export interface ICompletionReturn {
items: string[];
prompt_id: string;
}

export interface IFeedbackForm {
positive_feedback?: string;
comment?: string;
}
17 changes: 17 additions & 0 deletions style/base.css
Original file line number Diff line number Diff line change
@@ -18,6 +18,23 @@
cursor: pointer;
}

.positive-feedback {
font-size: large;
}
.jp-qiskit-code-assistant-feedback-prompt pre {
overflow: auto;
max-height: 200px;
border: solid thin;
}

.jp-qiskit-code-assistant-feedback-prompt textarea,
.jp-qiskit-code-assistant-feedback-general textarea {
width: 30em;
height: 5em;
font-family: inherit;
font-size: inherit;
}

.jp-qiskit-code-assistant-statusbar {
margin: 4px;
cursor: pointer;

0 comments on commit 021b361

Please sign in to comment.