icsstt 모듈 빠져있던것 추가
parent
095ac40fa3
commit
d2bac81363
@ -0,0 +1,180 @@
|
||||
package stt
|
||||
|
||||
import (
|
||||
"math"
|
||||
"sync"
|
||||
|
||||
"mybatch/icslog"
|
||||
)
|
||||
|
||||
const RR_200MSEC_SIZE = 3200
|
||||
|
||||
type RRData struct {
|
||||
wPos int
|
||||
wTPos int
|
||||
wtSize int
|
||||
rPos int
|
||||
size int // max size
|
||||
audio []byte
|
||||
rtAudio []byte //for GetAudio()
|
||||
rtAudioLen int
|
||||
m *sync.Mutex
|
||||
}
|
||||
|
||||
func NewRRData(size int) *RRData {
|
||||
if size <= 0 {
|
||||
return nil
|
||||
}
|
||||
rr := RRData{wPos: 0, rPos: 0, size: size, rtAudioLen: 0}
|
||||
rr.m = &sync.Mutex{}
|
||||
rr.audio = make([]byte, size)
|
||||
rr.rtAudio = make([]byte, size)
|
||||
|
||||
return &rr
|
||||
}
|
||||
|
||||
func (rr *RRData) AddAudio(data []byte) int {
|
||||
l := icslog.InitializeLogger()
|
||||
|
||||
size := len(data)
|
||||
if size <= 0 || rr.audio == nil {
|
||||
return -1
|
||||
}
|
||||
|
||||
rr.m.Lock()
|
||||
if rr.wPos == 0 && rr.wTPos != 0 {
|
||||
rr.wPos = rr.wtSize
|
||||
}
|
||||
|
||||
if rr.wPos+size > rr.size {
|
||||
l.Printf("AddAudio> RRData write size exceeded!!! size: %d-%d", rr.size, rr.wPos+size)
|
||||
rr.wPos = rr.wtSize
|
||||
//l.Printf(icslog.LOG_LEVEL_DEBUG2, -1, "AddAudio> RRData write size exceeded. wPos reset. %d-%d-%d", rr.wPos, rr.size, rr.wPos+size)
|
||||
}
|
||||
|
||||
//l.Printf(icslog.LOG_LEVEL_DEBUG2, -1, "AddAudio> wPos: %d, size: %d, total size: %d", rr.wPos, size, rr.size)
|
||||
|
||||
copy(rr.audio[rr.wPos:], data[:])
|
||||
rr.wPos += size
|
||||
|
||||
if rr.size <= rr.rtAudioLen {
|
||||
rr.rtAudio = append(rr.rtAudio, data...)
|
||||
} else {
|
||||
copy(rr.rtAudio[rr.rtAudioLen:], data)
|
||||
}
|
||||
rr.rtAudioLen += size
|
||||
|
||||
rr.m.Unlock()
|
||||
|
||||
return rr.wPos
|
||||
}
|
||||
|
||||
func (rr *RRData) AddTempAudio(data []byte) int {
|
||||
//1sec temp buffer
|
||||
if rr.size < 40000 || rr.audio == nil {
|
||||
return -1
|
||||
}
|
||||
|
||||
size := len(data)
|
||||
if size <= 0 {
|
||||
return -1
|
||||
}
|
||||
|
||||
rr.m.Lock()
|
||||
|
||||
//l := icslog.GetIcsLog()
|
||||
//l.Printf(icslog.LOG_LEVEL_DEBUG2, -1, "AddTempAudio> wtPos: %d, size: %d", rr.wTPos, size)
|
||||
|
||||
if rr.wTPos+size > 40000 {
|
||||
//rr.wTPos = 0
|
||||
rr.wtSize = 40000
|
||||
rr.audio = rr.audio[size:]
|
||||
copy(rr.audio[rr.wTPos-size:], data[:])
|
||||
} else {
|
||||
rr.wtSize += size
|
||||
copy(rr.audio[rr.wTPos:], data[:])
|
||||
rr.wTPos += size
|
||||
}
|
||||
|
||||
rr.m.Unlock()
|
||||
|
||||
return rr.wTPos
|
||||
}
|
||||
|
||||
func (rr *RRData) ReadAudio(size int) (int, []byte) {
|
||||
l := icslog.InitializeLogger()
|
||||
|
||||
if rr.audio == nil {
|
||||
return -2, nil
|
||||
}
|
||||
|
||||
rr.m.Lock()
|
||||
if int(math.Abs(float64(rr.wPos-rr.rPos))) < 1600 || int(math.Abs(float64(rr.wPos-rr.rPos))) < size {
|
||||
rr.m.Unlock()
|
||||
return 0, nil
|
||||
}
|
||||
rData := make([]byte, size)
|
||||
|
||||
if rr.size < rr.rPos+size {
|
||||
rr.m.Unlock()
|
||||
l.Printf("ReadAudio> RRData read size exceeded!!! size: %d-%d", rr.size, rr.rPos+size)
|
||||
return -1, nil
|
||||
//rr.rPos = 0
|
||||
}
|
||||
|
||||
//l.Printf(icslog.LOG_LEVEL_DEBUG2, -1, "ReadAudio> rPos: %d, size: %d, total size: %d", rr.rPos, size, rr.size)
|
||||
|
||||
copy(rData[:], rr.audio[rr.rPos:rr.rPos+size])
|
||||
//fmt.Println("read audio data:", rr.rPos)
|
||||
rr.rPos += size
|
||||
|
||||
rr.m.Unlock()
|
||||
|
||||
return rr.rPos, rData
|
||||
}
|
||||
|
||||
func (rr *RRData) Clear() {
|
||||
rr.m.Lock()
|
||||
rr.wPos = 0
|
||||
rr.rPos = 0
|
||||
rr.audio = nil
|
||||
rr.rtAudio = nil
|
||||
rr.m.Unlock()
|
||||
|
||||
l := icslog.InitializeLogger()
|
||||
l.Print("Cleared RRData")
|
||||
}
|
||||
|
||||
func (rr *RRData) GetAudio() []byte {
|
||||
if rr.audio == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
rr.m.Lock()
|
||||
|
||||
if rr.rtAudioLen <= 0 {
|
||||
rr.m.Unlock()
|
||||
return nil
|
||||
}
|
||||
//l.Printf(icslog.LOG_LEVEL_DEBUG2, -1, "GetAudio> audio length: %d", rr.rtAudioLen)
|
||||
|
||||
var rData []byte
|
||||
if rr.wtSize > 0 {
|
||||
rData = make([]byte, rr.wtSize+rr.rtAudioLen)
|
||||
copy(rData, rr.audio[:rr.wtSize])
|
||||
copy(rData[rr.wtSize:], rr.rtAudio)
|
||||
} else {
|
||||
rData = make([]byte, rr.rtAudioLen)
|
||||
copy(rData, rr.rtAudio)
|
||||
}
|
||||
|
||||
rr.m.Unlock()
|
||||
|
||||
return rData
|
||||
}
|
||||
|
||||
func (rr *RRData) Close() {
|
||||
rr.audio = nil
|
||||
rr.rtAudio = nil
|
||||
//rr = new(RRData)
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package stt
|
||||
|
||||
import (
|
||||
"cloud.google.com/go/speech/apiv1"
|
||||
"cloud.google.com/go/speech/apiv1/speechpb"
|
||||
"context"
|
||||
"log"
|
||||
"os"
|
||||
)
|
||||
|
||||
func RecognizeSpeech(language, filepath string) error {
|
||||
ctx := context.Background()
|
||||
client, err := speech.NewClient(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer client.Close()
|
||||
|
||||
audioData, err := os.ReadFile(filepath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
req := &speechpb.RecognizeRequest{
|
||||
Config: &speechpb.RecognitionConfig{
|
||||
Encoding: speechpb.RecognitionConfig_LINEAR16,
|
||||
SampleRateHertz: 16000,
|
||||
LanguageCode: language,
|
||||
},
|
||||
Audio: &speechpb.RecognitionAudio{
|
||||
AudioSource: &speechpb.RecognitionAudio_Content{
|
||||
Content: audioData,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
resp, err := client.Recognize(ctx, req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, result := range resp.Results {
|
||||
for _, alt := range result.Alternatives {
|
||||
log.Printf("Transcript: %s\n", alt.Transcript)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
package stt
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"mybatch/icsconf"
|
||||
"mybatch/icserror"
|
||||
"os"
|
||||
"strconv"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var config icsconf.AppInfo
|
||||
|
||||
func init() {
|
||||
config = icsconf.Getconfig()
|
||||
}
|
||||
|
||||
func TestXXX(t *testing.T) {
|
||||
data, _ := os.ReadFile("/home/prac/svc/icsbc/voice/pcm/20250913223412/20250913223412-left.pcm")
|
||||
connectSttServer()
|
||||
sttResTest(data)
|
||||
}
|
||||
|
||||
func connectSttServer(voicedata []byte) (bool, *icserror.IcsError) {
|
||||
var s *STTSelvas
|
||||
var sttErr *icserror.IcsError
|
||||
ip := config.STT.SrcIP
|
||||
port, _ := strconv.Atoi(cfg.STT.Port)
|
||||
callId := "00ef1234567899001"
|
||||
custid := "3002"
|
||||
RecordFilePath := "/home/prac/svc/icsbc/sttres"
|
||||
|
||||
// func NewSTTS(sid int, IP string, port int, callID string, custID string, filePath string)
|
||||
s, sttErr = NewSTTS(ip, port, callId, custid, RecordFilePath)
|
||||
if sttErr != nil {
|
||||
return false, icserror.ICSERRSTTConnectFail
|
||||
} else if s != nil {
|
||||
fmt.Println("STT session:", s)
|
||||
}
|
||||
fmt.Println("stt server is connected with: ", ip, ", port: ", port)
|
||||
return true, nil
|
||||
}
|
||||
func sttResTest(voicedata []byte) (bool, *icserror.IcsError) {
|
||||
|
||||
}
|
@ -0,0 +1,449 @@
|
||||
package stt
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"mybatch/icsconf"
|
||||
encry "mybatch/icsencry"
|
||||
"mybatch/icserror"
|
||||
httprequest "mybatch/icshttp"
|
||||
"mybatch/icslog"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
)
|
||||
|
||||
type RequestData struct {
|
||||
StartTime string `json:"starttime"`
|
||||
Ext string `json:"ext"`
|
||||
ConnID string `json:"connid"`
|
||||
}
|
||||
|
||||
type FileListResponse struct {
|
||||
TotalCnt string `json:"totalCnt"`
|
||||
ReturnCode string `json:"returnCode"`
|
||||
ReturnMsg string `json:"returnMsg"`
|
||||
List []FileInfo `json:"list"`
|
||||
}
|
||||
|
||||
type FileInfo struct {
|
||||
No int `json:"no"`
|
||||
ConnID string `json:"connid"`
|
||||
Ext string `json:"ext"`
|
||||
StartTime string `json:"starttime"`
|
||||
}
|
||||
|
||||
type Transcript struct {
|
||||
Text string `json:"text"`
|
||||
StartTime int `json:"startTime"`
|
||||
EndTime int `json:"endTime"`
|
||||
EndPoint bool `json:"endPoint"`
|
||||
}
|
||||
|
||||
type ResponseData struct {
|
||||
Uid string `json:"uid"`
|
||||
Ext string `json:"ext"`
|
||||
SpeakerTag string `json:"speakerTag"`
|
||||
Transcripts []Transcript `json:"transcripts"`
|
||||
}
|
||||
|
||||
type TAMessage struct {
|
||||
Cmd string `json:"cmd"` // STT 이벤트 상태 구분값 S:시작, E:종료, T:Text, P:Partial
|
||||
ConnID string `json:"connid"` //Cti 생성콜 key
|
||||
Tel string `json:"tel"` //고객 전화번호
|
||||
Ext string `json:"ext"` //상담사 내선번호
|
||||
CallStartTime string `json:"callStartTime"` //콜 시작시간 unixtime
|
||||
IgGbn string `json:"igGbn"` //통화유형 0:알수없음, 1:인바운드, 2:아웃바운드
|
||||
DateTime string `json:"datetime"` //STT 시작시간
|
||||
Stt string `json:"stt"` //STT 결과
|
||||
Dir string `json:"dir"` //STT 화자구분 R:고객, T:상담사
|
||||
}
|
||||
|
||||
var (
|
||||
cfg icsconf.AppInfo
|
||||
l *log.Logger
|
||||
)
|
||||
|
||||
func init() {
|
||||
cfg = icsconf.Getconfig()
|
||||
l = icslog.InitializeLogger()
|
||||
}
|
||||
|
||||
func ProcessPostRequestForDataList() {
|
||||
var starttime uint64
|
||||
currentDate := time.Now().Format("20060102")
|
||||
currentDateUint64, _ := strconv.ParseUint(currentDate, 10, 64)
|
||||
|
||||
starttime = currentDateUint64 - 1
|
||||
starttimeStr := strconv.FormatUint(starttime, 10)
|
||||
|
||||
data := RequestData{
|
||||
StartTime: starttimeStr,
|
||||
Ext: "",
|
||||
ConnID: "",
|
||||
}
|
||||
|
||||
jsonData, _ := json.Marshal(data)
|
||||
encryptedRequestBody := encry.Encrypting(jsonData)
|
||||
|
||||
url := "https://192.168.0.69:8080/sttRest.do"
|
||||
method := "POST"
|
||||
requestBody := fmt.Sprintf(`{"data":"%s"}`, encryptedRequestBody)
|
||||
|
||||
response, err := httprequest.HttpRequest(url, method, requestBody)
|
||||
if err != nil {
|
||||
l.Println("error occured while requesting http post for datalist:", err)
|
||||
return
|
||||
}
|
||||
|
||||
defer response.Body.Close()
|
||||
body, _ := io.ReadAll(response.Body)
|
||||
|
||||
fmt.Println("응답 on ProcessPostRequestForDataList: ", string(body))
|
||||
|
||||
var parsedRes FileListResponse
|
||||
if err := json.Unmarshal([]byte(body), &parsedRes); err != nil {
|
||||
l.Println("Error parsing JSON:", err)
|
||||
return
|
||||
}
|
||||
|
||||
var reqDataForVoiceFile RequestData
|
||||
if len(parsedRes.List) > 0 {
|
||||
for _, item := range parsedRes.List {
|
||||
reqDataForVoiceFile = RequestData{
|
||||
StartTime: item.StartTime,
|
||||
Ext: item.Ext,
|
||||
ConnID: item.ConnID,
|
||||
}
|
||||
// Requesting For wav file and download it at local
|
||||
postReqForWavFileAndDownload(reqDataForVoiceFile)
|
||||
}
|
||||
} else {
|
||||
l.Println("No items in the datalist.")
|
||||
}
|
||||
}
|
||||
|
||||
func postReqForWavFileAndDownload(parsedRes RequestData) {
|
||||
jsonData, _ := json.Marshal(parsedRes)
|
||||
encryptedRequestBody := encry.Encrypting(jsonData)
|
||||
|
||||
url := "https://192.168.0.69:8080/sttRest.do"
|
||||
method := "POST"
|
||||
requestBody := fmt.Sprintf(`{"data":"%s"}`, encryptedRequestBody)
|
||||
|
||||
response, err := httprequest.HttpRequest(url, method, requestBody)
|
||||
if err != nil {
|
||||
l.Println("error occured while requesting http post for datalist:", err)
|
||||
return
|
||||
}
|
||||
st := parsedRes.StartTime
|
||||
wavFilePath := cfg.Directories.WAVDirectory
|
||||
fileName := fmt.Sprintf(`%s/%s.wav`, wavFilePath, st)
|
||||
file, err := os.Create(fileName)
|
||||
if err != nil {
|
||||
l.Println("error occured while creating file:", err)
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
_, err = io.Copy(file, response.Body)
|
||||
if err != nil {
|
||||
l.Println("error occured while writing to file:", err)
|
||||
return
|
||||
}
|
||||
|
||||
// 잘 쪼개졌다면 각 left, right을 stt 돌리기
|
||||
pcmResult, folderName := devideWavTo2Pcm(fileName)
|
||||
|
||||
if pcmResult {
|
||||
sttCallRes, err := controlSTT(parsedRes, folderName)
|
||||
if err != nil {
|
||||
l.Println("runSTT() failed with the error: ", err)
|
||||
}
|
||||
// stt 콜이 성공이라면 pcm 파일 지우기
|
||||
if sttCallRes {
|
||||
pcmDir := filepath.Join(cfg.Directories.PCMDirectory, st)
|
||||
deletePcmFolder(pcmDir)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func deletePcmFolder(foldername string) (bool, *icserror.IcsError) {
|
||||
fmt.Println("foldername in deletePcmFolder func: ", foldername)
|
||||
if _, err := os.Stat(foldername); os.IsNotExist(err) {
|
||||
l.Println("pcm folder does not exist with the dir: ", foldername) //error here
|
||||
l.Println("error: ", err)
|
||||
return false, icserror.ICSERRFileOpen
|
||||
}
|
||||
err := os.RemoveAll(foldername)
|
||||
if err != nil {
|
||||
l.Panicln("error occured while deleting folder: ", foldername)
|
||||
return false, icserror.ICSERRWriteFile
|
||||
}
|
||||
l.Printf(`folder: %s has been successfully deleted`, foldername)
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func devideWavTo2Pcm(fileName string) (result bool, folderName string) {
|
||||
// fileName: /home/prac/svc/icsbc/voice/wav/20250913223412.wav
|
||||
fileNameWithoutWav := fileName[:len(fileName)-4]
|
||||
lastSlashIdx := strings.LastIndex(fileNameWithoutWav, "/")
|
||||
starttime := fileNameWithoutWav[lastSlashIdx+1:] //starttime: 20250913223412
|
||||
pcmDir := cfg.Directories.PCMDirectory
|
||||
|
||||
starttimeDir := fmt.Sprintf("%s/%s", pcmDir, starttime)
|
||||
os.MkdirAll(starttimeDir, os.ModePerm)
|
||||
|
||||
leftOutputFile := fmt.Sprintf(`%s/%s-left.pcm`, starttimeDir, starttime)
|
||||
rightOutputFile := fmt.Sprintf(`%s/%s-right.pcm`, starttimeDir, starttime)
|
||||
fmt.Println("inFile reading wav path: ", fileName)
|
||||
|
||||
inFile, err := os.Open(fileName)
|
||||
if err != nil {
|
||||
l.Println("failed to open input file: %v", err)
|
||||
return false, ""
|
||||
}
|
||||
defer inFile.Close()
|
||||
|
||||
leftFile, err := os.Create(leftOutputFile)
|
||||
if err != nil {
|
||||
l.Println("failed to create left channel file: %v", err)
|
||||
return false, ""
|
||||
}
|
||||
defer leftFile.Close()
|
||||
|
||||
rightFile, err := os.Create(rightOutputFile)
|
||||
if err != nil {
|
||||
l.Println("failed to create right channel file: %v", err)
|
||||
return false, ""
|
||||
}
|
||||
defer rightFile.Close()
|
||||
|
||||
// Skip WAV header (44 bytes)
|
||||
wavHeader := make([]byte, 44)
|
||||
if _, err := inFile.Read(wavHeader); err != nil {
|
||||
l.Println("failed to read WAV header: %v", err)
|
||||
return false, ""
|
||||
}
|
||||
|
||||
// Check if it's a valid WAV file
|
||||
if string(wavHeader[:4]) != "RIFF" || string(wavHeader[8:12]) != "WAVE" {
|
||||
l.Println("invalid WAV file format")
|
||||
return false, ""
|
||||
}
|
||||
|
||||
// Check if WAV file is stereo
|
||||
numChannels := binary.LittleEndian.Uint16(wavHeader[22:24])
|
||||
if numChannels != 2 {
|
||||
l.Println("unsupported channel count: this function only supports stereo (2 channels)")
|
||||
return false, ""
|
||||
}
|
||||
|
||||
buf := make([]byte, 4) // 2 bytes per sample * 2 channels
|
||||
|
||||
for {
|
||||
n, err := inFile.Read(buf)
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
l.Println("failed to read from input file: %v", err)
|
||||
return false, ""
|
||||
}
|
||||
|
||||
if n < 4 {
|
||||
l.Printf("unexpected sample size read: %d\n", n)
|
||||
// Break or handle the case based on your needs
|
||||
for i := n; i < 4; i++ {
|
||||
buf[i] = 0
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
leftSample := buf[:2]
|
||||
rightSample := buf[2:]
|
||||
|
||||
if err := binary.Write(leftFile, binary.LittleEndian, leftSample); err != nil {
|
||||
l.Println("failed to write to left channel file: %v", err)
|
||||
return false, ""
|
||||
}
|
||||
|
||||
if err := binary.Write(rightFile, binary.LittleEndian, rightSample); err != nil {
|
||||
l.Println("failed to write to right channel file: %v", err)
|
||||
return false, ""
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
l.Println("WAV file split successfully")
|
||||
return true, starttime
|
||||
}
|
||||
|
||||
// server 연결, stt 호출, 연결 해제
|
||||
func controlSTT(parsedRes RequestData, folderName string) (bool, *icserror.IcsError) {
|
||||
pcmDirectory := cfg.Directories.PCMDirectory
|
||||
pcmDirectory = filepath.Join(pcmDirectory, folderName)
|
||||
|
||||
// walking the file that has each left and right pcm files
|
||||
filepath.Walk(pcmDirectory, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
l.Println("Error occured while walking pcm folder. error: ", err)
|
||||
l.Println("The pcm file path: ", pcmDirectory)
|
||||
return err
|
||||
}
|
||||
if !info.IsDir() && filepath.Ext(path) == "left.pcm" {
|
||||
stterr := connectSelvasServerRunSTT(parsedRes, path, "left")
|
||||
if stterr != nil {
|
||||
l.Println("Error occured on recognizeSpeechFromPcmFile(). error: ", stterr)
|
||||
return err
|
||||
}
|
||||
}
|
||||
if !info.IsDir() && filepath.Ext(path) == "right.pcm" {
|
||||
stterr := connectSelvasServerRunSTT(parsedRes, path, "right")
|
||||
if stterr != nil {
|
||||
l.Println("Error occured on recognizeSpeechFromPcmFile(). error: ", stterr)
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func connectSelvasServerRunSTT(parsedRes RequestData, filePath string, leftright string) *icserror.IcsError {
|
||||
var sttRes NewSTTResult
|
||||
var sttErr *icserror.IcsError
|
||||
|
||||
voicedata, err := os.ReadFile(filePath)
|
||||
if err != nil {
|
||||
return icserror.ICSERRCONFOpenFile
|
||||
}
|
||||
ip := cfg.STT.SrcIP
|
||||
port, _ := strconv.Atoi(cfg.STT.Port)
|
||||
callId := parsedRes.ConnID
|
||||
custId := parsedRes.Ext
|
||||
recordFilePath := cfg.Directories.RecDirectory
|
||||
|
||||
// connecting with STT server
|
||||
s, sttErr := NewSTTS(ip, port, callId, custId, recordFilePath)
|
||||
if sttErr != nil {
|
||||
return icserror.ICSERRSTTConnectFail
|
||||
} else if s != nil {
|
||||
fmt.Println("STT session:", s)
|
||||
}
|
||||
l.Println("STT server is connected with: ", ip, ", port: ", port)
|
||||
|
||||
// STT 호출
|
||||
sttRes, sttErr = s.SendSTT(voicedata, true, nil)
|
||||
if sttErr != nil {
|
||||
l.Println("calling sendSTT() on sttselvas.go has failed with error: ", sttErr)
|
||||
return icserror.ICSERRSTTSendFail
|
||||
}
|
||||
|
||||
// STT server and chanel close
|
||||
s.CloseChanelAndServer()
|
||||
|
||||
// STT 호출 성공시 결과를 websocket, ta rest로 송신
|
||||
if sttRes.Res != "" {
|
||||
wssres, wsserr := webSocketSend(parsedRes, sttRes, leftright)
|
||||
httpres, httperr := taRestSend(parsedRes, sttRes, s.GetReqTime(), leftright)
|
||||
if wssres && httpres {
|
||||
l.Println("stt results have successfully sent through both wss and http(ta)")
|
||||
}
|
||||
if wsserr != nil {
|
||||
l.Println("sending stt result through websocket has failed with the error: ", wsserr)
|
||||
}
|
||||
if httperr != nil {
|
||||
l.Println("sending stt result through http for ta has failed with the error: ", httperr)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func webSocketSend(parsedRes RequestData, sttRes NewSTTResult, leftright string) (bool, *icserror.IcsError) {
|
||||
speaker := "X" // T: 상담사
|
||||
if leftright == "left" {
|
||||
speaker = "R" //R: 고객
|
||||
}
|
||||
url := "ws://192.168.0.69:8090/wss"
|
||||
headers := http.Header{
|
||||
"Origin": {"https://192.168.0.69"},
|
||||
}
|
||||
conn, _, err := websocket.DefaultDialer.Dial(url, headers)
|
||||
if err != nil {
|
||||
l.Println("Failed to connect to WebSocket: %v", err)
|
||||
return false, icserror.ICSERRWEBSOCKETConnectFailError
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
resData := ResponseData{
|
||||
Uid: parsedRes.ConnID,
|
||||
Ext: parsedRes.Ext,
|
||||
SpeakerTag: speaker,
|
||||
Transcripts: []Transcript{
|
||||
{
|
||||
Text: sttRes.Res,
|
||||
StartTime: sttRes.NStart,
|
||||
EndTime: sttRes.NEnd,
|
||||
EndPoint: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
jsonData, _ := json.Marshal(resData)
|
||||
encryptedResponseBody := encry.Encrypting(jsonData)
|
||||
|
||||
responseBody := fmt.Sprintf(`{"data":"%s"}`, encryptedResponseBody)
|
||||
|
||||
err = conn.WriteMessage(websocket.TextMessage, []byte(responseBody))
|
||||
if err != nil {
|
||||
l.Println("failed to send msg via websocket with the err: ", err)
|
||||
return false, icserror.ICSERRWEBSOCKETWriteError
|
||||
} else {
|
||||
l.Println("Sent the msg via websocket. message body: ", responseBody)
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
func taRestSend(parsedRes RequestData, sttRes NewSTTResult, reqTime time.Time, leftright string) (bool, *icserror.IcsError) {
|
||||
dir := "T" // T: 상담사
|
||||
if leftright == "left" {
|
||||
dir = "R" //R: 고객
|
||||
}
|
||||
resData := TAMessage{
|
||||
Cmd: "T",
|
||||
ConnID: parsedRes.ConnID,
|
||||
Tel: "", // 정보없음
|
||||
Ext: parsedRes.Ext,
|
||||
CallStartTime: parsedRes.StartTime,
|
||||
IgGbn: "1", // 인바운드
|
||||
DateTime: reqTime.Format("2006-01-02 15:04:05"),
|
||||
Stt: sttRes.Res,
|
||||
Dir: dir,
|
||||
}
|
||||
jsonData, _ := json.Marshal(resData)
|
||||
encryptedRequestBody := encry.Encrypting(jsonData)
|
||||
|
||||
url := "https://192.168.0.69:8080/taRest.do"
|
||||
method := "POST"
|
||||
requestBody := fmt.Sprintf(`{"data":"%s"}`, encryptedRequestBody)
|
||||
|
||||
response, err := httprequest.HttpRequest(url, method, requestBody)
|
||||
if err != nil {
|
||||
l.Println("error occured while requesting http post for datalist:", err)
|
||||
return false, icserror.ICSERRHTTPClientExcecution
|
||||
}
|
||||
|
||||
l.Println("TA msg has been successfully sent. response: ", response)
|
||||
return true, nil
|
||||
}
|
@ -0,0 +1,727 @@
|
||||
//go:build !test
|
||||
// +build !test
|
||||
|
||||
// for STT SELVAS STT
|
||||
package stt
|
||||
|
||||
/*
|
||||
#cgo LDFLAGS: -lstdc++ -ldl ./extlib/selvasstt/SDK/LIB/c_linux/x64/libASRLIB.a ./extlib/selvasstt/SDK/OpenSSL/Linux/Linux_x64/libssl.a ./extlib/selvasstt/SDK/OpenSSL/Linux/Linux_x64/libcrypto.a
|
||||
#cgo CFLAGS: -I ../extlib/selvasstt/SDK/INCLUDE
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <Lvcsr_Api.h>
|
||||
|
||||
char* getResultData(LVCSR_DATA_RESULT* pDataResult, long long nCount) {
|
||||
char* skip1 = "<eps>";
|
||||
char* space = " ";
|
||||
int len = 0;
|
||||
long long i;
|
||||
|
||||
for (i = 0; i < nCount; i++) {
|
||||
len += strlen(pDataResult[i].pTokenStr) + 1;
|
||||
printf("start: %ld, end: %ld\n", pDataResult[i].nStart, pDataResult[i].nEnd);
|
||||
}
|
||||
|
||||
char* result = malloc(sizeof(char) * len);
|
||||
strcpy(result, "");
|
||||
|
||||
for (i = 0; i < nCount; i++) {
|
||||
if (strcmp(pDataResult[i].pTokenStr,skip1) == 0) {
|
||||
} else {
|
||||
strcat(result, space);
|
||||
strcat(result, pDataResult[i].pTokenStr);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void freeResult(char* result){
|
||||
if(result == NULL) {
|
||||
return;
|
||||
}
|
||||
free(result);
|
||||
}
|
||||
|
||||
int getMidResultEPD(LVCSR_RECOG_MID_RESULT *midResult){
|
||||
return midResult->bEngineDetectionFlag;
|
||||
}
|
||||
|
||||
void printMidResult(LVCSR_RECOG_MID_RESULT *midResult){
|
||||
printf("result len : %ld\n", midResult->nResultLen);
|
||||
printf("pResult : %s\n", midResult->pResult);
|
||||
printf("flag : %d\n", midResult->bEngineDetectionFlag);
|
||||
printf("count: %ld\n\n", midResult->nCount);
|
||||
}
|
||||
|
||||
void setSid(LVCSR_DATA_LOGINFO *logInfo, char* sid, int size) {
|
||||
// memset(logInfo.tloItemSId, 0, 51);
|
||||
// memcpy(logInfo.tloItemSId, sid, size);
|
||||
sprintf(logInfo->tloItemSId, "%s", sid);
|
||||
// printf("logInfo.tloItemSId-%s\n ", logInfo.tloItemSId);
|
||||
}
|
||||
|
||||
void setCallId(LVCSR_DATA_LOGINFO *logInfo, char* callId, int size) {
|
||||
// memset(logInfo.tloItemCallId, 0, 61);
|
||||
// memcpy(logInfo.tloItemCallId, callId, size);
|
||||
sprintf(logInfo->tloItemCallId, "%s", callId);
|
||||
// printf("logInfo.tloItemCallId-%s\n ", logInfo.tloItemSId);
|
||||
}
|
||||
|
||||
void setTrId(LVCSR_DATA_LOGINFO *logInfo, char* trId, int size) {
|
||||
// memset(logInfo.tloItemTransactionId, 0, 101);
|
||||
// memcpy(logInfo.tloItemTransactionId, trId, size);
|
||||
sprintf(logInfo->tloItemTransactionId, "%s", trId);
|
||||
// printf("logInfo.tloItemTransactionId-%s\n ", logInfo.tloItemTransactionId);
|
||||
}
|
||||
|
||||
void setItemStartMessage(LVCSR_DATA_LOGINFO *logInfo, char* tloTime, int size) {
|
||||
// memset(logInfo.tloItemStartMessage, 0, 101);
|
||||
// memcpy(logInfo.tloItemStartMessage, trId, size);
|
||||
sprintf(logInfo->tloItemStartMessage, "%s", tloTime);
|
||||
// printf("logInfo.tloItemStartMessage-%s\n ", logInfo.tloItemStartMessage);
|
||||
}
|
||||
|
||||
long getSTTSockID(LVCSR_SOCK_HEAD sockhead) {
|
||||
return sockhead.uSock;
|
||||
}
|
||||
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
"fmt"
|
||||
"mybatch/icserror"
|
||||
"mybatch/icslog"
|
||||
"runtime/debug"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
// "git.icomsys.co.kr/icomsys/voicegateway/voiceagent/icsconf"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
const (
|
||||
CONNECT_TIMEOUT = 3
|
||||
READ_CONNECT_TIMEOUT = 5
|
||||
READ_CONNECT_TIMEOUT_LONGVOICE = 10
|
||||
|
||||
// model Info
|
||||
MODEL_ID = 0
|
||||
KWD_ID = -1
|
||||
CODEC_TYPE = 0 // 8k
|
||||
LANGUAGE = 1 // utf-8
|
||||
USED_EPD = 1 // epd used
|
||||
NO_USED_EPD = 0 // epd used
|
||||
//USED_EPD = 1 // epd used
|
||||
USED_SCORE = 0 // used off
|
||||
)
|
||||
|
||||
type STTSelvas struct {
|
||||
sessionID int
|
||||
//handle int
|
||||
authCode string
|
||||
//ch int
|
||||
sttID C.long
|
||||
text string
|
||||
voiceBuf []byte
|
||||
voiceBufCur int64
|
||||
silencenum int
|
||||
validnum int64 //rms counter
|
||||
uDataSize int
|
||||
uEndOfSpeech int
|
||||
STTInfo STTInfo
|
||||
IsClose bool
|
||||
SpeechStatus int
|
||||
RecordFilePath string
|
||||
RecordStart *bool
|
||||
rrData *RRData
|
||||
M *sync.Mutex
|
||||
txNum int //number of sending stt audio packet
|
||||
callID string
|
||||
custID string
|
||||
sreserved string
|
||||
trid string
|
||||
errCode string
|
||||
errFunName string
|
||||
errMsg string
|
||||
result string
|
||||
reqTime time.Time
|
||||
rspTime time.Time
|
||||
svcReqTime time.Time
|
||||
svcRspTime time.Time
|
||||
sttcount int
|
||||
sttStatus int
|
||||
//icsstat.StatInfos
|
||||
language string
|
||||
}
|
||||
|
||||
type STTInfo struct {
|
||||
LVCSR_SOCK_HEAD C.LVCSR_SOCK_HEAD
|
||||
LVCSR_EPD_INFO C.LVCSR_EPD_INFO
|
||||
LVCSR_DATA_AUTHENTICATION C.LVCSR_DATA_AUTHENTICATION
|
||||
LVCSR_RECOG_RESULT C.LVCSR_RECOG_RESULT
|
||||
LVCSR_DATA_RESULT C.LVCSR_DATA_RESULT
|
||||
LVCSR_RECOG_MID_RESULT C.LVCSR_RECOG_MID_RESULT
|
||||
LVCSR_DATA_INFO C.LVCSR_DATA_INFO
|
||||
LVCSR_DATA_LOGINFO C.LVCSR_DATA_LOGINFO
|
||||
LVCSR_ERROR_RESULT C.LVCSR_ERROR_RESULT
|
||||
}
|
||||
|
||||
type STTSResult struct {
|
||||
result string
|
||||
error *icserror.IcsError
|
||||
}
|
||||
type NewSTTResult struct {
|
||||
Res string
|
||||
NStart int
|
||||
NEnd int
|
||||
}
|
||||
|
||||
func (s STTSelvas) GetTrID() string {
|
||||
return s.trid
|
||||
}
|
||||
|
||||
// connect SELVAS STT Server
|
||||
func NewSTTS(IP string, port int, callID string, custID string, filePath string) (*STTSelvas, *icserror.IcsError) {
|
||||
//func NewSTTS(sid int, IP string, port int, callID string, custID string, filePath string, sreserved string, statOK bool) (*STTSelvas, *icserror.IcsError) {
|
||||
l := icslog.InitializeLogger()
|
||||
var derr *icserror.IcsError = nil
|
||||
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
switch v := err.(type) {
|
||||
case error:
|
||||
icserror.ICSERRSTTFailInit.SetError(v)
|
||||
l.Printf("PANIC! %s\n%s", icserror.ICSERRSTTFailInit.GetError().Error(), string(debug.Stack()))
|
||||
default:
|
||||
l.Print(icserror.ICSERRSTTFailInit.GetError().Error())
|
||||
}
|
||||
}
|
||||
derr = icserror.ICSERRSTTFailInit
|
||||
}()
|
||||
|
||||
if len(IP) <= 0 || port <= 0 {
|
||||
derr = icserror.ICSERRInvalidParam
|
||||
return nil, derr
|
||||
}
|
||||
|
||||
stts := STTSelvas{authCode: "LGUPlusManager", uDataSize: 1600, uEndOfSpeech: 0, IsClose: false, SpeechStatus: 0, reqTime: time.Now(), svcReqTime: time.Time{}, svcRspTime: time.Time{}, callID: callID, custID: custID, result: "", errCode: "", errMsg: "", errFunName: ""}
|
||||
//stts := STTSelvas{handle: -1, authCode: "LGUPlusManager", uDataSize: 1600, uEndOfSpeech: 0, IsClose: false}
|
||||
|
||||
stts.M = &sync.Mutex{}
|
||||
stts.txNum = 0
|
||||
|
||||
//recording
|
||||
stts.RecordFilePath = filePath
|
||||
stts.RecordStart = new(bool)
|
||||
*stts.RecordStart = false
|
||||
stts.rrData = NewRRData(960000) //60sec
|
||||
|
||||
csIP := C.CString(IP)
|
||||
defer C.free(unsafe.Pointer(csIP))
|
||||
csPort := C.long(port)
|
||||
csConTimeout := C.long(CONNECT_TIMEOUT)
|
||||
csReadTimeout := C.long(READ_CONNECT_TIMEOUT)
|
||||
|
||||
// 셀바스 API는 현재 통합통계가 있어야 동작을함
|
||||
trID := uuid.New().String()
|
||||
trID = strings.ReplaceAll(trID, "-", "a")
|
||||
stts.trid = trID
|
||||
|
||||
/*
|
||||
if stts.sttStatus == STTMemo {
|
||||
return &stts, nil
|
||||
}
|
||||
*/
|
||||
|
||||
//svcReqTime := time.Now()
|
||||
l.Printf("STT ASR_SVC_OPEN Start")
|
||||
rc := C.ASR_SVC_OPEN(csIP, csPort, csConTimeout, csReadTimeout, &stts.STTInfo.LVCSR_SOCK_HEAD) // add LVCSR_SOCK_HEAD
|
||||
if int(rc) == -1 {
|
||||
////////////////테스트코드/////////////////////
|
||||
rc = C.ASR_SVC_GET_ERROR(&stts.STTInfo.LVCSR_SOCK_HEAD, &stts.STTInfo.LVCSR_ERROR_RESULT)
|
||||
if int(rc) < 0 {
|
||||
l.Printf("[%d] ASR_SVC_GET_ERROR Fail.. %d", int(stts.sttID), rc)
|
||||
// return "", derr
|
||||
} else {
|
||||
l.Printf("[%d] LVCSR_ERROR_RESULT - [%d]%s", int(stts.sttID), stts.STTInfo.LVCSR_ERROR_RESULT.nErrorCode, C.GoString(&stts.STTInfo.LVCSR_ERROR_RESULT.pErrorMsg[0]))
|
||||
}
|
||||
l.Printf("STT ASR_SVC_OPEN Fail - rc:%d", rc)
|
||||
derr = icserror.ICSERRSTTConnectTimeout
|
||||
return nil, derr
|
||||
} else if int(rc) == -2 {
|
||||
l.Printf("STT ASR_SVC_OPEN Fail - rc:%d", rc)
|
||||
////////////////테스트코드/////////////////////
|
||||
rc = C.ASR_SVC_GET_ERROR(&stts.STTInfo.LVCSR_SOCK_HEAD, &stts.STTInfo.LVCSR_ERROR_RESULT)
|
||||
if int(rc) < 0 {
|
||||
l.Printf("[%d] ASR_SVC_GET_ERROR Fail.. %d", int(stts.sttID), rc)
|
||||
// return "", derr
|
||||
} else {
|
||||
l.Printf("[%d] LVCSR_ERROR_RESULT - [%d]%s ", int(stts.sttID), stts.STTInfo.LVCSR_ERROR_RESULT.nErrorCode, C.GoString(&stts.STTInfo.LVCSR_ERROR_RESULT.pErrorMsg[0]))
|
||||
}
|
||||
///////////////////////////////////////////////
|
||||
derr = icserror.ICSERRSTTFailInit
|
||||
return nil, derr
|
||||
}
|
||||
// 통합통계
|
||||
now := time.Now()
|
||||
tloTime := fmt.Sprintf("%d%02d%02d%02d%02d%02d", now.Year(), int(now.Month()), now.Day(), now.Hour(), now.Minute(), now.Minute())
|
||||
csTrId := C.CString(trID)
|
||||
defer C.free(unsafe.Pointer(csTrId))
|
||||
csCallId := C.CString(callID)
|
||||
defer C.free(unsafe.Pointer(csCallId))
|
||||
csTloTime := C.CString(tloTime)
|
||||
defer C.free(unsafe.Pointer(csTloTime))
|
||||
csCustID := C.CString(custID)
|
||||
defer C.free(unsafe.Pointer(csCustID))
|
||||
|
||||
C.setSid(&stts.STTInfo.LVCSR_DATA_LOGINFO, csCustID, C.int(len(custID)))
|
||||
C.setCallId(&stts.STTInfo.LVCSR_DATA_LOGINFO, csCallId, C.int(len(callID)))
|
||||
C.setTrId(&stts.STTInfo.LVCSR_DATA_LOGINFO, csTrId, C.int(len(trID)))
|
||||
C.setItemStartMessage(&stts.STTInfo.LVCSR_DATA_LOGINFO, csTloTime, C.int(len(tloTime)))
|
||||
|
||||
l.Printf("[%d] SET ASR_SVC_SET_LOGINFO > trID:%s, callID:%s, tloTime:%+v, custID:%s", int(stts.sttID), trID, callID, tloTime, custID)
|
||||
//svcReqTime = time.Now()
|
||||
rs := C.ASR_SVC_SET_LOGINFO(&stts.STTInfo.LVCSR_SOCK_HEAD, &stts.STTInfo.LVCSR_DATA_LOGINFO) // 통합통계 설정
|
||||
//ljhwan
|
||||
//rs = 0
|
||||
if int(rs) < 0 {
|
||||
l.Printf("[%d] STT ASR_SVC_SET_LOGINFO Fail Result rs:%d, LVCSR_DATA_LOGINFO: %+v", int(stts.sttID), rs, stts.STTInfo.LVCSR_DATA_LOGINFO)
|
||||
////////////////테스트코드/////////////////////
|
||||
rc = C.ASR_SVC_GET_ERROR(&stts.STTInfo.LVCSR_SOCK_HEAD, &stts.STTInfo.LVCSR_ERROR_RESULT)
|
||||
if int(rc) < 0 {
|
||||
l.Printf("[%d] ASR_SVC_GET_ERROR Fail..", int(stts.sttID))
|
||||
// return "", derr
|
||||
} else {
|
||||
l.Printf("[%d] LVCSR_ERROR_RESULT - [%d]%s", int(stts.sttID), stts.STTInfo.LVCSR_ERROR_RESULT.nErrorCode, C.GoString(&stts.STTInfo.LVCSR_ERROR_RESULT.pErrorMsg[0]))
|
||||
}
|
||||
///////////////////////////////////////////////
|
||||
|
||||
// Server Close
|
||||
//svcReqTime = time.Now()
|
||||
l.Printf("[%d] STT ASR_SVC_CLOS Start", int(stts.sttID))
|
||||
rc = C.ASR_SVC_CLOS(&stts.STTInfo.LVCSR_SOCK_HEAD)
|
||||
if int(rc) < 0 {
|
||||
l.Printf("[%d] STT ASR_SVC_CLOS Fail Result rs:%d", int(stts.sttID), rs)
|
||||
|
||||
derr = icserror.ICSERRSTTFailInit
|
||||
return nil, derr
|
||||
}
|
||||
|
||||
derr = icserror.ICSERRSTTFailInit
|
||||
return nil, derr
|
||||
}
|
||||
|
||||
// Channel Connect
|
||||
//svcReqTime = time.Now()
|
||||
l.Printf("[%d] STT ASR_SVC_RECG_OPEN Start", int(stts.sttID))
|
||||
rc = C.ASR_SVC_RECG_OPEN(&stts.STTInfo.LVCSR_SOCK_HEAD) // add LVCSR_SOCK_HEAD
|
||||
//ljhwan
|
||||
//rc = 0
|
||||
if int(rc) < 0 {
|
||||
l.Printf("[%d] STT ASR_SVC_RECG_OPEN Fail, LVCSR_SOCK_HEAD: %+v\r\n", int(stts.sttID), stts.STTInfo.LVCSR_SOCK_HEAD)
|
||||
// Server Close
|
||||
//svcReqTime = time.Now()
|
||||
l.Printf("[%d] STT ASR_SVC_CLOS Start", int(stts.sttID))
|
||||
rc = C.ASR_SVC_CLOS(&stts.STTInfo.LVCSR_SOCK_HEAD)
|
||||
if int(rc) < 0 {
|
||||
l.Printf("[%d]STT ASR_SVC_CLOS Fail Result rs:%d, LVCSR_SOCK_HEAD: %+v", int(stts.sttID), rs, stts.STTInfo.LVCSR_SOCK_HEAD)
|
||||
|
||||
derr = icserror.ICSERRSTTFailInit
|
||||
return nil, derr
|
||||
}
|
||||
|
||||
derr = icserror.ICSERRSTTFailInit
|
||||
return nil, derr
|
||||
}
|
||||
|
||||
// Set Model List
|
||||
stts.STTInfo.LVCSR_DATA_INFO.nModelId = MODEL_ID
|
||||
stts.STTInfo.LVCSR_DATA_INFO.nKwdId = KWD_ID
|
||||
stts.STTInfo.LVCSR_DATA_INFO.nCodecType = CODEC_TYPE
|
||||
stts.STTInfo.LVCSR_DATA_INFO.nCharSet = LANGUAGE
|
||||
// if stts.sttStatus == STTMemo {
|
||||
// stts.STTInfo.LVCSR_DATA_INFO.bEpdUsed = NO_USED_EPD
|
||||
// } else {
|
||||
// stts.STTInfo.LVCSR_DATA_INFO.bEpdUsed = USED_EPD
|
||||
// }
|
||||
stts.STTInfo.LVCSR_DATA_INFO.bScoreUsed = USED_SCORE
|
||||
|
||||
//svcReqTime = time.Now()
|
||||
rc = C.ASR_SVC_RECG_SET_LIST(&stts.STTInfo.LVCSR_SOCK_HEAD, &stts.STTInfo.LVCSR_DATA_INFO)
|
||||
//ljhwan
|
||||
//rc = 0
|
||||
if int(rc) < 0 {
|
||||
l.Printf("[%d]STT ASR_SVC_RECG_SET_LIST Fail Result rs:%d, LVCSR_SOCK_HEAD: %+v, stts.STTInfo.LVCSR_DATA_INFO: %+v", int(stts.sttID), rs, stts.STTInfo.LVCSR_SOCK_HEAD, stts.STTInfo.LVCSR_DATA_INFO)
|
||||
|
||||
// Channel Connection Close
|
||||
//svcReqTime = time.Now()
|
||||
l.Printf("[%d]STT ASR_SVC_RECG_CLOS Start", int(stts.sttID))
|
||||
rc = C.ASR_SVC_RECG_CLOS(&stts.STTInfo.LVCSR_SOCK_HEAD)
|
||||
if int(rc) < 0 {
|
||||
l.Printf("[%d]STT ASR_SVC_RECG_CLOS Fail Result rs:%d, LVCSR_SOCK_HEAD: %+v", int(stts.sttID), rs, stts.STTInfo.LVCSR_SOCK_HEAD)
|
||||
derr = icserror.ICSERRTTSNotInit
|
||||
}
|
||||
|
||||
// Server Close
|
||||
l.Printf("[%d]STT ASR_SVC_CLOS Start", int(stts.sttID))
|
||||
//svcReqTime = time.Now()
|
||||
rc = C.ASR_SVC_CLOS(&stts.STTInfo.LVCSR_SOCK_HEAD)
|
||||
if int(rc) < 0 {
|
||||
l.Printf("[%d]STT ASR_SVC_CLOS Fail Result rs:%d, LVCSR_SOCK_HEAD: %+v", int(stts.sttID), rs, stts.STTInfo.LVCSR_SOCK_HEAD)
|
||||
derr = icserror.ICSERRSTTFailInit
|
||||
return nil, derr
|
||||
}
|
||||
derr = icserror.ICSERRSTTFailInit
|
||||
return nil, derr
|
||||
}
|
||||
|
||||
l.Printf("[%d]Selvas STT New Connection > callID:'%s',trID:'%s'", int(stts.sttID), callID, trID)
|
||||
// fmt.Println("STT: Selvas STT New Connection")
|
||||
|
||||
return &stts, derr
|
||||
}
|
||||
|
||||
func (s *STTSelvas) Close(save bool) (string, string, *icserror.IcsError) {
|
||||
if s == nil {
|
||||
return "", "", icserror.ICSERRSTTNotInit
|
||||
}
|
||||
|
||||
l := icslog.InitializeLogger()
|
||||
// conf := icsconf.GetIcsConfig()
|
||||
var derr *icserror.IcsError = nil
|
||||
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
switch v := err.(type) {
|
||||
case error:
|
||||
icserror.ICSERRSTTFailInit.SetError(v)
|
||||
l.Printf("PANIC! %s\n%s", icserror.ICSERRSTTFailInit.GetError().Error(), string(debug.Stack()))
|
||||
default:
|
||||
l.Print(icserror.ICSERRSTTFailInit.GetError().Error())
|
||||
}
|
||||
derr = icserror.ICSERRSTTFailInit
|
||||
return
|
||||
}
|
||||
// derr = icserror.ICSERRSTTFailInit
|
||||
}()
|
||||
|
||||
//l.Printf(icslog.LOG_LEVEL_WARN, s.sessionID, "[%d]STT CLOSE : %s", int(s.sttID), string(debug.Stack()))
|
||||
l.Printf("Close STT[%d]. Send Audio Packet Num: %d", int(s.sttID), s.txNum)
|
||||
/*
|
||||
if s.handle < 0 || s.ch < 0 {
|
||||
fmt.Println("selvas stt", s.ch)
|
||||
return icserror.ICSERRSTTNotInit
|
||||
}
|
||||
*/
|
||||
|
||||
s.M.Lock()
|
||||
s.IsClose = true
|
||||
s.M.Unlock()
|
||||
|
||||
var localPath, URL string
|
||||
|
||||
if *s.RecordStart {
|
||||
if save {
|
||||
// aud := s.rrData.GetAudio()
|
||||
// audLen := len(aud)
|
||||
|
||||
// 여기 수정해야함
|
||||
|
||||
// path, ymd, serr := icsutil.Save(aud, s.RecordFilePath, conf.AppInfo.VoiceConfig.Path, true)
|
||||
// //path, ymd := Save(s.rrData.GetAudio(), s.RecordFilePath, conf.VoiceConfig.Path, true)
|
||||
// if serr == nil {
|
||||
// if len(path) == 0 {
|
||||
// l.Printf(icslog.LOG_LEVEL_WARN, s.sessionID, "[%d]Failed to save STT voice : %s", int(s.sttID), s.RecordFilePath)
|
||||
// } else {
|
||||
// localPath = path
|
||||
// URL = fmt.Sprintf("%s%s/%s.wav", conf.AppInfo.VoiceConfig.HTTPPath, ymd, s.RecordFilePath)
|
||||
// s.RecordFilePath = ""
|
||||
// l.Printf(icslog.LOG_LEVEL_INFO, s.sessionID, "[%d]Saved STT voice(%d). path: %s, URL: %s", int(s.sttID), audLen, localPath, URL)
|
||||
// }
|
||||
// } else {
|
||||
// l.Printf(icslog.LOG_LEVEL_WARN, s.sessionID, "[%d]Failed to save STT voice(%d) : %s, %s - %s", int(s.sttID), audLen, s.RecordFilePath, conf.AppInfo.VoiceConfig.Path, serr.GetMessage())
|
||||
// }
|
||||
}
|
||||
}
|
||||
*s.RecordStart = false
|
||||
|
||||
// l.Printf(icslog.LOG_LEVEL_DEBUG2, s.sessionID, "[%d]STT ASR_SVC_RECG_CLOS. sock header: %+v", int(s.sttID), s.STTInfo.LVCSR_SOCK_HEAD.uSock)
|
||||
|
||||
//l.Printf(icslog.LOG_LEVEL_INFO, s.sessionID, "[%d] s.STTInfo.LVCSR_RECOG_RESULT Start - s.STTInfo.LVCSR_RECOG_RESULT:%+v", int(s.sttID), s.STTInfo.LVCSR_RECOG_RESULT)
|
||||
rc := C.ASR_SVC_RECG_PROC_FREE(&s.STTInfo.LVCSR_RECOG_RESULT)
|
||||
if int(rc) < 0 {
|
||||
l.Printf("Failed to free STT result[%d]. rc: %d", int(s.sttID), rc)
|
||||
if strings.Compare(s.errCode, "54000013") != 0 {
|
||||
s.errCode, s.errMsg, s.errFunName = "54000010", "Fail", "ASR_SVC_RECG_PROC_FREE"
|
||||
}
|
||||
derr = icserror.ICSERRSTTFreeError
|
||||
// s.SendStasticInfo(s.callID, s.custID, s.trid, "STT", "ASR_SVC_RECG_PROC_FREE", "54000001", "Fail", "", "", s.reqTime, time.Now(), s.sreserved, svcReqTime, time.Now())
|
||||
}
|
||||
|
||||
// Channel Connection Close
|
||||
l.Printf("Close STT channel[%d]", int(s.sttID))
|
||||
rc = C.ASR_SVC_RECG_CLOS(&s.STTInfo.LVCSR_SOCK_HEAD)
|
||||
if int(rc) < 0 {
|
||||
l.Printf("Failed to close STT channel[%d], rc: %d", int(s.sttID), rc)
|
||||
if s.result == "$NO_RESULT$" {
|
||||
s.errCode, s.errMsg, s.errFunName = "20000003", "Success", ""
|
||||
} else if strings.Compare(s.errCode, "54000013") != 0 {
|
||||
s.errCode, s.errMsg, s.errFunName = "54000011", "Fail", "ASR_SVC_RECG_CLOS"
|
||||
}
|
||||
derr = icserror.ICSERRTTSNotInit
|
||||
// s.SendStasticInfo(s.callID, s.custID, s.trid, "STT", "ASR_SVC_RECG_CLOS", "54000001", "Fail", "", "", s.reqTime, time.Now(), s.sreserved, svcReqTime, time.Now())
|
||||
}
|
||||
|
||||
// Server Close
|
||||
l.Printf("Close STT SVC[%d]", int(s.sttID))
|
||||
rc = C.ASR_SVC_CLOS(&s.STTInfo.LVCSR_SOCK_HEAD)
|
||||
//ljhwan
|
||||
//rc = 0
|
||||
if int(rc) < 0 {
|
||||
l.Printf("Failed to close STT SVC[%d], rc: %d", int(s.sttID), rc)
|
||||
derr = icserror.ICSERRTTSNotInit
|
||||
if strings.Compare(s.errCode, "54000013") != 0 {
|
||||
s.errCode, s.errMsg, s.errFunName = "54000012", "Fail", "ASR_SVC_CLOS"
|
||||
}
|
||||
// s.SendStasticInfo(s.callID, s.custID, s.trid, "STT", "ASR_SVC_CLOS", "54000001", "Fail", "", "", s.reqTime, time.Now(), s.sreserved, s.svcReqTime, time.Now())
|
||||
// return derr
|
||||
}
|
||||
l.Printf("Closed STT[%d] sock header: %+v", int(s.sttID), s.STTInfo.LVCSR_SOCK_HEAD.uSock)
|
||||
|
||||
s.rrData.Clear()
|
||||
|
||||
l.Printf("Selvas STT Close - %d. %s", s.voiceBufCur, string(debug.Stack()))
|
||||
|
||||
return localPath, URL, derr
|
||||
}
|
||||
|
||||
func (s *STTSelvas) GetSTTStatus() bool {
|
||||
if s == nil {
|
||||
// fmt.Println("get status: stt handle nil")
|
||||
return false
|
||||
}
|
||||
s.M.Lock()
|
||||
b := s.IsClose
|
||||
s.M.Unlock()
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
type AsyncCBFunc func(sttResult string, epd int, inout bool)
|
||||
|
||||
func (s *STTSelvas) SendSTT(voicedata []byte, final bool, cbFunc AsyncCBFunc) (NewSTTResult, *icserror.IcsError) {
|
||||
l := icslog.InitializeLogger()
|
||||
var res NewSTTResult
|
||||
var derr *icserror.IcsError = nil
|
||||
var result string
|
||||
// var sendCount int
|
||||
|
||||
if s == nil {
|
||||
derr = icserror.ICSERRTTSNotInit
|
||||
l.Println("STTSelvas struct is not initialized")
|
||||
return res, derr
|
||||
}
|
||||
|
||||
// // setting the language
|
||||
// cLanguage := C.CString(language)
|
||||
// defer C.free(unsafe.Pointer(cLanguage))
|
||||
// rc := C.ASR_SVC_SET_PARAM(&s.sttInfo.LVCSR_SOCK_HEAD, C.LVCSR_PARAM_TYPE_LANGUAGE, cLanguage)
|
||||
// if rc != 0 {
|
||||
// return "", icserror.ICSERRSTTLanguageSetting
|
||||
// }
|
||||
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
switch v := err.(type) {
|
||||
case error:
|
||||
icserror.ICSERRSTTSendFail.SetError(v)
|
||||
l.Printf("PANIC! %s\n%s", icserror.ICSERRSTTSendFail.GetError().Error(), string(debug.Stack()))
|
||||
default:
|
||||
l.Print(icserror.ICSERRSTTSendFail.GetError().Error())
|
||||
}
|
||||
}
|
||||
derr = icserror.ICSERRSTTSendFail
|
||||
}()
|
||||
|
||||
s.uEndOfSpeech = 1
|
||||
|
||||
//recording audio
|
||||
if *s.RecordStart {
|
||||
s.rrData.AddAudio(voicedata)
|
||||
} else {
|
||||
s.rrData.AddTempAudio(voicedata)
|
||||
}
|
||||
|
||||
csUDataSize := C.long(s.uDataSize)
|
||||
csUEndSpeech := C.long(s.uEndOfSpeech)
|
||||
csBuff := (*C.char)(unsafe.Pointer(&voicedata))
|
||||
//csBuff := (*C.char)(unsafe.Pointer(&buff1[0]))
|
||||
rc := C.ASR_SVC_RECG_DATA(&s.STTInfo.LVCSR_SOCK_HEAD,
|
||||
csBuff,
|
||||
csUDataSize,
|
||||
csUEndSpeech,
|
||||
&s.STTInfo.LVCSR_EPD_INFO)
|
||||
|
||||
if int(rc) < 0 {
|
||||
l.Printf("[%d] ASR_SVC_RECG_DATA ERROR %d", int(s.sttID), rc)
|
||||
////////////////테스트코드/////////////////////
|
||||
rc = C.ASR_SVC_GET_ERROR(&s.STTInfo.LVCSR_SOCK_HEAD, &s.STTInfo.LVCSR_ERROR_RESULT)
|
||||
if int(rc) < 0 {
|
||||
l.Printf("[%d] ASR_SVC_GET_ERROR Fail.. %d", int(s.sttID), rc)
|
||||
// return "", derr
|
||||
} else {
|
||||
l.Printf("[%d] LVCSR_ERROR_RESULT - [%d]%s", int(s.sttID), s.STTInfo.LVCSR_ERROR_RESULT.nErrorCode, C.GoString(&s.STTInfo.LVCSR_ERROR_RESULT.pErrorMsg[0]))
|
||||
}
|
||||
///////////////////////////////////////////////
|
||||
|
||||
s.errCode, s.errMsg, s.errFunName = "54000013", "Fail", "ASR_SVC_RECG_DATA"
|
||||
if cbFunc != nil {
|
||||
cbFunc("", 99, true)
|
||||
}
|
||||
derr = icserror.ICSERRSTTSendFail
|
||||
return res, derr
|
||||
}
|
||||
|
||||
s.txNum++
|
||||
|
||||
rc = C.ASR_SVC_RECG_STR_PROC(&s.STTInfo.LVCSR_SOCK_HEAD, &s.STTInfo.LVCSR_RECOG_RESULT)
|
||||
s.svcRspTime = time.Now()
|
||||
|
||||
if int(rc) < 0 {
|
||||
l.Printf("[%d]!!!! ASR_SVC_RECG_STR_PROC Fail - rc:%d, s.STTInfo.LVCSR_RECOG_RESULT:%+v", int(s.sttID), rc, s.STTInfo.LVCSR_RECOG_RESULT)
|
||||
// s.errCode, s.errMsg, s.errFunName = "54000009", "Fail", "ASR_SVC_RECG_STR_PROC"
|
||||
s.result = "$NO_RESULT$"
|
||||
derr = icserror.ICSERRSTTSendFail
|
||||
if cbFunc != nil {
|
||||
cbFunc("", 2, true)
|
||||
}
|
||||
return res, icserror.ICSERRSTTContinue // 묵음으로 처리
|
||||
}
|
||||
|
||||
result = C.GoString(s.STTInfo.LVCSR_RECOG_RESULT.pResult)
|
||||
l.Printf("STT ID[%d] result: %s, result: %p, pointer: %p", int(s.sttID), result, &result, s.STTInfo.LVCSR_RECOG_RESULT.pResult)
|
||||
results := ""
|
||||
if s.STTInfo.LVCSR_RECOG_RESULT.nResultLen == 0 { // 길이 0일때 값 nil로 나옴
|
||||
result = ""
|
||||
}
|
||||
//result = "TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST"
|
||||
s.result = result
|
||||
results = result
|
||||
if result == "$NO_RESULT$" {
|
||||
results = ""
|
||||
}
|
||||
if cbFunc != nil {
|
||||
cbFunc(results, int(s.STTInfo.LVCSR_EPD_INFO), true)
|
||||
}
|
||||
|
||||
// jiyounc
|
||||
// return "", icserror.ICSERRSTTContinue
|
||||
|
||||
res = NewSTTResult{
|
||||
Res: results,
|
||||
NStart: int(s.STTInfo.LVCSR_DATA_RESULT.nStart),
|
||||
NEnd: int(s.STTInfo.LVCSR_DATA_RESULT.nEnd),
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// result return
|
||||
func NewSTTSResult(result string, err *icserror.IcsError) *STTSResult {
|
||||
return &STTSResult{result, err}
|
||||
}
|
||||
|
||||
// 말을 하지 않았을때 결과 조회
|
||||
func (s *STTSelvas) GetSTTResultToStopSTT() (string, *icserror.IcsError) {
|
||||
l := icslog.InitializeLogger()
|
||||
if s == nil {
|
||||
return "", icserror.ICSERRSTTNotInit
|
||||
}
|
||||
|
||||
l.Printf("[%d] LVCSR_RECOG_RESULT: %+v, LVCSR_RECOG_RESULT:%+v", int(s.sttID), &s.STTInfo.LVCSR_RECOG_RESULT, s.STTInfo.LVCSR_RECOG_RESULT)
|
||||
rc := C.ASR_SVC_RECG_STR_PROC(&s.STTInfo.LVCSR_SOCK_HEAD, &s.STTInfo.LVCSR_RECOG_RESULT)
|
||||
if int(rc) < 0 {
|
||||
l.Printf("[%d] ASR_SVC_RECG_STR_PROC Fail - rc:%d, s.STTInfo.LVCSR_RECOG_RESULT:%+v", int(s.sttID), rc, s.STTInfo.LVCSR_RECOG_RESULT)
|
||||
s.errCode, s.errMsg, s.errFunName = "54000009", "Fail", "ASR_SVC_RECG_STR_PROC"
|
||||
// s.SendStasticInfo(s.callID, s.custID, s.trid, "STT", "ASR_SVC_RECG_STR_PROC", "54000001", "Fail", "", "", s.reqTime, time.Now(), s.sreserved, svcReqTime, time.Now())
|
||||
return "", icserror.ICSERRSTTSendFail
|
||||
}
|
||||
return "", icserror.ICSERRSTTContinue
|
||||
}
|
||||
|
||||
// epd 1 이후 end 전송 => 결과조회
|
||||
func (s *STTSelvas) SendSTTProcGetResult() (string, *icserror.IcsError) {
|
||||
l := icslog.InitializeLogger()
|
||||
var derr *icserror.IcsError = nil
|
||||
if s == nil {
|
||||
return "", icserror.ICSERRSTTNotInit
|
||||
}
|
||||
|
||||
// buff1 := make([]byte, 0)
|
||||
s.uEndOfSpeech = 1
|
||||
uDataSize := 0
|
||||
csUDataSize := C.long(uDataSize)
|
||||
csUEndSpeech := C.long(s.uEndOfSpeech)
|
||||
// csBuff := nil
|
||||
|
||||
l.Printf("[%d] LVCSR_RECOG_RESULT: %+v, LVCSR_RECOG_RESULT:%+v", int(s.sttID), &s.STTInfo.LVCSR_RECOG_RESULT, s.STTInfo.LVCSR_RECOG_RESULT)
|
||||
// svcReqTime := time.Now()
|
||||
rc := C.ASR_SVC_RECG_DATA(&s.STTInfo.LVCSR_SOCK_HEAD,
|
||||
nil,
|
||||
csUDataSize,
|
||||
csUEndSpeech,
|
||||
&s.STTInfo.LVCSR_EPD_INFO)
|
||||
if int(rc) < 0 {
|
||||
l.Printf("[%d] ASR_SVC_RECG_STR_PROC Fail - rc:%d, s.STTInfo.LVCSR_RECOG_RESULT:%+v", int(s.sttID), rc, s.STTInfo.LVCSR_RECOG_RESULT)
|
||||
derr = icserror.ICSERRSTTSendFail
|
||||
s.errCode, s.errMsg, s.errFunName = "54000009", "Fail", "ASR_SVC_RECG_STR_PROC"
|
||||
// s.SendStasticInfo(s.callID, s.custID, s.trid, "STT", "ASR_SVC_RECG_DATA", "54000001", "Fail", "", "", s.reqTime, time.Now(), s.sreserved, svcReqTime, time.Now())
|
||||
return "", derr
|
||||
}
|
||||
|
||||
s.GetSTTResultToStopSTT()
|
||||
// l.Print(icslog.LOG_LEVEL_INFO, s.sessionID, "Request Recg Result")
|
||||
// rc = C.ASR_SVC_RECG_PROC(&s.STTInfo.LVCSR_SOCK_HEAD, &s.STTInfo.LVCSR_RECOG_RESULT)
|
||||
// if int(rc) < 0 {
|
||||
// derr = icserror.ICSERRSTTFail
|
||||
// return "", derr
|
||||
// }
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func (s STTSelvas) GetAudio() []byte {
|
||||
return s.rrData.GetAudio()
|
||||
}
|
||||
|
||||
func (s STTSelvas) GetReqTime() time.Time {
|
||||
return s.reqTime
|
||||
}
|
||||
|
||||
func (s *STTSelvas) CloseChanelAndServer() (bool, *icserror.IcsError) {
|
||||
// 서버 결과에 사용된 메모리 초기화
|
||||
rc := C.ASR_SVC_RECG_PROC_FREE(&s.STTInfo.LVCSR_RECOG_RESULT)
|
||||
if int(rc) < 0 {
|
||||
l.Println("Error occured while executing ASR_SVC_RECG_PROC_FREE()")
|
||||
return false, icserror.ICSERRSTTConnectCloseFail
|
||||
}
|
||||
// 채널 해제
|
||||
rc = C.ASR_SVC_RECG_CLOS(&s.STTInfo.LVCSR_SOCK_HEAD)
|
||||
if int(rc) < 0 {
|
||||
l.Println("Error occured while executing ASR_SVC_RECG_CLOS()")
|
||||
return false, icserror.ICSERRSTTConnectCloseFail
|
||||
}
|
||||
// stt 서버 종료
|
||||
rc = C.ASR_SVC_CLOS(&s.STTInfo.LVCSR_SOCK_HEAD)
|
||||
if int(rc) < 0 {
|
||||
l.Println("Error occured while executing ASR_SVC_CLOS()")
|
||||
return false, icserror.ICSERRSTTConnectCloseFail
|
||||
}
|
||||
s.rrData.Clear()
|
||||
return true, nil
|
||||
|
||||
}
|
Loading…
Reference in New Issue