├── go.mod
├── entity
├── Task.go
└── Context.go
├── example.go
├── README.md
└── chat
└── ChatGlmService.go
/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/solstice-gao/chatglm-go
2 |
3 | go 1.20
4 |
--------------------------------------------------------------------------------
/entity/Task.go:
--------------------------------------------------------------------------------
1 | package entity
2 |
3 | type TaskResponse struct {
4 | Message string `json:"message"`
5 | Result struct {
6 | TaskID string `json:"task_id"`
7 | } `json:"result"`
8 | Status int `json:"status"`
9 | }
10 |
--------------------------------------------------------------------------------
/entity/Context.go:
--------------------------------------------------------------------------------
1 | package entity
2 |
3 | type ContextResponse struct {
4 | Message string `json:"message"`
5 | Result struct {
6 | ContextID string `json:"context_id"`
7 | } `json:"result"`
8 | Status int `json:"status"`
9 | }
10 |
--------------------------------------------------------------------------------
/example.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/solstice-gao/chatglm-go/chat"
7 | )
8 |
9 | func main() {
10 | // 获取方式见下方常见问题
11 | authorization := "Bearer eyxxxx"
12 | cookie := "acw_tc=xxx;"
13 | prompt := "请写一篇2000字的申请书"
14 |
15 | // 创建 ChatService 实例
16 | chatService := chat.NewChatService(authorization, cookie)
17 |
18 | // 获取任务ID
19 | task := chatService.GetTaskId(prompt)
20 | fmt.Println("task id-------")
21 | fmt.Println(task.Result.TaskID)
22 | fmt.Println("-------")
23 |
24 | // 获取上下文ID
25 | context := chatService.GetContextId(prompt, task.Result.TaskID)
26 |
27 | fmt.Println("context id-------")
28 | fmt.Println(context.Result.ContextID)
29 | fmt.Println("-------")
30 |
31 | // 调用获取聊天数据的方法
32 | ans, err := chatService.GetChat(context.Result.ContextID)
33 |
34 | if err != nil {
35 | fmt.Println(err)
36 | return
37 | }
38 |
39 | //var lastLine string
40 | fmt.Println(ans)
41 | r := []rune(ans)
42 | fmt.Println(len(r))
43 |
44 | //// 处理聊天数据
45 | //// TODO: 根据自己的需求进行处理
46 | //
47 | //// 输出聊天数据
48 | //fmt.Println(chatData)
49 | }
50 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # chatglm-go
2 |
3 | ChatGLM Go SDK
4 |
5 | ## 项目简介
6 |
7 | ChatGLM Go SDK 是一个将网页版 ChatGLM 转换为 Go 语言的软件开发工具包。它提供了一组方便易用的函数和方法,使开发人员能够在 Go 项目中快速集成 ChatGLM 的功能。
8 |
9 | ## 特性
10 |
11 | - 与 ChatGLM 网页版一致的功能和交互体验
12 | - 支持从 ChatGLM 后端 API 获取实时聊天数据
13 | - 提供简洁的 API 接口,方便在 Go 项目中使用
14 | - 支持自定义输出方式,以满足不同的需求
15 |
16 | ## 安装
17 |
18 | 使用 Go 的包管理工具 `go get` 可以快速获取并安装 ChatGLM Go SDK:
19 |
20 | ```
21 | go get github.com/solstice-gao/chatglm-go
22 | ```
23 |
24 | ## 使用示例
25 |
26 | 下面是一个简单的示例代码,展示了如何在 Go 项目中使用 ChatGLM Go SDK:
27 | [example.go](example.go)
28 |
29 | ## 贡献
30 |
31 | 欢迎对 ChatGLM Go SDK 进行贡献!如果你发现了 bug,或者有改进建议,请提出 issue 或提交 pull request。在参与贡献之前,请阅读项目的贡献指南(CONTRIBUTING.md)。
32 |
33 | ## 许可证
34 |
35 | ChatGLM Go SDK 使用 MIT 许可证。详细信息请参阅许可证文件(LICENSE)。
36 |
37 | ## 联系方式
38 |
39 | 如果你有任何问题或建议,可以通过以下方式联系我:
40 |
41 | - 邮箱:原作者: 17604515707@163.com
42 | - GitHub 项目主页:https://github.com/solstice-gao
43 |
44 | 请随时提出问题或反馈,我会尽快回复。
45 |
46 | ## 常见问题
47 |
48 | 在这里列出一些常见问题和解答,以帮助其他用户更好地使用 ChatGLM Go SDK。
49 |
50 | 1. **怎么获取authorization/cookie?**
51 | - 首先需要有 https://chatglm.cn 的账号,目前可以直接注册登录
52 | - 登录账号,浏览器F12/开发者模式,选择Network
53 | - 输入问题进行提问
54 | -
55 | -
56 |
57 | ## 致谢
58 |
59 | 特别感谢以下人员对 ChatGLM Go SDK 的贡献和支持:
60 |
61 | - Gaoxu
62 |
63 | 感谢你们的支持!
64 |
65 | ## 更新
66 |
--------------------------------------------------------------------------------
/chat/ChatGlmService.go:
--------------------------------------------------------------------------------
1 | package chat
2 |
3 | import (
4 | "bufio"
5 | "encoding/json"
6 | "fmt"
7 | "io"
8 | "net/http"
9 | "strings"
10 | "time"
11 |
12 | "github.com/solstice-gao/chatglm-go/entity"
13 | )
14 |
15 | type ChatService struct {
16 | // ... 可能的依赖或其他属性
17 | authorization string
18 | cookie string
19 | }
20 |
21 | type tpe string
22 |
23 | const (
24 | baseUrl = "https://chatglm.cn/chatglm/backend-api/v1"
25 | chat = "/stream?context_id="
26 | task = "/conversation"
27 | context = "/stream_context"
28 |
29 | cookie = "cookie"
30 | Authorization = "Authorization"
31 | accept = "accept"
32 |
33 | chatType tpe = "chat"
34 | taskType tpe = "task"
35 | contextType tpe = "context"
36 |
37 | streamAccept = "text/event-stream"
38 | jsonAccept = "application/json, text/plain, */*"
39 | )
40 |
41 | var client = &http.Client{
42 | Timeout: time.Minute * 3,
43 | }
44 |
45 | var (
46 | headerCookie = map[string][]string{
47 | "authority": {"chatglm.cn"},
48 | "accept": {""},
49 | "accept-language": {"zh-CN,zh;q=0.9"},
50 | "cache-control": {"no-cache"},
51 | "cookie": {""},
52 | "referer": {"https://chatglm.cn/detail"},
53 | "sec-ch-ua": {"\"Not.A/Brand\";v=\"8\", \"Chromium\";v=\"114\", \"Google Chrome\";v=\"114\""},
54 | "sec-ch-ua-mobile": {"?0"},
55 | "sec-fetch-dest": {"empty"},
56 | "sec-fetch-mode": {"cors"},
57 | "sec-fetch-site": {"same-origin"},
58 | "user-agent": {"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36"},
59 | }
60 |
61 | headerAuth = map[string][]string{
62 | "Accept": {"application/json, text/plain, */*"},
63 | "Content-Type": {"application/json;charset=utf-8"},
64 | "Authorization": {""},
65 | }
66 | )
67 |
68 | func NewChatService(authorization string, cookie string) *ChatService {
69 | return &ChatService{
70 | // ... 初始化依赖或其他属性
71 | authorization: authorization,
72 | cookie: cookie,
73 | }
74 | }
75 |
76 | func (s *ChatService) GetChatStream(contextId string) (bufio.Scanner, error) {
77 | scanner := bufio.NewScanner(nil)
78 | url := baseUrl + chat + contextId
79 | req, err := http.NewRequest(http.MethodGet, url, nil)
80 | if err != nil {
81 | fmt.Println(err)
82 | return *scanner, err
83 | }
84 |
85 | req.Header = s.getHeaderByType(chatType)
86 |
87 | res, err1 := client.Do(req)
88 | if res != nil {
89 | defer res.Body.Close()
90 | }
91 | if err1 != nil {
92 | fmt.Println(err1)
93 | return *scanner, err1
94 | }
95 |
96 | scanner = bufio.NewScanner(res.Body)
97 | return *scanner, nil
98 | }
99 |
100 | func (s *ChatService) GetChat(contextId string) (string, error) {
101 | scanner := bufio.NewScanner(nil)
102 | url := baseUrl + chat + contextId
103 |
104 | req, err := http.NewRequest(http.MethodGet, url, nil)
105 |
106 | if err != nil {
107 | fmt.Println(err)
108 | return "", err
109 | }
110 | req.Header = s.getHeaderByType(chatType)
111 | res, err1 := client.Do(req)
112 | if res != nil {
113 | defer res.Body.Close()
114 | }
115 | if err1 != nil {
116 | fmt.Println(err1)
117 | return "", err1
118 | }
119 | scanner = bufio.NewScanner(res.Body)
120 | var ok bool
121 | var answer string
122 | for scanner.Scan() {
123 | str := scanner.Text()
124 | if ok {
125 | answer = answer + str + "\n"
126 | continue
127 | }
128 | if str == "event:finish" {
129 | ok = true
130 | }
131 | }
132 | answer = strings.ReplaceAll(answer, "data:", "")
133 | return answer, nil
134 | }
135 |
136 | func (s *ChatService) GetTaskId(prompt string) *entity.TaskResponse {
137 | url := baseUrl + task
138 | payload := strings.NewReader(`{"prompt":"` + prompt + `"}`)
139 | req, err := http.NewRequest(http.MethodPost, url, payload)
140 | if err != nil {
141 | fmt.Println(err)
142 | return nil
143 | }
144 | req.Header = s.getHeaderByType(taskType)
145 | res, err1 := client.Do(req)
146 | if res != nil {
147 | defer res.Body.Close()
148 | }
149 | if err1 != nil {
150 | fmt.Println(err1)
151 | return nil
152 | }
153 |
154 | body, err2 := io.ReadAll(res.Body)
155 | if err2 != nil {
156 | fmt.Println(err2)
157 | return nil
158 | }
159 | var response *entity.TaskResponse
160 | err = json.Unmarshal(body, &response)
161 | if err != nil {
162 | fmt.Println(err)
163 | return nil
164 | }
165 |
166 | return response
167 | }
168 |
169 | func (s *ChatService) GetContextId(prompt string, taskid string) *entity.ContextResponse {
170 | url := baseUrl + context
171 | str := `{"prompt":"` + prompt + `","seed":93549,"max_tokens":512,"conversation_task_id":"` +
172 | taskid + `","retry":false,"retry_history_task_id":null}`
173 | payload := strings.NewReader(str)
174 | req, err := http.NewRequest(http.MethodPost, url, payload)
175 |
176 | if err != nil {
177 | fmt.Println(err)
178 | return nil
179 | }
180 |
181 | req.Header = s.getHeaderByType(contextType)
182 |
183 | res, err1 := client.Do(req)
184 | if res != nil {
185 | defer res.Body.Close()
186 | }
187 | if err1 != nil {
188 | fmt.Println(err1)
189 | return nil
190 | }
191 |
192 | body, err2 := io.ReadAll(res.Body)
193 | if err2 != nil {
194 | fmt.Println(err2)
195 | return nil
196 | }
197 | var response *entity.ContextResponse
198 | err = json.Unmarshal(body, &response)
199 | if err != nil {
200 | fmt.Println(err)
201 | return nil
202 | }
203 |
204 | return response
205 | }
206 |
207 | func (s *ChatService) getHeaderByType(tpe tpe) map[string][]string {
208 | header := headerCookie
209 | switch tpe {
210 | case chatType:
211 | header[cookie][0] = s.cookie
212 | header[accept][0] = streamAccept
213 | case taskType:
214 | header = headerAuth
215 | header[Authorization][0] = s.authorization
216 | case contextType:
217 | header = headerAuth
218 | header[Authorization][0] = s.authorization
219 | default:
220 |
221 | }
222 | return header
223 | }
224 |
--------------------------------------------------------------------------------