Skip to content

Commit 66894a1

Browse files
First version of replacements for EMO
1 parent 7f94a29 commit 66894a1

3 files changed

Lines changed: 170 additions & 6 deletions

File tree

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,12 @@ This part of the knowledge bank is a Proxy server to analyze the traffic that go
1010
## Docker setup
1111
You can find a simplified setup using Docker Compose by SebbeJohansson here: https://github.com/SebbeJohansson/emo-proxy-docker
1212
It uses nginx, dnsmasq, and mitmproxy to be able to pass through the api requests to the EMO Proxy.
13+
14+
## Experimental
15+
### ChatGPT Speak server
16+
One of the most common responses from EMO is to respond using ChatGPT.
17+
An experimental feature is to use a local Speak server to generate EMO's chatgpt speak responses instead of using the living.ai servers.
18+
You can find a proof of concept server here: https://github.com/SebbeJohansson/EmoChatGptSpeakPOC
19+
20+
Connect the server by adding the following line to your emoProxy.conf file:
21+
`"chatGptSpeakServer": "http://localhost:8085"`

emoProxy.conf.example

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,6 @@
77
"postFS": "/tmp/",
88
"logFileName": "/var/log/emoProxyss.log",
99
"enableDatabaseAndAPI": false, # For now, default behavior is still without db and api.
10-
"sqliteLocation": "/var/data/emo_logs.db"
10+
"sqliteLocation": "/var/data/emo_logs.db",
11+
"chatGptSpeakServer": ""
1112
}

emoProxy.go

Lines changed: 159 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"io"
1010
"log"
1111
"net/http"
12+
"net/url"
1213
"os"
1314
"strconv"
1415
"time"
@@ -24,6 +25,53 @@ type emo_code struct {
2425
Errmessage string `json:"errmessage"`
2526
}
2627

28+
type Intent struct {
29+
Name string `json:"name,omitempty"`
30+
Confidence float64 `json:"confidence,omitempty"`
31+
}
32+
33+
type BehaviorParas struct {
34+
UtilityType string `json:"utility_type,omitempty"`
35+
Time []string `json:"time,omitempty"`
36+
Txt string `json:"txt,omitempty"`
37+
Url string `json:"url,omitempty"`
38+
PreAnimation string `json:"pre_animation,omitempty"`
39+
PostAnimation string `json:"post_animation,omitempty"`
40+
PostBehavior string `json:"post_behavior,omitempty"`
41+
RecBehavior string `json:"rec_behavior,omitempty"`
42+
BehaviorParas *BehaviorParas `json:"behavior_paras,omitempty"`
43+
Sentiment string `json:"sentiment,omitempty"`
44+
Listen int `json:"listen,omitempty"`
45+
AnimationName string `json:"animation_name,omitempty"`
46+
}
47+
48+
type QueryResult struct {
49+
ResultCode string `json:"resultCode,omitempty"`
50+
QueryText string `json:"queryText,omitempty"`
51+
Intent *Intent `json:"intent,omitempty"`
52+
RecBehavior string `json:"rec_behavior,omitempty"`
53+
BehaviorParas *BehaviorParas `json:"behavior_paras,omitempty"`
54+
}
55+
56+
type QueryResponse struct {
57+
QueryId string `json:"queryId,omitempty"`
58+
QueryResult *QueryResult `json:"queryResult,omitempty"`
59+
LanguageCode string `json:"languageCode,omitempty"`
60+
Index int `json:"index,omitempty"`
61+
}
62+
63+
type TokenResponse struct {
64+
AccessToken string `json:"access_token,omitempty"`
65+
ExpireIn int `json:"expire_in,omitempty"`
66+
Type string `json:"type,omitempty"`
67+
}
68+
69+
type EmoSpeechResponse struct {
70+
Code int64 `json:"code"`
71+
Errmessage string `json:"errmessage"`
72+
Url string `json:"url"`
73+
}
74+
2775
type Configuration struct {
2876
PidFile string `json:"pidFile"`
2977
Livingio_API_Server string `json:"livingio_api_server"`
@@ -34,6 +82,7 @@ type Configuration struct {
3482
LogFileName string `json:"logFileName"`
3583
EnableDatabaseAndAPI bool `json:"enableDatabaseAndAPI"`
3684
SqliteLocation string `json:"sqliteLocation"`
85+
ChatGptSpeakServer string `json:"chatGptSpeakServer"`
3786
}
3887

3988
var (
@@ -105,6 +154,7 @@ func loadConfig(filename string) error {
105154
LogFileName: "/var/log/emoProxy.log",
106155
EnableDatabaseAndAPI: false,
107156
SqliteLocation: "/var/data/emo_logs.db",
157+
ChatGptSpeakServer: "",
108158
}
109159

110160
bytes, err := os.ReadFile(filename)
@@ -315,6 +365,29 @@ func makeApiRequest(r *http.Request) string {
315365
body, _ := io.ReadAll(response.Body)
316366
log.Println("Server response: ", string(body))
317367

368+
typedBody := QueryResponse{}
369+
decoder := json.NewDecoder(bytes.NewReader([]byte(body)))
370+
decoder.DisallowUnknownFields()
371+
372+
err = decoder.Decode(&typedBody)
373+
if err != nil {
374+
log.Println("Error when decoding JSON (", string(body), ") will return unhandled:", err)
375+
} else {
376+
if typedBody.QueryId != "" {
377+
if typedBody.QueryResult.Intent.Name == "chatgpt_speak" && conf.ChatGptSpeakServer != "" {
378+
speakResponse := makeChatGptSpeakRequest(typedBody.QueryResult.QueryText, typedBody.LanguageCode, typedBody.QueryResult.BehaviorParas.Txt, r)
379+
if speakResponse.Url != "" && speakResponse.Txt != "" {
380+
log.Println("Successfully replaced chatgpt_speak response for request.")
381+
typedBody.QueryResult.BehaviorParas.Url = speakResponse.Url
382+
typedBody.QueryResult.BehaviorParas.Txt = speakResponse.Txt
383+
} else {
384+
log.Println("Failed to get valid response from ChatGptSpeakServer, keeping original response.")
385+
}
386+
}
387+
body, _ = json.Marshal(typedBody)
388+
}
389+
}
390+
318391
logResponse(response)
319392

320393
if useDatabaseAndAPI {
@@ -346,10 +419,8 @@ func makeTtsRequest(r *http.Request) string {
346419
}
347420
defer response.Body.Close()
348421

349-
// read response
350422
body, _ := io.ReadAll(response.Body)
351423

352-
// write post request body to fs
353424
logBody(response.Header.Get("Content-Type"), body, "tts_")
354425
logResponse(response)
355426

@@ -382,10 +453,8 @@ func makeApiTtsRequest(r *http.Request) string {
382453
}
383454
defer response.Body.Close()
384455

385-
// read response
386456
body, _ := io.ReadAll(response.Body)
387457

388-
// write post request body to fs
389458
logBody(response.Header.Get("Content-Type"), body, "apitts_")
390459
logResponse(response)
391460

@@ -418,7 +487,6 @@ func makeResRequest(r *http.Request, w http.ResponseWriter) string {
418487
}
419488
defer response.Body.Close()
420489

421-
// read response
422490
body, _ := io.ReadAll(response.Body)
423491

424492
logBody(response.Header.Get("Content-Type"), body, "res_")
@@ -434,3 +502,89 @@ func makeResRequest(r *http.Request, w http.ResponseWriter) string {
434502
}
435503
return string(body)
436504
}
505+
506+
func makeEmoSpeechRequest(text string, languageCode string, r *http.Request) EmoSpeechResponse {
507+
request, _ := http.NewRequest("GET", "https://"+conf.Livingio_API_Server+"/emo/speech/tts?q="+url.QueryEscape(text)+"&l="+url.QueryEscape(languageCode), nil)
508+
509+
val, exists := r.Header["Authorization"]
510+
if exists {
511+
request.Header.Add("Authorization", val[0])
512+
}
513+
514+
val, exists = r.Header["Secret"]
515+
if exists {
516+
request.Header.Add("Secret", val[0])
517+
}
518+
519+
request.Header.Del("User-Agent")
520+
521+
httpclient := &http.Client{}
522+
response, err := httpclient.Do(request)
523+
524+
if err != nil {
525+
log.Fatalf("An Error Occured %v", err)
526+
}
527+
defer response.Body.Close()
528+
529+
body, _ := io.ReadAll(response.Body)
530+
531+
var emoSpeechResponse EmoSpeechResponse
532+
if err := json.Unmarshal([]byte(body), &emoSpeechResponse); err != nil {
533+
log.Printf("Error unmarshaling ChatGptSpeakServer response: %v\n", err)
534+
return EmoSpeechResponse{}
535+
}
536+
537+
return emoSpeechResponse
538+
}
539+
540+
func makeChatGptSpeakRequest(queryText string, languageCode string, fallbackResponse string, r *http.Request) BehaviorParas {
541+
type ChatGptSpeakRequest struct {
542+
QueryText string `json:"queryText"`
543+
LanguageCode string `json:"languageCode"`
544+
FallbackResponse string `json:"fallbackResponse,omitempty"`
545+
}
546+
type ChatGptSpeakResponse struct {
547+
ResponseText string `json:"responseText"`
548+
}
549+
550+
chatGptRequestData := ChatGptSpeakRequest{
551+
QueryText: queryText,
552+
LanguageCode: languageCode,
553+
FallbackResponse: fallbackResponse,
554+
}
555+
chatGptRequestBody, _ := json.Marshal(chatGptRequestData)
556+
chatGptRequest, _ := http.NewRequest("POST", conf.ChatGptSpeakServer+"/speak", bytes.NewBuffer(chatGptRequestBody))
557+
chatGptRequest.Header.Add("Content-Type", "application/json")
558+
559+
chatGptClient := &http.Client{}
560+
chatGptResponse, err := chatGptClient.Do(chatGptRequest)
561+
if err != nil {
562+
log.Fatalf("An Error Occured while calling ChatGptSpeakServer %v", err)
563+
}
564+
defer chatGptResponse.Body.Close()
565+
566+
chatGptResponseBody, _ := io.ReadAll(chatGptResponse.Body)
567+
568+
var chatGptTypedResponse ChatGptSpeakResponse
569+
if err := json.Unmarshal([]byte(chatGptResponseBody), &chatGptTypedResponse); err != nil {
570+
log.Printf("Error unmarshaling ChatGptSpeakServer response: %v\n", err)
571+
return BehaviorParas{}
572+
}
573+
574+
if chatGptTypedResponse.ResponseText == "" {
575+
log.Println("ChatGptSpeakServer returned empty response text")
576+
return BehaviorParas{}
577+
}
578+
579+
emoSpeechResponse := makeEmoSpeechRequest(chatGptTypedResponse.ResponseText, languageCode, r)
580+
if emoSpeechResponse.Code != 200 || emoSpeechResponse.Url == "" {
581+
log.Printf("Error in EmoSpeechResponse: Code %d, Errmessage: %s\n", emoSpeechResponse.Code, emoSpeechResponse.Errmessage)
582+
return BehaviorParas{}
583+
}
584+
behaviorParasResponse := BehaviorParas{
585+
Txt: chatGptTypedResponse.ResponseText,
586+
Url: emoSpeechResponse.Url,
587+
}
588+
589+
return behaviorParasResponse
590+
}

0 commit comments

Comments
 (0)