add test
This commit is contained in:
parent
e36964859a
commit
d251763f73
|
@ -0,0 +1,7 @@
|
|||
<?php
|
||||
namespace SpeechSynthesis\Contracts;
|
||||
|
||||
interface AudioSynthesisStrategy
|
||||
{
|
||||
public function textToAudio(string $fileName):array ;
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
|
||||
namespace SpeechSynthesis\Example;
|
||||
|
||||
|
||||
use SpeechSynthesis\SynthesisFactory;
|
||||
|
||||
class Index
|
||||
{
|
||||
public function test(){
|
||||
$config = [
|
||||
'Iflytek'=>[
|
||||
'fileRoot'=>'/'
|
||||
]
|
||||
];
|
||||
$syn = new SynthesisFactory('Iflytek','测试的名字',$config);
|
||||
$msg = $syn->getErrorMsg();
|
||||
$speechFile = $syn->getSpeechFile();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
|
||||
use SpeechSynthesis\Example\Index;
|
||||
|
||||
require 'Index.php';
|
||||
require '../Contracts/AudioSynthesisStrategy.php';
|
||||
require '../SynthesisFactory.php';
|
||||
require '../Products/Config.php';
|
||||
require '../Products/Iflytek.php';
|
||||
|
||||
$res = new Index();
|
||||
$res->test();
|
|
@ -1,17 +0,0 @@
|
|||
<?php
|
||||
|
||||
|
||||
namespace SpeechSynthesis;
|
||||
|
||||
|
||||
use SpeechSynthesis\Test\Tests;
|
||||
|
||||
class Index
|
||||
{
|
||||
public function test()
|
||||
{
|
||||
$test = new Tests();
|
||||
echo 'success';
|
||||
echo $test->index();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
<?php
|
||||
|
||||
|
||||
namespace SpeechSynthesis\Products;
|
||||
|
||||
|
||||
class Config
|
||||
{
|
||||
static private $instance;
|
||||
public function __construct()
|
||||
{
|
||||
|
||||
}
|
||||
public static function getInstance()
|
||||
{
|
||||
//判断$instance是否是Singleton的对象,不是则创建
|
||||
if (!self::$instance instanceof self) {
|
||||
self::$instance = new self();
|
||||
}
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected static $config = [
|
||||
'Iflytek'=>[
|
||||
'fileRoot'=>'/',
|
||||
'url'=>'wss://tts-api.xfyun.cn/v2/tts',
|
||||
'algorithm'=>'hmac-sha256',
|
||||
'time'=>'',
|
||||
|
||||
'app_id' => '5e840bb8',
|
||||
'api_secret'=>'0b0f729b9e5302ba69f5b91aba91948f',
|
||||
'api_key'=>'09536ff9b5aeb8a4ccb51121b7844092',
|
||||
'aue' => 'lame',
|
||||
'sfl' => 1,
|
||||
'auf' => 'audio/L16;rate=16000',
|
||||
'vcn' => 'xiaoyan',
|
||||
'speed' => 50,
|
||||
'volume' => 100,
|
||||
'pitch' => 50,
|
||||
'tte' => 'UTF8',
|
||||
'ent' => 'intp65',
|
||||
'rdn' => '0',
|
||||
'ram' => '0',
|
||||
'reg' => '2',
|
||||
'bgs' => 0,
|
||||
|
||||
'status' => 2,
|
||||
'draftContent' => '测试一下哈哈哈,测试一下哈哈哈。测试一下哈哈哈,测试一下哈哈哈。测试一下哈哈哈,测试一下哈哈哈。测试一下哈哈哈,测试一下哈哈哈。
|
||||
测试一下哈哈哈,测试一下哈哈哈。测试一下哈哈哈,测试一下哈哈哈。测试一下哈哈哈,测试一下哈哈哈。测试一下哈哈哈,测试一下哈哈哈。测试一下哈哈哈,测试一下哈哈哈。
|
||||
测试一下哈哈哈,测试一下哈哈哈。测试一下哈哈哈,测试一下哈哈哈。测试一下哈哈哈,测试一下哈哈哈。测试一下哈哈哈,测试一下哈哈哈。
|
||||
测试一下哈哈哈,测试一下哈哈哈。测试一下哈哈哈,测试一下哈哈哈。测试一下哈哈哈,测试一下哈哈哈。测试一下哈哈哈,测试一下哈哈哈。
|
||||
测试一下哈哈哈,测试一下哈哈哈。测试一下哈哈哈,测试一下哈哈哈。测试一下哈哈哈,测试一下哈哈哈。测试一下哈哈哈,测试一下哈哈哈。
|
||||
测试一下哈哈哈,测试一下哈哈哈。测试一下哈哈哈,测试一下哈哈哈。测试一下哈哈哈,测试一下哈哈哈。',
|
||||
]
|
||||
];
|
||||
|
||||
/**
|
||||
* @param $type
|
||||
* @return array
|
||||
*/
|
||||
public function getConfig(string $type): array
|
||||
{
|
||||
return self::$config[$type];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $config
|
||||
*/
|
||||
public function setConfig(array $config)
|
||||
{
|
||||
|
||||
self::$config = array_merge($config, self::$config);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,164 @@
|
|||
<?php
|
||||
|
||||
|
||||
namespace SpeechSynthesis\Products;
|
||||
|
||||
|
||||
use SpeechSynthesis\Contracts\AudioSynthesisStrategy;
|
||||
use WebSocket\Client;
|
||||
|
||||
class Iflytek implements AudioSynthesisStrategy
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
* 科大讯飞配置
|
||||
*/
|
||||
private $config;
|
||||
|
||||
/**
|
||||
* Iflytek constructor.
|
||||
* @param array $config
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$key = __CLASS__;
|
||||
$len = strripos($key,'\\');
|
||||
if( $len !== false){
|
||||
$key = substr('peechSynthesis\Products\Iflytek', $len);
|
||||
}
|
||||
$configClass = Config::getInstance();
|
||||
$this->config = $configClass->getConfig($key);
|
||||
$this->config['time'] = date('D, d M Y H:i:s', strtotime('-8 hours')) . ' GMT';
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成音频文件
|
||||
* @param $fileName
|
||||
* @return array
|
||||
* code , msg, data
|
||||
*/
|
||||
public function textToAudio(string $fileName):array
|
||||
{
|
||||
if(empty($this->config['fileRoot'])){
|
||||
return ['code'=>0, 'msg' => '文件地址不能为空', 'data'=>['audio_name'=>'']];
|
||||
}
|
||||
if(!is_dir($this->config['fileRoot'])){
|
||||
@mkdir($this->config['fileRoot'], 0755, true);
|
||||
}
|
||||
|
||||
// 设置文件名
|
||||
$ext = $this->config['sfl'] ? '.mp3' : '.pcm';
|
||||
$fileName = $fileName . $ext;
|
||||
|
||||
// 完整文件地址
|
||||
$fullFileName = $this->config['fileRoot'] . DIRECTORY_SEPARATOR . $fileName;
|
||||
|
||||
// 文件冲突,重新命名一下,后缀加_new
|
||||
if(file_exists($fullFileName)){
|
||||
$fullFileName = $this->config['fileRoot'] . DIRECTORY_SEPARATOR . md5($fileName).'_new'.$ext;
|
||||
}
|
||||
|
||||
/**
|
||||
* 开始合成
|
||||
*/
|
||||
try {
|
||||
// 链接的url
|
||||
$url = $this->createUrl();
|
||||
// 要发送的消息
|
||||
$message = $this->createMsg();
|
||||
|
||||
// 建立链接
|
||||
$client = new Client($url,['timeout'=>60]);
|
||||
// 发送请求
|
||||
$client->send(json_encode($message, true));
|
||||
//需要以追加的方式进行写文件
|
||||
$audioFile = fopen($fullFileName, 'ab');
|
||||
// 科大讯飞会分多次发送消息
|
||||
do {
|
||||
//持续接收消息
|
||||
$response = $client->receive();
|
||||
$response = json_decode($response, true);
|
||||
|
||||
// 不成功会返回错误 code为0是成功
|
||||
if ($response['code']) {
|
||||
return ['code' => 0, 'msg' => $response, 'data'=>['audio_name'=>'']];
|
||||
}
|
||||
//返回的音频需要进行base64解码
|
||||
$audio = base64_decode($response['data']['audio']);
|
||||
// 追加
|
||||
fwrite($audioFile, $audio);
|
||||
|
||||
} while ($response['data']['status'] !== 2);// status=2代表发送完成
|
||||
|
||||
fclose($audioFile);
|
||||
|
||||
return ['code' => 1, 'msg' => '合成成功', 'data' => ['audio_name' => $fileName]];
|
||||
|
||||
} catch (\Exception $e) {
|
||||
|
||||
return ['code' => 0, 'msg' => $e->getMessage(), 'data'=>['audio_name'=>'']];
|
||||
|
||||
} finally {
|
||||
// 不管怎样,都需关掉连接
|
||||
$client->close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建参数
|
||||
*/
|
||||
private function createMsg():array
|
||||
{
|
||||
return [
|
||||
'common' => [
|
||||
'app_id' => $this->config['app_id'],
|
||||
],
|
||||
'business' => [
|
||||
'aue' => $this->config['aue'],
|
||||
'sfl' => $this->config['sfl'],
|
||||
'auf' => $this->config['auf'],
|
||||
'vcn' => $this->config['vcn'],
|
||||
'speed' => $this->config['speed'],
|
||||
'volume' => $this->config['volume'],
|
||||
'pitch' => $this->config['pitch'],
|
||||
'tte' => $this->config['tte'],
|
||||
'ent' => $this->config['ent'],
|
||||
'rdn' => $this->config['rdn'],
|
||||
'ram' => $this->config['ram'],
|
||||
'reg' => $this->config['reg'],
|
||||
'bgs' => $this->config['bgs']
|
||||
],
|
||||
'data' => [
|
||||
'status' => 2,
|
||||
'text' => base64_encode($this->config['draftContent']),
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建url
|
||||
* @return string
|
||||
*/
|
||||
private function createUrl():string
|
||||
{
|
||||
// 生成签名
|
||||
$urlInfo = parse_url($this->config['url']);
|
||||
$signatureOrigin = 'host: ' . $urlInfo['host'] . "\n";
|
||||
$signatureOrigin .= 'date: ' . $this->config['time'] . "\n";
|
||||
$signatureOrigin .= 'GET ' . $urlInfo['path'] . ' HTTP/1.1';
|
||||
|
||||
$signatureSha = hash_hmac('sha256', $signatureOrigin, $this->config['api_secret'], true);
|
||||
$signatureSha = base64_encode($signatureSha);
|
||||
|
||||
$authorizationOrigin = 'api_key="' . $this->config['api_key'] . '", algorithm="' . $this->config['algorithm'] . '", ';
|
||||
$authorizationOrigin .= 'headers="host date request-line", signature="' . $signatureSha . '"';
|
||||
$authorization = base64_encode($authorizationOrigin);
|
||||
|
||||
// 生成Url
|
||||
$signUrl = $this->config['url'] . '?' . 'authorization=' . $authorization . '&date='
|
||||
. urlencode($this->config['time']) . '&host=' . $urlInfo['host'];
|
||||
|
||||
return $signUrl;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
<?php
|
||||
|
||||
|
||||
namespace SpeechSynthesis;
|
||||
|
||||
|
||||
use SpeechSynthesis\Contracts\AudioSynthesisStrategy;
|
||||
use SpeechSynthesis\Products\Config;
|
||||
use SpeechSynthesis\Products\Iflytek;
|
||||
use traits\think\Instance;
|
||||
|
||||
class SynthesisFactory
|
||||
{
|
||||
private $synthesisRes = [];
|
||||
|
||||
public function __construct($synthesisType,$filename, $config = [])
|
||||
{
|
||||
// 增加配置
|
||||
if($config){
|
||||
$configClass = Config::getInstance();
|
||||
$configClass->setConfig($config);
|
||||
}
|
||||
$synthesisClass = new Iflytek();
|
||||
$synthesisRes = [];
|
||||
if($synthesisClass instanceof AudioSynthesisStrategy){
|
||||
$synthesisRes = (new Iflytek())->textToAudio($filename);
|
||||
}
|
||||
|
||||
$this->synthesisRes = $synthesisRes;
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件名
|
||||
* @return mixed
|
||||
*/
|
||||
public function getSpeechFile():string
|
||||
{
|
||||
return $this->synthesisRes['audio_name'];
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回错误信息
|
||||
* false代表没有错误
|
||||
* @return bool|mixed|string
|
||||
*/
|
||||
public function getErrorMsg()
|
||||
{
|
||||
if(!$this->synthesisRes){
|
||||
return '出错了,没有任何数据';
|
||||
}
|
||||
if($this->synthesisRes['code'] === 0){
|
||||
return $this->synthesisRes['msg'];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
<?php
|
||||
|
||||
|
||||
namespace SpeechSynthesis\Test;
|
||||
|
||||
|
||||
class Tests
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
return 'success';
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue