Browse Source

add nlp support

Andreas Peters 3 months ago
parent
commit
0c68e520ee
Signed by: Andreas Peters <ap@aventer.biz> GPG Key ID: 6A83F12541CFCCF9
5 changed files with 179 additions and 42 deletions
  1. 7
    22
      Dockerfile
  2. 8
    0
      README.md
  3. 1
    0
      app.go
  4. 31
    20
      clients/clients.go
  5. 132
    0
      services/nlp/nlp.go

+ 7
- 22
Dockerfile View File

@@ -3,36 +3,21 @@ LABEL maintainer="Andreas Peters <support@aventer.biz>"
3 3
 
4 4
 ENV BIND_ADDRESS=:4050 DATABASE_TYPE=sqlite3 DATABASE_URL=/go-avbot/data/go-neb.db?_busy_timeout=5000 
5 5
 
6
+COPY . /go-avbot/
7
+COPY run.sh /run.sh
8
+
6 9
 RUN apk update && \
7 10
     apk add git gcc libc-dev && \
8
-    go get github.com/sirupsen/logrus && \
9
-    go get git.aventer.biz/AVENTER/util && \
10
-    go get github.com/mattn/go-sqlite3 && \
11
-    go get github.com/prometheus/client_golang/prometheus && \
12
-    go get github.com/matrix-org/dugong && \
13
-    go get git.aventer.biz/AVENTER/gomatrix && \
14
-    go get github.com/mattn/go-shellwords && \
15
-    go get gopkg.in/yaml.v2 && \
16
-    go get golang.org/x/oauth2 && \
17
-    go get github.com/google/go-github/github && \
18
-    go get gopkg.in/alecthomas/kingpin.v2 && \
19
-    go get github.com/russross/blackfriday && \
20
-    go get github.com/aws/aws-sdk-go && \
21
-    go get github.com/golang/lint/golint && \
22
-    go get github.com/fzipp/gocyclo && \
23
-    go get github.com/client9/misspell/... && \
24
-    go get github.com/gordonklaus/ineffassign && \     
11
+    cd /go-avbot/ && \
12
+    go get -d && \
25 13
     mkdir -p /go-avbot/log
26 14
 
27 15
 VOLUME /go-avbot/data
28 16
 
29
-COPY . /go-avbot/
30
-COPY run.sh /run.sh
31
-
32 17
 RUN cd /go-avbot && \
33 18
     go build -ldflags "-X main.MinVersion=`date -u +%Y%m%d%.H%M%S`" app.go init.go
34 19
 
35 20
 EXPOSE 4050
36 21
 
37
-ENTRYPOINT ["/run.sh"]
38
-#CMD ["/bin/sh"]
22
+#ENTRYPOINT ["/run.sh"]
23
+CMD ["/bin/sh"]

+ 8
- 0
README.md View File

@@ -60,6 +60,10 @@ There are still a lot of work. Currently our main focus is the AWS support.
60 60
 
61 61
 - Receive Webhooks from your gitea repo
62 62
 
63
+### NLP (Natural Language Processing) 
64
+
65
+- Gateway to the IKY Framework
66
+
63 67
 ## Software Requirements
64 68
 
65 69
 ```bash
@@ -111,3 +115,7 @@ go get github.com/aws/aws-sdk-go
111 115
 
112 116
 - modify repo to git.aventer.biz
113 117
 - add gitea support
118
+
119
+### v0.0.5
120
+
121
+- add nlp support

+ 1
- 0
app.go View File

@@ -19,6 +19,7 @@ import (
19 19
 	_ "./services/gitea"
20 20
 	_ "./services/github"
21 21
 	_ "./services/invoice"
22
+	_ "./services/nlp"
22 23
 	_ "./services/pentest"
23 24
 	_ "./services/travisci"
24 25
 	_ "./services/wekan"

+ 31
- 20
clients/clients.go View File

@@ -12,6 +12,7 @@ import (
12 12
 	"../database"
13 13
 	"../matrix"
14 14
 	"../metrics"
15
+	nlp "../services/nlp"
15 16
 	"../types"
16 17
 	"git.aventer.biz/AVENTER/gomatrix"
17 18
 	shellwords "github.com/mattn/go-shellwords"
@@ -181,30 +182,40 @@ func (c *Clients) onMessageEvent(client *gomatrix.Client, event *gomatrix.Event)
181 182
 
182 183
 	var responses []interface{}
183 184
 
184
-	for _, service := range services {
185
-		if body[0] == '!' { // message is a command
186
-			args, err := shellwords.Parse(body[1:])
187
-			if err != nil {
188
-				args = strings.Split(body[1:], " ")
189
-			}
185
+	//  Ignore everymessage, if its from the bot byself
186
+	if event.Sender != client.UserID {
190 187
 
191
-			if response := runCommandForService(service.Commands(client), event, args); response != nil {
192
-				responses = append(responses, response)
188
+		// send every message to the natual language processor
189
+		response := nlp.CmdForwardToNLP(event.RoomID, client.UserID, body)
190
+		if response != nil {
191
+			responses = append(responses, response)
192
+		}
193
+
194
+		for _, service := range services {
195
+			if body[0] == '!' { // message is a command
196
+				args, err := shellwords.Parse(body[1:])
197
+				if err != nil {
198
+					args = strings.Split(body[1:], " ")
199
+				}
200
+
201
+				if response := runCommandForService(service.Commands(client), event, args); response != nil {
202
+					responses = append(responses, response)
203
+				}
204
+			} else { // message isn't a command, it might need expanding
205
+				expansions := runExpansionsForService(service.Expansions(client), event, body)
206
+				responses = append(responses, expansions...)
193 207
 			}
194
-		} else { // message isn't a command, it might need expanding
195
-			expansions := runExpansionsForService(service.Expansions(client), event, body)
196
-			responses = append(responses, expansions...)
197 208
 		}
198
-	}
199 209
 
200
-	for _, content := range responses {
201
-		if _, err := client.SendMessageEvent(event.RoomID, "m.room.message", content); err != nil {
202
-			log.WithFields(log.Fields{
203
-				log.ErrorKey: err,
204
-				"room_id":    event.RoomID,
205
-				"user_id":    event.Sender,
206
-				"content":    content,
207
-			}).Print("Failed to send command response")
210
+		for _, content := range responses {
211
+			if _, err := client.SendMessageEvent(event.RoomID, "m.room.message", content); err != nil {
212
+				log.WithFields(log.Fields{
213
+					log.ErrorKey: err,
214
+					"room_id":    event.RoomID,
215
+					"user_id":    event.Sender,
216
+					"content":    content,
217
+				}).Print("Failed to send command response")
218
+			}
208 219
 		}
209 220
 	}
210 221
 }

+ 132
- 0
services/nlp/nlp.go View File

@@ -0,0 +1,132 @@
1
+// Package nlp implements a gateeway service so IKY
2
+package nlp
3
+
4
+import (
5
+	"bytes"
6
+	"encoding/json"
7
+	"fmt"
8
+	"io/ioutil"
9
+	"log"
10
+	"net/http"
11
+	"time"
12
+
13
+	"../../types"
14
+	"git.aventer.biz/AVENTER/gomatrix"
15
+	"github.com/russross/blackfriday"
16
+)
17
+
18
+// ServiceType of the Echo service
19
+const ServiceType = "nlp"
20
+
21
+// Service represents the Echo service. It has no Config fields.
22
+type Service struct {
23
+	types.DefaultService
24
+}
25
+
26
+// NLPResponse represents the IKY chat response
27
+type NLPResponse struct {
28
+	CurrentNode         string        `json:"currentNode"`
29
+	Complete            bool          `json:"complete"`
30
+	Parameters          []interface{} `json:"parameters"`
31
+	ExtractedParameters struct {
32
+	} `json:"extractedParameters"`
33
+	SpeechResponse []string  `json:"speechResponse"`
34
+	Date           time.Time `json:"date"`
35
+	Intent         struct {
36
+		Confidence float64 `json:"confidence"`
37
+		ID         string  `json:"id"`
38
+		ObjectID   string  `json:"object_id"`
39
+	} `json:"intent"`
40
+	Context struct {
41
+	} `json:"context"`
42
+	Owner             string        `json:"owner"`
43
+	Input             string        `json:"input"`
44
+	MissingParameters []interface{} `json:"missingParameters"`
45
+}
46
+
47
+// ObjectID is the current nlp intend
48
+var ObjectID map[string]NLPResponse
49
+
50
+func CmdForwardToNLP(roomID, userID string, message string) interface{} {
51
+
52
+	var decodeResp NLPResponse
53
+
54
+	// if the user object already exists, get the data for the next response, if not, use default values
55
+	_, ok := ObjectID[userID]
56
+	if ok {
57
+		decodeResp = ObjectID[userID]
58
+	} else {
59
+		decodeResp.Complete = true
60
+	}
61
+
62
+	// remember the message of the user
63
+	decodeResp.Input = message
64
+
65
+	// set the username
66
+	decodeResp.Owner = userID
67
+
68
+	// convert the map to json
69
+	str, err := json.Marshal(decodeResp)
70
+
71
+	// send the message to the IKY service
72
+	buf := bytes.NewBuffer(str)
73
+
74
+	log.Println(buf)
75
+
76
+	resp, err := http.Post("http://localhost:8080/gateway/api/v1", "application/json", buf)
77
+	if err != nil {
78
+		return &gomatrix.TextMessage{"m.notice", fmt.Sprintf("nlp: Could not talk with the IKY: %s", err)}
79
+	}
80
+	defer resp.Body.Close()
81
+
82
+	if err != nil {
83
+		return &gomatrix.TextMessage{"m.notice", fmt.Sprintf("nlp: The IKY ignore me: %s", err)}
84
+	}
85
+
86
+	body, err := ioutil.ReadAll(resp.Body)
87
+
88
+	err = json.Unmarshal(body, &decodeResp)
89
+	ObjectID[userID] = decodeResp
90
+
91
+	// if i got nothing from IKY, just ignore it
92
+	if err != nil {
93
+		return nil
94
+	}
95
+
96
+	var strBuffer bytes.Buffer
97
+	strBuffer.WriteString("")
98
+	for _, value := range decodeResp.SpeechResponse {
99
+		strBuffer.WriteString(value)
100
+	}
101
+
102
+	return &gomatrix.HTMLMessage{strBuffer.String(), "m.text", "org.matrix.custom.html", markdownRender(strBuffer.String())}
103
+}
104
+
105
+func init() {
106
+
107
+	ObjectID = make(map[string]NLPResponse)
108
+
109
+	types.RegisterService(func(serviceID, serviceUserID, webhookEndpointURL string) types.Service {
110
+		return &Service{
111
+			DefaultService: types.NewDefaultService(serviceID, serviceUserID, ServiceType),
112
+		}
113
+	})
114
+}
115
+
116
+func markdownRender(content string) string {
117
+	htmlFlags := 0
118
+	htmlFlags |= blackfriday.HTML_USE_SMARTYPANTS
119
+	htmlFlags |= blackfriday.HTML_SMARTYPANTS_FRACTIONS
120
+
121
+	renderer := blackfriday.HtmlRenderer(htmlFlags, "", "")
122
+
123
+	extensions := 0
124
+	extensions |= blackfriday.EXTENSION_NO_INTRA_EMPHASIS
125
+	extensions |= blackfriday.EXTENSION_TABLES
126
+	extensions |= blackfriday.EXTENSION_FENCED_CODE
127
+	extensions |= blackfriday.EXTENSION_AUTOLINK
128
+	extensions |= blackfriday.EXTENSION_STRIKETHROUGH
129
+	extensions |= blackfriday.EXTENSION_SPACE_HEADERS
130
+
131
+	return string(blackfriday.Markdown([]byte(content), renderer, extensions))
132
+}

Loading…
Cancel
Save