Notificationqueue : suggestion d'amélioration pour passer le délai en dynamique en fonction de la durée du message entre deux notifications

Salut @Mips
Peux-tu ajouter dans ton plugin un paramètre dynamique pour la durée de la phrase devant être lue ?
La solution actuelle basée sur une durée fixe et commune à toutes les phrases est difficile à gérer dans la réalité :
Si je prends par exemple la lecture du dernier rapport météo je vais avoir une durée 10x plus grande que si je signale que du courrier est dans la boite !

J’ai testé chez moi (en local) en modifiant ton plugin, et j’arrive bien à gérer les durées des messages automatiquement à partir d’une simple petite fonction et cela avec tous mes périphériques Alexa…

Je me suis préparé cette fonction qui calcule le temps de lecture d’un texte en fonction du nombre de syllabes. Sans être précis à la seconde près, j’arrive avec mes quelques tests à obtenir une précision inférieure à 3 secondes d’écart environ, de plus j’ai intégré dans cette fonction deux paramètres pour ajuster selon les caractéristiques de chacun…

Donc au final on à 3 arguments :
$phrase : contient le texte à lire
$marge : durée (en seconde) de marge de sécurité qui sera ajoutée en fin de calcul pour ajuster le temps le temps de traitement TTS …
$vitesse : ajustement de la vitesse moyenne de lecture d’une syllabe (en fonction du périphérique TTS).

Voici mon bout de code que j’ai ajouté dans ma version modifiée de ton plugin :

au début de ton extends eqLogic(...) 
class notificationqueue extends eqLogic {
	
private static function tempsParole($phrase, $marge = 3, $vitesse = 0.2) {
	/*
	$phrase : contient le texte à lire
	$marge :  durée (en seconde) de marge de sécurité qui sera ajoutée pour ajuster le temps le temps de traitement TTS ...
	$vitesse : ajustement de la durée moyenne de lecture d'une syllabe (en fonction du périphérique TTS)
	*/
		$mot = strtok($phrase,"");
		$voyelles = array ("a","à","e","é","è","ê","ë","i","o","u","ù","û","y");
		$cvcv = "";
	
		for ($i=0;$i<strlen ($mot)-1;$i++) {
		if (in_array($mot[$i],$voyelles)) {$cvcv .="v";} else {$cvcv .="c";}
		}
		$cvcv .=" ";
		$cvcv = str_replace ("vv","v",$cvcv);
		$cvcv = str_replace ("vv","v",$cvcv);
		$cvcv = str_replace ("vv","v",$cvcv);
		$cvcv = str_replace ("cc","c",$cvcv);
		$cvcv = str_replace ("cc","c",$cvcv);
		$cvcv = str_replace ("cc","c",$cvcv);
	
		$cvcv = str_replace ("c ","",$cvcv);
		$cvcv = str_replace (" ","",$cvcv);
	
		$nbsyllabes1 = count (explode ("cv",$cvcv));
		$nbsyllabes2 = count (explode ("vc",$cvcv));
		$nbsyllabes = min ($nbsyllabes1,$nbsyllabes2);
	
		$duree = $marge + round($vitesse * $nbsyllabes,0,PHP_ROUND_HALF_UP); // temporisation minimum (en secondes) avant de lire un nouveau message

	return $duree; // durée de lecture de la phrase
	}

et à la fin de ta fonction public function sendAllMessages(), j’ai inséré l’execution de ma fonction :

		log::add('notificationqueue', 'info', "start sending message from queue {$this->getName()}");
		while (!$queue->isEmpty()) {
			$options = $queue->dequeue();
			if (!$this->sendMessage($options)) {
				log::add('notificationqueue', 'warning', "Error during send, put back in queue");
				$this->addMessageToQueue($options);
			};
			$sleep = notificationqueue::tempsParole($options['message'], $marge = 3, $vitesse = 0.2);
			notificationqueue::wait($condition, $sleep);
		}

Bien sur, il faut ensuite faire quelques ajustements notamment sur tes fonctions wait(), ou j’ai passé (temporairement) ta limite à 60 au lieu de 30 dans tes « if ($occurence > 60) », et dans preUpdate : (!is_numeric($sleep) || $sleep<1 || $sleep>60)
Car le temps devenant dynamique, imposer une limite (à 30sec), n’a plus vraiment lieu d’être dans cette version …
Bref, si tu es okay pour intégrer ces modifs dans ta prochaine version, ce serait bien cool !
Je reste à ta disposition si tu as besoin d’autre infos… :slightly_smiling_face:

1 « J'aime »

Salut,
J’ai un peu regardé à ceci mais j’étais occupé que d’autres sujets donc pas vraiment eu le temps.
Je me demandais : l’algo c’est un standard ?
Quid des autres langues ?

Sinon petit détail : les occurrences c’est multiplié par le sleep donc le passer à 60 ne sert pas trop.

Salut @Mips,
L’algo fonctionne sur le principe du comptage des syllabes. Il est basé sur la langue française, et devra être légèrement adapté pour les autres langues (par exemple la liste des voyelles peut être différente)…
Ensuite pour résumer, quand le nombre de syllabes est identifié, il applique un temps de diction ($vitesse) pour vocaliser une syllabe, et le multiplie par le nombre de syllabes.
donc sauf cas très particuliers, il restera fonctionnel dans d’autres langue si on adapte la liste de voyelles de cette langue (d’autant qu’on rajoute une $marge ajustable pour séparer les messages vocaux, ce qui permet d’affiner en fonction des caractéristiques linguistiques … :wink:

Ce script est plutôt pas mal, je vais m’en resservir.
En attendant une mini optimisation :

		$mot = strtok(sanitizeAccent($phrase),'');
		$voyelles = array ('a','e','i','o','u');

C’est plus long pour la transfo de la chaine. Mais le tableau dans la boucle for est vachement plus petit

Testé en soirée hier et ça m arche super bien…

J’ai ajouté une gestion du temps pour les points. Pour la synthèse vocale sur GH, il y a une véritable pause longue et en fonction du contenu du message, c’était pas suffisant.
J’ai aussi remplacé les " par des ’ là où l’évaluation n’est pas indispensable

public static function tempsParole($phrase, $marge = 4, $vitesse = 0.2, $point = 2) {
	/*
	$phrase : contient le texte à lire
	$marge :  durée (en seconde) de marge de sécurité qui sera ajoutée pour ajuster le temps le temps de traitement TTS ...
	$vitesse : ajustement de la durée moyenne de lecture d'une syllabe (en fonction du périphérique TTS)
	*/
		$mot = strtok(sanitizeAccent($phrase),'');
		$nbdot=substr_count($phrase,'.');
		$voyelles = array ('a','e','i','o','u','y');
		$cvcv = '';

		for ($i=0;$i<strlen ($mot)-1;$i++) {
		if (in_array($mot[$i],$voyelles)) {$cvcv .='v';} else {$cvcv .='c';}
		}
		$cvcv .=' ';
		$cvcv = str_replace ('vv','v',$cvcv);
		$cvcv = str_replace ('vv','v',$cvcv);
		$cvcv = str_replace ('vv','v',$cvcv);
		$cvcv = str_replace ('cc','c',$cvcv);
		$cvcv = str_replace ('cc','c',$cvcv);
		$cvcv = str_replace ('cc','c',$cvcv);
	
		$cvcv = str_replace ('c ','',$cvcv);
		$cvcv = str_replace (' ','',$cvcv);
	
		$nbsyllabes1 = count (explode ('cv',$cvcv));
		$nbsyllabes2 = count (explode ('vc',$cvcv));
		$nbsyllabes = min ($nbsyllabes1,$nbsyllabes2);

		$duree = $marge + round($vitesse * $nbsyllabes + $nbdot * $point,0,PHP_ROUND_HALF_UP); // temporisation minimum (en secondes) avant de lire un nouveau message

	return $duree; // durée de lecture de la phrase
}

Effectivement, je n’avais pas pensé à comptabiliser des temps de pauses spécifiques liées aux point;
même si je n’ai pas rencontré ton problème avec Alexa, cela peut donc être utile aux google Home …:wink:

Par contre, je ne vois pas trop de bénéfice à passer par la fonction sanitizeAccent…

Il faut peut-être aussi le faire avec ‹ ; ›

En fait c’est là :

		for ($i=0;$i<strlen ($mot)-1;$i++) {
		if (in_array($mot[$i],$voyelles)) {$cvcv .='v';} else {$cvcv .='c';}
		}

Le tableau des voyelles est potentiellement parcouru autant de fois qu’il y a de mots… Dans ta version, il a une taille de 12 (surtout que le y est tout à la fin)

En faisant le sanitizeAccent avant, le tableau n’est que de 6 (j’ai zappé le Y dans le code).

Donc le parcours (in_array) est plus rapide (quasi /2), même si i y a un surcoût de pour le remplacement initial.
C’est pas révolutionnaire mais c’est toujours bon à prendre. De plus il faut aussi prendre en compte les majuscules accentuées (et les autres langues ?) … Je vais tester une petite modification

		$mot = strtok(strtolower(sanitizeAccent($phrase)),'');
		$nbpoint=substr_count($phrase,'.');
		$nbpoint+=substr_count($phrase,';');
		$voyelles = array ('a','e','i','o','u','y');

bonjour à tous

j’avais soumis cette idée de pause en fonction du message au début du plugin, je le faisais dans mon scénario mais en comptant simplement le nombre de lettre, c’est vraiment plus pertinent de gérer les syllabes ? on arriverait pas à un resultat équivalent avec les lettres ?

cette évolution serait une bonne chose, surtout si une option pour concaténer les massages en attentes voit le jour

Salut,

Au final, la différence de comptage n’est pas forcement significative (puisqu’on applique des moyennes de « durée » dans les deux cas), mais c’est certainement plus « réel » et plus « souple » avec les syllabes.
Et puis des syllabes peuvent avoir 2,3 ou 4 caractères… La différence risque de se faire quand même sur les messages très court, ou très longs

mais le temps de traitement et surement plus optimal avec juste une ligne de code :slight_smile:

Oui certainement. c’est juste une question de choix.
Personnellement j’ai passé un certain temps à trouver les bons réglages avec juste les caractères (en une ligne justement) et plusieurs variations avant d’avoir un truc satisfaisant.
Désormais, c’est moins tordu à corriger/comprendre

Avant de poster cette fonction de calcul du temps de diction, j’avais fait plein de tests, et notamment tenté l’estimation basée uniquement sur le nombre de caractères.
Le résultat était trop aléatoire et très variable selon les textes, donc pas exploitable car les contenus étaient trop souvent tronqué ou avec de longue pauses entre les messages.

Avec cette méthode, même si elle reste imparfaite (mais déjà bien suffisante pour l’application qu’on en fait), j’arrive à avoir une précision avec un écart bien inférieur à 3 secondes chez moi (avec Alexa) avec des textes très courts comme avec des textes très longs (par exemple des rapports météo)…

Dès lors que l’on peut automatiquement faire attendre la fin de lecture d’un texte avant d’en lancer automatiquement un autre avec le plugin NotificationQueue, il n’y a plus aucun intérêt à les concaténer, a moins que tu ais une utilisation particulière à laquelle je n’ai pas pensé @Nemeraud ?

c’est pour chipoter mais quand il y a plusieurs messages en attente à la suite, il faut que la pause ne s’applique qu’une fois et non entre chaque message pour que cela soit plus fluide, d’ou l’idée de concaténer les messages afin de les envoyer au TTS

OK, mais comment vas tu gérer dans ce cas le fait que la longueur total du texte que peut « avaler » en une fois ton appareil TTS est limitée, même très limitée souvent en fait…

je pensais pas qu’il y avait une limite mais bon, ca me convient très bien comme ca :slight_smile:

Hello,
Peux-tu expliquer pourquoi tu fais ceci? ca ne sert à rien d’après moi.

ça transforme la chaine en tableau de lettres…
avec un ‹ espace › ça transforme en tableau de mots…

Et bien, pas du tout ! Cette fonction ne renvoi jamais un tableau. ( même si on met … :wink: )
Cela renvoi toujours une string, en l’occurrence exactement la même que l’originale, et on peut parfaitement parcourir une string caractère par caractère sans rien faire au préalable.

Et si on veut récupérer les tokens (= valeurs séparées par le caractère passé, par exemple un espace), il faut appeler cette fonction pour chaque mot: PHP: strtok - Manual

mais bref, je vais faire une version avec un temps de pause dynamique en fonction du nombre de syllabes vu l’engouement pour cette demande par contre je vais réécrire la détection des syllabes car cet algo est trop empirique et donne beaucoup d’erreur.

Salut Mips,
Tu as tout à fait raison, cet algo a été créé de façon totalement empirique et improvisé, et c’est totalement assumé (même si mon bricolage n’a pas généré d’erreurs chez moi) ! :joy:

J’avais un problème à résoudre pour pouvoir utiliser ton plugin : estimer le temps de lecture des phrases pour rendre ton plugin utilisable dans les conditions/configuration qui sont les miennes…

J’ai simplement bidouillé « à l’arrache » pour rechercher la solution qui répondais le mieux à mon besoin, et c’est en comptant les syllabes que j’y suis arrivé (j’ai fais plein d’autres tests avant d’arriver à cette solution par syllabes qui est la plus efficace en rapport boulot/résultat). Je n’ai absolument pas cherché à faire du code (et encore moins du code propre), mais juste à trouver une solution techniquement faisable pour réponde à ce problème (le fameux POC) :grin:

J’ai bien cru déceler une pointe de dédain dans tes interventions sur ce post pour les idées qui ne viennent pas de toi, mais l’essentiel est que tout le monde y trouve son compte :
Tu as maintenant un plugin encore plus polyvalent et plus abouti (que ce que tu avais imaginé jusque là), tu en retires les honneurs, et nous autres, nous bénéficions désormais d’un plugin pour lequel une lacune est maintenant comblée (et qui était à priori insoluble avant que je ré-ouvre de nouveau ce sujet), ce qui nous rends encore plus de services qu’avant !!!

Bref tout le monde est content :

MERCI POUR TON SUPER PLUGIN @Mips !!! :+1: :grinning: :wink:

Aucun dédain, et certainement pas sur une idée qui ne venait pas de moi; J’ai appliquée l’idée de compter les syllabes d’ailleurs (je voulais en faire crédit dans le changelog d’ailleurs et je me rend compte que j’ai oublié cette partie, ca sera corrigé dans une prochaine version).
Je m’excuse si c’est le ressenti que j’ai donné.
(par contre oui, j’ai réagi sur mon dernier post ou j’ai eu l’impression de passer pour un … alors que ma question était réelle. Et c’est probablement cela qui a paru dédaigneux, problème de ma communication par écrit allant juste au but sans mise en forme; mais bref, perso je suis passé à autre chose)

Ce que je ne voulais pas c’est introduire un algo dans le plugin que j’allais devoir maintenir en craignant justement une maintenance compliquée.
Je pense que tu comprendras que justement une solution qui convient à l’un (ou une petite poignée) risque d’être malmenée si distribué plus largement, donc tant qu’à faire je voulais avoir une solution que je choisi de défendre, à laquelle j’adhère à 100%; après tout, si je gère les conséquences, j’ai le droit de choisir :wink:

D’un autre coté, restons les pieds sur terre, plugin utilisé par une vingtaine de personne… ca reste très petit et gérable.

Et pour info, je n’ai pas inventé l’algo actuel, je me suis renseigné/inspiré des questions de méthodo similaire que l’on trouve sur le net, étonnamment la problématique de compter les syllabes a inspiré pas mal de monde.

Pour conclure, effectivement je ne m’imaginais pas du tout que ce petit plugin sans prétention allait déboucher sur ce type d’usage (gestion TTS), moi je ne l’utilise que pour délivrer des notifs par message sms ou telegram selon certaines conditions… mais je vais p-e m’y mettre :smiley: