Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

First round of design improvements #38

Merged
merged 26 commits into from
Feb 2, 2024
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
cb9c443
Free prompt -> Generate text
julien-nc Jan 17, 2024
74389ba
STT minimal design, custom button to reset
julien-nc Jan 17, 2024
6ba0bbd
fix issue in nc/vue radio-checkbox text alignment
julien-nc Jan 17, 2024
b55d326
use external STT recording control buttons
julien-nc Jan 17, 2024
2196c70
STT: focus on record/stop/reset buttons when needed (mounted, start, …
julien-nc Jan 17, 2024
b830f5b
'speech to text' -> 'transcribe' or 'audio transcription'
julien-nc Jan 24, 2024
dbb8db9
STT: stop recording when switching modes (record/file), keep recordin…
julien-nc Jan 24, 2024
a8fd14e
fix accessibility for some buttons
julien-nc Jan 24, 2024
cddb2fe
fix text2image error message
julien-nc Jan 24, 2024
5cab449
fix kb focus order in image generation picker
julien-nc Jan 24, 2024
6780c5e
fix style and design of image generation preview
julien-nc Jan 26, 2024
d46ce82
differenciate between 'empty result' or 'no result yet', add warning …
julien-nc Jan 26, 2024
a9445b8
warn about result being identical to input
julien-nc Jan 26, 2024
fca9a89
rename features
julien-nc Jan 26, 2024
b73533a
fix height of input/output fields
julien-nc Jan 26, 2024
5eb7e59
change description of freeprompt task type
julien-nc Jan 26, 2024
9fe2d0a
fix accessibility of task type selector action menu by setting its co…
julien-nc Jan 28, 2024
c6209fa
mistake in rebase
julien-nc Feb 1, 2024
49a3f37
to check if input and output are equal, use the 'prompt' input
julien-nc Feb 1, 2024
16c093b
fix z-index of top-right close button in modals
julien-nc Feb 1, 2024
659aeb0
harmonize the task-type/category names
julien-nc Feb 1, 2024
7b08186
display toast message on assistant error
julien-nc Feb 1, 2024
10bcbea
fix update:newInputs event not being fired when loading a file
julien-nc Feb 1, 2024
09605fc
simplify resetting result input since richContentEditable was apparen…
julien-nc Feb 2, 2024
9859215
fix lint issues
julien-nc Feb 2, 2024
90af780
improve and unify image generation previews style
julien-nc Feb 2, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 11 additions & 6 deletions lib/Notification/Notifier.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use OCP\Notification\INotification;

use OCP\Notification\INotifier;
use OCP\TextProcessing\FreePromptTaskType;
use OCP\TextProcessing\ITaskType;
use Psr\Container\ContainerInterface;
use Psr\Log\LoggerInterface;
Expand Down Expand Up @@ -75,21 +76,25 @@ public function prepare(INotification $notification, string $languageCode): INot

if ($params['taskTypeClass'] === 'copywriter') {
// Catch the custom copywriter task type built on top of the FreePrompt task type.
$taskTypeName = $l->t('Copywriting');
$taskTypeName = $l->t('AI context writer');
$taskInput = $l->t('Writing style: %1$s; Source material: %2$s', [$params['inputs']['writingStyle'], $params['inputs']['sourceMaterial']]);
} else {
try {
/** @var ITaskType $taskType */
$taskType = $this->container->get($params['taskTypeClass']);
$taskTypeName = $taskType->getName();
if ($params['taskTypeClass'] === FreePromptTaskType::class) {
$taskTypeName = $l->t('AI text generation');
} else {
/** @var ITaskType $taskType */
$taskType = $this->container->get($params['taskTypeClass']);
$taskTypeName = $taskType->getName();
}
} catch (\Exception | \Throwable $e) {
$this->logger->debug('Impossible to get task type ' . $params['taskTypeClass'], ['exception' => $e]);
}
}
} elseif ($params['taskCategory'] === Application::TASK_CATEGORY_TEXT_TO_IMAGE) {
$taskTypeName = $l->t('Text to image');
$taskTypeName = $l->t('AI image generation');
} elseif ($params['taskCategory'] === Application::TASK_CATEGORY_SPEECH_TO_TEXT) {
$taskTypeName = $l->t('Speech to text');
$taskTypeName = $l->t('AI audio transcription');
}

switch ($notification->getSubject()) {
Expand Down
2 changes: 1 addition & 1 deletion lib/Reference/SpeechToTextReferenceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public function getId(): string {
* @inheritDoc
*/
public function getTitle(): string {
return $this->l10n->t('Speech to Text');
return $this->l10n->t('AI audio transcription');
}

/**
Expand Down
4 changes: 4 additions & 0 deletions src/assistant.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { STATUS, TASK_TYPES } from './constants.js'
import { linkTo } from '@nextcloud/router'
import { getRequestToken } from '@nextcloud/auth'
import { showError } from '@nextcloud/dialogs'

__webpack_nonce__ = btoa(getRequestToken()) // eslint-disable-line
__webpack_public_path__ = linkTo('assistant', 'js/') // eslint-disable-line
Expand Down Expand Up @@ -90,6 +91,7 @@ export async function openAssistantTextProcessingForm({
.catch(error => {
view.$destroy()
console.error('Assistant scheduling error', error)
showError(t('assistant', 'Assistant error') + ': ' + error?.response?.data)
reject(new Error('Assistant scheduling error'))
})
})
Expand Down Expand Up @@ -122,6 +124,7 @@ export async function openAssistantTextProcessingForm({
} else {
view.$destroy()
console.error('Assistant sync run error', error)
showError(t('assistant', 'Assistant error') + ': ' + error?.response?.data)
reject(new Error('Assistant sync run error'))
}
})
Expand All @@ -141,6 +144,7 @@ export async function openAssistantTextProcessingForm({
.catch(error => {
view.$destroy()
console.error('Assistant scheduling error', error)
showError(t('assistant', 'Assistant error') + ': ' + error?.response?.data)
reject(new Error('Assistant scheduling error'))
})
})
Expand Down
15 changes: 9 additions & 6 deletions src/components/AssistantFormInputs.vue
Original file line number Diff line number Diff line change
Expand Up @@ -132,12 +132,6 @@ export default {
}
},
methods: {
onUpdateCopywriter() {
this.$emit('update:newInputs', {
writingStyle: this.writingStyle,
sourceMaterial: this.sourceMaterial,
})
},
async onChooseFile(target) {
const filePath = await picker.pick()
if (!filePath) {
Expand All @@ -155,12 +149,15 @@ export default {
switch (target) {
case 'sourceMaterial':
this.sourceMaterial = response.data.parsedText
this.onUpdateCopywriter()
break
case 'writingStyle':
this.writingStyle = response.data.parsedText
this.onUpdateCopywriter()
break
default:
this.prompt = response.data.parsedText
this.onUpdate()
}
}).catch((error) => {
console.error(error)
Expand All @@ -172,6 +169,12 @@ export default {
prompt: this.prompt,
})
},
onUpdateCopywriter() {
this.$emit('update:newInputs', {
writingStyle: this.writingStyle,
sourceMaterial: this.sourceMaterial,
})
},
},
}

Expand Down
1 change: 1 addition & 0 deletions src/components/AssistantPlainTextModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ export default {
position: absolute;
top: 4px;
right: 4px;
z-index: 1;
// No border on hover
&:hover {
outline: none;
Expand Down
19 changes: 2 additions & 17 deletions src/components/AssistantPlainTextResult.vue
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
<NcButton :disabled="output === myOutput"
type="secondary"
:title="t('assistant', 'Reset the output value to the originally generated one')"
@click="delayedReset">
@click="onReset">
{{ t('assistant', 'Reset') }}
</NcButton>
</div>
Expand Down Expand Up @@ -98,7 +98,7 @@ export default {
case TASK_TYPES.text_generation:
return t('assistant', 'Text Generation')
case TASK_TYPES.speech_to_text:
return t('assistant', 'Speech to Text')
return t('assistant', 'Audio transcription')
default:
return t('assistant', 'Unknown Result Type')
}
Expand Down Expand Up @@ -126,21 +126,6 @@ export default {
onReset() {
this.myOutput = this.output
},

delayedReset() {
// This is a hack to ensure the text box is updated
// when we reset the text since removing newlines or spaces
// from the end of the text does not trigger an update.

// Delete any trailing newlines
this.myOutput = this.myOutput.replace(/\n+$/, '')
this.myOutput += '.'

// Let the ui refresh before resetting the text
setTimeout(() => {
this.onReset()
}, 0)
},
},
}
</script>
Expand Down
42 changes: 33 additions & 9 deletions src/components/AssistantTextProcessingForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
:inputs="inputs"
:selected-task-type-id="mySelectedTaskTypeId"
:new-inputs.sync="myInputs" />
<div v-if="myOutput"
<div v-if="myOutput !== null"
class="output">
<label
for="assistant-output"
Expand All @@ -37,11 +37,21 @@
:disabled="loading"
:placeholder="t('assistant', 'Result')"
:link-autocomplete="false" />
<NcNoteCard
<NcNoteCard v-if="outputEqualsInput"
class="warning-note"
type="warning">
{{ t('assistant', 'The task ran successfully but the result is identical to the input.') }}
</NcNoteCard>
<NcNoteCard v-else-if="hasInitialOutput"
class="warning-note"
type="warning">
{{ t('assistant', 'This output was generated by AI. Make sure to double-check and adjust.') }}
</NcNoteCard>
<NcNoteCard v-else
class="warning-note"
type="warning">
{{ t('assistant', 'The task ran successfully but the generated text is empty.') }}
</NcNoteCard>
</div>
<div class="footer">
<NcButton
Expand Down Expand Up @@ -148,8 +158,8 @@ export default {
default: () => {},
},
output: {
type: String,
default: '',
type: [String, null],
default: null,
},
selectedTaskTypeId: {
type: [String, null],
Expand Down Expand Up @@ -182,7 +192,7 @@ export default {
return this.taskTypes.find(tt => tt.id === this.mySelectedTaskTypeId)
},
submitButtonType() {
return this.myOutput.trim() ? 'secondary' : 'primary'
return this.hasOutput ? 'secondary' : 'primary'
},
showSubmit() {
return this.selectedTaskType
Expand All @@ -192,21 +202,27 @@ export default {
return Object.values(this.myInputs).every(v => !!v.trim()) && this.selectedTaskType
},
submitButtonLabel() {
return this.myOutput.trim()
return this.hasOutput
? t('assistant', 'Try again')
: this.selectedTaskType.id === FREE_PROMPT_TASK_TYPE_ID
? t('assistant', 'Send request')
: this.selectedTaskType.name
},
syncSubmitButtonLabel() {
return this.myOutput.trim()
return this.output !== null
? t('assistant', 'Try again')
: this.selectedTaskType.id === FREE_PROMPT_TASK_TYPE_ID
? t('assistant', 'Send request')
: this.selectedTaskType.name
},
hasInitialOutput() {
return !!this.output?.trim()
},
hasOutput() {
return !!this.myOutput.trim()
return !!this.myOutput?.trim()
},
outputEqualsInput() {
return this.hasInitialOutput && this.output?.trim() === this.inputs.prompt?.trim()
},
},
watch: {
Expand All @@ -227,7 +243,15 @@ export default {

// Check if FREE_PROMPT_TASK_TYPE_ID is available
if (this.taskTypes.find(tt => tt.id === FREE_PROMPT_TASK_TYPE_ID)) {
// If it is, inject a copywriter task type into the list
// change free prompt task type name
this.taskTypes = this.taskTypes.map(type => {
if (type.id === FREE_PROMPT_TASK_TYPE_ID) {
type.name = t('assistant', 'Generate text')
type.description = t('assistant', 'Send a request to the Assistant, for example: write a first draft of a presentation, give me suggestions for a presentation, write a draft reply to my colleague.')
}
return type
})
// inject a copywriter task type
this.taskTypes.push({
id: 'copywriter',
name: t('assistant', 'Context write'),
Expand Down
5 changes: 3 additions & 2 deletions src/components/AssistantTextProcessingModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,8 @@ export default {
default: () => {},
},
output: {
type: String,
default: '',
type: [String, null],
default: null,
},
textProcessingTaskTypeId: {
type: [String, null],
Expand Down Expand Up @@ -166,6 +166,7 @@ export default {
position: absolute;
top: 4px;
right: 4px;
z-index: 1;
}

.assistant-modal--wrapper {
Expand Down
6 changes: 3 additions & 3 deletions src/components/PersonalSettings.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,21 @@
:checked="state.free_prompt_picker_enabled"
@update:checked="onCheckboxChanged($event, 'free_prompt_picker_enabled')">
<div class="checkbox-text">
{{ t('assistant', 'Free prompt smart picker') }}
{{ t('assistant', 'AI text generation smart picker') }}
</div>
</NcCheckboxRadioSwitch>
<NcCheckboxRadioSwitch v-if="state.text_to_image_picker_available"
:checked="state.text_to_image_picker_enabled"
@update:checked="onCheckboxChanged($event, 'text_to_image_picker_enabled')">
<div class="checkbox-text">
{{ t('assistant', 'Text-to-image smart picker') }}
{{ t('assistant', 'AI image generation smart picker') }}
</div>
</NcCheckboxRadioSwitch>
<NcCheckboxRadioSwitch v-if="state.speech_to_text_picker_available"
:checked="state.speech_to_text_picker_enabled"
@update:checked="onCheckboxChanged($event, 'speech_to_text_picker_enabled')">
<div class="checkbox-text">
{{ t('assistant', 'Speech-to-text smart picker') }}
{{ t('assistant', 'AI transcription smart picker') }}
</div>
</NcCheckboxRadioSwitch>
<div v-if="noProvidersAvailable" class="settings-hint">
Expand Down
5 changes: 3 additions & 2 deletions src/components/TaskTypeSelect.vue
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
<template>
<div class="task-type-select">
<div id="task-type-select" class="task-type-select">
<NcButton v-for="(t, i) in buttonTypes"
:key="i + t.id"
:type="getButtonType(t)"
@click="onTaskSelected(t)">
{{ t.name }}
</NcButton>
<NcActions v-if="actionTypes.length > 0"
:force-menu="true">
:force-menu="true"
container="#task-type-select">
<NcActionButton v-for="(t, i) in actionTypes"
:key="i + t.id"
class="no-icon-action"
Expand Down
Loading
Loading