使用go语言、Python脚本搭建一个简单的GPT服务网站
前言
研0在暑假想提升一下自己,自学了go语言编程和机器学习相关学习,但是一味学习理论,终究是枯燥的,于是自己弄点小项目做。
在这之前,建议您需要掌握以下两个技巧,我在这里不赘述了
- 一个openAI账号,并申请了KEY(b站有教程)
- 魔法的method(自己摸索哈~网上应该也有教程嘿嘿~)
现在开始!!!
文章目录
- Python准备
- go服务器与html页面
- 总结与效果展示
一、准备一个Python脚本
第一步:利用pip下载OpenAi依赖包
pip install openai
第二步:将openai的操作封装成一个类,OpenAi.py
import openai
class OpenAi:
def __init__(self, key):
"""
传入一个key
:param key: 你申请的key
"""
openai.api_key = key # 这里设置key
self.model_name = "gpt-3.5-turbo" # 使用默认chatgpt3.5模型
self.role = "user" # 使用user的角色,此外还有system等角色,可以自己改着来玩玩
def submit(self, question):
"""
这个方法向gpt发送你想发给gpt的message, 返回一个response对象,是json格式的
"""
response = openai.ChatCompletion.create(
model=self.model_name, # 使用ChatGPT引擎
messages=[
{"role": "user", "content": question},
],
temperature=0,
# stream=True # this time, we set stream=True
)
return response
第三步:编写Python脚本 testGPT2.py,注意修改自己的key
import os, sys
# 这里我们导入刚才封装的类
import OpenAI as op
def main():
# 接受命令行参数
args = sys.argv[1:]
message = " ".join(args)
open_ai_object = op.OpenAi("把你申请的key复制到这里来")
response = open_ai_object.submit(message)
# 取出gpt的回答
gpt_answer = response["choices"][0]["message"]["content"]
# 以utf-8的形式输出到命令行,避免中文乱码,后续go语言将会读取
print(gpt_answer.encode('utf-8'))
if __name__ == '__main__':
main()
第四步:测试一下下,启动cmd,cd到testgpt2.py的目录下
python testgpt2.py 你是谁啊?
python testgpt2.py who are you?
可以发现当询问中文时,脚本会返回中文的utf-8编码,询问英文的时候,会返回英文内容。
运行成功!!!!!!
小结:截至目前,python脚本准备好了,我们接下来使用go搭建一个简单的服务器。
二、搭建一个go服务器和一个html页面,注意修改自己的路径
这里需要准备一个服务器代码和一个html页面,这里直接提供给大家。
初学go!可能有漏洞,欢迎大家指正!
server.go
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"os"
"os/exec"
"strings"
)
var count int = 0
func main() {
// 注册处理函数
http.HandleFunc("/data", askForGpt)
http.HandleFunc("/", helloHandler)
// 启动服务器,监听在指定的端口
port := 8080
fmt.Printf("Server started at :%d\n", port)
err := http.ListenAndServe(fmt.Sprintf(":%d", port), nil)
if err != nil {
fmt.Println("Error:0", err)
}
}
const (
// 这里大家改成自己html页面的路径即可
HTML_PATH = "C:\\Users\\45191\\Desktop\\test8.html"
)
// 这个函数调用后会向前端返回一个html页面
func helloHandler(w http.ResponseWriter, r *http.Request) {
countUsers()
responseHtmlContent := readHtmlFileAll(HTML_PATH)
// 向客户端发送响应
fmt.Fprint(w, responseHtmlContent)
}
// 服务器读取本地html页面
func readHtmlFileAll(path string) string {
// 打开文件
file, err := os.Open(path)
if err != nil {
fmt.Printf("Error: %v\n", err)
return "ERROR"
}
defer file.Close()
// 读取文件内容
content, err := io.ReadAll(file)
if err != nil {
fmt.Println("Error:", err)
return "Error"
}
return string(content)
}
// 简单地统计一下多少个用户访问
func countUsers() {
count++
fmt.Printf("第%d个用户访问服务器!\n", count)
}
// 这个函数负责从前端发来的请求中解析出用户要问gpt的问题,然后执行python脚本,
// 将答案返回
func askForGpt(w http.ResponseWriter, r *http.Request) {
countUsers()
// 读取 POST 请求的内容
body, err := io.ReadAll(r.Body)
if err != nil {
http.Error(w, "Error reading request body", http.StatusInternalServerError)
return
}
defer r.Body.Close()
question := parseJson(body)
answer := execPythonScript(question)
answerJsonObject := ResponseData{
Answer: answer,
}
data, err := json.Marshal(answerJsonObject)
fmt.Fprint(w, string(data))
}
// 定义一个接受json数据的内容,用来接受前端发来的json格式数据
type RequestData struct {
Content string `json:"content"`
}
// 定义一个reponse数据
type ResponseData struct {
Answer string `json:"answer"`
}
// 解析json格式数据
func parseJson(body []byte) string {
var requestData RequestData
err := json.Unmarshal(body, &requestData)
if err != nil {
fmt.Printf("Error parseJson: %v", err)
}
fmt.Printf("requestData: %v\n", requestData)
return requestData.Content
}
const (
// 这里大家改成自己的python脚本路径即可
SCRIPT_PATH = "D:\\pyprojects\\MachineLearning\\testGPT2.py"
)
// 运行python脚本的函数
func execPythonScript(question string) string {
// 定义要运行的Python参数
scriptArgs := []string{question}
// 创建一个Command对象运行Python脚本
cmd := exec.Command("python", append([]string{SCRIPT_PATH}, scriptArgs...)...)
fmt.Println(cmd)
var stdout, stderr bytes.Buffer
// 设置命令的输出和错误输出
cmd.Stdout = &stdout
cmd.Stderr = &stderr
// 执行命令等待完成
err := cmd.Run()
if err != nil {
fmt.Println("Error running Python script: ", err)
return ""
}
fmt.Println("Python script completed")
// 从python脚本的输出中获得答案
rawString := strings.TrimSpace(stdout.String())[2:]
rawString = rawString[:len(rawString)-1]
s := strings.ReplaceAll(rawString, "\\n", "\n")
return s
}
test8.html
偷偷告诉大家这个代码大部分是我叫gpt帮我写的,哈哈哈哈,毕竟搞不来前端,我只是改了少量内容,比如js部分代码。
<!DOCTYPE html>
<html>
<head>
<title>精美左右布局页面</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
background-color: #f5f5f5;
}
.container {
display: flex;
justify-content: space-between;
align-items: stretch;
height: 100vh;
background-color: #fff;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
border-radius: 5px;
margin: 20px auto;
overflow: hidden;
}
.left {
width: 40%;
padding: 20px;
padding-right: 30px;
background-color: #f8f8f8;
}
.right {
flex: 1;
padding: 20px;
padding-left: 30px;
background-color: #fff;
overflow: auto;
border-left: 1px solid #ddd;
}
h1, h2 {
margin: 0 0 10px;
color: #333;
}
input[type="text"] {
width: 100%;
padding: 10px;
margin-bottom: 15px;
border: 1px solid #ccc;
border-radius: 5px;
font-size: 16px;
box-sizing: border-box;
}
button {
padding: 10px 20px;
background-color: #007bff;
color: #fff;
border: none;
border-radius: 5px;
cursor: pointer;
}
pre {
white-space: pre-wrap;
word-wrap: break-word;
}
.history-icon {
font-size: 20px;
cursor: pointer;
}
</style>
</head>
<body>
<div class="container">
<div class="left">
<h2>输入问题:</h2>
<input type="text" id="question" name="question">
<button onclick="getAnswer()">获取答案</button>
<details>
<summary>
<span class="history-icon">📝</span> 查看历史问题
</summary>
<ul>
<li>历史问题 1</li>
<li>历史问题 2</li>
<li>历史问题 3</li>
<!-- 在这里添加更多历史问题 -->
</ul>
</details>
</div>
<div class="right">
<h2>答案:</h2>
<pre id="answer"></pre>
</div>
</div>
<script>
function getAnswer() {
// 获取输入框内容
var questionInput = document.getElementById("question");
var answerPre = document.getElementById("answer");
// 构造 POST 请求的数据
var data = {
content: questionInput.value
};
// 发送 POST 请求
fetch("http://localhost:8080/data", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(data)
})
.then(response => response.json())
.then(data => {
// 将 UTF-8 编码的字节序列转换为 Uint8Array
var byteString = data.answer
var decodedString = decodeUtf8(byteString)
answerPre.textContent = decodedString
})
.catch(error => {
});
}
// 自己写的utf-8格式转文本函数
function decodeUtf8(byteString){
var resStr = ""
var subStr = ""
var count = 0
for (var i = 0;i<byteString.length-1;){
if (byteString[i] == '\\' && byteString[i+1] == 'x'){
subStr += byteString.substr(i+2,2)
i = i + 4
count ++
if (count == 3){
resStr += hexToUtf8String(subStr)
subStr = ""
count = 0
}
} else {
resStr += byteString[i]
i ++
}
}
return resStr
}
function hexToUtf8String(hex) {
const bytes = [];
for (let i = 0; i < hex.length; i += 2) {
bytes.push(parseInt(hex.substr(i, 2), 16));
}
return new TextDecoder().decode(new Uint8Array(bytes));
}
</script>
</body>
</html>
三、总结与效果展示
通过以上步骤,就已经实现了本题目的简单的要求,下面进行效果展示。
前端页面输出,访问127.0.0.1:8080
后台服务器输出
后续,我将继续学习,继续完善加强这个小项目,添加更多功能,欢迎关注!!!如果有什么问题,欢迎在评论区发表,一起学习,一起纠错!!!