-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpato.go
128 lines (107 loc) · 3.2 KB
/
pato.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
package main
import (
"bufio"
"encoding/json"
"fmt"
"github.com/seanvelasco/pato/ddg"
"log"
"net/url"
"strings"
)
func generateCompleteAnswer(prompt string) (string, error) {
res, err := ddg.Chat(prompt)
if err != nil {
return "", err
}
defer res.Close()
scanner := bufio.NewScanner(res)
var wholeResponse string
for scanner.Scan() {
line := scanner.Text()
if strings.HasPrefix(line, "data:") {
data := strings.TrimPrefix(line, "data:")
if strings.HasSuffix(data, "[DONE]") {
break
}
var body MessageSSE
if err := json.Unmarshal([]byte(data), &body); err != nil {
log.Println("Unable to unmarshal SSE", err)
}
wholeResponse += body.Message
}
}
if err := scanner.Err(); err != nil {
return "", err
}
return wholeResponse, nil
}
func processQuery(query string) (string, []string, error) {
log.Println("Getting VQD")
token, err := ddg.GetSearchVQD(query)
if err != nil {
return "", nil, err
}
log.Println("Retrieved VQD")
resultsChan := make(chan ddg.TextResults)
imagesChan := make(chan ddg.ImageResults)
errChan := make(chan error)
go func() {
log.Println("Starting to text search")
results, err := ddg.SearchText(query, token)
if err != nil {
errChan <- err
return
}
log.Println("Retrieved results")
resultsChan <- results
}()
go func() {
log.Println("Starting to image search")
images, err := ddg.SearchImages(query, token)
if err != nil {
errChan <- err
return
}
log.Println("Retrieved images")
imagesChan <- images
}()
var imageURLs []string
var reference string
select {
case results := <-resultsChan:
for i, r := range results.Results {
//results.Results[i].Title = removeHTMLBTag(r.Title)
//results.Results[i].Body = formatString(r.Body)
if r.Body != "" {
results.Results[i].Body = formatString(r.Body)
reference += fmt.Sprintf("%s: %s (%s)\n\n", removeHTMLBTag(r.Title), formatString(r.Body), r.URL)
}
}
case images := <-imagesChan:
for _, image := range images.Results {
validURL, _ := url.Parse(image.URL)
if validURL != nil {
imageURLs = append(imageURLs, validURL.String())
}
}
case err := <-errChan:
return "", nil, err
}
prompt := fmt.Sprintf(
"Answer the question or find more information to %s. "+
"The format of each source is 'TITLE: CONTENT (SOURCE)'. "+
"The resulting answer should be an answer to the query, indicated with indices [n], "+
"and the URLs of the references used should be listed (1., 2., 3., ..., n.) as the last part. "+
"Strictly do not use a source if it has no relation to the main answer or if it's off-topic. "+
"Strictly do not include references if they haven't been used as indices on the answer. "+
"Do not return the query as the heading of the answer. "+
"Do not attempt to interpret the question. "+
"If the query is one word, then it's just one word. Do not make it longer."+
"Supplement the answer with %s. This should not be the the main content of the answer. The answer must be factual and positive. Include as little news as possible. You may introduce a fun fact. ",
query, reference)
answer, err := generateCompleteAnswer(prompt)
if err != nil {
return "", nil, err
}
return answer, imageURLs, nil
}