@zipify/wysiwyg 3.5.1-ai-prototype → 3.5.3-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.
@@ -1,12 +1,12 @@
1
1
  export const aiAdapter = {
2
- generateText: async ({ prompt, context, istruction }) => {
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) {
@@ -18,5 +18,35 @@ export const aiAdapter = {
18
18
  // eslint-disable-next-line no-console
19
19
  console.error('An error occurred while sending the request:', error);
20
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
+ ]
21
51
  }
22
52
  };
@@ -50,7 +50,7 @@
50
50
  </template>
51
51
 
52
52
  <script>
53
- import { inject, ref, unref, computed } from 'vue';
53
+ import { inject, ref, unref, computed, watch } from 'vue';
54
54
  import { FloatingMenu } from '@tiptap/vue-2';
55
55
  import { Button, Icon, Modal, useModalToggler } from '../base';
56
56
  import { InjectionTokens } from '../../injectionTokens';
@@ -83,6 +83,20 @@ export default {
83
83
 
84
84
  const selectedText = computed(() => editor.commands.getSelectedText());
85
85
 
86
+ const settings = ref({
87
+ tone: '',
88
+ textLength: '500',
89
+ textStyle: ''
90
+ });
91
+
92
+ if (localStorage.getItem('ai-settings')) {
93
+ settings.value = JSON.parse(localStorage.getItem('ai-settings'));
94
+ }
95
+
96
+ watch(settings, () => {
97
+ localStorage.setItem('ai-settings', JSON.stringify(settings.value));
98
+ });
99
+
86
100
  const iconName = computed(() => {
87
101
  return unref(isLoading) ? 'loading' : 'send';
88
102
  });
@@ -111,7 +125,11 @@ export default {
111
125
 
112
126
  const context = lastSuggestions ? lastSuggestions.content : selectedText.value;
113
127
 
114
- const result = await editor.commands.generateText({ prompt: prompt.value, context });
128
+ const result = await editor.commands.generateText({
129
+ prompt: prompt.value,
130
+ instructions: unref(settings),
131
+ context
132
+ });
115
133
 
116
134
  isLoading.value = false;
117
135
  suggestions.value.push(result);
@@ -5,18 +5,15 @@
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
- <AiSuggestionItem
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
13
  <AiSuggestionItem
18
14
  v-else-if="lastSuggestions"
19
15
  :suggestion="lastSuggestions"
16
+ @action="onAction"
20
17
  />
21
18
 
22
19
  <label class="zw-field__label">
@@ -24,32 +21,30 @@
24
21
  </label>
25
22
 
26
23
  <div class="zw-position--relative">
27
- <TextArea
28
- class="zw-margin-bottom--sm"
29
- v-model="prompt"
30
- />
24
+ <TextArea class="zw-margin-bottom--sm" v-model="prompt" />
31
25
  <Button type="submit" class="zw-ai-component__send-button">
32
26
  <Icon auto-color class="zw-ai-component__icon" name="send" size="32px" />
33
27
  </Button>
34
28
  </div>
35
29
 
30
+ <AiSettings v-model="settings" />
31
+
36
32
  <Button :disabled="!lastSuggestions" type="button" skin="primary" @click="applyText">
37
33
  Apply
38
34
  </Button>
39
35
  </form>
40
-
41
-
42
36
  </Modal>
43
37
  </div>
44
38
  </template>
45
39
 
46
40
  <script>
47
- import { computed, ref, inject, unref } from 'vue';
41
+ import { computed, ref, inject, unref, watch } from 'vue';
48
42
  import { InjectionTokens } from '../../../../injectionTokens';
49
43
  import { tooltip } from '../../../../directives';
50
44
  import { Button, Icon, Modal, TextArea, useModalToggler } from '../../../base';
51
45
  import AiControlHeader from './AiControlHeader';
52
46
  import AiSuggestionItem from './AiSuggestionItem';
47
+ import AiSettings from './AiSettings';
53
48
 
54
49
  export default {
55
50
  name: 'AiControl',
@@ -60,7 +55,8 @@ export default {
60
55
  Button,
61
56
  TextArea,
62
57
  AiControlHeader,
63
- AiSuggestionItem
58
+ AiSuggestionItem,
59
+ AiSettings
64
60
  },
65
61
 
66
62
  directives: {
@@ -75,6 +71,20 @@ export default {
75
71
  const suggestions = ref([]);
76
72
  const isLoading = ref(false);
77
73
 
74
+ const settings = ref({
75
+ tone: '',
76
+ textLength: '500',
77
+ textStyle: ''
78
+ });
79
+
80
+ if (localStorage.getItem('ai-settings')) {
81
+ settings.value = JSON.parse(localStorage.getItem('ai-settings'));
82
+ }
83
+
84
+ watch(settings, () => {
85
+ localStorage.setItem('ai-settings', JSON.stringify(settings.value));
86
+ });
87
+
78
88
  const textAreaLabel = computed(() => {
79
89
  return suggestions.value.length ? 'Tell AI what to do next…' : 'Write you request';
80
90
  });
@@ -83,7 +93,7 @@ export default {
83
93
 
84
94
  const editor = inject(InjectionTokens.EDITOR);
85
95
 
86
- const onBeforeOpened = () => {};
96
+ const onBeforeOpened = () => { };
87
97
 
88
98
  const toggler = useModalToggler({
89
99
  onBeforeOpened: () => onBeforeOpened(),
@@ -97,23 +107,29 @@ export default {
97
107
  const lastSuggestions = suggestions.value[suggestions.value.length - 1];
98
108
 
99
109
  const context = lastSuggestions ? lastSuggestions.content : '';
100
-
101
- const result = await editor.commands.generateText({ prompt: action, context });
110
+ const result = await editor.commands.generateText({
111
+ prompt: action,
112
+ context,
113
+ instructions: unref(settings)
114
+ });
102
115
 
103
116
  isLoading.value = false;
104
117
  suggestions.value.push(result);
105
118
  };
106
119
 
107
120
  const generateText = async () => {
108
- if(isLoading.value) return;
121
+ if (isLoading.value) return;
109
122
 
110
123
  isLoading.value = true;
111
124
 
112
125
  const lastSuggestions = suggestions.value[suggestions.value.length - 1];
113
126
 
114
127
  const context = lastSuggestions ? lastSuggestions.content : '';
115
-
116
- const result = await editor.commands.generateText({ prompt: prompt.value, context });
128
+ const result = await editor.commands.generateText({
129
+ prompt: prompt.value,
130
+ context,
131
+ instructions: unref(settings)
132
+ });
117
133
 
118
134
  isLoading.value = false;
119
135
  prompt.value = '';
@@ -121,7 +137,8 @@ export default {
121
137
  };
122
138
 
123
139
  const applyText = () => {
124
- editor.commands.setContent(lastSuggestions.value.content);
140
+ editor.commands.clearContent(true);
141
+ editor.commands.insertContent(lastSuggestions.value.content);
125
142
  toggler.close();
126
143
  suggestions.value = [];
127
144
  prompt.value = '';
@@ -140,7 +157,8 @@ export default {
140
157
  textAreaLabel,
141
158
  isLoading,
142
159
  onAction,
143
- applyText
160
+ applyText,
161
+ settings
144
162
  };
145
163
  }
146
164
  };
@@ -0,0 +1,153 @@
1
+ <template>
2
+ <div>
3
+ <h4>Settings</h4>
4
+ <div class="zw-selectors ">
5
+ <div class="zw-ai__dropdown zw-margin-right--xs">
6
+ <FieldLabel class="zw-margin-bottom--xxs">
7
+ Tone
8
+ </FieldLabel>
9
+
10
+ <Dropdown
11
+ class="zw-margin-bottom--sm"
12
+ color="gray"
13
+ :value="settings.tone"
14
+ :options="tones"
15
+ @change="changeTone"
16
+ >
17
+ <template #option="{ option }">
18
+ <DropdownOption
19
+ class="zw-link-modal-dropdown__option"
20
+ :option="option"
21
+ />
22
+ </template>
23
+ </Dropdown>
24
+ </div>
25
+
26
+ <div class="zw-ai__dropdown zw-margin-right--xs ">
27
+ <FieldLabel class="zw-margin-bottom--xxs">
28
+ Text Style
29
+ </FieldLabel>
30
+
31
+ <Dropdown
32
+ class="zw-margin-bottom--sm"
33
+ color="gray"
34
+ :value="settings.textStyle"
35
+ :options="textStyles"
36
+ @change="changeTextStyle"
37
+ >
38
+ <template #option="{ option }">
39
+ <DropdownOption
40
+ class="zw-link-modal-dropdown__option"
41
+ :option="option"
42
+ />
43
+ </template>
44
+ </Dropdown>
45
+ </div>
46
+
47
+ <div class="zw-ai__dropdown">
48
+ <FieldLabel class="zw-margin-bottom--xxs">
49
+ Length
50
+ </FieldLabel>
51
+
52
+ <Dropdown
53
+ class="zw-margin-bottom--sm"
54
+ color="gray"
55
+ :value="settings.textLength"
56
+ :options="textLength"
57
+ @change="changeTextLength"
58
+ >
59
+ <template #option="{ option }">
60
+ <DropdownOption
61
+ class="zw-link-modal-dropdown__option"
62
+ :option="option"
63
+ />
64
+ </template>
65
+ </Dropdown>
66
+ </div>
67
+ </div>
68
+ <Checkbox
69
+ class="zw-margin-bottom--sm"
70
+ label="Use block context"
71
+ :value="settings.useBlockContext"
72
+ @input="changUseBlockContext"
73
+ />
74
+ </div>
75
+ </template>
76
+
77
+ <script>
78
+ import { computed, inject } from 'vue';
79
+ import { FieldLabel, Dropdown, DropdownOption, Checkbox } from '../../../base';
80
+ import { InjectionTokens } from '../../../../injectionTokens';
81
+
82
+ export default {
83
+ name: 'AiSettings',
84
+
85
+ components: {
86
+ FieldLabel,
87
+ Dropdown,
88
+ DropdownOption,
89
+ Checkbox
90
+ },
91
+
92
+ props: {
93
+ value: {
94
+ type: Object,
95
+ default: () => ({})
96
+ }
97
+ },
98
+
99
+ setup(props, { emit }) {
100
+ const settings = computed(() => {
101
+ return {
102
+ tone: props.value.tone,
103
+ textStyle: props.value.textStyle,
104
+ textLength: props.value.textLength,
105
+ useBlockContext: props.value.useBlockContext
106
+ };
107
+ });
108
+
109
+ const editor = inject(InjectionTokens.EDITOR);
110
+ const tones = editor.commands.getAiSettings().tones;
111
+ const textStyles = editor.commands.getAiSettings().textStyles;
112
+ const textLength = editor.commands.getAiSettings().textLength;
113
+
114
+ const changeTone = (value) => {
115
+ settings.value.tone = value;
116
+ emit('input', settings.value);
117
+ };
118
+ const changeTextStyle = (value) => {
119
+ settings.value.textStyle = value;
120
+ emit('input', settings.value);
121
+ };
122
+ const changeTextLength = (value) => {
123
+ settings.value.textLength = value;
124
+ emit('input', settings.value);
125
+ };
126
+ const changUseBlockContext = (value) => {
127
+ settings.value.useBlockContext = value;
128
+ emit('input', settings.value);
129
+ };
130
+
131
+ return {
132
+ tones,
133
+ textStyles,
134
+ textLength,
135
+ changeTone,
136
+ changeTextStyle,
137
+ changeTextLength,
138
+ changUseBlockContext,
139
+ settings
140
+ };
141
+ }
142
+ };
143
+ </script>
144
+
145
+ <style scoped>
146
+ .zw-selectors {
147
+ display: flex;
148
+ }
149
+
150
+ .zw-ai__dropdown {
151
+ width: 100%;
152
+ }
153
+ </style>
@@ -5,16 +5,24 @@
5
5
  </p>
6
6
  <p :class="{'zw-margin-bottom--sm': !isLoading }" v-html="suggestion.content" />
7
7
 
8
- <Button type="button" v-if="!isLoading" @click="sendAction('Rewrite text')" class="zw-ai-component-suggestion__button">
9
- Rewrite text
8
+ <Button type="button" v-if="!isLoading" @click="sendAction($event, 'Rewrite text')" class="zw-ai-component-suggestion__button">
9
+ Rewrite
10
+ </Button>
11
+ <Button type="button" v-if="!isLoading" @click="sendAction($event, 'Simplify it')" class="zw-ai-component-suggestion__button">
12
+ Simplify it
13
+ </Button>
14
+ <Button type="button" v-if="!isLoading" @click="sendAction($event, 'Shorten it')" class="zw-ai-component-suggestion__button">
15
+ Shorten it
16
+ </Button>
17
+ <Button type="button" v-if="!isLoading" @click="sendAction($event, 'Make it exciting')" class="zw-ai-component-suggestion__button">
18
+ Make it exciting
10
19
  </Button>
11
20
  </div>
12
21
  </template>
13
22
 
14
23
  <script>
15
- import { inject, computed } from 'vue';
24
+ import { computed } from 'vue';
16
25
  import { Button } from '../../../base';
17
- import { InjectionTokens } from '../../../../injectionTokens';
18
26
 
19
27
  export default {
20
28
  name: 'AiSuggestionItem',
@@ -33,7 +41,8 @@ export default {
33
41
  setup(props, { emit }) {
34
42
  const isLoading = computed(() => props.suggestion.state === 'loading');
35
43
 
36
- const sendAction = (action) => {
44
+ const sendAction = (event, action) => {
45
+ event.stopPropagation();
37
46
  emit('action', action);
38
47
  };
39
48
 
@@ -65,6 +74,7 @@ export default {
65
74
  background-color: #A4A4A4;
66
75
  color: #FFF;
67
76
  border-radius: 2px;
77
+ margin-right: 8px;
68
78
  }
69
79
 
70
80
  .zw-ai-component-suggestion__button:hover {
@@ -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: 'device_manager',
5
+ name: 'ai_component',
7
6
 
8
7
  addCommands() {
9
8
  return {
10
- // _getAiAdapter: createCommand(() => toRef(this.options, 'device'))
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;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zipify/wysiwyg",
3
- "version": "3.5.1-ai-prototype",
3
+ "version": "3.5.3-ai-prototype",
4
4
  "description": "Zipify modification of TipTap text editor",
5
5
  "main": "dist/wysiwyg.mjs",
6
6
  "bin": {