Compare commits

...

2 Commits

@ -1,4 +1,4 @@
module mybatch module batchmodule
go 1.22.0 go 1.22.0

@ -1,11 +1,18 @@
package icsbatch package icsbatch
import ( import (
"batchmodule/icsconf"
"batchmodule/icshttp"
"batchmodule/icslog"
"batchmodule/icsstt"
"batchmodule/icsutil"
"fmt" "fmt"
"io"
"log" "log"
"mybatch/icsconf" "os"
"mybatch/icslog" "path/filepath"
stt "mybatch/icsstt" "strconv"
"strings"
"time" "time"
"github.com/robfig/cron/v3" "github.com/robfig/cron/v3"
@ -14,28 +21,94 @@ import (
var ( var (
cfg icsconf.AppInfo cfg icsconf.AppInfo
l *log.Logger l *log.Logger
fList icshttp.FailedList
) )
type FailedList struct {
No int `json:"no"`
ConnId string `json:"connid"`
Ext string `json:"ext"`
StartTime string `json:"starttime"`
}
func init() { func init() {
cfg = icsconf.Getconfig() cfg = icsconf.Getconfig()
l = icslog.InitializeLogger() l = icslog.InitializeLogger()
} }
func BatchForPostRequestForDataList() { func BatchForFailedSTT() {
wavFilePath := cfg.Directories.WAVDirectory
loc, err := time.LoadLocation("Asia/Seoul") loc, err := time.LoadLocation("Asia/Seoul")
if err != nil { if err != nil {
l.Fatalln("타임존 로드 실패: ", err) l.Fatalln("타임존 로드 실패: ", err)
} }
cronInstance := cron.New(cron.WithLocation(loc)) cronInstance := cron.New(cron.WithLocation(loc))
// 매일 새벽 1시에 동작하는 크론인스턴스 추가 // Adding Cron Instance which runs at every 1am
_, err = cronInstance.AddFunc("0 1 * * *", func() { _, err = cronInstance.AddFunc("0 1 * * *", func() {
l.Println("calling ProcessPostRequestForDataList()") l.Println("cron is working...calling ProcessPostRequestForDataList()...at ", time.Now().Format("2006-01-02_15:04:05"))
stt.ProcessPostRequestForDataList()
// request for failed datalist
response, err := icshttp.PostReqForFailedDataList()
if err != nil {
l.Printf("batch_everyday.go>BatchForFailedSTT> icshttp.PostReqForFailedDataList() failed. err: %+v", err)
}
totalCnt, _ := strconv.ParseInt(response.TotalCnt, 10, 64)
if int(totalCnt) <= 0 {
l.Printf("batch_everyday.go>BatchForFailedSTT> icshttp.PostReqForFailedDataList()> The Failed Data is Zero. totalCnt: %d", totalCnt)
} else {
for _, item := range response.List {
reqDataForVoiceFile := icshttp.FailedDataListReqBody{
StartTime: item.StartTime,
Ext: item.Ext,
ConnId: item.ConnId,
}
// request for each voice file on the failed datalist
response, err := icshttp.PostReqForEachVoiceFile(reqDataForVoiceFile)
if err != nil {
l.Printf("batch_everyday.go>BatchForFailedSTT> icshttp.PostReqForEachVoiceFile() failed. err: %+v", err)
}
voiceFile := response.VoiceFile
if voiceFile == "" {
l.Printf("batch_everyday.go>BatchForFailedSTT> voiceFile is empty on %+v", reqDataForVoiceFile)
break
}
fileName := fmt.Sprintf(`%s/%s/%s.wav`, wavFilePath, item.StartTime, item.ConnId)
file, error := os.Create(fileName)
if error != nil {
l.Println("Error at batch_everyday.go>BatchForFailedSTT> os.Create() err: ", error)
break
}
defer file.Close()
voiceFileReader := strings.NewReader(voiceFile)
_, error = io.Copy(file, voiceFileReader)
if error != nil {
l.Println("Error at batch_everyday.go>BatchForFailedSTT> io.Copy(file, voiceFileReader) err: ", error)
break
}
// devide the wav file to 2 channels
pcmResult, folderName := icsutil.DevideWavTo2Pcm(fileName, item.StartTime)
if pcmResult {
// RUN STT
sttCallRes, err := icsstt.STTController(reqDataForVoiceFile, folderName)
if err != nil {
l.Println("runSTT() failed with the error: ", err)
}
// Delete the pcm files if stt was successful
if sttCallRes {
pcmDir := filepath.Join(cfg.Directories.PCMDirectory, st)
icsutil.DeletePcmFolder(pcmDir)
}
}
}
}
}) })
if err != nil { if err != nil {
fmt.Println("스케줄 추가 오류:", err) l.Printf("Error at batch_everyday.go>BatchForFailedSTT> Adding cron instance failed. error: %v", err)
return return
} }
cronInstance.Start() cronInstance.Start()
@ -43,7 +116,7 @@ func BatchForPostRequestForDataList() {
select {} select {}
} }
func BatchForPostRequestForDataListTest() { func BatchForFailedSTTTest() {
loc, err := time.LoadLocation("Asia/Seoul") loc, err := time.LoadLocation("Asia/Seoul")
if err != nil { if err != nil {
l.Fatalln("타임존 로드 실패: ", err) l.Fatalln("타임존 로드 실패: ", err)

@ -12,6 +12,13 @@ type AppInfo struct {
Speech Speech `xml:"Speech"` Speech Speech `xml:"Speech"`
Directories Directories `xml:"Directories"` Directories Directories `xml:"Directories"`
STT STTConf `xml:"STT"` STT STTConf `xml:"STT"`
Urls Urls `xml:"Urls"`
}
type Urls struct {
FailedDataListUrl string `xml:"FailedDataListUrl"`
NockChiServerUrl string `xml:"NockChiServerUrl"`
TAUrl string `xml:"TAUrl"`
} }
type Speech struct { type Speech struct {
@ -39,7 +46,7 @@ var (
) )
func loadConfig() { func loadConfig() {
file, err := os.Open("/home/prac/svc/icsbc/conf/Appinfo.xml") file, err := os.Open("/home/jiyoungc/svc/icsbc/config/Appinfo.xml")
if err != nil { if err != nil {
fmt.Println("failed to open config file: ", err) fmt.Println("failed to open config file: ", err)
return return

@ -37,6 +37,9 @@ const (
ICS_ERROR_STRING_CONV ICS_ERROR_STRING_CONV
ICS_ERROR_DAEMONIZE ICS_ERROR_DAEMONIZE
ICS_ERROR_INVALID_DATA ICS_ERROR_INVALID_DATA
ICS_ERROR_MARSHAL
ICS_ERROR_UNMARSHAL
ICS_ERROR_READ
) )
var ( var (
@ -49,6 +52,9 @@ var (
ICSERRStrConv = NewIcsError("Atoi Error", ICS_ERROR_STRING_CONV) ICSERRStrConv = NewIcsError("Atoi Error", ICS_ERROR_STRING_CONV)
ICSERRDeamonize = NewIcsError("Process Deamonize Error", ICS_ERROR_DAEMONIZE) ICSERRDeamonize = NewIcsError("Process Deamonize Error", ICS_ERROR_DAEMONIZE)
ICSERRInvalidData = NewIcsError("There is not valid data", ICS_ERROR_INVALID_DATA) ICSERRInvalidData = NewIcsError("There is not valid data", ICS_ERROR_INVALID_DATA)
ICSERRMarshal = NewIcsError("Json marshal Error", ICS_ERROR_MARSHAL)
ICSERRUnmarshal = NewIcsError("Json unmarshal Error", ICS_ERROR_UNMARSHAL)
ICSERRRead = NewIcsError("io read Error", ICS_ERROR_READ)
) )
// config error // config error
@ -287,20 +293,24 @@ var (
// http client // http client
const ( const (
ICS_ERROR_HTTP_CLIENT_RESPONSE = iota + ICS_ERROR_HTTP_CLIENT ICS_ERROR_HTTP_CLIENT_RESPONSE = iota + ICS_ERROR_HTTP_CLIENT
ICS_ERROR_HTTP_CLIENT_CREATE ICS_ERROR_HTTP_CLIENT_RESPONSE_FAIL = iota + ICS_ERROR_HTTP_CLIENT
ICS_ERROR_HTTP_CLIENT_MARSHAL ICS_ERROR_HTTP_CLIENT_CREATE = iota + ICS_ERROR_HTTP_CLIENT
ICS_ERROR_HTTP_CLIENT_UNMARSHAL ICS_ERROR_HTTP_CLIENT_MARSHAL = iota + ICS_ERROR_HTTP_CLIENT
ICS_ERROR_HTTP_CLIENT_EXCUTION ICS_ERROR_HTTP_CLIENT_UNMARSHAL = iota + ICS_ERROR_HTTP_CLIENT
ICS_ERROR_HTTP_CLIENT_READBODY ICS_ERROR_HTTP_CLIENT_EXCUTION = iota + ICS_ERROR_HTTP_CLIENT
ICS_ERROR_HTTP_CLIENT_READBODY = iota + ICS_ERROR_HTTP_CLIENT
ICS_ERROR_HTTP_POST_REQUEST = iota + ICS_ERROR_HTTP_CLIENT
) )
var ( var (
ICSERRHTTPClientResponse = NewIcsError("icshttpclient: No Response", ICS_ERROR_HTTP_CLIENT_RESPONSE) ICSERRHTTPClientResponse = NewIcsError("icshttpclient: No Response", ICS_ERROR_HTTP_CLIENT_RESPONSE)
ICSERRHTTPClientResponseFail = NewIcsError("icshttpclient: returned fail ", ICS_ERROR_HTTP_CLIENT_RESPONSE_FAIL)
ICSERRHTTPClientCreate = NewIcsError("icshttpclient: http.NewRequest", ICS_ERROR_HTTP_CLIENT_CREATE) ICSERRHTTPClientCreate = NewIcsError("icshttpclient: http.NewRequest", ICS_ERROR_HTTP_CLIENT_CREATE)
ICSERRHTTPClientMarshal = NewIcsError("icshttpclient: Data Marshal", ICS_ERROR_HTTP_CLIENT_MARSHAL) ICSERRHTTPClientMarshal = NewIcsError("icshttpclient: Data Marshal", ICS_ERROR_HTTP_CLIENT_MARSHAL)
ICSERRHTTPClientUnmarshal = NewIcsError("icshttpclient: Data Unmarshal", ICS_ERROR_HTTP_CLIENT_UNMARSHAL) ICSERRHTTPClientUnmarshal = NewIcsError("icshttpclient: Data Unmarshal", ICS_ERROR_HTTP_CLIENT_UNMARSHAL)
ICSERRHTTPClientExcecution = NewIcsError("icshttpclient: Request http", ICS_ERROR_HTTP_CLIENT_EXCUTION) ICSERRHTTPClientExcecution = NewIcsError("icshttpclient: Request http", ICS_ERROR_HTTP_CLIENT_EXCUTION)
ICSERRHTTPClientReadBody = NewIcsError("icshttpclient: Read Response Body", ICS_ERROR_HTTP_CLIENT_READBODY) ICSERRHTTPClientReadBody = NewIcsError("icshttpclient: Read Response Body", ICS_ERROR_HTTP_CLIENT_READBODY)
ICSERRHTTPClientPostRequest = NewIcsError("icshttpclient: Post request failed", ICS_ERROR_HTTP_POST_REQUEST)
) )
// s3 // s3

@ -0,0 +1,319 @@
package icshttp
import (
"batchmodule/icsconf"
"batchmodule/icserror"
"batchmodule/icslog"
"bytes"
"crypto/tls"
"encoding/json"
"fmt"
"io"
"log"
"net/http"
"strconv"
"strings"
"time"
"github.com/gorilla/websocket"
)
var (
conf icsconf.AppInfo
l *log.Logger
)
func init() {
conf = icsconf.Getconfig()
l = icslog.InitializeLogger()
}
type TAInfoJSON struct {
Cmd string `json:"cmd"`
ConnId string `json:"connId"`
Tel string `json:"tel"`
Ext string `json:"ext"`
EmpId string `json:"empId"`
DateTime string `json:"dateTime"`
CallStartTime string `json:"callStartTime"`
Index string `json:"index"`
Stt string `json:"stt"`
Dir string `json:"dir"`
IoGbn string `json:"ioGbn"`
}
type FailedList struct {
No int `json:"no"`
ConnId string `json:"connid"`
Ext string `json:"ext"`
StartTime string `json:"starttime"`
}
type FailedDataListReqBody struct {
StartTime string `json:"starttime"`
Ext string `json:"ext"`
ConnId string `json:"connid"`
}
type FailedDataListResBody struct {
TotalCnt string `json:"totalCnt"`
ReturnCode string `json:"returnCode"`
ReturnMsg string `json:"returnMsg"`
List []FailedList `json:"list"`
}
type FailedDataVoiceResBody struct {
VoiceFile string `json:"voiceFile"`
ReturnCode string `json:"returnCode"`
ReturnMsg string `json:"returnMsg"`
}
type IcsHttpClient struct {
Method string
URL string
Request *http.Request
http.Client
}
type TAResp struct {
Success bool `json:"success"`
ReturnCode string `json:"returnCode"`
Message string `json:"message"`
}
type NockChiReqBody struct {
Uid string `json:"uid"`
Ext string `json:"ext"`
SpeakerTag string `json:"speackertag"`
Transcripts string `json:"transcripts"`
}
func NewIcsHttpClient(method, url string, body io.Reader) *IcsHttpClient {
c := &IcsHttpClient{Method: method, URL: url}
r, err := http.NewRequest(method, url, body)
if err != nil {
l.Println("HTTP Client error while http.NewRequest(). error: ", err)
return nil
}
c.Request = r
c.SetTimeout(time.Millisecond * 1000 * 5)
return c
}
func (c *IcsHttpClient) SetTimeout(timeout time.Duration) {
c.Timeout = timeout
}
func HttpRequest(url, method, requestBody string) (*http.Response, error) {
// TLS 설정
tr := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, // 인증서 검증 비활성화
}
client := &http.Client{Transport: tr}
// client := &http.Client{}
payload := strings.NewReader(requestBody)
req, _ := http.NewRequest(method, url, payload)
req.Header.Set("Content-Type", "application/json")
// 요청
res, err := client.Do(req)
if err != nil {
return nil, fmt.Errorf("요청 오류: %w", err)
}
if res.StatusCode != http.StatusOK {
return nil, fmt.Errorf("error: received non-200 response status: %s", res.Status)
}
return res, nil
}
func PostReqForFailedDataList() (response *FailedDataListResBody, cerr *icserror.IcsError) {
url := conf.Urls.FailedDataListUrl
currentDate := time.Now().Format("20060102")
currentDateUint64, _ := strconv.ParseUint(currentDate, 10, 64)
starttime := currentDateUint64 - 1
starttimeStr := strconv.FormatUint(starttime, 10)
body := FailedDataListReqBody{
StartTime: starttimeStr,
Ext: "",
ConnId: "",
}
jsonBody, err := json.Marshal(body)
if err != nil {
return nil, icserror.ICSERRMarshal
}
reqBody := bytes.NewBuffer(jsonBody)
l.Printf("client.go>PostReqForFailedDataList()> url: %s, reqBody: %+v", url, reqBody.String())
client := NewIcsHttpClient("POST", url, reqBody)
if client == nil {
return nil, icserror.ICSERRHTTPClientCreate
}
client.Request.Header.Add("Content-Type", "application/json;charset=utf-8")
client.Request.Header.Add("Accept", "application/json")
l.Printf("Error at client.go>PostReqForFailedDataList()> client.Request: %+v", client)
resp, err := client.Do(client.Request)
if err != nil {
l.Printf("Err at client.go>PostReqForFailedDataList()> client.Do failed. resp: %+v", resp)
l.Printf("The err: %+v", err)
return nil, icserror.ICSERRHTTPClientExcecution
}
l.Printf("client.go>PostReqForFailedDataList()> resp: %+v", resp)
resBody, err := io.ReadAll(resp.Body)
if err != nil {
l.Printf("client.go>PostReqForFailedDataList()> ReadAll err: %+v", err)
return nil, icserror.ICSERRRead
}
defer resp.Body.Close()
if err := json.Unmarshal(resBody, &response); err != nil {
l.Printf("Error at client.go>PostReqForFailedDataList()> Unmarshal err: %+v", err)
return nil, icserror.ICSERRUnmarshal
}
if strings.Contains(response.ReturnCode, "9999") {
l.Printf("Error at client.go>PostReqForFailedDataList()> response returnCode is 9999 with the message: %s", response.ReturnMsg)
return nil, icserror.ICSERRHTTPClientResponseFail
}
return response, nil
}
func PostReqForEachVoiceFile(reqDataForVoiceFile FailedDataListReqBody) (response *FailedDataVoiceResBody, cerr *icserror.IcsError) {
url := conf.Urls.FailedDataListUrl
jsonBody, err := json.Marshal(reqDataForVoiceFile)
if err != nil {
return nil, icserror.ICSERRMarshal
}
reqBody := bytes.NewBuffer(jsonBody)
l.Printf("client.go>PostReqForEachVoiceFile()> url: %s, reqBody: %+v", url, reqBody.String())
client := NewIcsHttpClient("POST", url, reqBody)
if client == nil {
return nil, icserror.ICSERRHTTPClientCreate
}
client.Request.Header.Add("Content-Type", "application/json;charset=utf-8")
client.Request.Header.Add("Accept", "application/json")
l.Printf("Error at client.go>PostReqForEachVoiceFile()> client.Request: %+v", client)
resp, err := client.Do(client.Request)
if err != nil {
l.Printf("Error at client.go>PostReqForEachVoiceFile()> client.Do failed. resp: %+v", resp)
l.Printf("The err: %+v", err)
return nil, icserror.ICSERRHTTPClientExcecution
}
l.Printf("client.go>PostReqForEachVoiceFile()> resp: %+v", resp)
resBody, err := io.ReadAll(resp.Body)
if err != nil {
l.Printf("client.go>PostReqForEachVoiceFile()> ReadAll err: %+v", err)
return nil, icserror.ICSERRRead
}
defer resp.Body.Close()
if err := json.Unmarshal(resBody, &response); err != nil {
l.Printf("Error at client.go>PostReqForEachVoiceFile()> Unmarshal err: %+v", err)
return nil, icserror.ICSERRUnmarshal
}
if strings.Contains(response.ReturnCode, "9999") {
l.Printf("Error at client.go>PostReqForEachVoiceFile()> response returnCode is 9999 with the message: %s", response.ReturnMsg)
return nil, icserror.ICSERRHTTPClientResponseFail
}
l.Printf("client.go>PostReqForEachVoiceFile()> response: %+v", response)
return response, nil
}
func SendSTTResToNockChiServer(parsedRes FailedDataListReqBody, sttRes string, dir string) *icserror.IcsError {
url := conf.Urls.NockChiServerUrl
conn, _, err := websocket.DefaultDialer.Dial(url, nil)
if err != nil {
l.Println("[ERR] client.go>SendSTTResToNockChiServer()> connecting websocket failed. err: %v", err)
return icserror.ICSERRWEBSOCKETConnectFailError
}
defer conn.Close()
reqData := NockChiReqBody{
Uid: parsedRes.ConnId,
Ext: parsedRes.Ext,
SpeakerTag: dir,
Transcripts: sttRes,
}
jsonData, _ := json.Marshal(reqData)
reqBody := fmt.Sprintf(`{"data":"%s"}`, jsonData)
err = conn.WriteMessage(websocket.TextMessage, []byte(reqBody))
if err != nil {
l.Println("[ERR] client.go>SendSTTResToNockChiServer()> conn.WriteMessage() failed. err: ", err)
return icserror.ICSERRWEBSOCKETWriteError
}
l.Println("[LOG] client.go>SendSTTResToNockChiServer()> the stt result(connId: %s) was successfully sent via websocket. reqBody: %s", parsedRes.ConnId, reqBody)
return nil
}
func PostProcessTA(url, cmd string, connId string, tel string, ext string, empId string, dateTime string, callStartTime string, index string, stt string, dir string, ioGbn string) (tAResp *TAResp, cerr *icserror.IcsError) {
tAInfoJSON := TAInfoJSON{
Cmd: cmd,
ConnId: connId,
Tel: tel,
Ext: ext,
EmpId: empId,
DateTime: dateTime,
CallStartTime: callStartTime,
Index: index,
Stt: stt,
Dir: dir,
IoGbn: ioGbn,
}
b, err := json.Marshal(tAInfoJSON)
if err != nil {
return nil, icserror.ICSERRMarshal
}
body := bytes.NewBuffer(b)
client := NewIcsHttpClient("POST", url, body)
if client == nil {
l.Printf("[ERR] client.go>PostProcessTA()> NewIcsHttpClient() failed. err: %v", err)
l.Printf("[ERR] client.go>PostProcessTA()> NewIcsHttpClient() failed. url: %s, body: %s", url, body)
return nil, icserror.ICSERRHTTPClientCreate
}
client.Request.Header.Add("Content-Type", "application/json;charset=utf-8")
client.Request.Header.Add("Accept", "application/json")
l.Printf("[LOG] client.go>PostProcessTA()> Post Request Body: %+v", client.Request.Body)
resp, err := client.Do(client.Request)
if err != nil {
l.Printf("[ERR] client.go>PostProcessTA()> client.Do failed. err: %v", err)
l.Printf("[ERR] client.go>PostProcessTA()> client.Do failed. resp: %v", resp)
return nil, icserror.ICSERRHTTPClientPostRequest
}
l.Printf("[LOG] client.go>PostProcessTA()> client.Do() resp: %v", resp)
resBody, err := io.ReadAll(resp.Body)
if err != nil {
l.Printf("[ERR] client.go>PostProcessTA()> ReadAll failed. err: %v", err)
return nil, icserror.ICSERRRead
}
defer resp.Body.Close()
if err := json.Unmarshal(resBody, &tAResp); err != nil {
l.Printf("[ERR] client.go>PostProcessTA()> Unmarshal failed. err: %v", err)
return nil, icserror.ICSERRUnmarshal
}
return tAResp, nil
}

@ -1,33 +0,0 @@
package httprequest
import (
"crypto/tls"
"fmt"
"net/http"
"strings"
)
func HttpRequest(url, method, requestBody string) (*http.Response, error) {
// TLS 설정
tr := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, // 인증서 검증 비활성화
}
client := &http.Client{Transport: tr}
// client := &http.Client{}
payload := strings.NewReader(requestBody)
req, _ := http.NewRequest(method, url, payload)
req.Header.Set("Content-Type", "application/json")
// 요청
res, err := client.Do(req)
if err != nil {
return nil, fmt.Errorf("요청 오류: %w", err)
}
if res.StatusCode != http.StatusOK {
return nil, fmt.Errorf("error: received non-200 response status: %s", res.Status)
}
return res, nil
}

@ -1,8 +1,8 @@
package icslog package icslog
import ( import (
"batchmodule/icsconf"
"log" "log"
"mybatch/icsconf"
"os" "os"
"path/filepath" "path/filepath"
"time" "time"

@ -1,10 +1,10 @@
package stt package icsstt
import ( import (
"math" "math"
"sync" "sync"
"mybatch/icslog" "batchmodule/icslog"
) )
const RR_200MSEC_SIZE = 3200 const RR_200MSEC_SIZE = 3200

@ -1,4 +1,4 @@
package stt package icsstt
import ( import (
"cloud.google.com/go/speech/apiv1" "cloud.google.com/go/speech/apiv1"

@ -1,9 +1,9 @@
package stt package icsstt
import ( import (
"batchmodule/icsconf"
"batchmodule/icserror"
"fmt" "fmt"
"mybatch/icsconf"
"mybatch/icserror"
"os" "os"
"strconv" "strconv"
"testing" "testing"

@ -1,4 +1,4 @@
package stt package icsstt
import ( import (
"encoding/binary" "encoding/binary"
@ -6,42 +6,18 @@ import (
"fmt" "fmt"
"io" "io"
"log" "log"
"net/http"
"os" "os"
"path/filepath" "path/filepath"
"strconv" "strconv"
"strings" "strings"
"time"
"mybatch/icsconf" "batchmodule/icsconf"
encry "mybatch/icsencry" encry "batchmodule/icsencry"
"mybatch/icserror" "batchmodule/icserror"
httprequest "mybatch/icshttp" "batchmodule/icshttp"
"mybatch/icslog" "batchmodule/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 { type Transcript struct {
Text string `json:"text"` Text string `json:"text"`
StartTime int `json:"startTime"` StartTime int `json:"startTime"`
@ -69,52 +45,18 @@ type TAMessage struct {
} }
var ( var (
cfg icsconf.AppInfo conf icsconf.AppInfo
l *log.Logger l *log.Logger
taUrl string
) )
func init() { func init() {
cfg = icsconf.Getconfig() conf = icsconf.Getconfig()
l = icslog.InitializeLogger() l = icslog.InitializeLogger()
taUrl = conf.Urls.TAUrl
} }
func ProcessPostRequestForDataList() { 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 var reqDataForVoiceFile RequestData
if len(parsedRes.List) > 0 { if len(parsedRes.List) > 0 {
@ -140,14 +82,14 @@ func postReqForWavFileAndDownload(parsedRes RequestData) {
method := "POST" method := "POST"
requestBody := fmt.Sprintf(`{"data":"%s"}`, encryptedRequestBody) requestBody := fmt.Sprintf(`{"data":"%s"}`, encryptedRequestBody)
response, err := httprequest.HttpRequest(url, method, requestBody) response, err := icshttp.HttpRequest(url, method, requestBody)
if err != nil { if err != nil {
l.Println("error occured while requesting http post for datalist:", err) l.Println("error occured while requesting http post for datalist:", err)
return return
} }
st := parsedRes.StartTime st := parsedRes.StartTime
wavFilePath := cfg.Directories.WAVDirectory wavFilePath := conf.Directories.WAVDirectory
fileName := fmt.Sprintf(`%s/%s.wav`, wavFilePath, st) fileName := fmt.Sprintf(`%s/%s/%s.wav`, wavFilePath, st, parsedRes.ConnId)
file, err := os.Create(fileName) file, err := os.Create(fileName)
if err != nil { if err != nil {
l.Println("error occured while creating file:", err) l.Println("error occured while creating file:", err)
@ -165,13 +107,13 @@ func postReqForWavFileAndDownload(parsedRes RequestData) {
pcmResult, folderName := devideWavTo2Pcm(fileName) pcmResult, folderName := devideWavTo2Pcm(fileName)
if pcmResult { if pcmResult {
sttCallRes, err := controlSTT(parsedRes, folderName) sttCallRes, err := ControlSTT(parsedRes, folderName)
if err != nil { if err != nil {
l.Println("runSTT() failed with the error: ", err) l.Println("runSTT() failed with the error: ", err)
} }
// stt 콜이 성공이라면 pcm 파일 지우기 // stt 콜이 성공이라면 pcm 파일 지우기
if sttCallRes { if sttCallRes {
pcmDir := filepath.Join(cfg.Directories.PCMDirectory, st) pcmDir := filepath.Join(conf.Directories.PCMDirectory, st)
deletePcmFolder(pcmDir) deletePcmFolder(pcmDir)
} }
@ -199,7 +141,7 @@ func devideWavTo2Pcm(fileName string) (result bool, folderName string) {
fileNameWithoutWav := fileName[:len(fileName)-4] fileNameWithoutWav := fileName[:len(fileName)-4]
lastSlashIdx := strings.LastIndex(fileNameWithoutWav, "/") lastSlashIdx := strings.LastIndex(fileNameWithoutWav, "/")
starttime := fileNameWithoutWav[lastSlashIdx+1:] //starttime: 20250913223412 starttime := fileNameWithoutWav[lastSlashIdx+1:] //starttime: 20250913223412
pcmDir := cfg.Directories.PCMDirectory pcmDir := conf.Directories.PCMDirectory
starttimeDir := fmt.Sprintf("%s/%s", pcmDir, starttime) starttimeDir := fmt.Sprintf("%s/%s", pcmDir, starttime)
os.MkdirAll(starttimeDir, os.ModePerm) os.MkdirAll(starttimeDir, os.ModePerm)
@ -289,30 +231,28 @@ func devideWavTo2Pcm(fileName string) (result bool, folderName string) {
return true, starttime return true, starttime
} }
// server 연결, stt 호출, 연결 해제 func STTController(reqDataForVoiceFile icshttp.FailedDataListReqBody, folderName string) (bool, *icserror.IcsError) {
func controlSTT(parsedRes RequestData, folderName string) (bool, *icserror.IcsError) { pcmDirectory := conf.Directories.PCMDirectory
pcmDirectory := cfg.Directories.PCMDirectory
pcmDirectory = filepath.Join(pcmDirectory, folderName) pcmDirectory = filepath.Join(pcmDirectory, folderName)
// walking the file that has each left and right pcm files // walking the file that has each left and right pcm files
filepath.Walk(pcmDirectory, func(path string, info os.FileInfo, err error) error { filepath.Walk(pcmDirectory, func(path string, info os.FileInfo, err error) error {
if err != nil { if err != nil {
l.Println("Error occured while walking pcm folder. error: ", err) l.Printf("[ERR] sttcontroller>ControlSTT()> filepath.Walk() failed. pcmDirectory: %s", pcmDirectory)
l.Println("The pcm file path: ", pcmDirectory)
return err return err
} }
if !info.IsDir() && filepath.Ext(path) == "left.pcm" { if !info.IsDir() && filepath.Ext(path) == "left.pcm" {
stterr := connectSelvasServerRunSTT(parsedRes, path, "left") stterr := connectSelvasServerRunSTT(reqDataForVoiceFile, path, "left")
if stterr != nil { if stterr != nil {
l.Println("Error occured on recognizeSpeechFromPcmFile(). error: ", stterr) l.Println("[ERR] sttcontroller>ControlSTT()> connectSelvasServerRunSTT(). error: ", stterr)
return err return stterr
} }
} }
if !info.IsDir() && filepath.Ext(path) == "right.pcm" { if !info.IsDir() && filepath.Ext(path) == "right.pcm" {
stterr := connectSelvasServerRunSTT(parsedRes, path, "right") stterr := connectSelvasServerRunSTT(reqDataForVoiceFile, path, "right")
if stterr != nil { if stterr != nil {
l.Println("Error occured on recognizeSpeechFromPcmFile(). error: ", stterr) l.Println("[ERR] sttcontroller>ControlSTT()> connectSelvasServerRunSTT(). error: ", stterr)
return err return stterr
} }
} }
return nil return nil
@ -320,130 +260,66 @@ func controlSTT(parsedRes RequestData, folderName string) (bool, *icserror.IcsEr
return true, nil return true, nil
} }
func connectSelvasServerRunSTT(parsedRes RequestData, filePath string, leftright string) *icserror.IcsError { func connectSelvasServerRunSTT(reqDataForVoiceFile icshttp.FailedDataListReqBody, filePath string, leftright string) *icserror.IcsError {
var sttRes NewSTTResult
var sttErr *icserror.IcsError
voicedata, err := os.ReadFile(filePath) voicedata, err := os.ReadFile(filePath)
if err != nil { if err != nil {
return icserror.ICSERRCONFOpenFile return icserror.ICSERRCONFOpenFile
} }
ip := cfg.STT.SrcIP ip := conf.STT.SrcIP
port, _ := strconv.Atoi(cfg.STT.Port) port, _ := strconv.Atoi(conf.STT.Port)
callId := parsedRes.ConnID
custId := parsedRes.Ext connId := reqDataForVoiceFile.ConnId
recordFilePath := cfg.Directories.RecDirectory ext := reqDataForVoiceFile.Ext
recordFilePath := conf.Directories.RecDirectory
dir := "R"
if strings.Contains(leftright, "right") {
dir = "T"
}
// connecting with STT server // connecting with STT server
s, sttErr := NewSTTS(ip, port, callId, custId, recordFilePath) s, sttErr := NewSTTSshort(ip, port, connId, recordFilePath, isRx, true)
if sttErr != nil { if sttErr != nil {
l.Printf("sttcontroller>connectSelvasServerRunSTT> Failed to initialize Selvas STT connId(%s) - error: %s", connId, sttErr.GetMessage())
return icserror.ICSERRSTTConnectFail return icserror.ICSERRSTTConnectFail
} else if s != nil {
fmt.Println("STT session:", s)
} }
l.Println("STT server is connected with: ", ip, ", port: ", port) l.Printf("sttcontroller>connectSelvasServerRunSTT> Initialized Selvas STT connId(%s) - %s:%d", connId, ip, port)
// STT 호출 // STT 호출
sttRes, sttErr = s.SendSTT(voicedata, true, nil) sttRes, sttErr := s.SendSTT(voicedata, true, nil)
if sttErr != nil { if sttErr != nil {
l.Println("calling sendSTT() on sttselvas.go has failed with error: ", sttErr) l.Println("[ERR] sttcontroller>connectSelvasServerRunSTT> sendSTT() failed. error: ", sttErr)
s.Close()
return icserror.ICSERRSTTSendFail return icserror.ICSERRSTTSendFail
} }
// STT server and chanel close l.Println("sttcontroller>connectSelvasServerRunSTT> sttRes: ", sttRes)
s.CloseChanelAndServer()
// STT 호출 성공시 결과를 websocket, ta rest로 송신 finalSTTRes, err := s.SendSTTProcGetResult()
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 { if err != nil {
l.Println("Failed to connect to WebSocket: %v", err) l.Printf("[ERR] sttcontroller>connectSelvasServerRunSTT> SendSTTProcGetResult() Failed. error: %v", err)
return false, icserror.ICSERRWEBSOCKETConnectFailError
} }
defer conn.Close()
resData := ResponseData{ // STT server and chanel close
Uid: parsedRes.ConnID, err = s.Close()
Ext: parsedRes.Ext, if err != nil {
SpeakerTag: speaker, l.Println("[ERR] sttcontroller>connectSelvasServerRunSTT> s.Close() failed. err: %v", err)
Transcripts: []Transcript{
{
Text: sttRes.Res,
StartTime: sttRes.NStart,
EndTime: sttRes.NEnd,
EndPoint: true,
},
},
} }
jsonData, _ := json.Marshal(resData) // STT 호출 성공시 결과를 websocket, ta로 송신
encryptedResponseBody := encry.Encrypting(jsonData) if finalSTTRes != "" {
l.Printf("[DEBUG] sttcontroller>connectSelvasServerRunSTT> taUrl: %s", taUrl)
responseBody := fmt.Sprintf(`{"data":"%s"}`, encryptedResponseBody)
err = conn.WriteMessage(websocket.TextMessage, []byte(responseBody)) _, err := icshttp.PostProcessTA(taUrl, "E", connId, "", ext, "empIdSample", "", "", "0", finalSTTRes, dir, "1")
if err != nil { if err != nil {
l.Println("failed to send msg via websocket with the err: ", err) l.Printf("[ERR] sttcontroller>connectSelvasServerRunSTT> PostProcessTA() got error : %v", 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" err = icshttp.SendSTTResToNockChiServer(reqDataForVoiceFile, finalSTTRes, dir)
method := "POST"
requestBody := fmt.Sprintf(`{"data":"%s"}`, encryptedRequestBody)
response, err := httprequest.HttpRequest(url, method, requestBody)
if err != nil { if err != nil {
l.Println("error occured while requesting http post for datalist:", err) l.Printf("[ERR] sttcontroller>connectSelvasServerRunSTT> SendSTTResToNockChiServer() got error : %v", err)
return false, icserror.ICSERRHTTPClientExcecution
} }
l.Println("TA msg has been successfully sent. response: ", response) }
return true, nil return nil
} }

File diff suppressed because it is too large Load Diff

@ -0,0 +1,125 @@
package icsutil
import (
"batchmodule/icsconf"
"batchmodule/icserror"
"batchmodule/icslog"
"encoding/binary"
"fmt"
"io"
"log"
"os"
)
var (
conf icsconf.AppInfo
l *log.Logger
)
func init() {
conf = icsconf.Getconfig()
l = icslog.InitializeLogger()
}
func DeletePcmFolder(dir string) (bool, *icserror.IcsError) {
l.Println("util.go>deletePcmFolder> dir: ", dir)
if _, err := os.Stat(dir); os.IsNotExist(err) {
l.Println("Error at util.go>deletePcmFolder> pcm folder does not exist with the dir: ", dir)
return false, icserror.ICSERRFileOpen
}
err := os.RemoveAll(dir)
if err != nil {
l.Panicln("Error at util.go>deletePcmFolder> os.RemoveAll() dir: ", dir)
return false, icserror.ICSERRWriteFile
}
l.Printf(`util.go>deletePcmFolder> %s has been successfully deleted`, dir)
return true, nil
}
func DevideWavTo2Pcm(fileName string, starttime string) (result bool, folderName string) {
pcmDir := conf.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)
inFile, err := os.Open(fileName)
if err != nil {
l.Printf("Error at util.go>devideWavTo2Pcm()> os.Open failed. dir: %s", fileName)
return false, ""
}
defer inFile.Close()
leftFile, err := os.Create(leftOutputFile)
if err != nil {
l.Printf("Error at util.go>devideWavTo2Pcm()> os.Create failed. dir: %s", leftOutputFile)
return false, ""
}
defer leftFile.Close()
rightFile, err := os.Create(rightOutputFile)
if err != nil {
l.Printf("Error at util.go>devideWavTo2Pcm()> os.Create failed. dir: %s", leftOutputFile)
return false, ""
}
defer rightFile.Close()
// Skip WAV header (44 bytes)
wavHeader := make([]byte, 44)
if _, err := inFile.Read(wavHeader); err != nil {
l.Printf("Error at util.go>devideWavTo2Pcm()> inFile.Read(wavHeader) failed. err: %+v", err)
return false, ""
}
// Check if it's a valid WAV file
if string(wavHeader[:4]) != "RIFF" || string(wavHeader[8:12]) != "WAVE" {
l.Printf("Error at util.go>devideWavTo2Pcm()> invalid WAV file format. Header content: %s", string(wavHeader[:4]))
return false, ""
}
// Check if WAV file is stereo
numChannels := binary.LittleEndian.Uint16(wavHeader[22:24])
if numChannels != 2 {
l.Printf("Error at util.go>devideWavTo2Pcm()> unsupported channel count: %d. This function only supports stereo (2 channels)", numChannels)
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.Printf("Error at util.go>devideWavTo2Pcm()> inFile.Read(buf) failed. failed to read from input file: %v", err)
return false, ""
}
if n < 4 {
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.Printf("Error at util.go>devideWavTo2Pcm()> binary.Write(leftFile, binary.LittleEndian, leftSample) failed. err: %v", err)
return false, ""
}
if err := binary.Write(rightFile, binary.LittleEndian, rightSample); err != nil {
l.Printf("Error at util.go>devideWavTo2Pcm()> binary.Write(rightFile, binary.LittleEndian, rightSample) failed. err: %v", err)
return false, ""
}
}
l.Printf("util.go>devideWavTo2Pcm()> WAV file split successfully to dir: %s, %s", leftOutputFile, rightOutputFile)
return true, starttime
}

@ -1,14 +1,14 @@
package main package main
import ( import (
mybatch "mybatch/icsbatch" batchmodule "batchmodule/icsbatch"
// stt "mybatch/icsstt" // stt "batchmodule/icsstt"
) )
func main() { func main() {
mybatch.BatchForPostRequestForDataList() batchmodule.BatchForFailedSTT()
// mybatch.BatchForPostRequestForDataListTest() // batchmodule.BatchForPostRequestForDataListTest()
// 배치 없이 http, ws, stt 바로 호출 // 배치 없이 http, ws, stt 바로 호출
//stt.ProcessPostRequestForDataList() //stt.ProcessPostRequestForDataList()

Loading…
Cancel
Save