Commit dac6de19 authored by Lamahewa D's avatar Lamahewa D

Completed middleware code

parent de2cc233
default: run
run:
@go run routes.go dcsrp.go
build:
set GOOS=linux
go build -o dcsrp-mw -ldflags "-s -w" -trimpath routes.go dcsrp.go
# DCSRP ( Middleware )
\ No newline at end of file
package app
import (
"bytes"
"dcsrp-mw/models"
"encoding/json"
"fmt"
"io"
"log"
"net/http"
"time"
"golang.org/x/exp/slices"
)
type (
Message struct {
Content string `json:"content"`
}
Choice struct {
Message Message `json:"message"`
}
Data struct {
ID string `json:"id"`
Choices []Choice `json:"choices"`
}
Functions struct {
Name string `json:"function_name"`
}
)
/**
* Dispatch request to OpenAI platform API to parse
* using GPT LLM to retrive the relevent function
* for the question
*/
func GPTDispatcher(Ticket *models.Tickets, Call models.Calls, transcript string) {
/**
* This is the prompt we submit to GPT LLM to get the
* response. This include all the functions we are
* capable of executing inside in the application
*/
payload := []byte(fmt.Sprintf(`{
"model": "gpt-3.5-turbo-0613",
"messages": [
{ "role": "user", "content": "make decisions based on the following guided dataset. if you prompt with any matching scenarios to the following queries output only the function name in json format. Don't output anything else. match similier queries to best fit. [{\n \"function_name\": \"track_package\", \"function_description\": \"Track package or packages\", \"defect_status\": \"Detect if the package is defected or not\", \"working_hours\": \"Get company working hours\", \"contact_information\":\"Get company contact information\"\n}]" },
{ "role": "user", "content": "%s" }
]
}`, transcript))
client := &http.Client{
Timeout: time.Second * 10,
}
Request, err := http.NewRequest("POST", "https://api.openai.com/v1/chat/completions", bytes.NewBuffer(payload))
if err != nil {
log.Println(err)
return
}
Request.Header.Add("Authorization", "Bearer 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")
Request.Header.Add("Content-Type", "application/json")
// DISPATCH
Response, err := client.Do(Request)
if err != nil {
log.Println(err)
return
}
defer Response.Body.Close()
/**
* Read and parse the JSON response coming from GPT
* and parse to find the function
*/
content, err := io.ReadAll(Response.Body)
if err != nil {
log.Println(err)
return
}
var Result Data
var Function Functions
json.Unmarshal(content, &Result)
json.Unmarshal([]byte(Result.Choices[0].Message.Content), &Function)
/**
* Check if the LLM returned function is valid and
* defined in the application
*/
ListOfFunctions := []string{"track_package", "working_hours", "contact_information", "defect_status"}
if slices.Contains(ListOfFunctions, Function.Name) {
/**
* We have the function defined in the backend
* application, so we are dispatching the request
* to backend
*/
http.Post(fmt.Sprintf("http://localhost:8282/v1.0/function/%s", Function.Name), "application/json", bytes.NewBuffer([]byte(fmt.Sprintf(`{"ticket": %d}`, Ticket.ID))))
} else {
/**
* We don't have the required function defined in
* our backend API and we switch the ticket to manual
* mode
*/
go UpdateTicketTimeline(Ticket, "AI cannot decide what to do, falling back to manual mode")
go ChangeTicketModeToManual(Ticket, "manual")
}
}
package app
import (
"bytes"
"dcsrp-mw/models"
"fmt"
"net/http"
)
func UpdateTicketTimeline(Ticket *models.Tickets, Description string) {
fmt.Println("func::app::UpdateTicketTimeline()")
http.Post("http://localhost:8282/v1.0/ticket/timeline", "application/json", bytes.NewBuffer([]byte(fmt.Sprintf(`{"ticket": %d, "description": "%s"}`, Ticket.ID, Description))))
}
func ChangeTicketModeToManual(Ticket *models.Tickets, Mode string) {
fmt.Println("func::app::ChangeTicketModeToManual()")
http.Post("http://localhost:8282/v1.0/ticket/agent", "application/json", bytes.NewBuffer([]byte(fmt.Sprintf(`{ "mode": "%s", "ticket": %d }`, Mode, Ticket.ID))))
}
package call package call
import ( import (
"dcsrp/models" "dcsrp-mw/models"
"fmt" "fmt"
"strconv" "strconv"
"strings" "strings"
...@@ -28,27 +28,45 @@ func Welcome(c *gin.Context) { ...@@ -28,27 +28,45 @@ func Welcome(c *gin.Context) {
return return
} }
var FromNumber string
if Request.From == "Anonymous" {
FromNumber = "+94777123456"
} else {
FromNumber = Request.From
}
/**
* Update incoming number to customer profile to avoid
* conflicts on dynamic number calls
*/
db.Model(&models.Customers{}).Where("id", 5).Update("mobile", strings.TrimPrefix(FromNumber, "+"))
/** /**
* Create relevent call tracking information in the * Create relevent call tracking information in the
* database to retain call session inside in the * database to retain call session inside in the
* application * application
*/ */
from, _ := strconv.Atoi(strings.Replace(Request.From, "+", "", 1)) from, _ := strconv.Atoi(strings.Replace(FromNumber, "+", "", 1))
db.Create(&models.Calls{ db.Create(&models.Calls{
SID: Request.CallID, SID: Request.CallID,
Number: uint64(from), Number: uint64(from),
}) })
say := &twiml.VoiceSay{ say_welcome_en := &twiml.VoiceSay{
Voice: "women", Voice: "women",
Language: "en-us", Language: "en-us",
Message: "Thank you for calling Prompt Express.", Message: "Thank you for calling Prompt Express.",
} }
say_welcome_si := &twiml.VoicePlay{
Loop: "1",
Url: "https://dcsrp.s3.ap-southeast-1.amazonaws.com/assets/audio/clip-01.mp3",
}
// Language // Language
gather_language := &twiml.VoiceGather{ gather_language := &twiml.VoiceGather{
Input: "dtmf", Input: "dtmf",
Timeout: "5", Timeout: "10",
NumDigits: "1", NumDigits: "1",
Action: "/call/receive/language", Action: "/call/receive/language",
Method: "POST", Method: "POST",
...@@ -64,12 +82,12 @@ func Welcome(c *gin.Context) { ...@@ -64,12 +82,12 @@ func Welcome(c *gin.Context) {
}, },
&twiml.VoicePlay{ &twiml.VoicePlay{
Loop: "1", Loop: "1",
Url: "https://dcsrpxyz.s3.us-west-002.backblazeb2.com/sinhala-tracking.mp3", Url: "https://dcsrp.s3.ap-southeast-1.amazonaws.com/assets/audio/clip-02.mp3",
}, },
} }
// RESPONSE // RESPONSE
response, err := twiml.Voice([]twiml.Element{say, gather_language}) response, err := twiml.Voice([]twiml.Element{say_welcome_en, say_welcome_si, gather_language})
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
return return
...@@ -105,7 +123,7 @@ func Language(c *gin.Context) { ...@@ -105,7 +123,7 @@ func Language(c *gin.Context) {
gather_tracking := &twiml.VoiceGather{ gather_tracking := &twiml.VoiceGather{
Input: "dtmf", Input: "dtmf",
Timeout: "5", Timeout: "10",
NumDigits: "4", NumDigits: "4",
Action: "/call/receive/tracking", Action: "/call/receive/tracking",
Method: "POST", Method: "POST",
...@@ -122,7 +140,7 @@ func Language(c *gin.Context) { ...@@ -122,7 +140,7 @@ func Language(c *gin.Context) {
if Request.Digits == 2 { if Request.Digits == 2 {
gather_tracking.InnerElements = []twiml.Element{&twiml.VoicePlay{ gather_tracking.InnerElements = []twiml.Element{&twiml.VoicePlay{
Loop: "1", Loop: "1",
Url: "https://dcsrpxyz.s3.us-west-002.backblazeb2.com/sinhala-tracking.mp3", Url: "https://dcsrp.s3.ap-southeast-1.amazonaws.com/assets/audio/clip-03.mp3",
}} }}
} }
...@@ -162,7 +180,7 @@ func Tracking(c *gin.Context) { ...@@ -162,7 +180,7 @@ func Tracking(c *gin.Context) {
db.Where("sid", Request.CallID).First(&Call) db.Where("sid", Request.CallID).First(&Call)
db.Model(&Call).Updates(models.Calls{DTMF_Tracking: Request.Digits}) db.Model(&Call).Updates(models.Calls{DTMF_Tracking: Request.Digits})
var say *twiml.VoiceSay // var say *twiml.VoiceSay
gather_record := &twiml.VoiceRecord{ gather_record := &twiml.VoiceRecord{
Action: "/call/receive/record", Action: "/call/receive/record",
...@@ -177,31 +195,31 @@ func Tracking(c *gin.Context) { ...@@ -177,31 +195,31 @@ func Tracking(c *gin.Context) {
// ENGLISH // ENGLISH
if Call.DTMF_Lang == 1 { if Call.DTMF_Lang == 1 {
say = &twiml.VoiceSay{ resp, err := twiml.Voice([]twiml.Element{&twiml.VoiceSay{
Voice: "women", Voice: "women",
Language: "en-US", Language: "en-US",
Message: "Please record your question after the beep and press hash key once complete.", Message: "Please record your question after the beep and press hash key once complete.",
}, gather_record, &twiml.VoiceHangup{}})
if err != nil {
fmt.Println(err)
return
} }
c.Writer.Write([]byte(resp))
} }
// SINHALA // SINHALA
if Call.DTMF_Lang == 2 { if Call.DTMF_Lang == 2 {
say = &twiml.VoiceSay{ resp, err := twiml.Voice([]twiml.Element{&twiml.VoicePlay{
Voice: "women", Loop: "1",
Language: "en-US", Url: "https://dcsrp.s3.ap-southeast-1.amazonaws.com/assets/audio/clip-04.mp3",
Message: "Please record your question after the beep and press hash key once complete.", }, gather_record, &twiml.VoiceHangup{}})
if err != nil {
fmt.Println(err)
return
} }
c.Writer.Write([]byte(resp))
} }
response, err := twiml.Voice([]twiml.Element{say, gather_record, &twiml.VoiceHangup{}})
if err != nil {
fmt.Println(err)
return
}
// RETURN
c.Writer.Write([]byte(response))
} }
func Record(c *gin.Context) { func Record(c *gin.Context) {
......
...@@ -2,7 +2,8 @@ package webhook ...@@ -2,7 +2,8 @@ package webhook
import ( import (
"context" "context"
"dcsrp/models" "dcsrp-mw/app"
"dcsrp-mw/models"
"fmt" "fmt"
"io" "io"
"net/http" "net/http"
...@@ -10,7 +11,9 @@ import ( ...@@ -10,7 +11,9 @@ import (
speech "cloud.google.com/go/speech/apiv1" speech "cloud.google.com/go/speech/apiv1"
"cloud.google.com/go/speech/apiv1/speechpb" "cloud.google.com/go/speech/apiv1/speechpb"
"cloud.google.com/go/translate"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"golang.org/x/text/language"
"google.golang.org/api/option" "google.golang.org/api/option"
"google.golang.org/api/storage/v1" "google.golang.org/api/storage/v1"
"gorm.io/gorm" "gorm.io/gorm"
...@@ -38,17 +41,17 @@ func Recording(c *gin.Context) { ...@@ -38,17 +41,17 @@ func Recording(c *gin.Context) {
/** /**
* Initiate GCP API client with Google Storage service * Initiate GCP API client with Google Storage service
* and Google Speech service to further * and Google Speech service to facilititate further
* operations. * operations.
*/ */
ctx := context.Background() ctx := context.Background()
storage_service, err := storage.NewService(ctx, option.WithCredentialsFile("gcp-dcsrp-svc.json")) storage_service, err := storage.NewService(ctx, option.WithCredentialsFile("/usr/share/dcsrp/gcp-dcsrp-svc.json"))
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
return return
} }
speech_client, err := speech.NewClient(ctx, option.WithCredentialsFile("gcp-dcsrp-svc.json")) speech_client, err := speech.NewClient(ctx, option.WithCredentialsFile("/usr/share/dcsrp/gcp-dcsrp-svc.json"))
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
return return
...@@ -107,34 +110,242 @@ func Recording(c *gin.Context) { ...@@ -107,34 +110,242 @@ func Recording(c *gin.Context) {
} }
/** /**
* Upload voice clip to the GCP and get the response * Check if the call language from DTMF codes and send the
* in the text format to parse from the next * correct language code to the Speach to Text API
* application
*/ */
speech_response, err := speech_client.Recognize(ctx, &speechpb.RecognizeRequest{ var Call models.Calls
Config: &speechpb.RecognitionConfig{ db.Where("sid", Request.CallID).First(&Call)
Encoding: speechpb.RecognitionConfig_LINEAR16,
SampleRateHertz: 8000, /**
LanguageCode: "en-US", * Upload the voice clip to GCP for the English language
Model: "phone_call", * calls and update the database with the returned
UseEnhanced: true, * transcript
}, */
Audio: &speechpb.RecognitionAudio{ if Call.DTMF_Lang == 1 {
AudioSource: &speechpb.RecognitionAudio_Uri{
Uri: fmt.Sprintf("gs://dcsrp/recordings/dcsrp-%s.wav", Request.RecordingID), /**
* Get customer information from the call and append
* them into the tickets table when creating the
* ticket
*/
var Customer models.Customers
db.Where("mobile", Call.Number).First(&Customer)
/**
* Create new ticket for the customer support call and
* update it with relevent information
*/
Ticket := &models.Tickets{
CallID: Call.ID,
CustomerID: Customer.ID,
Status: "open",
Agent: "auto",
}
db.Create(&Ticket)
/**
* Do the transcripting in the google cloud service
* and get the response
*/
speech_response, err := speech_client.Recognize(ctx, &speechpb.RecognizeRequest{
Config: &speechpb.RecognitionConfig{
Encoding: speechpb.RecognitionConfig_LINEAR16,
SampleRateHertz: 8000,
LanguageCode: "en-US",
Model: "phone_call",
UseEnhanced: true,
}, },
}, Audio: &speechpb.RecognitionAudio{
}) AudioSource: &speechpb.RecognitionAudio_Uri{
if err != nil { Uri: fmt.Sprintf("gs://dcsrp/recordings/dcsrp-%s.wav", Request.RecordingID),
fmt.Println(err) },
return },
})
if err != nil {
fmt.Println(err)
return
}
/**
* Parse the returned speech response to see if we
* got valid transcript or not
*/
transcript, err := GetTranscript(speech_response)
if err != nil {
go app.UpdateTicketTimeline(Ticket, "Voice recognition failed")
go app.ChangeTicketModeToManual(Ticket, "manual")
return
} else {
/**
* Update the call information in the database
* with the text transcript returned from the
* Google cloud speech to text service
*/
db.Model(&models.Calls{}).Where("sid", Request.CallID).Update("transcript", transcript)
/**
* Finally invoke the GPT dispatcher and send the data
* using custom defined prompt to get the relevent answer
* to the question
*/
go app.GPTDispatcher(Ticket, Call, transcript)
}
}
/**
* Upload the voice clip to the GCP for Sinhala language
* calls and update the database with the returned
* transcript. Once done we need to invoke Translate function
* to translate this Sinhala string to English using GCP
*/
if Call.DTMF_Lang == 2 {
/**
* Get customer information from the call and append
* them into the tickets table when creating the
* ticket
*/
var Customer models.Customers
db.Where("mobile", Call.Number).First(&Customer)
/**
* Create new ticket for the customer support call and
* update it with relevent information
*/
Ticket := &models.Tickets{
CallID: Call.ID,
CustomerID: Customer.ID,
Status: "open",
Agent: "auto",
}
db.Create(&Ticket)
/**
* Do the transcripting in the google cloud service
* and get the response
*/
speech_response, err := speech_client.Recognize(ctx, &speechpb.RecognizeRequest{
Config: &speechpb.RecognitionConfig{
Encoding: speechpb.RecognitionConfig_LINEAR16,
SampleRateHertz: 8000,
LanguageCode: "si-LK",
UseEnhanced: true,
},
Audio: &speechpb.RecognitionAudio{
AudioSource: &speechpb.RecognitionAudio_Uri{
Uri: fmt.Sprintf("gs://dcsrp/recordings/dcsrp-%s.wav", Request.RecordingID),
},
},
})
if err != nil {
fmt.Println(err)
return
}
/**
* Parse the returned speech response to see if we
* got valid transcript or not
*/
transcript_si, err := GetTranscript(speech_response)
if err != nil {
go app.UpdateTicketTimeline(Ticket, "Voice recognition failed")
go app.ChangeTicketModeToManual(Ticket, "manual")
return
} else {
/**
* Update the call information in the database
* with the text transcript returned from the
* Google cloud speech to text service
*/
db.Model(&models.Calls{}).Where("sid", Request.CallID).Update("transcript", transcript_si)
/**
* Invoke translation function to translate the
* Sinhala string to English in order to pass
* information before NLP
*/
transcript_en, err := Translate(transcript_si)
if err != nil {
fmt.Println(err)
return
}
/**
* Update the translate to the database in English
* language
*/
db.Model(&models.Calls{}).Where("sid", Request.CallID).Update("transcript", transcript_en)
/**
* Finally invoke the GPT dispatcher and send the data
* using custom defined prompt to get the relevent answer
* to the question
*/
go app.GPTDispatcher(Ticket, Call, transcript_en)
}
} }
}
func Translate(transcript string) (string, error) {
/** /**
* Update the call information in the database * Get the call transcript from the database and
* with the text transcript returned from the * prepare to make the request to upstream
* Google cloud speech to text service
*/ */
db.Model(&models.Calls{}).Where("sid", Request.CallID).Update("transcript", speech_response.Results[0].Alternatives[0].Transcript) fmt.Println(transcript)
ctx := context.Background()
client, err := translate.NewClient(ctx, option.WithCredentialsFile("/usr/share/dcsrp/gcp-dcsrp-svc.json"))
if err != nil {
return "", err
}
translate_response, err := client.Translate(ctx, []string{transcript}, language.English, &translate.Options{
Source: language.Sinhala,
Format: translate.Text,
})
if err != nil {
return "", err
}
// RETURN
return translate_response[0].Text, nil
}
func GetTranscript(RecognizeResponse *speechpb.RecognizeResponse) (string, error) {
speech_results := RecognizeResponse.GetResults()
if len(speech_results) != 1 {
return "", fmt.Errorf("no results found")
} else {
/**
* Seems like we have received speech response
* and now we can try to get the alternatives
* from first element
*/
speech_alternatives := speech_results[0].GetAlternatives()
if len(speech_alternatives) != 1 {
return "", fmt.Errorf("no alternatives found")
} else {
/**
* We have the alternative in the struct and we
* can process it from here
*/
return speech_alternatives[0].Transcript, nil
}
}
} }
package main package main
import ( import (
middleware "dcsrp/middlewares" middleware "dcsrp-mw/middlewares"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
) )
......
module dcsrp module dcsrp-mw
go 1.20 go 1.20
require ( require (
cloud.google.com/go/speech v1.15.0 cloud.google.com/go/speech v1.15.0
cloud.google.com/go/translate v1.7.0
github.com/gin-gonic/gin v1.9.0 github.com/gin-gonic/gin v1.9.0
github.com/twilio/twilio-go v1.7.0 github.com/twilio/twilio-go v1.7.0
golang.org/x/exp v0.0.0-20230801115018-d63ba01acd4b
golang.org/x/text v0.8.0
google.golang.org/api v0.114.0 google.golang.org/api v0.114.0
gorm.io/driver/mysql v1.5.0 gorm.io/driver/mysql v1.5.0
gorm.io/gorm v1.25.0 gorm.io/gorm v1.25.0
...@@ -49,7 +52,6 @@ require ( ...@@ -49,7 +52,6 @@ require (
golang.org/x/net v0.8.0 // indirect golang.org/x/net v0.8.0 // indirect
golang.org/x/oauth2 v0.6.0 // indirect golang.org/x/oauth2 v0.6.0 // indirect
golang.org/x/sys v0.6.0 // indirect golang.org/x/sys v0.6.0 // indirect
golang.org/x/text v0.8.0 // indirect
google.golang.org/appengine v1.6.7 // indirect google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect
google.golang.org/grpc v1.54.0 // indirect google.golang.org/grpc v1.54.0 // indirect
......
...@@ -9,6 +9,8 @@ cloud.google.com/go/longrunning v0.4.1 h1:v+yFJOfKC3yZdY6ZUI933pIYdhyhV8S3NpWrXW ...@@ -9,6 +9,8 @@ cloud.google.com/go/longrunning v0.4.1 h1:v+yFJOfKC3yZdY6ZUI933pIYdhyhV8S3NpWrXW
cloud.google.com/go/longrunning v0.4.1/go.mod h1:4iWDqhBZ70CvZ6BfETbvam3T8FMvLK+eFj0E6AaRQTo= cloud.google.com/go/longrunning v0.4.1/go.mod h1:4iWDqhBZ70CvZ6BfETbvam3T8FMvLK+eFj0E6AaRQTo=
cloud.google.com/go/speech v1.15.0 h1:JEVoWGNnTF128kNty7T4aG4eqv2z86yiMJPT9Zjp+iw= cloud.google.com/go/speech v1.15.0 h1:JEVoWGNnTF128kNty7T4aG4eqv2z86yiMJPT9Zjp+iw=
cloud.google.com/go/speech v1.15.0/go.mod h1:y6oH7GhqCaZANH7+Oe0BhgIogsNInLlz542tg3VqeYI= cloud.google.com/go/speech v1.15.0/go.mod h1:y6oH7GhqCaZANH7+Oe0BhgIogsNInLlz542tg3VqeYI=
cloud.google.com/go/translate v1.7.0 h1:GvLP4oQ4uPdChBmBaUSa/SaZxCdyWELtlAaKzpHsXdA=
cloud.google.com/go/translate v1.7.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/beevik/etree v1.1.0 h1:T0xke/WvNtMoCqgzPhkX2r4rjY3GDZFi+FjpRZY2Jbs= github.com/beevik/etree v1.1.0 h1:T0xke/WvNtMoCqgzPhkX2r4rjY3GDZFi+FjpRZY2Jbs=
github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A= github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A=
...@@ -141,6 +143,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh ...@@ -141,6 +143,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE= golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE=
golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU= golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20230801115018-d63ba01acd4b h1:r+vk0EmXNmekl0S0BascoeeoHk/L7wmaW2QF90K+kYI=
golang.org/x/exp v0.0.0-20230801115018-d63ba01acd4b/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
......
package models
type Customers struct {
ID uint64 `gorm:"column:id;primaryKey"`
Email string `gorm:"column:email"`
Password string `gorm:"column:password"`
Name string `gorm:"column:name"`
Type string `gorm:"column:type"`
Mobile uint64 `gorm:"column:mobile"`
NoOfPices uint64 `gorm:"column:no_of_pices"`
Province string `gorm:"column:province"`
Date string `gorm:"column:date"`
}
func (Customers) TableName() string {
return "customers"
}
package models
import (
"gorm.io/plugin/soft_delete"
)
type Tickets struct {
ID uint64 `gorm:"column:id;primaryKey"`
CallID uint64 `gorm:"column:call_id"`
CustomerID uint64 `gorm:"column:customer_id"`
Status string `gorm:"column:status"`
Agent string `gorm:"column:agent"`
CreatedAt int64 `gorm:"column:created_at;autoCreateTime"`
UpdatedAt int64 `gorm:"column:updated_at;autoUpdateTime"`
DeletedAt soft_delete.DeletedAt `gorm:"column:deleted_at;default:null"`
}
func (Tickets) TableName() string {
return "tickets"
}
package main package main
import ( import (
Call_Controller "dcsrp/controllers/call" Call_Controller "dcsrp-mw/controllers/call"
Webhook_Controller "dcsrp/controllers/webhook" Webhook_Controller "dcsrp-mw/controllers/webhook"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
) )
func Routes(Router *gin.Engine) { func Routes(Router *gin.Engine) {
Router.POST("/call/receive", Call_Controller.Language)
Router.POST("/call/receive/welcome", Call_Controller.Welcome) Router.POST("/call/receive/welcome", Call_Controller.Welcome)
Router.POST("/call/receive/language", Call_Controller.Language) Router.POST("/call/receive/language", Call_Controller.Language)
Router.POST("/call/receive/tracking", Call_Controller.Tracking) Router.POST("/call/receive/tracking", Call_Controller.Tracking)
...@@ -23,8 +22,7 @@ func Routes(Router *gin.Engine) { ...@@ -23,8 +22,7 @@ func Routes(Router *gin.Engine) {
*/ */
Router.GET("/ping", func(c *gin.Context) { Router.GET("/ping", func(c *gin.Context) {
c.AbortWithStatusJSON(200, gin.H{ c.AbortWithStatusJSON(200, gin.H{
"status": "success", "status": "success",
"version": "1.0.0",
}) })
}) })
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment