一、windows server端
package main
import (
"net"
"bufio"
"fmt"
"net/http"
"encoding/json"
"strings"
"io"
)
type ChatResponse struct {
Choices []struct {
Delta struct {
Content string `json:"content"`
} `json:"delta"`
} `json:"choices"`
}
func process(conn net.Conn) {
defer conn.Close() // 关闭连接
remoteAddr := conn.RemoteAddr().String()
for {
//----------------------------------
//receive question from client
reader := bufio.NewReader(conn)
var buf [128]byte
n, err := reader.Read(buf[:]) // 读取数据
if err != nil {
if err == io.EOF {
//正常退出
fmt.Println("client " + remoteAddr + " leaved! bye!")
}else{
//异常退出
fmt.Println("read from client failed, err:", err)
}
break
}
recvStr := string(buf[:n])
question := recvStr
fmt.Println("问题:", question)
//----------------------------------
//call deepseek api
myapikey := "<your-deepseek-api-key>"
url := "https://api.deepseek.com/chat/completions"
mymodel := "deepseek-chat"
systemrole := "<系统角色描述>"
payload := fmt.Sprintf(`{
"model": "%s",
"messages": [
{
"role": "system",
"content": "%s"
},
{
"role": "user",
"content": "%s"
}
],
"stream": true,
"temperature": 0.3
}`, mymodel, systemrole, question)
//fmt.Print(payload)
req, _ := http.NewRequest("POST", url, strings.NewReader(payload))
req.Header.Add("Content-Type", "application/json")
req.Header.Add("Authorization", "Bearer " + myapikey)
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
scanner := bufio.NewReader(res.Body)
for {
line, err := scanner.ReadString('\n')
if err != nil {
break
}
line = strings.TrimSpace(line)
if line == "" || line == "data: [DONE]" {
continue
}
if strings.HasPrefix(line, "data: ") {
line = strings.TrimPrefix(line, "data: ")
}
var response ChatResponse
if err := json.Unmarshal([]byte(line), &response); err != nil {
continue
}
if len(response.Choices) > 0 {
content := response.Choices[0].Delta.Content
if content != "" {
conn.Write([]byte(content))
}
}
}
//end of answer
conn.Write([]byte("ENDENDEND\n"))
}
}
func main() {
listen, err := net.Listen("tcp", "0.0.0.0:8001")
if err != nil {
fmt.Println("listen failed, err:", err)
return
}
fmt.Println("AI Server is up!")
for {
conn, err := listen.Accept() // 建立连接
if err != nil {
fmt.Println("accept failed, err:", err)
continue
}
remoteAddr := conn.RemoteAddr().String()
fmt.Println("Client " + remoteAddr + " is connected!")
go process(conn) // 启动一个goroutine处理连接
}
}
二、linux client端
package main
import (
"os"
"net"
"strings"
"regexp"
"fmt"
)
func main() {
conn, err := net.Dial("tcp", "<server-ip:port>")
if err != nil {
fmt.Println("err :", err)
return
}
defer conn.Close()
//get question
question := os.Args[1]
strings.Trim(question, "\"")
//ask server
_, err = conn.Write([]byte(question))
if err != nil {
return
}
//collect answer from server
for {
buf := [512]byte{}
n, err := conn.Read(buf[:])
if err != nil {
fmt.Println("recv failed, err:", err)
return
}
if n > 0 {
//fmt.Println(string(buf[:n]))
s := string(buf[:n])
//fmt.Print(s)
//end of answer
r, _ := regexp.Compile(`ENDENDEND`)
if r.MatchString(s) {
fmt.Print(r.ReplaceAllString(s, ""))
break
}else{
fmt.Print(s)
}
}
}
}
三、命令行调用
aiserversingle "<here is my question>"
四、emacs配置
(defun askai ()
"ask ai"
(interactive)
(progn
(setq q (read-string "Question? " nil nil ""))
(setq mycmd (concat "aiserversingle \"" q "\""))
(switch-to-buffer "*scratch*")
(goto-char (point-max))
(call-process-shell-command mycmd nil t t)))
(global-set-key (kbd "s-q") 'askai)