Skip to content

Commit 355582b

Browse files
authored
Merge pull request #843 from 10up/feature/tldr-block
Add new Key Takeaways Feature
2 parents 477da51 + a94dc0a commit 355582b

File tree

18 files changed

+1250
-1
lines changed

18 files changed

+1250
-1
lines changed

README.md

+5
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ Tap into leading cloud-based services like [OpenAI](https://openai.com/), [Micro
1717
## Features
1818

1919
* Generate a summary of post content and store it as an excerpt using [OpenAI's ChatGPT API](https://platform.openai.com/docs/guides/chat), [Microsoft Azure's OpenAI service](https://azure.microsoft.com/en-us/products/ai-services/openai-service) or [Google's Gemini API](https://ai.google.dev/docs/gemini_api_overview)
20+
* Generate key takeaways from post content and render at the top of a post using [OpenAI's ChatGPT API](https://platform.openai.com/docs/guides/chat) or [Microsoft Azure's OpenAI service](https://azure.microsoft.com/en-us/products/ai-services/openai-service)
2021
* Generate titles from post content using [OpenAI's ChatGPT API](https://platform.openai.com/docs/guides/chat), [Microsoft Azure's OpenAI service](https://azure.microsoft.com/en-us/products/ai-services/openai-service) or [Google's Gemini API](https://ai.google.dev/docs/gemini_api_overview)
2122
* Expand or condense text content using [OpenAI's ChatGPT API](https://platform.openai.com/docs/guides/chat), [Microsoft Azure's OpenAI service](https://azure.microsoft.com/en-us/products/ai-services/openai-service) or [Google's Gemini API](https://ai.google.dev/docs/gemini_api_overview)
2223
* Generate new images on demand to use in-content or as a featured image using [OpenAI's DALL·E 3 API](https://platform.openai.com/docs/guides/images)
@@ -41,6 +42,10 @@ Tap into leading cloud-based services like [OpenAI](https://openai.com/), [Micro
4142
| :-: | :-: | :-: | :-: |
4243
| ![Screenshot of ClassifAI audio transcript generation](assets/img/screenshot-9.png "Example of automatic audio transcript generation with OpenAI.") | ![Screenshot of ClassifAI title generation](assets/img/screenshot-10.png "Example of automatic title generation with OpenAI.") | ![Screenshot of ClassifAI expand/condense text feature](assets/img/screenshot-12.png "Example of expanding or condensing text with OpenAI.") | ![Screenshot of ClassifAI text to speech generation](assets/img/screenshot-11.png "Example of automatic text to speech generation with Azure.") |
4344

45+
| Key Takeaways | | | |
46+
| :-: | :-: | :-: | :-: |
47+
| ![Screenshot of the ClassifAI Key Takeaways block](assets/img/screenshot-14.png "Example of generating key takeaways using OpenAI.") | | | |
48+
4449
### Image Processing
4550

4651
| Alt Text | Smart Cropping | Tagging | Generate Images |

assets/img/screenshot-14.png

103 KB
Loading
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
{
2+
"$schema": "https://schemas.wp.org/trunk/block.json",
3+
"apiVersion": 3,
4+
"title": "Key Takeaways",
5+
"description": "Generate a list of key takeaways from post content",
6+
"textdomain": "classifai",
7+
"name": "classifai/key-takeaways",
8+
"category": "text",
9+
"keywords": [ "tldr", "summary", "takeaways", "abstract" ],
10+
"attributes": {
11+
"render": {
12+
"type": "string",
13+
"default": "list"
14+
},
15+
"title": {
16+
"type": "string",
17+
"default": "Key Takeaways"
18+
},
19+
"takeaways": {
20+
"type": "array",
21+
"default": []
22+
}
23+
},
24+
"supports": {
25+
"html": false,
26+
"multiple": false
27+
},
28+
"editorScript": "key-takeaways-editor-script",
29+
"style": "file:./style.css",
30+
"render": "file:./render.php"
31+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
/**
2+
* WordPress dependencies
3+
*/
4+
import {
5+
useBlockProps,
6+
BlockControls,
7+
InspectorControls,
8+
RichText,
9+
} from '@wordpress/block-editor';
10+
import { select } from '@wordpress/data';
11+
import {
12+
Placeholder,
13+
ToolbarGroup,
14+
Spinner,
15+
PanelBody,
16+
Button,
17+
} from '@wordpress/components';
18+
import { useEffect, useState } from '@wordpress/element';
19+
import { postList, paragraph } from '@wordpress/icons';
20+
import { __ } from '@wordpress/i18n';
21+
import apiFetch from '@wordpress/api-fetch';
22+
23+
/**
24+
* Internal dependencies
25+
*/
26+
import { ReactComponent as icon } from '../../../../assets/img/block-icon.svg';
27+
28+
const BlockEdit = ( props ) => {
29+
const [ isLoading, setIsLoading ] = useState( false );
30+
const [ run, setRun ] = useState( false );
31+
const { attributes, setAttributes } = props;
32+
const { render, takeaways, title } = attributes;
33+
const blockProps = useBlockProps();
34+
35+
useEffect( () => {
36+
if ( ( ! isLoading && takeaways.length === 0 ) || run ) {
37+
const postId = select( 'core/editor' ).getCurrentPostId();
38+
const postContent =
39+
select( 'core/editor' ).getEditedPostAttribute( 'content' );
40+
const postTitle =
41+
select( 'core/editor' ).getEditedPostAttribute( 'title' );
42+
43+
setRun( false );
44+
setIsLoading( true );
45+
46+
apiFetch( {
47+
path: '/classifai/v1/key-takeaways/',
48+
method: 'POST',
49+
data: {
50+
id: postId,
51+
content: postContent,
52+
title: postTitle,
53+
render,
54+
},
55+
} ).then(
56+
async ( res ) => {
57+
// Ensure takeaways is always an array.
58+
if ( ! Array.isArray( res ) ) {
59+
res = [ res ];
60+
}
61+
62+
setAttributes( { takeaways: res } );
63+
setIsLoading( false );
64+
},
65+
( err ) => {
66+
setAttributes( {
67+
takeaways: [ `Error: ${ err?.message }` ],
68+
} );
69+
setIsLoading( false );
70+
}
71+
);
72+
}
73+
}, [ run ] );
74+
75+
const renderControls = [
76+
{
77+
icon: postList,
78+
title: __( 'List view', 'classifai' ),
79+
onClick: () => setAttributes( { render: 'list' } ),
80+
isActive: render === 'list',
81+
},
82+
{
83+
icon: paragraph,
84+
title: __( 'Paragraph view', 'classifai' ),
85+
onClick: () => setAttributes( { render: 'paragraph' } ),
86+
isActive: render === 'paragraph',
87+
},
88+
];
89+
90+
const editTakeaways = ( index, value ) => {
91+
const newTakeaways = [ ...takeaways ];
92+
93+
if ( ! value ) {
94+
newTakeaways.splice( index, 1 );
95+
} else {
96+
newTakeaways[ index ] = value;
97+
}
98+
99+
setAttributes( {
100+
takeaways: newTakeaways,
101+
} );
102+
};
103+
104+
return (
105+
<>
106+
<BlockControls>
107+
<ToolbarGroup controls={ renderControls } />
108+
</BlockControls>
109+
<InspectorControls>
110+
<PanelBody title={ __( 'Settings', 'classifai' ) }>
111+
<Button
112+
label={ __( 'Re-generate key takeaways', 'classifai' ) }
113+
text={ __( 'Refresh results', 'classifai' ) }
114+
variant={ 'secondary' }
115+
onClick={ () => setRun( true ) }
116+
isBusy={ isLoading }
117+
/>
118+
</PanelBody>
119+
</InspectorControls>
120+
121+
{ isLoading && (
122+
<Placeholder
123+
icon={ icon }
124+
label={ __( 'Generating Key Takeaways', 'classifai' ) }
125+
>
126+
<Spinner
127+
style={ {
128+
height: 'calc(4px * 10)',
129+
width: 'calc(4px * 10)',
130+
} }
131+
/>
132+
</Placeholder>
133+
) }
134+
135+
{ ! isLoading && (
136+
<div { ...blockProps }>
137+
<RichText
138+
tagName="h2"
139+
className="wp-block-heading wp-block-classifai-key-takeaways__title"
140+
value={ title }
141+
onChange={ ( value ) =>
142+
setAttributes( { title: value } )
143+
}
144+
placeholder="Key Takeaways"
145+
/>
146+
<div
147+
className="wp-block-classifai-key-takeways__content"
148+
style={ { fontStyle: 'italic' } }
149+
>
150+
{ render === 'list' && (
151+
<ul>
152+
{ takeaways.map( ( takeaway, index ) => (
153+
<RichText
154+
tagName="li"
155+
value={ takeaway }
156+
key={ index }
157+
onChange={ ( value ) =>
158+
editTakeaways( index, value )
159+
}
160+
/>
161+
) ) }
162+
</ul>
163+
) }
164+
{ render === 'paragraph' && (
165+
<>
166+
{ takeaways.map( ( takeaway, index ) => (
167+
<RichText
168+
tagName="p"
169+
value={ takeaway }
170+
key={ index }
171+
onChange={ ( value ) =>
172+
editTakeaways( index, value )
173+
}
174+
/>
175+
) ) }
176+
</>
177+
) }
178+
</div>
179+
</div>
180+
) }
181+
</>
182+
);
183+
};
184+
185+
export default BlockEdit;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/**
2+
* Key Takeaways block
3+
*/
4+
5+
/**
6+
* WordPress dependencies
7+
*/
8+
import { registerBlockType } from '@wordpress/blocks';
9+
10+
/**
11+
* Internal dependencies
12+
*/
13+
import edit from './edit';
14+
import save from './save';
15+
import block from './block.json';
16+
import { ReactComponent as icon } from '../../../../assets/img/block-icon.svg';
17+
18+
/**
19+
* Register block
20+
*/
21+
registerBlockType( block, {
22+
edit,
23+
save,
24+
icon,
25+
} );
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php
2+
/**
3+
* Render callback for the Key Takeaways block.
4+
*
5+
* @var array $attributes Block attributes.
6+
* @var string $content Block content.
7+
* @var WP_Block $block Block instance.
8+
*/
9+
10+
$block_title = $attributes['title'] ?? '';
11+
$layout = $attributes['render'] ?? 'list';
12+
$takeaways = $attributes['takeaways'] ?? [];
13+
?>
14+
15+
<div <?php echo get_block_wrapper_attributes(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>>
16+
<?php if ( $block_title ) : ?>
17+
<h2 class="wp-block-heading wp-block-classifai-key-takeaways__title">
18+
<?php echo wp_kses_post( $block_title ); ?>
19+
</h2>
20+
<?php endif; ?>
21+
22+
<div class="wp-block-classifai-key-takeaways__content">
23+
<?php
24+
if ( 'list' === $layout ) {
25+
echo '<ul>';
26+
foreach ( (array) $takeaways as $takeaway ) {
27+
printf(
28+
'<li>%s</li>',
29+
esc_html( $takeaway )
30+
);
31+
}
32+
echo '</ul>';
33+
} else {
34+
foreach ( (array) $takeaways as $takeaway ) {
35+
printf(
36+
'<p>%s</p>',
37+
esc_html( $takeaway )
38+
);
39+
}
40+
}
41+
?>
42+
</div>
43+
</div>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
/**
2+
* See https://wordpress.org/gutenberg/handbook/designers-developers/developers/block-api/block-edit-save/#save
3+
*
4+
* @return {null} Dynamic blocks do not save the HTML.
5+
*/
6+
const BlockSave = () => null;
7+
8+
export default BlockSave;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.wp-block-classifai-key-takeaways__content {
2+
font-style: italic;
3+
}

0 commit comments

Comments
 (0)