Skip to content

Commit

Permalink
AI Assistant: Add long sentences feature to proofread (#38314)
Browse files Browse the repository at this point in the history
* add long sentences feature

* changelog

* fix ts test

* rename word to text

* fix popover on second-level highlight
  • Loading branch information
dhasilva authored Jul 15, 2024
1 parent 39a7ca4 commit 29f2c97
Show file tree
Hide file tree
Showing 13 changed files with 195 additions and 54 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: patch
Type: other

AI Assistant: Add long sentences feature to proofread
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
$features-colors: (
'complex-words': rgba( 240, 184, 73, 1 ),
'ambiguous-words': rgba( 0, 175, 82, 1 ),
'long-sentences': rgba( 122, 0, 223, 1 ),
);

@mixin properties( $feature, $color, $properties ) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import weaselWords from './words';
/**
* Types
*/
import type { BreveFeatureConfig, HighlightedWord } from '../../types';
import type { BreveFeatureConfig, HighlightedText } from '../../types';

export const AMBIGUOUS_WORDS: BreveFeatureConfig = {
name: 'ambiguous-words',
Expand All @@ -17,18 +17,18 @@ export const AMBIGUOUS_WORDS: BreveFeatureConfig = {

const list = new RegExp( `\\b(${ weaselWords.map( escapeRegExp ).join( '|' ) })\\b`, 'gi' );

export default function ambiguousWords( text: string ): Array< HighlightedWord > {
const matches = text.matchAll( list );
const highlightedWords: Array< HighlightedWord > = [];
export default function ambiguousWords( blockText: string ): Array< HighlightedText > {
const matches = blockText.matchAll( list );
const highlightedTexts: Array< HighlightedText > = [];

for ( const match of matches ) {
const word = match[ 0 ].trim();
highlightedWords.push( {
word,
const text = match[ 0 ].trim();
highlightedTexts.push( {
text,
startIndex: match.index,
endIndex: match.index + word.length,
endIndex: match.index + text.length,
} );
}

return highlightedWords;
return highlightedTexts;
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import phrases from './phrases';
/**
* Types
*/
import type { BreveFeatureConfig, HighlightedWord } from '../../types';
import type { BreveFeatureConfig, HighlightedText } from '../../types';

export const COMPLEX_WORDS: BreveFeatureConfig = {
name: 'complex-words',
Expand All @@ -20,19 +20,19 @@ const list = new RegExp(
'gi'
);

export default function complexWords( text: string ): Array< HighlightedWord > {
const matches = text.matchAll( list );
const highlightedWords: Array< HighlightedWord > = [];
export default function complexWords( blockText: string ): Array< HighlightedText > {
const matches = blockText.matchAll( list );
const highlightedTexts: Array< HighlightedText > = [];

for ( const match of matches ) {
const word = match[ 0 ].trim();
highlightedWords.push( {
word,
suggestion: phrases[ word ],
const text = match[ 0 ].trim();
highlightedTexts.push( {
text,
suggestion: phrases[ text ],
startIndex: match.index,
endIndex: match.index + word.length,
endIndex: match.index + text.length,
} );
}

return highlightedWords;
return highlightedTexts;
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/**
* External dependencies
*/
import { dispatch } from '@wordpress/data';
import { dispatch, select } from '@wordpress/data';
/**
* Internal dependencies
*/
Expand All @@ -10,22 +10,31 @@ import features from './index';
/**
* Types
*/
import type { BreveDispatch } from '../types';
import type { BreveDispatch, BreveSelect } from '../types';

let timeout: number;
let highlightTimeout: number;

function handleMouseEnter( e: React.MouseEvent ) {
e.stopPropagation();
clearTimeout( timeout );
clearTimeout( highlightTimeout );
( dispatch( 'jetpack/ai-breve' ) as BreveDispatch ).increasePopoverLevel();
( dispatch( 'jetpack/ai-breve' ) as BreveDispatch ).setHighlightHover( true );
( dispatch( 'jetpack/ai-breve' ) as BreveDispatch ).setPopoverAnchor( e.target );
}

function handleMouseLeave( e: React.MouseEvent ) {
e.stopPropagation();
timeout = setTimeout( () => {
( dispatch( 'jetpack/ai-breve' ) as BreveDispatch ).decreasePopoverLevel();

highlightTimeout = setTimeout( () => {
// If the mouse is still over any highlight, don't hide the popover
const { getPopoverLevel } = select( 'jetpack/ai-breve' ) as BreveSelect;
if ( getPopoverLevel() > 0 ) {
return;
}

( dispatch( 'jetpack/ai-breve' ) as BreveDispatch ).setHighlightHover( false );
}, 100 );
}, 50 );
}

export default function registerEvents( clientId: string ) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
*/
import ambiguousWords, { AMBIGUOUS_WORDS } from './ambiguous-words';
import complexWords, { COMPLEX_WORDS } from './complex-words';
import longSentences, { LONG_SENTENCES } from './long-sentences';
/**
* Types
*/
Expand All @@ -14,6 +15,10 @@ const features: Array< BreveFeature > = [
config: COMPLEX_WORDS,
highlight: complexWords,
},
{
config: LONG_SENTENCES,
highlight: longSentences,
},
{
config: AMBIGUOUS_WORDS,
highlight: ambiguousWords,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/**
* Internal dependencies
*/
import { escapeRegExp } from '../../utils/escapeRegExp';
/**
* Types
*/
import type { BreveFeatureConfig, HighlightedText } from '../../types';

export const LONG_SENTENCES: BreveFeatureConfig = {
name: 'long-sentences',
title: 'Long sentences',
tagName: 'span',
className: 'has-proofread-highlight--long-sentences',
};

const sentenceRegex = /[^\s][^.!?]+[.!?]+/g;

export default function longSentences( text: string ): Array< HighlightedText > {
const highlightedTexts: Array< HighlightedText > = [];

const sentenceMatches = text.match( sentenceRegex );

if ( ! sentenceMatches ) {
return highlightedTexts;
}

const sentences = [
// Unique sentences with more than 20 words
...new Set( sentenceMatches.filter( sentence => sentence.split( /\s+/ ).length > 20 ) ),
];

sentences.forEach( sentence => {
const regex = new RegExp( escapeRegExp( sentence ), 'gi' );
const matches = text.matchAll( regex );

for ( const match of matches ) {
highlightedTexts.push( {
text: sentence,
startIndex: match.index,
endIndex: match.index + sentence.length,
} );
}
} );

return highlightedTexts;
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,19 @@ import { applyFormat } from '@wordpress/rich-text';
*/
import type { RichTextFormat, RichTextValue } from '@wordpress/rich-text/build-types/types';

export type HighlightProps = {
content: RichTextValue;
type: string;
indexes: Array< { startIndex: number; endIndex: number } >;
attributes?: { [ key: string ]: string };
};

const applyHighlightFormat = ( {
content,
type,
indexes,
attributes = {},
}: {
content: RichTextValue;
type: string;
indexes: Array< { startIndex: number; endIndex: number } >;
attributes: { [ key: string ]: string };
} ): RichTextValue => {
}: HighlightProps ): RichTextValue => {
let newContent = content;

if ( indexes.length > 0 ) {
Expand All @@ -40,6 +42,6 @@ const applyHighlightFormat = ( {
return newContent;
};

export default function highlight( { content, type, indexes, attributes } ) {
export default function highlight( { content, type, indexes, attributes }: HighlightProps ) {
return applyHighlightFormat( { indexes, content, type, attributes } );
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,13 @@ import './style.scss';
/**
* Types
*/
import type { BreveSelect } from '../types';
import type { BreveDispatch, BreveSelect } from '../types';
import type { WPFormat } from '@wordpress/rich-text/build-types/register-format-type';
import type { RichTextFormatList } from '@wordpress/rich-text/build-types/types';

// Setup the Breve highlights
export default function Highlight() {
const { setPopoverHover } = useDispatch( 'jetpack/ai-breve' );
const { setPopoverHover } = useDispatch( 'jetpack/ai-breve' ) as BreveDispatch;

const popoverOpen = useSelect( select => {
const store = select( 'jetpack/ai-breve' ) as BreveSelect;
Expand All @@ -45,11 +46,13 @@ export default function Highlight() {
title: '',
};

const handleMouseEnter = () => {
const handleMouseEnter = ( e: React.MouseEvent ) => {
e.stopPropagation();
setPopoverHover( true );
};

const handleMouseLeave = () => {
const handleMouseLeave = ( e: React.MouseEvent ) => {
e.stopPropagation();
setPopoverHover( false );
};

Expand Down Expand Up @@ -86,8 +89,12 @@ export function registerBreveHighlights() {
features.forEach( feature => {
const { highlight: featureHighlight, config } = feature;
const { name, ...configSettings } = config;
const formatName = `jetpack/ai-proofread-${ name }`;

const settings = {
name: formatName,
interactive: false,
edit: () => {},
...configSettings,

__experimentalGetPropsForEditableTreePreparation() {
Expand All @@ -106,7 +113,7 @@ export function registerBreveHighlights() {
) {
return ( formats: Array< RichTextFormatList >, text: string ) => {
const record = { formats, text } as RichTextValue;
const type = `jetpack/ai-proofread-${ config.name }`;
const type = formatName;

if ( text && isProofreadEnabled && isFeatureEnabled ) {
const applied = highlight( {
Expand All @@ -126,8 +133,8 @@ export function registerBreveHighlights() {
return removeFormat( record, type, 0, record.text.length ).formats;
};
},
} as never;
} as WPFormat;

registerFormatType( `jetpack/ai-proofread-${ name }`, settings );
registerFormatType( formatName, settings );
} );
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,23 @@ export function setPopoverHover( isHover: boolean ) {
};
}

export function setPopoverAnchor( anchor: HTMLElement | EventTarget ) {
export function setPopoverAnchor( anchor: HTMLElement | EventTarget, level: number ) {
return {
type: 'SET_POPOVER_ANCHOR',
anchor,
level,
};
}

export function increasePopoverLevel() {
return {
type: 'INCREASE_POPOVER_LEVEL',
};
}

export function decreasePopoverLevel() {
return {
type: 'DECREASE_POPOVER_LEVEL',
};
}

Expand Down
Loading

0 comments on commit 29f2c97

Please sign in to comment.