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

Implement tone of voice options to the plugin #25

Merged
merged 52 commits into from
Oct 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
4c7c4ba
removed api declaration
heikkivihersalo Oct 20, 2024
ba9f5b8
moved types from component files
heikkivihersalo Oct 20, 2024
b097fd2
fixed change event typing
heikkivihersalo Oct 20, 2024
59d7f53
get types from global declarations
heikkivihersalo Oct 20, 2024
7bcb26f
initial commit
heikkivihersalo Oct 20, 2024
1f7cfca
initial commit
heikkivihersalo Oct 20, 2024
0b6f733
added select tone
heikkivihersalo Oct 20, 2024
70fae78
added select tone
heikkivihersalo Oct 20, 2024
5e9b74b
set keys to contain full tone
heikkivihersalo Oct 20, 2024
dcd8b54
initial commit
heikkivihersalo Oct 20, 2024
ad1490c
change name to only as select
heikkivihersalo Oct 20, 2024
2fc10c6
change name to select
heikkivihersalo Oct 20, 2024
3b2a4cf
change select as global element
heikkivihersalo Oct 20, 2024
2ccc58d
add select
heikkivihersalo Oct 20, 2024
dbc23a2
add tone of voice
heikkivihersalo Oct 20, 2024
2b4abae
fix types to accept different types of change events
heikkivihersalo Oct 20, 2024
32df30b
get options from parent element
heikkivihersalo Oct 20, 2024
9f7c088
add tone of voice to settings
heikkivihersalo Oct 20, 2024
d058210
fixed encryptor init
heikkivihersalo Oct 20, 2024
d4fcd20
undefined to select props
heikkivihersalo Oct 20, 2024
ec243c4
fixed when value is null
heikkivihersalo Oct 20, 2024
9150ed9
add tone of voice to the prompt
heikkivihersalo Oct 20, 2024
9a5c8f0
add reasoning to prompts
heikkivihersalo Oct 20, 2024
de33c49
moved component from pages
heikkivihersalo Oct 21, 2024
767af1f
added tone of voice to chatgpt requests
heikkivihersalo Oct 21, 2024
443b633
moved content to index
heikkivihersalo Oct 21, 2024
932c71c
get tone of voice from frontend
heikkivihersalo Oct 21, 2024
a3f3ce3
add new line
heikkivihersalo Oct 21, 2024
d9934e7
fixed import
heikkivihersalo Oct 21, 2024
a45be32
refactored folder structure
heikkivihersalo Oct 21, 2024
2a31d10
base settings component as index
heikkivihersalo Oct 21, 2024
2d2c4bc
moved under components folder
heikkivihersalo Oct 21, 2024
f87820a
added popover menu
heikkivihersalo Oct 21, 2024
6dccf3f
added popover menu
heikkivihersalo Oct 21, 2024
e406930
get mode from own store object
heikkivihersalo Oct 21, 2024
5b4d937
get mode from own object
heikkivihersalo Oct 21, 2024
215822f
add mode
heikkivihersalo Oct 21, 2024
7380e1a
add mode
heikkivihersalo Oct 21, 2024
27c5743
add settings controls
heikkivihersalo Oct 21, 2024
94ba738
add mode reducer
heikkivihersalo Oct 21, 2024
af82c56
add get settings resolver
heikkivihersalo Oct 21, 2024
aa33ea7
add get mode
heikkivihersalo Oct 21, 2024
50f865b
add mode, resolver and controls
heikkivihersalo Oct 21, 2024
938279a
add mode and tone of voice
heikkivihersalo Oct 21, 2024
09ebb8a
add mode to store
heikkivihersalo Oct 21, 2024
8f70a4a
allow ts imports
heikkivihersalo Oct 21, 2024
cfcc50a
set tone of voice
heikkivihersalo Oct 21, 2024
64f6d56
added sub menu styling
heikkivihersalo Oct 21, 2024
8634811
added select module styles
heikkivihersalo Oct 21, 2024
aa56b18
add mode jsdoc param and more specific return type
heikkivihersalo Oct 21, 2024
eabfd48
fix jsdoc
heikkivihersalo Oct 21, 2024
daa082b
add jsdoc
heikkivihersalo Oct 21, 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
96 changes: 83 additions & 13 deletions includes/api/class-utils.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,17 +37,19 @@ public static function get_chatgpt_settings(): array {
$settings = get_option(
'gutenberg_native_ai',
array(
'model' => 'gpt-4o-mini',
'api_key' => '',
'model' => 'gpt-4o-mini',
'api_key' => '',
'tone_of_voice' => 'none',
)
);

$encryptor = new Encryption();
$decrypted_api_key = $encryptor->decrypt( $settings['api_key'] );

return array(
'model' => $settings['model'],
'api_key' => $decrypted_api_key,
'model' => $settings['model'],
'api_key' => $decrypted_api_key,
'tone_of_voice' => $settings['tone_of_voice'],
);
}

Expand All @@ -69,14 +71,15 @@ public static function update_chatgpt_settings( \WP_REST_Request $request ): arr
return $current;
}

$encryptor = new \Kotisivu\Gutenberg_Native_AI\Data_Encryption();
$encryptor = new Encryption();
$encrypted_api_key = $encryptor->encrypt( $body['api_key'] ?? $current['api_key'] ?? '' );

$update = update_option(
'gutenberg_native_ai',
array(
'model' => $body['model'] ?? $current['model'] ?? 'gpt-4o-mini',
'api_key' => $encrypted_api_key,
'model' => $body['model'] ?? $current['model'] ?? 'gpt-4o-mini',
'api_key' => $encrypted_api_key,
'tone_of_voice' => $body['tone_of_voice'] ?? $current['tone_of_voice'] ?? 'none',
),
true
);
Expand All @@ -86,11 +89,77 @@ public static function update_chatgpt_settings( \WP_REST_Request $request ): arr
}

return array(
'model' => $body['model'] ?? $current['model'] ?? 'gpt-4o-mini',
'api_key' => $body['api_key'] ?? $current['api_key'] ?? '',
'model' => $body['model'] ?? $current['model'] ?? 'gpt-4o-mini',
'api_key' => $body['api_key'] ?? $current['api_key'] ?? '',
'tone_of_voice' => $body['tone_of_voice'] ?? $current['tone_of_voice'] ?? 'none',
);
}

/**
* Get system instructions for text prompts
*
* @since 0.1.3
* @access private
* @param string $tone_of_voice The tone of voice.
* @return string
*/
private static function get_system_instructions_for_text_prompts( string $tone_of_voice ): string {
/**
* Set base instructions for AI text prompts
* To get the result that can be converted to Gutenberg blocks, we must use markdown format and return only the result.
* Otherwise, the AI might return additional content like the prompt itself or other unnecessary information.
*/
$base_instructions = 'You are a helpful assistant that returns text in markdown format. Return only the result.';

/**
* Set tone of voice instructions
* If the tone of voice is not set, return the base instructions.
* Otherwise, add the tone of voice to the base instructions.
*/
switch ( $tone_of_voice ) {
case 'none':
return $base_instructions;

case 'friendly-professional':
return $base_instructions . ' You are expected to use a friendly and professional tone of voice.';

case 'authoritative-informative':
return $base_instructions . ' You are expected to use an authoritative and informative tone of voice.';

case 'urgent-persuasive':
return $base_instructions . ' You are expected to use an urgent and persuasive tone of voice.';

case 'casual-conversational':
return $base_instructions . ' You are expected to use a casual and conversational tone of voice.';

case 'professional-trustworthy':
return $base_instructions . ' You are expected to use a professional and trustworthy tone of voice.';

case 'humorous-informal':
return $base_instructions . ' You are expected to use a humorous and informal tone of voice.';

case 'professional-straightforward':
return $base_instructions . ' You are expected to use a professional and straightforward tone of voice.';

case 'serious-empathetic':
return $base_instructions . ' You are expected to use a serious and empathetic tone of voice.';

case 'positive-enthusiastic':
return $base_instructions . ' You are expected to use a positive and enthusiastic tone of voice.';

case 'authoritative-professional':
return $base_instructions . ' You are expected to use an authoritative and professional tone of voice.';

case 'casual-funny':
return $base_instructions . ' You are expected to use a casual and funny tone of voice.';

case 'authoritative-expert':
return $base_instructions . ' You are expected to use an authoritative and expert tone of voice.';
default:
return $base_instructions;
}
}

/**
* Get content from Open AI
*
Expand All @@ -101,14 +170,15 @@ public static function update_chatgpt_settings( \WP_REST_Request $request ): arr
* @throws \Exception If failed to update contact information.
*/
public static function get_open_ai_text_content( \WP_REST_Request $request ): array {
$body = json_decode( $request->get_body(), true );
$api = self::get_chatgpt_settings();
$data = array(
$body = json_decode( $request->get_body(), true );
$api = self::get_chatgpt_settings();
$tone_of_voice = $body['tone_of_voice'] ?? 'none';
$data = array(
'model' => $api['model'] ?? 'gpt-4o-mini',
'messages' => array(
(object) array(
'role' => 'system',
'content' => 'You are a helpful assistant that returns text in markdown format. Return only the result.',
'content' => self::get_system_instructions_for_text_prompts( $tone_of_voice ),
),
(object) array(
'role' => 'user',
Expand Down
2 changes: 2 additions & 0 deletions src/constants/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ export const ACTIONS = {
SET_IMAGE: 'SET_IMAGE',
GET_SELECTION: 'GET_SELECTION',
SET_SELECTION: 'SET_SELECTION',
GET_MODE: 'GET_MODE',
SET_MODE: 'SET_MODE',
GET_SETTINGS: 'GET_SETTINGS',
SET_SETTINGS: 'SET_SETTINGS',
SET_STATUS: 'SET_STATUS',
Expand Down
5 changes: 5 additions & 0 deletions src/constants/modal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ export const MODAL_STATUS = {
ERROR: 'error',
};

export const MODAL_MODE = {
TEXT: 'text',
IMAGE: 'image',
};

export const ALLOWED_TEXT_BLOCKS = [
'core/paragraph',
'core/heading',
Expand Down
53 changes: 53 additions & 0 deletions src/constants/options.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { __ } from '@wordpress/i18n';

export const TONE_OF_VOICE = [
{ value: 'none', label: __('None', 'gutenberg-native-ai') },
{
value: 'friendly-professional',
label: __('Friendly and Professional', 'gutenberg-native-ai'),
},
{
value: 'authoritative-informative',
label: __('Authoritative and Informative', 'gutenberg-native-ai'),
},
{
value: 'urgent-persuasive',
label: __('Urgent and Persuasive', 'gutenberg-native-ai'),
},
{
value: 'casual-conversational',
label: __('Casual and Conversational', 'gutenberg-native-ai'),
},
{
value: 'professional-trustworthy',
label: __('Professional and Trustworthy', 'gutenberg-native-ai'),
},
{
value: 'humorous-informal',
label: __('Humorous and Informal', 'gutenberg-native-ai'),
},
{
value: 'professional-straightforward',
label: __('Professional and Straightforward', 'gutenberg-native-ai'),
},
{
value: 'serious-empathetic',
label: __('Serious and Empathetic', 'gutenberg-native-ai'),
},
{
value: 'positive-enthusiastic',
label: __('Positive and Enthusiastic', 'gutenberg-native-ai'),
},
{
value: 'authoritative-professional',
label: __('Authoritative and Professional', 'gutenberg-native-ai'),
},
{
value: 'casual-funny',
label: __('Casual and Funny', 'gutenberg-native-ai'),
},
{
value: 'authoritative-expert',
label: __('Authoritative and Expert', 'gutenberg-native-ai'),
},
];
1 change: 1 addition & 0 deletions src/features/admin/components/inputs/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from './lib/Input';
export * from './lib/Toggle';
export * from './lib/Select';
16 changes: 2 additions & 14 deletions src/features/admin/components/inputs/lib/Input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,10 @@
*/
import styles from './Input.module.css';

type InputType = 'text' | 'textarea' | 'number' | 'email';

type InputProps = {
type: InputType;
label: string;
name: string;
value: string | number | readonly string[] | undefined;
placeholder?: string;
onChange?: React.ChangeEventHandler<HTMLInputElement>;
disabled?: boolean;
};

/**
* Component for number input
* @param {Object} props - Component props
* @param {InputType} props.type - Type of the input
* @param {FormInputType} props.type - Type of the input
* @param {string} props.label - Label for the input
* @param {string} props.name - Name for the input
* @param {string} props.value - Value for the input
Expand All @@ -35,7 +23,7 @@ const Input = ({
placeholder = '',
onChange = () => {},
disabled = false,
}: InputProps): JSX.Element => {
}: FormInputProps): JSX.Element => {
return (
<div className={styles.input}>
<label htmlFor={name}>{label}</label>
Expand Down
10 changes: 10 additions & 0 deletions src/features/admin/components/inputs/lib/Select.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
.select {
display: grid;
grid-template-columns: 5rem 1fr;
align-items: center;
gap: 1rem;
}

.select > label {
line-height: 1.1;
}
42 changes: 42 additions & 0 deletions src/features/admin/components/inputs/lib/Select.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/**
* Internal dependencies
*/
import styles from './Select.module.css';

/**
* Select Component
* @param {Object} props - Component props
* @param {string} props.label - Label for the select
* @param {string} props.name - Name of the select
* @param {string} props.value - Value of the select
* @param {Array} props.options - Options for the select
* @param {Function} props.onChange - Change handler for the select
* @return {JSX.Element} Toggle component
*/
const Select = ({
label,
name,
value,
options,
onChange,
}: FormSelectProps): JSX.Element => {
return (
<div className={styles.select}>
<label htmlFor={name}>{label}</label>
<select
id={name}
name={name}
value={value || undefined}
onChange={onChange}
>
{options.map((option) => (
<option key={option.value} value={option.value}>
{option.label}
</option>
))}
</select>
</div>
);
};

export { Select };
10 changes: 1 addition & 9 deletions src/features/admin/components/inputs/lib/Toggle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,6 @@
*/
import styles from './Toggle.module.css';

type ToggleProps = {
label: string;
name: string;
checked: boolean;
onChange: (event: React.MouseEvent<HTMLInputElement, MouseEvent>) => void;
hideLabel?: boolean;
};

/**
* Toggle Component
* @param {Object} props - Component props
Expand All @@ -27,7 +19,7 @@ const Toggle = ({
checked,
onChange,
hideLabel = false,
}: ToggleProps): JSX.Element => {
}: FormToggleProps): JSX.Element => {
return (
<div className={styles.toggle}>
<label htmlFor={name}>
Expand Down
Loading