@zipify/wysiwyg 3.5.0-ai-prototype → 3.5.2-ai-prototype
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +1 -1
- package/dist/wysiwyg.css +18 -11
- package/dist/wysiwyg.mjs +703 -517
- package/example/aiAdapter.js +33 -2
- package/lib/components/toolbar/controls/aiComponent/AiControl.vue +37 -24
- package/lib/components/toolbar/controls/aiComponent/AiSettings.vue +137 -0
- package/lib/components/toolbar/controls/aiComponent/AiSuggestionItem.vue +1 -2
- package/lib/extensions/AiComponent.js +6 -5
- package/package.json +1 -1
package/example/aiAdapter.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
export const aiAdapter = {
|
|
2
|
-
generateText: async ({ prompt, context,
|
|
2
|
+
generateText: async ({ prompt, context, instructions }) => {
|
|
3
3
|
try {
|
|
4
4
|
const response = await fetch('https://mendelson-test.eu.ngrok.io/process-text', {
|
|
5
5
|
method: 'POST',
|
|
6
6
|
headers: {
|
|
7
7
|
'Content-Type': 'application/json'
|
|
8
8
|
},
|
|
9
|
-
body: JSON.stringify({ text: prompt, context })
|
|
9
|
+
body: JSON.stringify({ text: prompt, context, instructions })
|
|
10
10
|
});
|
|
11
11
|
|
|
12
12
|
if (!response.ok) {
|
|
@@ -15,7 +15,38 @@ export const aiAdapter = {
|
|
|
15
15
|
|
|
16
16
|
return await response.json();
|
|
17
17
|
} catch (error) {
|
|
18
|
+
// eslint-disable-next-line no-console
|
|
18
19
|
console.error('An error occurred while sending the request:', error);
|
|
19
20
|
}
|
|
21
|
+
},
|
|
22
|
+
|
|
23
|
+
settings: {
|
|
24
|
+
tones: [
|
|
25
|
+
{ id: 'expert', title: 'Expert' },
|
|
26
|
+
{ id: 'daring', title: 'Daring' },
|
|
27
|
+
{ id: 'playful', title: 'Playful' },
|
|
28
|
+
{ id: 'sophisticated', title: 'Sophisticated' },
|
|
29
|
+
{ id: 'Persuasive', title: 'Persuasive' },
|
|
30
|
+
{ id: 'supportive', title: 'Supportive' },
|
|
31
|
+
{ id: 'personable', title: 'Personable' },
|
|
32
|
+
{ id: 'direct', title: 'Direct' },
|
|
33
|
+
{ id: 'empathetic', title: 'Empathetic' },
|
|
34
|
+
{ id: 'engaging', title: 'Engaging' },
|
|
35
|
+
{ id: 'neutral', title: 'Neutral' }
|
|
36
|
+
],
|
|
37
|
+
textStyles: [
|
|
38
|
+
{ id: 'formal', title: 'Formal' },
|
|
39
|
+
{ id: 'informal', title: 'Informal' },
|
|
40
|
+
{ id: 'technical', title: 'Technical' },
|
|
41
|
+
{ id: 'persuasive', title: 'Persuasive' },
|
|
42
|
+
{ id: 'promotional', title: 'Promotional' },
|
|
43
|
+
{ id: 'product description', title: 'Product description' },
|
|
44
|
+
{ id: 'befits', title: 'Befits' }
|
|
45
|
+
],
|
|
46
|
+
textLength: [
|
|
47
|
+
{ id: '200', title: 'Short (200)' },
|
|
48
|
+
{ id: '500', title: 'Medium (500)' },
|
|
49
|
+
{ id: '1000', title: 'Long (1000)' }
|
|
50
|
+
]
|
|
20
51
|
}
|
|
21
52
|
};
|
|
@@ -5,51 +5,42 @@
|
|
|
5
5
|
</Button>
|
|
6
6
|
|
|
7
7
|
<Modal class="zw-suggestion-modal" :toggler="toggler" ref="modalRef" focus-first-control>
|
|
8
|
-
|
|
9
8
|
<AiControlHeader />
|
|
10
9
|
<form class="zw-link-modal__body" @submit.prevent="generateText">
|
|
11
10
|
|
|
12
|
-
<
|
|
13
|
-
v-if="isLoading"
|
|
14
|
-
:suggestion="{ content: 'Working on it...', state: 'loading' }"
|
|
15
|
-
/>
|
|
11
|
+
<Icon v-if="isLoading" auto-color class="zw-ai-component__icon" name="loading" size="32px" />
|
|
16
12
|
|
|
17
|
-
<AiSuggestionItem
|
|
18
|
-
v-else-if="lastSuggestions"
|
|
19
|
-
:suggestion="lastSuggestions"
|
|
20
|
-
/>
|
|
13
|
+
<AiSuggestionItem v-else-if="lastSuggestions" :suggestion="lastSuggestions" />
|
|
21
14
|
|
|
22
15
|
<label class="zw-field__label">
|
|
23
16
|
{{ textAreaLabel }}
|
|
24
17
|
</label>
|
|
25
18
|
|
|
26
19
|
<div class="zw-position--relative">
|
|
27
|
-
<TextArea
|
|
28
|
-
class="zw-margin-bottom--sm"
|
|
29
|
-
v-model="prompt"
|
|
30
|
-
/>
|
|
20
|
+
<TextArea class="zw-margin-bottom--sm" v-model="prompt" />
|
|
31
21
|
<Button type="submit" class="zw-ai-component__send-button">
|
|
32
22
|
<Icon auto-color class="zw-ai-component__icon" name="send" size="32px" />
|
|
33
23
|
</Button>
|
|
34
24
|
</div>
|
|
35
25
|
|
|
26
|
+
<AiSettings v-model="settings" />
|
|
27
|
+
|
|
36
28
|
<Button :disabled="!lastSuggestions" type="button" skin="primary" @click="applyText">
|
|
37
29
|
Apply
|
|
38
30
|
</Button>
|
|
39
31
|
</form>
|
|
40
|
-
|
|
41
|
-
|
|
42
32
|
</Modal>
|
|
43
33
|
</div>
|
|
44
34
|
</template>
|
|
45
35
|
|
|
46
36
|
<script>
|
|
47
|
-
import { computed, ref, inject, unref } from 'vue';
|
|
37
|
+
import { computed, ref, inject, unref, watch } from 'vue';
|
|
48
38
|
import { InjectionTokens } from '../../../../injectionTokens';
|
|
49
39
|
import { tooltip } from '../../../../directives';
|
|
50
40
|
import { Button, Icon, Modal, TextArea, useModalToggler } from '../../../base';
|
|
51
41
|
import AiControlHeader from './AiControlHeader';
|
|
52
42
|
import AiSuggestionItem from './AiSuggestionItem';
|
|
43
|
+
import AiSettings from './AiSettings';
|
|
53
44
|
|
|
54
45
|
export default {
|
|
55
46
|
name: 'AiControl',
|
|
@@ -60,7 +51,8 @@ export default {
|
|
|
60
51
|
Button,
|
|
61
52
|
TextArea,
|
|
62
53
|
AiControlHeader,
|
|
63
|
-
AiSuggestionItem
|
|
54
|
+
AiSuggestionItem,
|
|
55
|
+
AiSettings
|
|
64
56
|
},
|
|
65
57
|
|
|
66
58
|
directives: {
|
|
@@ -75,6 +67,20 @@ export default {
|
|
|
75
67
|
const suggestions = ref([]);
|
|
76
68
|
const isLoading = ref(false);
|
|
77
69
|
|
|
70
|
+
const settings = ref({
|
|
71
|
+
tone: '',
|
|
72
|
+
textLength: '500',
|
|
73
|
+
textStyle: ''
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
if (localStorage.getItem('ai-settings')) {
|
|
77
|
+
settings.value = JSON.parse(localStorage.getItem('ai-settings'));
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
watch(settings, () => {
|
|
81
|
+
localStorage.setItem('ai-settings', JSON.stringify(settings.value));
|
|
82
|
+
});
|
|
83
|
+
|
|
78
84
|
const textAreaLabel = computed(() => {
|
|
79
85
|
return suggestions.value.length ? 'Tell AI what to do next…' : 'Write you request';
|
|
80
86
|
});
|
|
@@ -83,7 +89,7 @@ export default {
|
|
|
83
89
|
|
|
84
90
|
const editor = inject(InjectionTokens.EDITOR);
|
|
85
91
|
|
|
86
|
-
const onBeforeOpened = () => {};
|
|
92
|
+
const onBeforeOpened = () => { };
|
|
87
93
|
|
|
88
94
|
const toggler = useModalToggler({
|
|
89
95
|
onBeforeOpened: () => onBeforeOpened(),
|
|
@@ -97,23 +103,29 @@ export default {
|
|
|
97
103
|
const lastSuggestions = suggestions.value[suggestions.value.length - 1];
|
|
98
104
|
|
|
99
105
|
const context = lastSuggestions ? lastSuggestions.content : '';
|
|
100
|
-
|
|
101
|
-
|
|
106
|
+
const result = await editor.commands.generateText({
|
|
107
|
+
prompt: action,
|
|
108
|
+
context,
|
|
109
|
+
instructions: unref(settings)
|
|
110
|
+
});
|
|
102
111
|
|
|
103
112
|
isLoading.value = false;
|
|
104
113
|
suggestions.value.push(result);
|
|
105
114
|
};
|
|
106
115
|
|
|
107
116
|
const generateText = async () => {
|
|
108
|
-
if(isLoading.value) return;
|
|
117
|
+
if (isLoading.value) return;
|
|
109
118
|
|
|
110
119
|
isLoading.value = true;
|
|
111
120
|
|
|
112
121
|
const lastSuggestions = suggestions.value[suggestions.value.length - 1];
|
|
113
122
|
|
|
114
123
|
const context = lastSuggestions ? lastSuggestions.content : '';
|
|
115
|
-
|
|
116
|
-
|
|
124
|
+
const result = await editor.commands.generateText({
|
|
125
|
+
prompt: prompt.value,
|
|
126
|
+
context,
|
|
127
|
+
instructions: unref(settings)
|
|
128
|
+
});
|
|
117
129
|
|
|
118
130
|
isLoading.value = false;
|
|
119
131
|
prompt.value = '';
|
|
@@ -140,7 +152,8 @@ export default {
|
|
|
140
152
|
textAreaLabel,
|
|
141
153
|
isLoading,
|
|
142
154
|
onAction,
|
|
143
|
-
applyText
|
|
155
|
+
applyText,
|
|
156
|
+
settings
|
|
144
157
|
};
|
|
145
158
|
}
|
|
146
159
|
};
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="zw-selectors">
|
|
3
|
+
<div class="zw-ai__dropdown zw-margin-right--xs">
|
|
4
|
+
<FieldLabel class="zw-margin-bottom--xxs">
|
|
5
|
+
Tone
|
|
6
|
+
</FieldLabel>
|
|
7
|
+
|
|
8
|
+
<Dropdown
|
|
9
|
+
class="zw-margin-bottom--sm"
|
|
10
|
+
color="gray"
|
|
11
|
+
:value="settings.tone"
|
|
12
|
+
:options="tones"
|
|
13
|
+
@change="changeTone"
|
|
14
|
+
>
|
|
15
|
+
<template #option="{ option }">
|
|
16
|
+
<DropdownOption
|
|
17
|
+
class="zw-link-modal-dropdown__option"
|
|
18
|
+
:option="option"
|
|
19
|
+
/>
|
|
20
|
+
</template>
|
|
21
|
+
</Dropdown>
|
|
22
|
+
</div>
|
|
23
|
+
|
|
24
|
+
<div class="zw-ai__dropdown zw-margin-right--xs ">
|
|
25
|
+
<FieldLabel class="zw-margin-bottom--xxs">
|
|
26
|
+
Text Style
|
|
27
|
+
</FieldLabel>
|
|
28
|
+
|
|
29
|
+
<Dropdown
|
|
30
|
+
class="zw-margin-bottom--sm"
|
|
31
|
+
color="gray"
|
|
32
|
+
:value="settings.textStyle"
|
|
33
|
+
:options="textStyles"
|
|
34
|
+
@change="changeTextStyle"
|
|
35
|
+
>
|
|
36
|
+
<template #option="{ option }">
|
|
37
|
+
<DropdownOption
|
|
38
|
+
class="zw-link-modal-dropdown__option"
|
|
39
|
+
:option="option"
|
|
40
|
+
/>
|
|
41
|
+
</template>
|
|
42
|
+
</Dropdown>
|
|
43
|
+
</div>
|
|
44
|
+
|
|
45
|
+
<div class="zw-ai__dropdown">
|
|
46
|
+
<FieldLabel class="zw-margin-bottom--xxs">
|
|
47
|
+
Length
|
|
48
|
+
</FieldLabel>
|
|
49
|
+
|
|
50
|
+
<Dropdown
|
|
51
|
+
class="zw-margin-bottom--sm"
|
|
52
|
+
color="gray"
|
|
53
|
+
:value="settings.textLength"
|
|
54
|
+
:options="textLength"
|
|
55
|
+
@change="changeTextLength"
|
|
56
|
+
>
|
|
57
|
+
<template #option="{ option }">
|
|
58
|
+
<DropdownOption
|
|
59
|
+
class="zw-link-modal-dropdown__option"
|
|
60
|
+
:option="option"
|
|
61
|
+
/>
|
|
62
|
+
</template>
|
|
63
|
+
</Dropdown>
|
|
64
|
+
</div>
|
|
65
|
+
</div>
|
|
66
|
+
</template>
|
|
67
|
+
|
|
68
|
+
<script>
|
|
69
|
+
import { computed, inject } from 'vue';
|
|
70
|
+
import { FieldLabel, Dropdown, DropdownOption } from '../../../base';
|
|
71
|
+
import { InjectionTokens } from '../../../../injectionTokens';
|
|
72
|
+
|
|
73
|
+
export default {
|
|
74
|
+
name: 'AiSettings',
|
|
75
|
+
|
|
76
|
+
components: {
|
|
77
|
+
FieldLabel,
|
|
78
|
+
Dropdown,
|
|
79
|
+
DropdownOption
|
|
80
|
+
},
|
|
81
|
+
|
|
82
|
+
props: {
|
|
83
|
+
value: {
|
|
84
|
+
type: Object,
|
|
85
|
+
default: () => ({})
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
|
|
89
|
+
setup(props, { emit }) {
|
|
90
|
+
const settings = computed(() => {
|
|
91
|
+
return {
|
|
92
|
+
tone: props.value.tone,
|
|
93
|
+
textStyle: props.value.textStyle,
|
|
94
|
+
textLength: props.value.textLength
|
|
95
|
+
};
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
const editor = inject(InjectionTokens.EDITOR);
|
|
99
|
+
const tones = editor.commands.getAiSettings().tones;
|
|
100
|
+
const textStyles = editor.commands.getAiSettings().textStyles;
|
|
101
|
+
const textLength = editor.commands.getAiSettings().textLength;
|
|
102
|
+
|
|
103
|
+
const changeTone = (value) => {
|
|
104
|
+
settings.value.tone = value;
|
|
105
|
+
emit('input', settings.value);
|
|
106
|
+
};
|
|
107
|
+
const changeTextStyle = (value) => {
|
|
108
|
+
settings.value.textStyle = value;
|
|
109
|
+
emit('input', settings.value);
|
|
110
|
+
};
|
|
111
|
+
const changeTextLength = (value) => {
|
|
112
|
+
settings.value.textLength = value;
|
|
113
|
+
emit('input', settings.value);
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
return {
|
|
117
|
+
tones,
|
|
118
|
+
textStyles,
|
|
119
|
+
textLength,
|
|
120
|
+
changeTone,
|
|
121
|
+
changeTextStyle,
|
|
122
|
+
changeTextLength,
|
|
123
|
+
settings
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
</script>
|
|
128
|
+
|
|
129
|
+
<style scoped>
|
|
130
|
+
.zw-selectors {
|
|
131
|
+
display: flex;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
.zw-ai__dropdown {
|
|
135
|
+
width: 100%;
|
|
136
|
+
}
|
|
137
|
+
</style>
|
|
@@ -12,9 +12,8 @@
|
|
|
12
12
|
</template>
|
|
13
13
|
|
|
14
14
|
<script>
|
|
15
|
-
import {
|
|
15
|
+
import { computed } from 'vue';
|
|
16
16
|
import { Button } from '../../../base';
|
|
17
|
-
import { InjectionTokens } from '../../../../injectionTokens';
|
|
18
17
|
|
|
19
18
|
export default {
|
|
20
19
|
name: 'AiSuggestionItem',
|
|
@@ -1,17 +1,18 @@
|
|
|
1
|
-
import { toRef } from 'vue';
|
|
2
1
|
import { Extension } from '@tiptap/vue-2';
|
|
3
2
|
import { createCommand } from '../utils';
|
|
4
3
|
|
|
5
4
|
export const AiComponent = Extension.create({
|
|
6
|
-
name: '
|
|
5
|
+
name: 'ai_component',
|
|
7
6
|
|
|
8
7
|
addCommands() {
|
|
9
8
|
return {
|
|
10
|
-
|
|
9
|
+
getAiSettings: createCommand(() => {
|
|
10
|
+
return this.options.aiComponent.settings;
|
|
11
|
+
}),
|
|
11
12
|
|
|
12
|
-
generateText: createCommand(async ({ commands }, { prompt, context }) => {
|
|
13
|
+
generateText: createCommand(async ({ commands }, { prompt, context, instructions }) => {
|
|
13
14
|
const aiComponent = this.options.aiComponent;
|
|
14
|
-
const result = await aiComponent.generateText({ prompt, context });
|
|
15
|
+
const result = await aiComponent.generateText({ prompt, context, instructions });
|
|
15
16
|
|
|
16
17
|
result.content = result.content.replace(/\n/g, '');
|
|
17
18
|
return result;
|