【应用】PHP调用百度文档翻译接口

百度翻译 的文档是需要消费的,并且它的api请求是一个异步的过程,如果业务上用户不需要登录的时候,无法直接获取到翻译结果文档。因此,做了个异步返回的功能。

思路:

1、上传文档;

2、调用翻译接口;

3、通过kafka监听接口回调,处理返回数据,保存到本地(方便以后扩展,如加入用户信息,查看我的翻译记录)

4、前端监听后端服务,通过swoole的websocket实时请求文档数据

关键部分代码(赶工做的,未做优化):


//上传文件
public function upload()
{
	header("Access-Control-Allow-Origin:*");  
	set_time_limit(300);

	$file = $_FILES['file'];
	if(!$file){
        $show = array('status'=>422,'message'=>'请上传图片或者文档文件');
        json($show);
	}

	$app = '2020bd';

	if($_SERVER['SERVER_ADDR']=='127.0.0.1'){
	    $sPath = '/Users/kunyuan/www/activity/storage/'.$app.'/';
	}else{
	    $sPath = '/var/www/html/activity/storage/'.$app.'/';
	}
	if(!mk_dir($sPath)){
	    $show = array('status'=>500,'message'=>'目录不存在');
    	json($show);
	}

    $path_parts = pathinfo($file['name']);
    $ext = strtolower($path_parts["extension"]);
    $extAry = array(
    	'jpg','jpeg','png','docx','xls','xlsx','ppt','pptx','pdf'
    );
    if(!in_array($ext, $extAry)){
        $show = array('status'=>422,'message'=>'请上传图片或者文档文件');
        json($show);
    }

    try{
    	//保存到服务器本地
    	$filename = date('Ymd'). '_' .rand(10000, 99999).'_'.time();
	    $tmpfile = $filename . '.'.$ext;
	    $tmp = $file["tmp_name"];
	    $img = file_get_contents($tmp);
	    $path1 = $sPath . $tmpfile;
	    $res = file_put_contents($path1, $img);
	    if(is_https()){
	    	$url = 'https://'.$_SERVER['SERVER_NAME'].'/storage/'.$app.'/'.$tmpfile;
	    }else{
	    	$url = 'http://'.$_SERVER['SERVER_NAME'].'/storage/'.$app.'/'.$tmpfile;
	    }
	    
	    $error = '上传失败';
	    if($res){
	    	//判断文件类型,为了文件调用百度的图片接口或者文档接口
	    	if(in_array($ext,array('jpg','jpeg','png'))){
	    		$resExt = 'pic';
	    	}else{
	    		$resExt = 'docs';
	    	}
	    	//保存数据库
	    	$fileid = $this->common->setFiles(array(
	    		'sourceFile'	=> $url,
	    		'localFile'		=> $path1,
	    		'type'	=> $resExt
	    	));
			$show = array('status'=>0,'fileUrl'=>$url,'fileSize'=>ceil(filesize($path1)/1000)."k",'ext'=>$resExt, 'id' => $fileid,'resExt'=>$resExt);
	    }else{
	    	$show = array('status'=>500,'message'=>$error,'info'=>$info,'fileSize'=>ceil(filesize($path1)/1000)."k");
	    }

	    json($show);

    }catch(Exception $e){
        $show = array('status'=>$e->getCode(),'message'=>$e->getMessage());
        json($show);
    }
}

//调用百度接口
public function api()
{
	//$type = I('type','docs');
	$id = I('id',0);
	$callback = I('callback');
	//判断是否为上传的文件
	$data = $this->common->getFiles(array('id'=>$id));
	if(empty($data)){
        $show = array('status'=>420,'message'=>'数据有误');
        json($show, $callback);
	}
	$type = $data['type'];
	switch($type){
		case 'docs':
			$this->docsTran($data);
		break;
		case 'pic':
			$this->picTran($data);
		break;
		default:
			$this->docsTran($data);
		break;
	}
}

//文档翻译接口
private function docsTran($data)
{
	//die('ooo');
	$file = $data['localFile'];//I('file');
	$from = I('from', 'zh');
	$to = I('to','en');
	$callback = I('callback');
	if(empty($file)){
        $show = array('status'=>422,'message'=>'请上传文档文件');
        json($show, $callback);
	}
    $path_parts = pathinfo($file);
    $ext = strtolower($path_parts["extension"]);
    $extAry = array(
    	'docx','xls','xlsx','ppt','pptx','pdf'
    );
    if(!in_array($ext, $extAry)){
        $show = array('status'=>423,'message'=>'请上传文档文件');
        json($show, $callback);
    }

	if($from == $to){
        $show = array('status'=>424,'message'=>'翻译语言不能与原文档言语一样');
        json($show, $callback);
	}

	$arr = array(
		'requestId'		=> uniqid(),
		'sourceFile'	=> $data['sourceFile'],
		'localFile'		=> '',
		'type'			=> 'docs',
		'content'		=> '',
		'create_time'	=> time()
	);
	$id = $this->common->set($arr);

	$params = array(
	    'appid' => $this->appid, //你的appid
	    'from' => $from, 
	    'to' => $to,
	    'timestamp' => time(), //10位时间戳
	    'type' => $ext, //文档类型,根据具体文档而定
	);
	$seckey = $this->seckey; //你的密钥
	ksort($params);
	$querySign = '';
	foreach ($params as $key => $value) {
	    $querySign .= $key . '=' . $value . '&';
	}
	$filePath = $file; //文档路径
	$params['sign'] = md5($querySign . '' . md5_file($filePath) . '' . $seckey);

	$url = 'http://fanyi-api.baidu.com/api/trans/vip/doctrans';
	$header = array(
	    'Content-Type' => 'multipart/form-data',
	       );

	$params['file'] =  '@' . realpath($imagePath);
	//高版本兼容
	if (class_exists('\CURLFile')) {
	    $params['file'] = new \CURLFile(realpath($filePath));
	}

	$ch = curl_init();
	curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
	curl_setopt($ch, CURLOPT_POST, 1);
	curl_setopt($ch, CURLOPT_POSTFIELDS,$params);
	curl_setopt($ch,CURLOPT_URL,$url);
	curl_setopt($ch,CURLOPT_TIMEOUT, 10);
	curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
	$result=curl_exec($ch);
	curl_close($ch);
	logs('Docs Result>>>'.$result);
	$callRet = json_decode($result, true);
	//print_R($result); 
	if($callRet['error_code'] == 52000){
		$arr = array(
			'requestId'		=> $callRet['data']['requestId'],

		);
		$this->common->update($arr, array('id'=>$id));
		//$this->load->libraliry('Kafka');
    	$this->kafkaMsg($callRet['data']['requestId']);
        $show = array('status'=>0,'message'=>'翻译成功','requestId'=>$callRet['data']['requestId']);
        json($show, $callback);
	}else{
        $show = array('status'=>$callRet['error_code'],'message'=>$callRet['error_msg']);
        json($show, $callback);
	}

}

//图片翻译接口
private function picTran($data)
{

	$file = $data['localFile'];//I('file');
	//echo $file;
	$from = I('from', 'zh');
	$to = I('to','en');
	$callback = I('callback');

	if(empty($file)){
        $show = array('status'=>422,'message'=>'请上传图片文件');
        json($show, $callback);
	}
    $path_parts = pathinfo($file);
    $ext = strtolower($path_parts["extension"]);
    $extAry = array(
    	'jpg','jpeg','png'
    );
    if(!in_array($ext, $extAry)){
        $show = array('status'=>423,'message'=>'请上传图片文件');
        json($show, $callback);
    }

	if($from == $to){
        $show = array('status'=>424,'message'=>'翻译语言不能与原文件言语一样');
        json($show, $callback);
	}
	$appid = $this->appid;

	$salt = rand();

	$cuid = 'APICUID';
	$mac = 'MAC';
	$secKey = $this->seckey;

	$imagePath = $file;
	//echo $imagePath;

	$sign = md5($appid . md5(file_get_contents($imagePath)) . $salt . $cuid . $mac . $secKey);


	$url = 'https://fanyi-api.baidu.com/api/trans/sdk/picture?appid=' . $this->appid . '&from=' . $from . '&to=' . $to . '&salt=' . $salt . '&cuid=' . $cuid . '&mac=' . $mac . '&sign=' . $sign;
	$header = array(
			'Content-Type' => 'multipart/form-data',
		       );
	$sendData = array(
			'image' => '@' . realpath($imagePath) . ';type=image/jpeg',
			);
	if (class_exists('\CURLFile')) {
		$sendData['image'] = new \CURLFile(realpath($imagePath));
	}

	$ch = curl_init();
	curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
	curl_setopt($ch, CURLOPT_POST, 1);
	curl_setopt($ch, CURLOPT_POSTFIELDS,$sendData);
	curl_setopt($ch,CURLOPT_URL,$url);
	curl_setopt($ch,CURLOPT_TIMEOUT, 10);
	curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
	$result=curl_exec($ch);
	curl_close($ch);
	logs('PIC Result>>>'.$result);
	$callRet = json_decode($result, true);
	//print_R($callRet); 
	if($callRet['error_code'] == 0){
		$arr = array(
			'requestId'		=> uniqid(),
			'sourceFile'	=> $data['sourceFile'],
			'localFile'		=> $file,
			'type'			=> 'pic',
			'content'		=> $callRet['data']['sumSrc'],
			'create_time'	=> time()
		);
		//print_r($arr);
		$this->common->set($arr);
        $show = array('status'=>0,'message'=>'翻译成功','srcContent'=>$callRet['data']['sumSrc'] ,'tranContent'	=> $callRet['data']['sumDst']);
        json($show, $callback);
	}else{
        $show = array('status'=>$callRet['error_code'],'message'=>$callRet['error_msg']);
        json($show, $callback);
	}
	
}

//消息生产
private function kafkaMsg($requestId)
{
    $topicname = "testlin";
    logs('kafkaMsgStart>>>' . $requestId . '>>' . $topicname);
    
	$conf = new RdKafka\Conf();
	$conf->set('metadata.broker.list', 'localhost:9092');
	$producer = new RdKafka\Producer($conf);

	$topic = $producer->newTopic($topicname);

    $topic->produce(RD_KAFKA_PARTITION_UA, 0, $requestId);
    //$producer->poll(0);
    $result = $producer->flush(1000);


	if (RD_KAFKA_RESP_ERR_NO_ERROR !== $result) {
		logs('ERROR>>>' . 'Was unable to flush, messages might be lost!');
	}

    logs('kafkaMsgEnd>>>' . $requestId);
     
}

//百度返回后的处理,通过kafka订阅消息
public function dealLocal()
{
    $topicname = "testlin";
    logs('deal start>>>'.$topicname);
    $conf = new RdKafka\Conf();

    // Set the group id. This is required when storing offsets on the broker
    $conf->set('group.id', 'myConsumerGroup');

    $rk = new RdKafka\Consumer($conf);
    $rk->addBrokers("localhost:9092");

    $topicConf = new RdKafka\TopicConf();
    $topicConf->set('auto.commit.interval.ms', 100);

    // Set the offset store method to 'file'
    $topicConf->set('offset.store.method', 'broker');

    // Alternatively, set the offset store method to 'none'
    // $topicConf->set('offset.store.method', 'none');

    // Set where to start consuming messages when there is no initial offset in
    // offset store or the desired offset is out of range.
    // 'earliest': start from the beginning
    $topicConf->set('auto.offset.reset', 'earliest');

    $topic = $rk->newTopic($topicname, $topicConf);

    // Start consuming partition 0
    $topic->consumeStart(0, RD_KAFKA_OFFSET_STORED);

    while (true) {
        $message = $topic->consume(0, 120*10000);
        switch ($message->err) {
            case RD_KAFKA_RESP_ERR_NO_ERROR:
                logs('MESSAGE>>>'  . $message->payload);
                $this->dd($message->payload);
                break;
            case RD_KAFKA_RESP_ERR__PARTITION_EOF:
                logs( "No more messages; will wait for more\n");
                break;
            case RD_KAFKA_RESP_ERR__TIMED_OUT:
                logs( "Timed out\n");
                break;
            default:
                logs( $message->errstr());
                //throw new \Exception($message->errstr(), $message->err);
                break;
        }
    }


}

//下载文档保存
private function dd($requestId)
{
    $app = '2020bd';
    $dataEx = $this->common->getLog( array('requestId' => $requestId) );
    logs('原数据ID>>>>'.json_encode($dataEx));
    $fileSrcUrl = $dataEx['fileSrcUrl'];

    $this->common->update(array('bdfile' => $fileSrcUrl, 'status' => 1, 'update_time' => time()), array('requestId' => $requestId));
    //die();

    //下载文件
    $sPath = '/var/www/html/activity/storage/'.$app.'/';
    

    if(empty($fileSrcUrl)){
        logs('文件不存在,结束>>>>>');
        die();
    }
    $fileTemp = explode('?', $fileSrcUrl);
    $path_parts = pathinfo($fileTemp[0]);
    $ext = strtolower($path_parts["extension"]);
    logs('ext:'.$ext);

    try{
        logs('下载中>>>>'.$fileSrcUrl);
        $filename = date('Ymd'). '_' .rand(10000, 99999).'_'.time();
        $tmpfile = $filename . '.'.$ext;
        $img = file_get_contents($fileSrcUrl);
//logs('下载成功'.var_dump($img));

        $path1 = $sPath . $tmpfile;
        //logs('下载中>>>>'.$path1);
        $res = file_put_contents($path1, $img);
        $_SERVER['SERVER_NAME'] = 'w.com';
        if(is_https()){
            $url = 'https://'.$_SERVER['SERVER_NAME'].'/storage/'.$app.'/'.$tmpfile;
        }else{
            $url = 'http://'.$_SERVER['SERVER_NAME'].'/storage/'.$app.'/'.$tmpfile;
        }
        
        //if($res){
            $this->common->update(array('localFile' => $url), array('requestId' => $requestId));
            logs('下载成功>>>>'.$url);
        /*}else{

            logs('下载失败');
        }*/


    }catch(Exception $e){
        logs($e->getMessage());
    }

    logs($requestId.'校验结束');
    echo 'ok';
}

//通过swoole处理,返回给前端
public function dealForUser()
{
    $topicname = "getDocs";
    logs('swoole start>>>'.$topicname);
    //创建WebSocket Server对象,监听0.0.0.0:9502端口
    $ws = new Swoole\WebSocket\Server('0.0.0.0', 9502);

    //监听WebSocket连接打开事件
    $ws->on('Open', function ($ws, $request) {
        $ws->push($request->fd, '');
    });

    //监听WebSocket消息事件
    $ws->on('Message', function ($ws, $frame) {
        log("Message: {$frame->data}\n") ;
        $requestId = $frame->data;
        $file = $this->getDocs($requestId);
        if(!empty($file)){
            $ws->push($frame->fd, "{$file}");
        }
        
    });

    //监听WebSocket连接关闭事件
    $ws->on('Close', function ($ws, $fd) {
        //echo "client-{$fd} is closed\n";
    });

    $ws->start();
    logs('swoole end>>>'.$topicname);


}

//读取文档内容
private function getDocs($requestId)
{
    $app = '2020bd';
    $dataEx = $this->common->get_one( array('requestId' => $requestId) );
    if(!empty($dataEx)){
       logs('DATA FIND>>>'.$dataEx['bdfile']) ;
       return $dataEx['bdfile'];
    }
    return '';
    

    logs($requestId.'校验结束');
    echo 'ok';
}

 前端测试代码




    
    
    
    Document Test
    
    


文件上传框

显示进度条
上传成功后的返回内容
翻译测试:
<翻译》》》
下载文档》》》 下载
图片翻译内容>>>

 

你可能感兴趣的:(PHP,php)