添加语音合成,待开发
This commit is contained in:
parent
ffd2c21bf8
commit
d01bf2c8bf
|
|
@ -0,0 +1,183 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin\pbx;
|
||||
|
||||
use App\Models\Audio;
|
||||
use GuzzleHttp\Client;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
|
||||
class AudioController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
return view('admin.audio.index');
|
||||
}
|
||||
|
||||
public function data(Request $request)
|
||||
{
|
||||
$res = Audio::orderBy('id')->paginate($request->get('limit', 30));
|
||||
$data = [
|
||||
'code' => 0,
|
||||
'msg' => '正在请求中...',
|
||||
'count' => $res->total(),
|
||||
'data' => $res->items(),
|
||||
];
|
||||
return response()->json($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
$text = $request->get('text');
|
||||
if ($text==null){
|
||||
return response()->json(['code'=>1,'msg'=>'请输入待合成文本']);
|
||||
}
|
||||
$url = 'http://api.xfyun.cn/v1/service/v1/tts';
|
||||
$appid = config('freeswitch.xfyun.appid');
|
||||
$apikey = config('freeswitch.xfyun.apikey');
|
||||
$param = array (
|
||||
'auf' => 'audio/L16;rate=8000',
|
||||
'aue' => 'raw',
|
||||
'voice_name' => 'xiaoyan',
|
||||
'speed' => '50', //这三个参数必需是字符串
|
||||
'volume' => '50', //这三个参数必需是字符串
|
||||
'pitch' => '50', //这三个参数必需是字符串
|
||||
'engine_type' => 'intp65',
|
||||
);
|
||||
$time = (string)time();
|
||||
$xparam = base64_encode(json_encode(($param)));
|
||||
$checksum = md5($apikey.$time.$xparam);
|
||||
$header = array(
|
||||
'X-CurTime:'.$time,
|
||||
'X-Param:'.$xparam,
|
||||
'X-Appid:'.$appid,
|
||||
'X-CheckSum:'.$checksum,
|
||||
'X-Real-Ip:127.0.0.1',
|
||||
'Content-Type:application/x-www-form-urlencoded; charset=utf-8'
|
||||
);
|
||||
$content = [
|
||||
'text' => $text,
|
||||
];
|
||||
try{
|
||||
$response = $this->tocurl($url, $header, $content);
|
||||
$header = $response['header'];
|
||||
if($header['content_type'] == 'audio/mpeg'){
|
||||
$ext = $param['aue']=='raw'?'.wav':'.mp3';
|
||||
$filename = config('freeswitch.xfyun.sounds').$time.$ext;
|
||||
file_put_contents($filename, $response['body']);
|
||||
Audio::create(array_merge($param,[
|
||||
'url' => $filename,
|
||||
'text' => $text
|
||||
]));
|
||||
return response()->json(['code'=>0,'msg'=>'合成成功','data'=>['url'=>$filename]]);
|
||||
}
|
||||
return response()->json(['code'=>1,'msg'=>'合成失败','data'=>json_decode($response['body'],true)]);
|
||||
}catch (\Exception $exception){
|
||||
return response()->json(['code'=>1,'msg'=>'合成失败:'.$exception->getMessage()]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function show($id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function edit($id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function update(Request $request, $id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function destroy(Request $request)
|
||||
{
|
||||
$ids = $request->get('ids');
|
||||
$audio = Audio::where('id',$ids[0])->first();
|
||||
if ($ids == null){
|
||||
return response()->json(['code'=>1,'msg'=>'请选择删除项']);
|
||||
}
|
||||
try{
|
||||
if (file_exists($audio->url)){
|
||||
unlink($audio->url);
|
||||
}
|
||||
$audio->delete();
|
||||
return response()->json(['code'=>0,'msg'=>'删除成功']);
|
||||
}catch (\Exception $exception){
|
||||
return response()->json(['code'=>1,'msg'=>'删除失败:'.$exception->getMessage()]);
|
||||
}
|
||||
}
|
||||
|
||||
public function tocurl($url, $header, $content){
|
||||
$ch = curl_init();
|
||||
if(substr($url,0,5)=='https'){
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // 跳过证书检查
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, true); // 从证书中检查SSL加密算法是否存在
|
||||
}
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_URL, $url);
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
|
||||
curl_setopt($ch, CURLOPT_POST, true);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($content));
|
||||
$response = curl_exec($ch);
|
||||
$error=curl_error($ch);
|
||||
//var_dump($error);
|
||||
if($error){
|
||||
die($error);
|
||||
}
|
||||
$header = curl_getinfo($ch);
|
||||
|
||||
curl_close($ch);
|
||||
$data = array('header' => $header,'body' => $response);
|
||||
return $data;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
@extends('admin.base')
|
||||
|
||||
@section('content')
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header layuiadmin-card-header-auto">
|
||||
<form class="layui-form">
|
||||
<div class="layui-form-item">
|
||||
<textarea name="text" class="layui-textarea" placeholder="请输入要合成的文本"></textarea>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<button lay-submit lay-filter="tts" class="layui-btn">合成</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="layui-card-body">
|
||||
<table id="dataTable" lay-filter="dataTable"></table>
|
||||
<script type="text/html" id="options">
|
||||
<div class="layui-btn-group">
|
||||
@can('pbx.audio.destroy')
|
||||
<a class="layui-btn layui-btn-danger layui-btn-sm " lay-event="del">删除</a>
|
||||
@endcan
|
||||
</div>
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@section('script')
|
||||
<script>
|
||||
layui.use(['layer','table','form'],function () {
|
||||
var layer = layui.layer;
|
||||
var form = layui.form;
|
||||
var table = layui.table;
|
||||
//用户表格初始化
|
||||
var dataTable = table.render({
|
||||
elem: '#dataTable'
|
||||
,height: 500
|
||||
,url: "{{ route('admin.audio.data') }}" //数据接口
|
||||
,page: true //开启分页
|
||||
,cols: [[ //表头
|
||||
{checkbox: true,fixed: true}
|
||||
//,{field: 'id', title: 'ID', sort: true,width:80}
|
||||
,{field: 'text', title: '文本'}
|
||||
,{field: 'url', title: '地址'}
|
||||
,{field: 'auf', title: '采样率'}
|
||||
,{field: 'aue', title: '编码'}
|
||||
,{field: 'voice_name', title: '发音人'}
|
||||
,{field: 'speed', title: '语速'}
|
||||
,{field: 'volume', title: '音量'}
|
||||
,{field: 'pitch', title: '音高'}
|
||||
,{field: 'engine_type', title: '引擎'}
|
||||
,{fixed: 'right', width: 150, align:'center', toolbar: '#options', title:'操作'}
|
||||
]]
|
||||
});
|
||||
//监听工具条
|
||||
table.on('tool(dataTable)', function(obj){ //注:tool是工具条事件名,dataTable是table原始容器的属性 lay-filter="对应的值"
|
||||
var data = obj.data //获得当前行数据
|
||||
,layEvent = obj.event; //获得 lay-event 对应的值
|
||||
if(layEvent === 'del'){
|
||||
layer.confirm('确认删除吗?', function(index){
|
||||
$.post("{{ route('admin.audio.destroy') }}",{_method:'delete',ids:[data.id]},function (result) {
|
||||
if (result.code==0){
|
||||
obj.del(); //删除对应行(tr)的DOM结构
|
||||
}
|
||||
layer.close(index);
|
||||
var icon = result.code==0?6:5;
|
||||
layer.msg(result.msg,{icon:icon})
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
//提交
|
||||
form.on('submit(tts)', function (data) {
|
||||
layer.load();
|
||||
parms = data.field;
|
||||
parms['_token'] = "{{csrf_token()}}";
|
||||
$.post("{{route('admin.audio.store')}}",parms,function (res) {
|
||||
layer.closeAll('loading');
|
||||
if (res.code==0){
|
||||
layer.msg(res.msg,{icon:6},function () {
|
||||
dataTable.reload({
|
||||
page:{curr:1}
|
||||
});
|
||||
})
|
||||
} else {
|
||||
layer.msg(res.msg,{icon:5})
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
|
||||
})
|
||||
</script>
|
||||
@endsection
|
||||
Loading…
Reference in New Issue