Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
| Total | |
0.00% |
0 / 85 |
|
0.00% |
0 / 2 |
CRAP | |
0.00% |
0 / 1 |
| SpecialTestListen | |
0.00% |
0 / 85 |
|
0.00% |
0 / 2 |
30 | |
0.00% |
0 / 1 |
| __construct | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
| execute | |
0.00% |
0 / 81 |
|
0.00% |
0 / 1 |
20 | |||
| 1 | <?php |
| 2 | |
| 3 | namespace MediaWiki\Wikispeech\Specials; |
| 4 | |
| 5 | /** |
| 6 | * @file |
| 7 | * @ingroup Extensions |
| 8 | * @license GPL-2.0-or-later |
| 9 | */ |
| 10 | |
| 11 | use MediaWiki\Html\Html; |
| 12 | use MediaWiki\HTMLForm\HTMLForm; |
| 13 | use MediaWiki\Languages\LanguageNameUtils; |
| 14 | use MediaWiki\Wikispeech\SpeechoidConnector; |
| 15 | use MediaWiki\Wikispeech\VoiceHandler; |
| 16 | use SpecialPage; |
| 17 | use Wikimedia\Codex\Utility\Codex; |
| 18 | use Wikimedia\Codex\Utility\Sanitizer; |
| 19 | |
| 20 | /** |
| 21 | * Special page for listening to a synthesised utterance. |
| 22 | * |
| 23 | * @since 0.1.13 |
| 24 | */ |
| 25 | |
| 26 | class SpecialTestListen extends SpecialPage { |
| 27 | use LanguageOptionsTrait; |
| 28 | |
| 29 | /** @var SpeechoidConnector */ |
| 30 | private $speechoidConnector; |
| 31 | |
| 32 | /** @var VoiceHandler */ |
| 33 | private $voiceHandler; |
| 34 | |
| 35 | /** |
| 36 | * @since 0.1.13 |
| 37 | * @param LanguageNameUtils $languageNameUtils |
| 38 | * @param mixed $speechoidConnector |
| 39 | * @param VoiceHandler $voiceHandler |
| 40 | */ |
| 41 | public function __construct( |
| 42 | $languageNameUtils, |
| 43 | $speechoidConnector, |
| 44 | VoiceHandler $voiceHandler |
| 45 | ) { |
| 46 | parent::__construct( 'TestListen', 'wikispeech-listen' ); |
| 47 | |
| 48 | $this->languageNameUtils = $languageNameUtils; |
| 49 | $this->speechoidConnector = $speechoidConnector; |
| 50 | $this->voiceHandler = $voiceHandler; |
| 51 | } |
| 52 | |
| 53 | /** |
| 54 | * @since 0.1.13 |
| 55 | * @param string|null $subPage |
| 56 | */ |
| 57 | public function execute( $subPage ) { |
| 58 | $this->setHeaders(); |
| 59 | $this->checkPermissions(); |
| 60 | |
| 61 | $form = HTMLForm::factory( |
| 62 | 'codex', |
| 63 | [ |
| 64 | 'text' => [ |
| 65 | 'name' => 'text', |
| 66 | 'type' => 'text', |
| 67 | 'label' => $this->msg( 'wikispeech-testlisten-text' )->text(), |
| 68 | 'required' => true |
| 69 | ], |
| 70 | 'language' => [ |
| 71 | 'name' => 'language', |
| 72 | 'type' => 'select', |
| 73 | 'label' => $this->msg( 'wikispeech-language' )->text(), |
| 74 | 'options' => $this->getLanguageOptions() |
| 75 | ], |
| 76 | 'ssml' => [ |
| 77 | 'name' => 'ssml', |
| 78 | 'type' => 'check', |
| 79 | 'label' => $this->msg( 'wikispeech-testlisten-ssml' )->text() |
| 80 | ] |
| 81 | ], |
| 82 | $this->getContext() |
| 83 | ); |
| 84 | |
| 85 | $codex = new Codex(); |
| 86 | // phpcs:ignore Generic.Files.LineLength |
| 87 | $ssmlSpeakTag = '<speak xml:lang="en-US" version="1.0" xmlns="http://www.w3.org/2001/10/synthesis" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemalocation="http://www.w3.org/2001/10/synthesis http://www.w3.org/TR/speech-synthesis/synthesis.xsd">...</speak>'; |
| 88 | $sanitizer = new Sanitizer(); |
| 89 | $tag = $sanitizer->sanitizeText( $ssmlSpeakTag ); |
| 90 | // This note intentionally doesn't use messages. It's likely that it |
| 91 | // will change or be removed before it's relevant to end users. |
| 92 | $noteContent = "<p>This page is only intened to help developers.</p>" |
| 93 | . '<p>When SSML is enabled the input has to be a speak tag like the one below.</p>' |
| 94 | . "<pre>$tag</pre>"; |
| 95 | $note = $codex |
| 96 | ->message() |
| 97 | ->setType( 'notice' ) |
| 98 | ->setHeading( 'For development' ) |
| 99 | ->setContentHtml( |
| 100 | $codex |
| 101 | ->htmlSnippet() |
| 102 | ->setContent( $noteContent ) |
| 103 | ->build() |
| 104 | ) |
| 105 | ->build() |
| 106 | ->getHtml(); |
| 107 | $form->addHeaderHtml( $note ); |
| 108 | |
| 109 | $form->setSubmitCallback( function ( array $data, HTMLForm $form ) { |
| 110 | $language = $data['language']; |
| 111 | $voice = $this->voiceHandler->getDefaultVoice( $language ); |
| 112 | $speechoidData = []; |
| 113 | if ( $data['ssml'] ) { |
| 114 | $speechoidData['ssml'] = $data['text']; |
| 115 | } else { |
| 116 | $speechoidData['text'] = $data['text']; |
| 117 | } |
| 118 | $speechoidResponse = $this->speechoidConnector->synthesize( |
| 119 | $language, |
| 120 | $voice, |
| 121 | $speechoidData |
| 122 | ); |
| 123 | $tokens = json_encode( $speechoidResponse['tokens'] ); |
| 124 | $audioDataString = 'data:audio/ogg;base64,' . $speechoidResponse['audio_data']; |
| 125 | $html = Html::element( 'audio', [ 'controls' => '', 'src' => $audioDataString ], $tokens ); |
| 126 | $html .= Html::openElement( 'table', [ 'class' => 'wikitable' ] ); |
| 127 | $html .= Html::openElement( 'tr' ); |
| 128 | $html .= Html::element( 'th', [], 'orth' ); |
| 129 | $html .= Html::element( 'th', [], 'expanded' ); |
| 130 | $html .= Html::element( 'th', [], 'endtime' ); |
| 131 | $html .= Html::openElement( 'tr' ); |
| 132 | foreach ( $speechoidResponse['tokens'] as $token ) { |
| 133 | $html .= Html::openElement( 'tr' ); |
| 134 | $html .= Html::openElement( 'td' ) |
| 135 | . Html::element( 'code', [], $token['orth'] ) |
| 136 | . Html::closeElement( 'td' ); |
| 137 | $html .= Html::openElement( 'td' ); |
| 138 | if ( array_key_exists( 'expanded', $token ) ) { |
| 139 | $html .= Html::element( 'code', [], $token['expanded'] ); |
| 140 | } |
| 141 | $html .= Html::closeElement( 'td' ); |
| 142 | $html .= Html::element( 'td', [], $token['endtime'] ); |
| 143 | $html .= Html::closeElement( 'tr' ); |
| 144 | } |
| 145 | $html .= Html::openElement( 'table' ); |
| 146 | $form->addFooterHtml( $html ); |
| 147 | } ); |
| 148 | $form->show(); |
| 149 | } |
| 150 | } |