Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 85
0.00% covered (danger)
0.00%
0 / 2
CRAP
0.00% covered (danger)
0.00%
0 / 1
SpecialTestListen
0.00% covered (danger)
0.00%
0 / 85
0.00% covered (danger)
0.00%
0 / 2
30
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 execute
0.00% covered (danger)
0.00%
0 / 81
0.00% covered (danger)
0.00%
0 / 1
20
1<?php
2
3namespace MediaWiki\Wikispeech\Specials;
4
5/**
6 * @file
7 * @ingroup Extensions
8 * @license GPL-2.0-or-later
9 */
10
11use MediaWiki\Html\Html;
12use MediaWiki\HTMLForm\HTMLForm;
13use MediaWiki\Languages\LanguageNameUtils;
14use MediaWiki\Wikispeech\SpeechoidConnector;
15use MediaWiki\Wikispeech\VoiceHandler;
16use SpecialPage;
17use Wikimedia\Codex\Utility\Codex;
18use Wikimedia\Codex\Utility\Sanitizer;
19
20/**
21 * Special page for listening to a synthesised utterance.
22 *
23 * @since 0.1.13
24 */
25
26class 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}