Skip to content

Commit ff5772b

Browse files
committed
Added Chat functionality
1 parent 7464ff6 commit ff5772b

File tree

2 files changed

+159
-0
lines changed

2 files changed

+159
-0
lines changed

examples/chat/main.go

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"time"
6+
7+
"github.com/prasad89/golamify/pkg/golamify"
8+
)
9+
10+
func main() {
11+
// Optional config; pass nil for defaults
12+
config := golamify.Config{
13+
OllamaHost: "http://localhost:11434",
14+
Timeout: 30 * time.Second,
15+
}
16+
17+
client, err := golamify.NewClient(&config)
18+
if err != nil {
19+
fmt.Println("Error creating client:", err)
20+
return
21+
}
22+
23+
// Required parameters for Chat; others optional
24+
payload := golamify.ChatPayload{
25+
Model: "llama3.2:1b",
26+
Messages: []golamify.Message{
27+
{
28+
Role: "user",
29+
Content: "What we discussed earlier?",
30+
},
31+
},
32+
}
33+
34+
responseChannel, errorChannel := golamify.Chat(client, &payload)
35+
36+
for {
37+
select {
38+
case response, ok := <-responseChannel:
39+
if !ok {
40+
return
41+
}
42+
43+
// Check to safely extract "message" and "content"
44+
if messMap, exists := response["message"].(map[string]interface{}); exists {
45+
if content, exists := messMap["content"].(string); exists {
46+
fmt.Print(content)
47+
} else {
48+
fmt.Println("Content key missing or not a string")
49+
}
50+
} else {
51+
fmt.Println("Message key missing or not a valid map")
52+
}
53+
54+
case err, ok := <-errorChannel:
55+
if ok && err != nil {
56+
fmt.Println("Error:", err)
57+
} else if !ok {
58+
return
59+
}
60+
}
61+
}
62+
}

pkg/golamify/chat.go

+97
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
package golamify
2+
3+
import (
4+
"bufio"
5+
"bytes"
6+
"encoding/json"
7+
"fmt"
8+
"io"
9+
"net/http"
10+
)
11+
12+
type ChatPayload struct {
13+
Model string `json:"model" validate:"required"`
14+
Messages []Message `json:"messages" validate:"required,dive"`
15+
Tools []string `json:"tools,omitempty"`
16+
Format string `json:"format,omitempty" validate:"omitempty,oneof=json"`
17+
Stream *bool `json:"stream,omitempty"`
18+
KeepAlive string `json:"keep_alive,omitempty"`
19+
}
20+
21+
type Message struct {
22+
Role string `json:"role" validate:"required,oneof=system user assistant tool"`
23+
Content string `json:"content" validate:"required"`
24+
Images []string `json:"images,omitempty"`
25+
ToolCalls []string `json:"tool_calls,omitempty"`
26+
}
27+
28+
func Chat(c *Client, payload *ChatPayload) (<-chan map[string]interface{}, <-chan error) {
29+
responseChannel := make(chan map[string]interface{})
30+
errorChannel := make(chan error, 1)
31+
32+
go func() {
33+
defer close(responseChannel)
34+
defer close(errorChannel)
35+
36+
statusCode, err := ShowModel(c, payload.Model)
37+
if err != nil {
38+
errorChannel <- fmt.Errorf("error showing model: %w", err)
39+
return
40+
}
41+
42+
if statusCode == http.StatusNotFound {
43+
err := PullModel(c, payload.Model)
44+
if err != nil {
45+
errorChannel <- fmt.Errorf("failed to pull model: %w", err)
46+
return
47+
}
48+
}
49+
50+
body, err := json.Marshal(payload)
51+
if err != nil {
52+
errorChannel <- fmt.Errorf("failed to encode request payload: %w", err)
53+
return
54+
}
55+
56+
req, err := http.NewRequest("POST", c.config.OllamaHost+"/api/chat", bytes.NewBuffer(body))
57+
if err != nil {
58+
errorChannel <- fmt.Errorf("failed to create request: %w", err)
59+
return
60+
}
61+
req.Header.Set("User-Agent", c.userAgent)
62+
req.Header.Set("Content-Type", "application/json")
63+
64+
resp, err := c.httpClient.Do(req)
65+
if err != nil {
66+
errorChannel <- fmt.Errorf("failed to connect to generate endpoint: %w", err)
67+
return
68+
}
69+
defer resp.Body.Close()
70+
71+
if resp.StatusCode != http.StatusOK {
72+
respBody, _ := io.ReadAll(resp.Body)
73+
errorChannel <- fmt.Errorf("generate endpoint is not reachable, received status: %s, body: %s", resp.Status, string(respBody))
74+
return
75+
}
76+
77+
scanner := bufio.NewScanner(resp.Body)
78+
for scanner.Scan() {
79+
var generated map[string]interface{}
80+
err := json.Unmarshal(scanner.Bytes(), &generated)
81+
if err != nil {
82+
errorChannel <- fmt.Errorf("error parsing JSON: %w", err)
83+
continue
84+
}
85+
responseChannel <- generated
86+
if done, exists := generated["done"].(bool); exists && done {
87+
break
88+
}
89+
}
90+
91+
if err := scanner.Err(); err != nil {
92+
errorChannel <- fmt.Errorf("error reading response body: %w", err)
93+
}
94+
}()
95+
96+
return responseChannel, errorChannel
97+
}

0 commit comments

Comments
 (0)