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

Text2Speech Plugin #4622 #4623

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from 6 commits
Commits
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
18 changes: 16 additions & 2 deletions plugin/ai_helper/tool/learnpath.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,13 @@

require_once __DIR__.'/../../../main/inc/global.inc.php';
require_once __DIR__.'/../AiHelperPlugin.php';
require_once __DIR__.'/../../text2speech/Text2SpeechPlugin.php';
require_once api_get_path(SYS_CODE_PATH).'exercise/export/aiken/aiken_classes.php';
require_once api_get_path(SYS_CODE_PATH).'exercise/export/aiken/aiken_import.inc.php';

$text2speechPlugin = Text2SpeechPlugin::create();
$isTextToSpeechEnabled = $text2speechPlugin->get('tool_enable') && $text2speechPlugin->get('tool_lp_enable');

$plugin = AiHelperPlugin::create();

$apiList = $plugin->getApiList();
Expand All @@ -35,6 +39,7 @@

$messageGetItems = 'Generate the table of contents of a course in "%s" in %d or less chapters on the topic of "%s" in a list separated with comma, without chapter number. Do not include a conclusion chapter.';
$prompt = sprintf($messageGetItems, $courseLanguage, $chaptersCount, $topic);

$resultText = $plugin->openAiGetCompletionText($prompt, 'learnpath');

if (isset($resultText['error']) && true === $resultText['error']) {
Expand Down Expand Up @@ -65,10 +70,19 @@
$promptItem = sprintf($messageGetItemContent, $topic, $courseLanguage, $wordsCount, $title);
$resultContentText = $plugin->openAiGetCompletionText($promptItem, 'learnpath');
$lpItemContent = (!empty($resultContentText) ? trim($resultContentText) : '');
$audioControl = '';
if ($isTextToSpeechEnabled && !empty($lpItemContent)) {
$filePath = $text2speechPlugin->convert(strip_tags($lpItemContent));
$audioControl = '<audio controls>'.
'<source src="'.$filePath.'" type="audio/ogg">'.
'Your browser does not support the audio element.'.
'</audio>';
}

if (false !== stripos($lpItemContent, '</head>')) {
$lpItemContent = preg_replace("|</head>|i", "\r\n$style\r\n\\0", $lpItemContent);
$lpItemContent = preg_replace("|</head>|i", "\r\n$style\r\n\\0", $audioControl.$lpItemContent);
} else {
$lpItemContent = '<html><head><title>'.trim($title).'</title>'.$style.'</head><body>'.$lpItemContent.'</body></html>';
$lpItemContent = '<html><head><title>'.trim($title).'</title>'.$style.'</head><body>'.$audioControl.$lpItemContent.'</body></html>';
}
$lpItems[$position]['content'] = $lpItemContent;
$position++;
Expand Down
Binary file added plugin/text2speech/.DS_Store
Binary file not shown.
4 changes: 4 additions & 0 deletions plugin/text2speech/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Text2Speech
======

Version 0.1
108 changes: 108 additions & 0 deletions plugin/text2speech/Text2SpeechPlugin.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
<?php
/* For license terms, see /license.txt */

/**
* Description of Text2SpeechPlugin.
*
* @author Francis Gonzales <[email protected]>
*/
class Text2SpeechPlugin extends Plugin
{
public const MOZILLATTS_API = 'mozillatts';
public const PATH_TO_SAVE_FILES = __DIR__.'/../../app/upload/plugins/text2speech/';

protected function __construct()
{
$version = '0.1';
$author = 'Francis Gonzales';

$message = 'Description';

$settings = [
$message => 'html',
'tool_enable' => 'boolean',
'api_name' => [
'type' => 'select',
'options' => $this->getApiList(),
],
'api_key' => 'text',
'url' => 'text',
'tool_lp_enable' => 'boolean',
];

parent::__construct($version, $author, $settings);
}

/**
* Get the list of apis availables.
*
* @return array
*/
public function getApiList()
{
return [
self::MOZILLATTS_API => 'MozillaTTS',
];
}

/**
* Get the completion text from openai.
*
* @return string
*/
public function convert(string $text)
{
$path = '/app/upload/plugins/text2speech/';
switch ($this->get('api_name')) {
case self::MOZILLATTS_API:
require_once __DIR__.'/src/mozillatts/MozillaTTS.php';

$mozillaTTS = new MozillaTTS($this->get('url'), $this->get('api_key'), self::PATH_TO_SAVE_FILES);
$path .= $mozillaTTS->convert($text);
break;
}

return $path;
}

/**
* Get the plugin directory name.
*/
public function get_name(): string
{
return 'text2speech';
}

/**
* Get the class instance.
*
* @staticvar Text2SpeechPlugin $result
*/
public static function create(): Text2SpeechPlugin
{
static $result = null;

return $result ?: $result = new self();
}

/**
* Install the plugin. create folder to save files.
*/
public function install()
{
if (!file_exists(self::PATH_TO_SAVE_FILES)) {
mkdir(self::PATH_TO_SAVE_FILES);
}
}

/**
* Unistall plugin. Clear the folder.
*/
public function uninstall()
{
if (file_exists(self::PATH_TO_SAVE_FILES)) {
array_map('unlink', glob(self::PATH_TO_SAVE_FILES. '/*.*'));
rmdir(self::PATH_TO_SAVE_FILES);
}
}
}
16 changes: 16 additions & 0 deletions plugin/text2speech/install.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php
/* For license terms, see /license.txt */

/**
* Install the Text2Speech Plugin.
*
* @package chamilo.plugin.text2speech
*/
require_once __DIR__.'/../../main/inc/global.inc.php';
require_once __DIR__.'/Text2SpeechPlugin.php';

if (!api_is_platform_admin()) {
exit('You must have admin permissions to install plugins');
}

Text2SpeechPlugin::create()->install();
6 changes: 6 additions & 0 deletions plugin/text2speech/lang/english.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?php
/* For license terms, see /license.txt */

$strings['plugin_title'] = 'Text to Speech (Text2Speech)';
$strings['plugin_comment'] = 'Plugin to convert text to speech using a 3rd-party service';
$strings['tool_enable'] = 'Enable plugin';
6 changes: 6 additions & 0 deletions plugin/text2speech/lang/french.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?php
/* For license terms, see /license.txt */

$strings['plugin_title'] = 'Texte pour parler (Text2Speech)';
$strings['plugin_comment'] = "Ce plugin permet de convertir du texte en parole à l'aide d'un service tiers";
$strings['tool_enable'] = 'Activer le plug-in';
5 changes: 5 additions & 0 deletions plugin/text2speech/lang/spanish.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?php
/* For license terms, see /license.txt */
$strings['plugin_title'] = 'Texto a Voz (Text2Speech)';
$strings['plugin_comment'] = 'Este plugin es para convertir texto a voz usando un servicio de terceros';
$strings['tool_enable'] = 'Enable plugin';
6 changes: 6 additions & 0 deletions plugin/text2speech/plugin.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?php
/* For license terms, see /license.txt */

require_once __DIR__.'/Text2SpeechPlugin.php';

$plugin_info = Text2SpeechPlugin::create()->get_info();
Binary file added plugin/text2speech/src/.DS_Store
Binary file not shown.
8 changes: 8 additions & 0 deletions plugin/text2speech/src/IProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php

interface IProvider
{
public function __construct(string $url, string $key, string $filePath);

public function convert(string $text): string;
}
Binary file added plugin/text2speech/src/mozillatts/.DS_Store
Binary file not shown.
41 changes: 41 additions & 0 deletions plugin/text2speech/src/mozillatts/MozillaTTS.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php

require_once __DIR__.'/../IProvider.php';

class MozillaTTS implements IProvider
{
private $url;
private $apiKey;
private $filePath;

public function __construct(string $url, string $apiKey, string $filePath)
{
$this->url = $url;
$this->apiKey = $apiKey;
$this->filePath = $filePath;
}

public function convert(string $text): string
{
return $this->request($text);
}

private function request(string $data): string
{
$filename = uniqid().'.wav';
$filePath = $this->filePath.$filename;
$resource = fopen($filePath, 'w');

$client = new GuzzleHttp\Client();
$client->get($this->url.'?api_key='.urlencode($this->apiKey).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

El api_key es necesario? Cómo lo genero? En mi TTS que tengo no pide api_key y me genera los audios por el api solo con el texto
🤔

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Creo que no es necesario y que lo pone solo para abrirlo a la posibilidad de tener uno a futuro (para este u otro servicio)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

exacto en este momento no es necesario pero lo dejo abierto por si se necesita en algún otro servicio.

'&text='.str_replace('%0A', '+', urlencode($data)), [
'headers' => [
'Cache-Control' => 'no-cache',
'Content-Type' => 'audio/wav'
],
'sink' => $resource,
]);

return $filename;
}
}
16 changes: 16 additions & 0 deletions plugin/text2speech/uninstall.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php
/* For license terms, see /license.txt */

/**
* Uninstall the Text2Speech Plugin.
*
* @package chamilo.plugin.text2speech
*/
require_once __DIR__.'/../../main/inc/global.inc.php';
require_once __DIR__.'/Text2SpeechPlugin.php';

if (!api_is_platform_admin()) {
exit('You must have admin permissions to install plugins');
}

Text2SpeechPlugin::create()->uninstall();