前端:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Sample</title>
</head>
<body><label for="textInput">Prompt:</label><input type="textarea" id="textInput" placeholder="您有什么问题"><button onclick="run_prompt()">执行prompt</button><p><textarea id="answer" rows="10" cols="50" readonly></textarea></p>
<script>current_text = document.getElementById('answer');text = "";char_index = 0function run_prompt() {var inputValue = document.getElementById('textInput').value;document.getElementById('answer').value = "";// 调用服务端的流式接口, 修改为自己的服务器地址和端口号fetch('http://<server address>:8000/eb_stream', {method: 'post',headers: {'Content-Type': 'text/plain'},body: JSON.stringify({'prompt': inputValue})}).then(response => {return response.body;}).then(body => {const reader = body.getReader();const decoder = new TextDecoder();function read() {return reader.read().then(({ done, value }) => {if (done) { // 读取完成return;}data = decoder.decode(value, { stream: true });text += JSON.parse(data).result;type(); // 打字机效果输出return read();});}return read();}).catch(error => {console.error('发生错误:', error);});}function type() {let enableCursor = true; // 启用光标效果if (char_index < text.length) {let txt = document.getElementById('answer').value;let cursor = enableCursor ? "|" : "";if (enableCursor && txt.endsWith("|")) {txt = txt.slice(0, -1);}document.getElementById('answer').value = txt + text.charAt(char_index) + cursor;char_index++;setTimeout(type, 1000/5); // 打字机速度控制, 每秒5个字}}
</script>
</body>
</html>
// go run main.gopackage mainimport ("bufio""encoding/json""fmt""io""log""net/http""strings""github.com/gin-contrib/cors""github.com/gin-gonic/gin"
)const (// 运行端口号SERVER_PORT = ":8000"// 千帆应用 AK/SKAPI_KEY = "JMLF5n6eWqxxxx9ECh"SECRET_KEY = "s1ii7dGJBK5Jxxxx8iIrAET"// 鉴权接口URLTOKEN_URL = "https://aip.baidubce.com/oauth/2.0/token"// 大模型接口URLEB_URL = "https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/eb-instant"
)// GetAccessToken 使用 AK,SK 生成鉴权签名(Access Token)
func GetAccessToken() (string, error) {// 拼接请求参数postData := fmt.Sprintf("grant_type=client_credentials&client_id=%s&client_secret=%s", API_KEY, SECRET_KEY)client := &http.Client{}req, err := http.NewRequest("POST", TOKEN_URL, strings.NewReader(postData))if err != nil {return "", fmt.Errorf("创建HTTP Request报错: %s", err.Error())}// 设置请求头req.Header.Add("Content-Type", "application/json")req.Header.Add("Accept", "application/json")// 发起请求并获取响应ret, err := client.Do(req)if err != nil {return "", fmt.Errorf("执行HTTP请求报错: %s", err.Error())}defer ret.Body.Close()// 解析响应内容body, err := io.ReadAll(ret.Body)if err != nil {return "", fmt.Errorf("获取Token报错: %s", err.Error())}// 解析并返回 access_tokenaccessTokenObj := map[string]string{}_ = json.Unmarshal([]byte(body), &accessTokenObj)return accessTokenObj["access_token"], nil
}// main 主入口
func main() {// 初始化Gin实例r := gin.Default()// 跨域配置r.Use(cors.Default())// 注册路由r.POST("/eb_stream", func(c *gin.Context) {// 设置响应头c.Header("Connection", "keep-alive")c.Header("Cache-Control", "no-cache")c.Header("Transfer-Encoding", "chunked")c.Header("Content-Type", "text/event-stream")// 获取入参var prompt struct {Prompt string `json:"prompt"`}if err := c.ShouldBindJSON(&prompt); err != nil {c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})return}// 获取 Access Tokentoken, err := GetAccessToken()if err != nil {c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})return}// 组装请求参数并请求文心source := "&sourceVer=0.0.1&source=app_center&appName=streamDemo"url := EB_URL + "?access_token=" + token + sourcepayload := strings.NewReader(fmt.Sprintf(`{"messages":[{"role":"user","content":"%s"}],"stream":true}`, prompt.Prompt))resp, err := http.Post(url, "application/json", payload)if err != nil {c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})return}defer resp.Body.Close()// 处理返回结果并写入响应流c.Stream(func(w io.Writer) bool {reader := bufio.NewReader(resp.Body)for {// 逐行读取line, err := reader.ReadBytes('\n')if err != nil {log.Println("读取大模型响应数据失败: ", err.Error())break}// 对读到的这行数据进行处理lineStr := string(line)if strings.HasPrefix(lineStr, "data:") {lineStr = strings.TrimPrefix(lineStr, "data:")lineStr = strings.TrimSuffix(lineStr, "\n")log.Println("收到大模型的响应: ", lineStr)// 写入响应流_, err = w.Write([]byte(lineStr))if err != nil {log.Println("写入响应流失败: ", err.Error())return false}// 判断是否为结束if strings.Contains(lineStr, `"is_end":true`) {log.Println("收到大模型反馈的结束标志")break}}log.Println("等待大模型下一次响应")return true}log.Println("流式响应结束")return false})})// 启动服务r.Run(SERVER_PORT)
}
ERNIE-Bot 4.0
package mainimport ("encoding/json""fmt""io/ioutil""net/http""strings"
)
const API_KEY = "JMLF5n6eWq2xxxECh"
const SECRET_KEY = "s1ii7dGJBxxxzT8iIrAET"func main() {url := "https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/completions_pro?access_token=" + GetAccessToken()payload := strings.NewReader(`{"disable_search":false,"enable_citation":false}`)client := &http.Client {}req, err := http.NewRequest("POST", url, payload)if err != nil {fmt.Println(err)return}req.Header.Add("Content-Type", "application/json")res, err := client.Do(req)if err != nil {fmt.Println(err)return}defer res.Body.Close()body, err := ioutil.ReadAll(res.Body)if err != nil {fmt.Println(err)return}fmt.Println(string(body))
}/*** 使用 AK,SK 生成鉴权签名(Access Token)* @return string 鉴权签名信息(Access Token)*/
func GetAccessToken() string {url := "https://aip.baidubce.com/oauth/2.0/token"postData := fmt.Sprintf("grant_type=client_credentials&client_id=%s&client_secret=%s", API_KEY, SECRET_KEY)resp, err := http.Post(url, "application/x-www-form-urlencoded", strings.NewReader(postData))if err != nil {fmt.Println(err)return ""}defer resp.Body.Close()body, err := ioutil.ReadAll(resp.Body)if err != nil {fmt.Println(err)return ""}accessTokenObj := map[string]string{}json.Unmarshal([]byte(body), &accessTokenObj)return accessTokenObj["access_token"]
}