Upload
dangdieu
View
224
Download
0
Embed Size (px)
Citation preview
1 / 22
GiGA Genie AI API 서비스 가이드
2 / 22
작성이력
작성일자 버전 변경사항
2018. 1.0 최초 작성
2019.4.30 1.1 음성인식 API 개요 및 안내
-API 1회 호출 시(인식 1회)의 Time Limit은 15초 5초
3 / 22
GiGA Genie AI API 신청방법
회원가입 방법
1. ucloud biz 포탈 메인 페이지에서 회원가입이 가능합니다
2. 자세한 방법은 고객센터 > 매뉴얼 > Server > 사용자가이드 중 첫 걸음 떼기의
내용을 참조하시기 바랍니다
사전준비사항
1. 상품 > 컴퓨팅 > Server 항목에서 ucloud server 상품을 먼저 싞청합니다
GiGA Genie AI API 은 Running 상태인 VM(Virtual Machine)이 최소 1대는 존재해야
싞청 가능하도록 제한하고 있습니다.
이미 ucloud server 상품을 사용하고 계싞 사용자라면, 본 과정을 넘어가면 됩니다.
4 / 22
2. ucloud server 상품 싞청 후 클라우드 콘솔에 접속합니다
3. 클라우드 콘솔에서 서버를 1개 생성합니다
4. 서버 생성 후 상품 > GiGA Genie AI API 항목으로 이동하여, 상품싞청을 진행합니다
5 / 22
GiGA Genie AI API 상품 신청
1. 상품 > GiGA Genie AI API 을 선택하여 해당 페이지로 접근합니다
2. 우측 플로팅 버튼 [상품 싞청하기]를 클릭하여, 상품싞청을 진행합니다
3. ucloud biz 포탈에서의 상품싞청으로, 기가지니 개발자 센터(www.gigagenie.ai)의 회
원가입 처리가 자동으로 이루어집니다.
사용자는 두 개의 웹 사이트에 별도로 회원 가입하실 필요가 없습니다.
기가지니 개발자 센터의 회원가입이 자동 처리되는 만큼, 해당 사이트의 약관을 제
공하고 있습니다. 약관 확인 후 동의하셔야 다음 단계가 진행됩니다
6 / 22
4. 상품가입이 완료되면, 기가지니 개발자 포탈(www.gigagenie.ai)에서 해당 사이트의
임시 비밀번호를 메일로 전달합니다. 해당 임시 비밀번호는 기가지니 개발자 포탈
에 로그인할 때 필요합니다
7 / 22
GiGA Genie AI API 서비스 생성
1. 클라우드 콘솔 > AI API Cloud 아이콘을 선택합니다.
2. GiGA Genie AI API를 사용하기 위해선 서비스 생성이 필요합니다.
서비스란 AI API를 통해 개발하는 새로운 서비스 프로젝트 개념에 가깝습니다.
1개 계정에는 하나의 GiGA Genie AI 서비스만 생성 가능합니다.
서비스마다 키가 부여되어 AI API를 호출할 수 있게 됩니다.
3. [GiGA Genie AI 서비스 생성] 버튼을 클릭합니다
서비스명: GiGA Genie AI를 활용하기 위한 프로젝트 명칭입니다.
개발시작일: YYYY-MM-DD 형식으로 API를 사용할 시점을 입력합니다.
개발종료일: YYYY-MM-DD 형식으로 API 사용을 종료할 시점을 입력합니다.
앱명: 서비스의 하위 개념으로,
앱설명: 해당 앱의 관리를 위해 필요한 정보를 텍스트로 기술하시면 됩니다
사용자ID: ucloud biz 계정 정보가 노출됩니다.
위 정보를 입력한 후 싞청 버튼을 클릭합니다.
GiGA Genie AI API는 API 호출 건수를 기준으로 사용한만큼 과금 됩니다. 서비스 생
성 시 개발시작일과 개발종료일을 입력할 때 요금 때문에 종료일을 짧게 설정하실
필요는 없습니다.
8 / 22
GiGA Genie AI API 키 확인
1. [GiGA Genie AI 키보기] 버튼을 클릭합니다.
2. API 호출을 위한 Client Key, Client ID, Client Secret 값을 확인하실 수 있습니다.
3. API Key가 타인에게 유출되지 않도록 유의하시기 바랍니다.
GIGA Genie AI API 사용 전 준비
키 확인 및 파일 다운로드
1. GiGA Genie AI API 키보기 버튼을 클릭합니다.
2. API 호출을 위한 Client Key, Client ID, Client Secret값을 확인하실 수 있습니다.
3. 음성인식, 대화 API 사용을 위해 GRPC Spec인 gigagenieRPC.proto 파일과 인증서
번들 ca-bundle.pem 파일을 다운로드하여 API 호출 시 사용합니다.
- curl https://connector.gigagenie.ai/sdk/grpcapi > gigagenieRPC.proto
- curl https://connector.gigagenie.ai/sdk/certbundle > ca-bundle.pem
GRPC 설치
1. Python
1) grpcio 설치: $ python -m pip install grpcio
2) grpc tool 설치: $ python -m pip install grpcio-tools
3) gigagenieRPC.proto 파일을 python code로 generate
$ python -m grpc_tools.protoc -I../../protos --python_out=. --
grpc_python_out=. ../../protos/gigagenieRPC.proto
옵션(예시) 설명
-I../../protos proto파일이 있는 소스 디렉토리
9 / 22
--python_out=. gigagenieRPC_pb2.py 파일이 생성될 디렉
토리
--grpc_python_out=. gigagenieRPC_pb2_grpc.py 파일이 생성될
디렉토리
../../protos/gigagenieRPC.proto proto 파일 정의
4) 3)에서 생성된 gigagenieRPC_pb2.py, gigagenieRPC_pb2_grpc.py 파일을 python
내 import 하여 사용
2. C++
1) protoc 설치(Linux 환경)
- git clone https://github.com/google/protobuf.git
cd protobuf
git submodule update –init –recursive
./autogen.sh
./configure
make;sudo make install;sudo ldconfig
2) grpc 설치(Linux 환경)
- git clone –b $(curl –L https://grpc.io/release) https://github.com/grpc/grpc
cd grpc
git submodule update –init
make; sudo make install
3) proto 소스 생성(.pb.h 및 .pb.cc)
- protoc –I ./ --cpp_out=. gigagenieRPC.proto
4) grpc 소스 생성 (.grpc.pb.h 및 .grpc.pb.cc)
- protoc –I ./ --grpc_out=. –plugin=protoc-gen-grpc=`which grpc_cpp_plugin`
gigagenieRPC.proto
옵션(예시) 설명
-I../../protos proto파일이 있는 소스 디렉토리
--cpp_out=. gigagenieRPC.pb.h 및 gigagenieRPC.pb.cc 가
생성되는 폴더
--grpc_out=. gigagenieRPC.grpc.pb.h 및
gigagenieRPC.grpc.pb.cc 가 생성되는 폴더
-plugin=protoc-gen-grpc 이용 plugin 패스
10 / 22
Signature 생성
1. Signature는 발급받은 client_id와 client_secret을 이용해서 생성합니다.
2. Signature는 timestamp를 생성하고 client_id, timestamp을 조합한 Text를
client_secret으로 sign 하는 방식으로 digest 합니다.
3. timestamp 형식은 ‘YYYYMMDD24hhmmssSSS’ 입니다. (milliseconds 3자리까지)
ex) 20180425113110123
4. Signature는 hex string으로 최종 생성합니다.
Signature=HMAC-SHA256(client_secret, client_id+”:”+timestamp)
GiGA Genie AI 음성인식 API
개요 및 안내사항
사용자의 음성을 스트리밍 형식으로 입력 받아, 텍스트로 인식 값을 반환해주는 API로,
GRPC 형식의 API를 제공합니다.
* API 1회 호출 시(인식 1회)의 Time Limit은 5초입니다.
GiGA Genie AI 음성인식 API 명세
Endpoint https://connector.gigagenie.ai:4080
Package kt.gigagenie.ai.speech
Method getVoice2Text
Credentials Server connector.gigagenie.ai 인증서(ca-bundle.pem)
Metadata name type Description
x-auth-clientkey String 발급받은 client-Key
x-auth-timestamp String Signature생성 Timestamp
x-auth-signature String Signature 값
Request
Parameters
Name reqVoice Type Streaming
Union reqVoiceOpt 또는 audioContent
Fields name type description
reqOptions reqVoiceOpt 음성인식 요청 옵션
audioContent bytes PCM 데이터
Response
Parameters
Name resText Type Streaming
Fields name type description
resultCd Int32 결과 코드
recognizedText string 인식 텍스트
Messages Name reqVoiceOpt
Fields name type description
11 / 22
mode Int32 음성인식모드로 현재
0(Streaming) 만 지원한
다.
lang Int32 음성인식언어로 현재 0(한
국어) 만 지원한다.
ResultCode ResultCode Desc
200 부분음성인식 결과
201 음성인식 결과(완료)
202 음성인식 타임아웃 발생
401 Signature 불일치
404 존재하지 않는 Client Key
500 시스템 에러
509 호출 제한 초과
Sample Code
1. node.js
/* node-record-lpcm16 module을 사용하기 위해서는 sox 설치가 필요합니다. */
const record=require('node-record-lpcm16');
const grpc=require('grpc')
const proto=grpc.load('./gigagenieRPC.proto').kt.gigagenie.ai.speech;
const fs=require('fs');
const crypto=require('crypto');
const dateFormat=require('dateformat');
const sslCred=grpc.credentials.createSsl( fs.readFileSync('./ca-bundle.pem'));
const client_id='YOUR_CLIENT_ID';
const client_key='YOUR_CLIENT_KEY';
const client_secret='YOUR_CLIENT_SECRET';
function getTimeStamp(){
return dateFormat(new Date(),'yyyymmddHHmmssL');
};
function createSignature(id,timestamp,secret){
return crypto.createHmac('sha256',secret).update(id+':'+timestamp).digest('hex');
};
function generateMetadata(params,callback){
const metadata=new grpc.Metadata();
const timeStamp=getTimeStamp();
metadata.add('x-auth-clientkey',client_key);
metadata.add('x-auth-timestamp',timeStamp);
const signature=createSignature(client_id,timeStamp,client_secret);
metadata.add('x-auth-signature',signature);;
callback(null,metadata);
12 / 22
};
function initMic(){
return record.start({
sampleRateHertz: 16000,
threshold: 0,
verbose: false,
recordProgram: 'rec',
silence: '10.0',
})
};
console.log(getTimeStamp());
const authCred=grpc.credentials.createFromMetadataGenerator(generateMetadata);
console.log(authCred);
const credentials=grpc.credentials.combineChannelCredentials(sslCred,authCred);
const client=new proto.Gigagenie('connector.gigagenie.ai:4080',credentials);
const pcm=client.getVoice2Text().on('error',(error)=>{
console.log('Error:'+error);
}).on('data',(data)=>{
console.log('data:'+JSON.stringify(data));
})
pcm.on('end',()=>{
console.log('pcm end');
record.stop();
});
pcm.write({reqOptions:{mode:0,lang:0}});
const mic=initMic();
mic.on('data',(data)=>{
pcm.write({audioContent:data});
});
2. Python
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""The Python implementation of GiGA Genie gRPC client"""
from __future__ import print_function
import grpc
import gigagenieRPC_pb2
import gigagenieRPC_pb2_grpc
import os
import datetime
import hmac
import hashlib
13 / 22
# Config for GiGA Genie gRPC
CLIENT_ID = 'YOUR_CLIENT_ID'
CLIENT_KEY = 'YOUR_CLIENT_KEY'
CLIENT_SECRET = 'YOUR_CLIENT_SECRET'
HOST = 'connector.gigagenie.ai'
PORT = 4080
### COMMON : Client Credentials ###
def getMetadata():
timestamp = datetime.datetime.now().strftime("%Y%m%d%H%M%S%f")[:-3]
message = CLIENT_ID + ':' + timestamp
signature = hmac.new(CLIENT_SECRET, message, hashlib.sha256).hexdigest()
metadata = [('x-auth-clientkey', CLIENT_KEY),
('x-auth-timestamp', timestamp),
('x-auth-signature', signature)]
return metadata
def credentials(context, callback):
callback(getMetadata(), None)
def getCredentials():
with open('ca-bundle.pem', 'rb') as f:
trusted_certs = f.read()
sslCred = grpc.ssl_channel_credentials(root_certificates=trusted_certs)
authCred = grpc.metadata_call_credentials(credentials)
return grpc.composite_channel_credentials(sslCred, authCred)
### END OF COMMON ###
### STT
import pyaudio
import audioop
from six.moves import queue
FORMAT = pyaudio.paInt16
CHANNELS = 1
RATE = 16000
CHUNK = 1024
# MicrophoneStream - original code in https://goo.gl/7Xy3TT
class MicrophoneStream(object):
14 / 22
"""Opens a recording stream as a generator yielding the audio chunks."""
def __init__(self, rate, chunk):
self._rate = rate
self._chunk = chunk
# Create a thread-safe buffer of audio data
self._buff = queue.Queue()
self.closed = True
def __enter__(self):
self._audio_interface = pyaudio.PyAudio()
self._audio_stream = self._audio_interface.open(
format=pyaudio.paInt16,
channels=1, rate=self._rate,
input=True, frames_per_buffer=self._chunk,
# Run the audio stream asynchronously to fill the buffer object.
# This is necessary so that the input device's buffer doesn't
# overflow while the calling thread makes network requests, etc.
stream_callback=self._fill_buffer,
)
self.closed = False
return self
def __exit__(self, type, value, traceback):
self._audio_stream.stop_stream()
self._audio_stream.close()
self.closed = True
# Signal the generator to terminate so that the client's
# streaming_recognize method will not block the process termination.
self._buff.put(None)
self._audio_interface.terminate()
def _fill_buffer(self, in_data, frame_count, time_info, status_flags):
"""Continuously collect data from the audio stream, into the buffer."""
self._buff.put(in_data)
return None, pyaudio.paContinue
def generator(self):
while not self.closed:
# Use a blocking get() to ensure there's at least one chunk of
# data, and stop iteration if the chunk is None, indicating the
# end of the audio stream.
chunk = self._buff.get()
if chunk is None:
return
data = [chunk]
15 / 22
# Now consume whatever other data's still buffered.
while True:
try:
chunk = self._buff.get(block=False)
if chunk is None:
return
data.append(chunk)
except queue.Empty:
break
yield b''.join(data)
# [END audio_stream]
def print_rms(rms):
out = ''
for _ in xrange(int(round(rms/30))):
out = out + '*'
print (out)
def generate_request():
with MicrophoneStream(RATE, CHUNK) as stream:
audio_generator = stream.generator()
for content in audio_generator:
message = gigagenieRPC_pb2.reqVoice()
message.audioContent = content
yield message
rms = audioop.rms(content,2)
print_rms(rms)
def getVoice2Text():
print ("Ctrl+\ to quit ...")
channel = grpc.secure_channel('{}:{}'.format(HOST, PORT), getCredentials())
stub = gigagenieRPC_pb2_grpc.GigagenieStub(channel)
request = generate_request()
resultText = ''
for response in stub.getVoice2Text(request):
if response.resultCd == 200: # partial
print('resultCd=%d | recognizedText= %s'
% (response.resultCd, response.recognizedText))
16 / 22
resultText = response.recognizedText
elif response.resultCd == 201: # final
print('resultCd=%d | recognizedText= %s'
% (response.resultCd, response.recognizedText))
resultText = response.recognizedText
break
else:
print('resultCd=%d | recognizedText= %s'
% (response.resultCd, response.recognizedText))
break
print ("TEXT: %s" % (resultText))
return resultText
def main():
# STT
text = getVoice2Text()
if __name__ == '__main__':
main()
3. C++
#define ALSA_PCM_NEW_HW_PARAMS_API
#define PCM_DEVICE "default"
#include <iostream>
#include <string>
#include <fstream>
#include <grpcpp/grpcpp.h>
#include <openssl/hmac.h>
#include <alsa/asoundlib.h>
#include <alsa/control.h>
#include <time.h>
#include <sys/time.h>
#include <thread>
#include "gigagenieRPC.pb.h"
#include "gigagenieRPC.grpc.pb.h"
using namespace std;
using namespace grpc;
using namespace kt::gigagenie::ai::speech;
//for metadata credential processing
class GigagenieRPCAuthenticator:public grpc::MetadataCredentialsPlugin{
public:
GigagenieRPCAuthenticator(const grpc::string& clientId,const grpc::string& clientKey,const
17 / 22
grpc::string& clientSecret):clientId_(clientId),clientKey_(clientKey),clientSecret_(clientSecret){}
grpc::Status GetMetadata(
grpc::string_ref service_url, grpc::string_ref method_name,
const grpc::AuthContext& channel_auth_context,
std::multimap<grpc::string, grpc::string>* metadata) override {
metadata->insert(std::make_pair("x-auth-clientkey",clientKey_));
timeStamp_=makeTimeStamp();
metadata->insert(std::make_pair("x-auth-timestamp",timeStamp_));
metadata->insert(std::make_pair("x-auth-signature",makeSignature()));
return grpc::Status::OK;
}
private:
grpc::string clientKey_;
grpc::string clientId_;
grpc::string clientSecret_;
grpc::string timeStamp_;
grpc::string makeTimeStamp(){
char buffer[15];//YYYYMMDDHHMMSS
buffer[14]=0x00;
int millisec;
struct tm* tm_info;
struct timeval tv;
gettimeofday(&tv, NULL);
millisec = lrint(tv.tv_usec/1000.0);
if (millisec>=1000) {
millisec -=1000;
tv.tv_sec++;
}
tm_info = localtime(&tv.tv_sec);
strftime(buffer,14,"%Y%m%d%H%M%S",tm_info);
char milli[4];
milli[3]=0x00;
sprintf(milli,"%03d",millisec);
grpc::string time2(milli);
grpc::string returnStr(buffer);
returnStr=returnStr+time2;
return returnStr;
}
grpc::string makeSignature(){
unsigned char* result=(unsigned char *)malloc(HMAC_MAX_MD_CBLOCK);
unsigned int len=0;
auto ctx=HMAC_CTX_new();
const char* key=clientSecret_.c_str();
HMAC_Init_ex(ctx,key,clientSecret_.length(),EVP_sha256(),NULL);
18 / 22
grpc::string shaData=clientId_+":"+timeStamp_;
const unsigned char* data=(unsigned char*)shaData.c_str();
HMAC_Update(ctx,data ,shaData.length());
HMAC_Final(ctx,result,&len);
HMAC_CTX_free(ctx);
grpc::string returnStr;
for(int i=0;i!=len;i++) {
char hex[2];
sprintf(hex,"%02x",(unsigned int)result[i]);
returnStr.append(hex);
}
free(result);
cout<<"Signature:"<<returnStr<<endl;
return returnStr;
}
};
//for read certificate
static std::string get_file_contents(const char *fpath)
{
std::ifstream finstream(fpath);
std::string contents((std::istreambuf_iterator<char>(finstream)),
std::istreambuf_iterator<char>());
return contents;
}
int main() {
//SSL Credentials
SslCredentialsOptions sslOpts;
auto server_ca_pem = get_file_contents("/home/ca-bundle.pem");
sslOpts.pem_root_certs=server_ca_pem;
auto creds=SslCredentials(sslOpts);
//Meta Credentials
grpc::string clientId="YOUR_CLIENT_ID";
grpc::string clientKey="YOUR_CLIENT_KEY";
grpc::string clientSecret="YOUR_CLIENT_SECRET ";
auto call_creds=grpc::MetadataCredentialsFromPlugin(
std::unique_ptr<grpc::MetadataCredentialsPlugin>(new
GigagenieRPCAuthenticator(clientId,clientKey,clientSecret))
);
//composite Credentials
auto compositeChannelCreds=grpc::CompositeChannelCredentials(creds,call_creds);
19 / 22
//create Channel
auto channel=grpc::CreateChannel("connector.gigagenie.ai:4080",compositeChannelCreds);
//Create Stub
ClientContext context;
resQueryText reply;
auto callStub=Gigagenie::NewStub(channel);
//Sound Capture
int num_channels=1;
int samplebit=16;
snd_pcm_uframes_t read_frames=2048;
int dir;
snd_pcm_format_t format = SND_PCM_FORMAT_S16_LE;
int err;
int size;
snd_pcm_hw_params_t *hw_params;
unsigned int rate = 16000;
snd_pcm_uframes_t frames=16;
unsigned char *buffer;
unsigned int period_time;
long loops;//to remove later
int rc;
snd_pcm_t *capture_handle;
if ((err = snd_pcm_open (&capture_handle, "default", SND_PCM_STREAM_CAPTURE, 0)) < 0) {
fprintf (stderr, "cannot open audio device %s (%s)\n",PCM_DEVICE,snd_strerror
(err));
exit (1);
}
if ((err = snd_pcm_hw_params_malloc (&hw_params)) < 0) {
fprintf (stderr, "cannot allocate hardware parameter structure (%s)\n",snd_strerror
(err));
exit (1);
}
if ((err = snd_pcm_hw_params_any (capture_handle, hw_params)) < 0) {
fprintf (stderr, "cannot initialize hardware parameter structure (%s)\n",
snd_strerror (err));
exit (1);
}
if ((err = snd_pcm_hw_params_set_access (capture_handle, hw_params,
SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
fprintf (stderr, "cannot set access type (%s)\n",snd_strerror (err));
exit (1);
20 / 22
}
if ((err = snd_pcm_hw_params_set_format (capture_handle, hw_params,
SND_PCM_FORMAT_S16_LE)) < 0) {
fprintf (stderr, "cannot set sample format (%s)\n",snd_strerror (err));
exit (1);
}
if ((err = snd_pcm_hw_params_set_channels (capture_handle, hw_params, 1)) < 0) {
fprintf (stderr, "cannot set channel count (%s)\n",snd_strerror (err));
exit (1);
}
//if ((err = snd_pcm_hw_params_set_rate_near (capture_handle, hw_params, &rate, &dir)) < 0) {
if ((err = snd_pcm_hw_params_set_rate_near (capture_handle, hw_params, &rate, 0)) < 0) {
fprintf (stderr, "cannot set sample rate (%s)\n",snd_strerror (err));
exit (1);
}
if ((err = snd_pcm_hw_params_set_period_size_near(capture_handle, hw_params, &frames,
&dir)) < 0) {
fprintf (stderr, "cannot set frame (%s)\n",snd_strerror (err));
exit (1);
}
if ((err = snd_pcm_hw_params (capture_handle, hw_params)) < 0) {
fprintf (stderr, "cannot set parameters (%s)\n", snd_strerror (err));
exit (1);
}
snd_pcm_hw_params_get_period_size(hw_params,&frames, &dir);
size=frames*2;/* 2bytes/sample, 1Channels*/
buffer=(unsigned char*)malloc(size);
snd_pcm_hw_params_get_period_time(hw_params,&period_time, &dir);
loops = 5000000/period_time;
reqVoice getVoiceTextReqVoice;
getVoiceTextReqVoice.mutable_reqoptions()->set_lang(0);
getVoiceTextReqVoice.mutable_reqoptions()->set_mode(0);
CompletionQueue cq;
void* got_tag_write;
void* got_tag_read;
void* got_tag_finish;
bool ok=false;
//async processing.
auto stream(callStub->AsyncgetVoice2Text(&context,&cq,got_tag_read));
cq.Next(&got_tag_read,&ok);
cout<<"Write ReqOption Async"<<endl;
stream->Write(getVoiceTextReqVoice,got_tag_write);
21 / 22
cq.Next(&got_tag_write,&ok);
bool loop=true;
reqVoice getVoiceTextReqVoiceStream;
resText repText;
//read async
stream->Read(&repText,got_tag_read);
Status finStatus;
//check finish status
bool checkFinStat=false;
while(loop){
rc = snd_pcm_readi(capture_handle, buffer, frames);
if (rc == -EPIPE) {
fprintf(stderr, "overrun occurred\n");
snd_pcm_prepare(capture_handle);
} else if (rc < 0) {
fprintf(stderr,"error from read: %s\n",
snd_strerror(rc));
} else if (rc != (int)frames) {
fprintf(stderr, "short read, read %d frames\n", rc);
}
//auto sendBufferBas64=Base64Encode(buffer,size);
//cout<<"Write Audio Data Size:"<<rc<<endl;
getVoiceTextReqVoiceStream.set_audiocontent((void*)buffer,size);
stream->Write(getVoiceTextReqVoiceStream,got_tag_write);
cq.Next(&got_tag_write,&ok);
auto
readStat=cq.AsyncNext(&got_tag_read,&ok,std::chrono::system_clock::now()+std::chrono::milliseconds(1));
switch(readStat){
case grpc::CompletionQueue::GOT_EVENT:
if(ok) {
cout<<"Read Success
ResultCd:"<<repText.resultcd()<<" recogText:"<<repText.recognizedtext()<<endl;
//check finish condition
if(repText.resultcd()==202){
stream-
>Finish(&finStatus,got_tag_finish);
checkFinStat=true;
} else stream->Read(&repText,got_tag_read);
} else {
cout<<"Read Failed"<<endl;
stream->Finish(&finStatus,got_tag_finish);
checkFinStat=true;
}
break;
case grpc::CompletionQueue::SHUTDOWN:
cout<<"ShutDown"<<endl;
break;
22 / 22
case grpc::CompletionQueue::TIMEOUT:
//cout<<"TimeOut"<<endl;
break;
}
if(checkFinStat){
auto
finStat=cq.AsyncNext(&got_tag_finish,&ok,std::chrono::system_clock::now()+std::chrono::milliseconds(5));
switch(finStat){
case grpc::CompletionQueue::GOT_EVENT:
cout<<"FinStat GOT_EVETN"<<endl;
loop=false;
break;
case grpc::CompletionQueue::SHUTDOWN:
cout<<"FinStat SHUTDOWN"<<endl;
break;
case grpc::CompletionQueue::TIMEOUT:
//cout<<"TimeOut"<<endl;
break;
}
}
}
snd_pcm_drain(capture_handle);
snd_pcm_close(capture_handle);
free(buffer);
cout<<"Everything is done"<<endl;
return 0;
}
Signature 생성
1. Signature는 발급받은 client_id와 client_secret을 이용해서 생성합니다.
2. Signature는 timestamp를 생성하고 client_id, timestamp을 조합한 Text를
client_secret으로 sign 하는 방식으로 digest 합니다.
3. timestamp 형식은 ‘YYYYMMDD24hhmmssSSS’ 입니다. (milliseconds 3자리까지)
ex) 20180425113110123
4. Signature는 hex string으로 최종 생성합니다.
Signature=HMAC-SHA256(client_secret, client_id+”:”+timestamp)