当前位置:   article > 正文

go搭建ai服务器

搭建ai服务器

ai接口申请:http://www.tuling123.com

需要用到的第三方包有:

  1. github.com/gin-gonic/gin
  2. github.com/spf13/viper
  3. github.com/tidwall/gjson

 

目录结构如下: 
项目根目录是 aichat
 
aichat 的目录结构
├── conf                         # 配置文件统一存放目录
│   ├── config.yaml              # 配置文件
├── config                       # 专门用来处理配置和配置文件的Go package
│   └── config.go                 
├── handler                      # 类似MVC架构中的C,用来读取输入,并将处理流程转发给实际的处理函数,最后返回结果
│   ├── handler.go
├── model                        #数据模型
│   ├── chater.go                  # 图灵参数构造体模型
├── pkg                          # 引用的包
│   ├── errno                    # 错误码存放位置
│   │   ├── code.go
│   │   └── errno.go
├── router                       # 路由相关处理
│   ├── middleware               # API服务器用的是Gin Web框架,Gin中间件存放位置
│   │   ├── header.go
│   └── router.go                # 路由
├── service                      # 实际业务处理函数存放位置
│   └── service.go
├── main.go                      # Go程序唯一入口

下面,我们根据目录结构,从上往下建立文件夹和文件

建立文件夹和文件 aichat/conf/config.yaml ,config.yaml 内容如下:

  1. common:
  2. #http://www.tuling123.com 图灵机器人接口
  3. tuling:
  4. apikey: 你自己申请的图灵apikey
  5. api: http://openapi.tuling123.com/openapi/api/v2
  6. server: #服务器配置
  7. runmode: debug # 开发模式, debug, release, test
  8. addr: :6663 # HTTP绑定端口
  9. name: apiserver # API Server的名字
  10. url: http://10.10.87.243:6663 # pingServer函数请求的API服务器的ip:port
  11. max_ping_count: 10 # pingServer函数尝试的次数

建立文件夹和文件 aichat/config/config.go ,config.go 内容如下:

  1. package config
  2. import (
  3. "github.com/spf13/viper"
  4. "time"
  5. "os"
  6. "log"
  7. )
  8. // LogInfo 初始化日志配置
  9. func LogInfo() {
  10. file := "./logs/" + time.Now().Format("2006-01-02") + ".log"
  11. logFile, _ := os.OpenFile(file,os.O_RDWR| os.O_CREATE| os.O_APPEND, 0755)
  12. log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)
  13. log.SetOutput(logFile)
  14. }
  15. // Init 读取初始化配置文件
  16. func Init() error {
  17. //初始化配置
  18. if err := Config();err != nil{
  19. return err
  20. }
  21. //初始化日志
  22. LogInfo()
  23. return nil
  24. }
  25. // Config viper解析配置文件
  26. func Config() error{
  27. viper.AddConfigPath("conf")
  28. viper.SetConfigName("config")
  29. if err := viper.ReadInConfig();err != nil{
  30. return err
  31. }
  32. return nil
  33. }

建立文件夹和文件 aichat/handler/handler.go ,handler.go 内容如下:

  1. package handler
  2. import (
  3. "bytes"
  4. "net/http"
  5. "io/ioutil"
  6. "github.com/gin-gonic/gin"
  7. "aichat/pkg/errno"
  8. )
  9. type Response struct {
  10. Code int `json:"code"`
  11. Message string `json:"message"`
  12. Data interface{} `json:"data"`
  13. }
  14. //返回json 格式
  15. func SendResponse(c *gin.Context,err error,data interface{}){
  16. code,message := errno.DecodeErr(err)
  17. //总是返回http状态ok
  18. c.JSON(http.StatusOK,Response{
  19. Code: code,
  20. Message:message,
  21. Data: data,
  22. })
  23. }
  24. //返回html 格式
  25. func SendResponseHtml(c *gin.Context,err error,data string){
  26. c.Header("Content-Type", "text/html; charset=utf-8")
  27. //总是返回http状态ok
  28. c.String(http.StatusOK,data)
  29. }
  30. //http请求
  31. func HttpRequest(api string,json string,method string) (string, error) {
  32. jsonStr := []byte(json)
  33. req, err := http.NewRequest(method, api, bytes.NewBuffer(jsonStr))
  34. req.Header.Set("Content-Type", "application/json") //使用json格式传参
  35. client := &http.Client{}
  36. resp, err := client.Do(req)
  37. if err != nil {
  38. return "", errno.ApiServerError
  39. }
  40. defer resp.Body.Close()
  41. body, _ := ioutil.ReadAll(resp.Body)
  42. if !(resp.StatusCode == 200) {
  43. return "", errno.ApiServerError
  44. }
  45. return string(body), nil
  46. }

建立文件夹 aichat/logs 存放日志文件, logs文件夹的权限 0777

建立文件夹和文件 aichat/model/chater.go ,chater.go 内容如下:

  1. package model
  2. import (
  3. "encoding/json"
  4. "aichat/pkg/errno"
  5. )
  6. /*
  7. 传入参数 json
  8. {
  9. "reqType":0,
  10. "perception": {
  11. "inputText": {
  12. "text": "附近的酒店"
  13. },
  14. "inputImage": {
  15. "url": "imageUrl"
  16. },
  17. "selfInfo": {
  18. "location": {
  19. "city": "北京",
  20. "province": "北京",
  21. "street": "信息路"
  22. }
  23. }
  24. },
  25. "userInfo": {
  26. "apiKey": "",
  27. "userId": ""
  28. }
  29. }
  30. */
  31. type Chatting struct {
  32. ReqType int `json:"reqType"`
  33. Perception Perception `json:"perception"`
  34. UserInfo UserInfo `json:"userInfo"`
  35. }
  36. type InputText struct {
  37. Text string `json:"text"`
  38. }
  39. type Perception struct {
  40. InputText InputText `json:"inputText"`
  41. }
  42. type UserInfo struct {
  43. ApiKey string `json:"apiKey"`
  44. UserId string `json:"userId"`
  45. }
  46. //更新 图灵参数构造体 信息
  47. func UpdateChatting(userId string, text string, chattingInfo Chatting) Chatting {
  48. chattingInfo.UserInfo.UserId = userId
  49. chattingInfo.Perception.InputText.Text = text
  50. return chattingInfo
  51. }
  52. //建立 图灵参数构造体
  53. func BuildChatting(text string, userId string,appKey string) Chatting {
  54. chatting := Chatting{ReqType: 0}
  55. chatting.Perception = buildPerception(text)
  56. chatting.UserInfo = buildUserInfo(userId,appKey)
  57. return chatting
  58. }
  59. //建立 Perception
  60. func buildPerception(text string) Perception {
  61. perception := Perception{buildInputText(text)}
  62. return perception
  63. }
  64. //建立 InputText
  65. func buildInputText(text string) InputText {
  66. inputText := InputText{text}
  67. return inputText
  68. }
  69. //建立 UserInfo
  70. func buildUserInfo(userId string,appKey string) UserInfo {
  71. return UserInfo{appKey, userId}
  72. }
  73. //构造体转换成字符串
  74. func ConvertJson(chattingInfo Chatting) (string,error) {
  75. jsons, errs := json.Marshal(chattingInfo)
  76. if errs != nil {
  77. return "", errno.ModelError
  78. }
  79. return string(jsons),nil
  80. }

建立文件夹和文件 aichat/pkg/errno/code.go ,code.go 内容如下:

  1. package errno
  2. var (
  3. // Common errors
  4. OK = &Errno{Code: 0, Message: "OK"}
  5. VALUEERROR = &Errno{Code: -1, Message: "输入错误"}
  6. InternalServerError = &Errno{Code: 10001, Message: "服务器错误"}
  7. ApiServerError = &Errno{Code: 20001, Message: "接口服务器错误"}
  8. ModelError = &Errno{Code: 30001, Message: "聊天模型错误"}
  9. )

建立文件夹和文件 aichat/pkg/errno/errno.go ,errno.go 内容如下:

  1. package errno
  2. import "fmt"
  3. type Errno struct {
  4. Code int
  5. Message string
  6. }
  7. //返回错误信息
  8. func (err Errno) Error() string{
  9. return err.Message
  10. }
  11. //设置 Err 结构体
  12. type Err struct {
  13. Code int
  14. Message string
  15. Err error
  16. }
  17. //声明构造体
  18. func New(errno *Errno,err error) *Err{
  19. return &Err{Code:errno.Code,Message:errno.Message,Err:err}
  20. }
  21. //添加错误信息
  22. func (err *Err) Add(message string) error{
  23. err.Message += " " + message
  24. return err
  25. }
  26. //添加指定格式的错误信息
  27. func (err * Err) Addf(format string,args...interface{}) error{
  28. err.Message += " " + fmt.Sprintf(format,args...)
  29. return err
  30. }
  31. //拼接错误信息字符串
  32. func (err *Err) Error() string{
  33. return fmt.Sprintf("Err - code: %d, message: %s, error: %s",err.Code,err.Message,err.Err)
  34. }
  35. // 解析 错误信息, 返回字符串
  36. func DecodeErr(err error) (int,string){
  37. if err == nil{
  38. return OK.Code,OK.Message
  39. }
  40. switch typed := err.(type) {
  41. case *Err:
  42. return typed.Code,typed.Message
  43. case *Errno:
  44. return typed.Code,typed.Message
  45. default:
  46. }
  47. return InternalServerError.Code,err.Error()
  48. }

建立文件夹和文件 aichat/router/middleware/header.go ,header.go 内容如下:

  1. package middleware
  2. import (
  3. "net/http"
  4. "time"
  5. "github.com/gin-gonic/gin"
  6. )
  7. //无缓存头部中间件 ,
  8. //要来防止客户端获取已经缓存的响应信息
  9. func NoCache(c *gin.Context){
  10. c.Header("Cache-Control", "no-cache, no-store, max-age=0, must-revalidate, value")
  11. c.Header("Expires", "Thu, 01 Jan 1970 00:00:00 GMT")
  12. c.Header("Last-Modified", time.Now().UTC().Format(http.TimeFormat))
  13. c.Next()
  14. }
  15. //选项中间件
  16. //要来给预请求 终止并退出中间件 ,链接并结束请求
  17. func Options(c *gin.Context){
  18. if c.Request.Method != "OPTIONS"{
  19. c.Next()
  20. }else{
  21. c.Header("Access-Control-Allow-Origin","*")
  22. c.Header("Access-Control-Allow-Methods", "GET,POST,PUT,PATCH,DELETE,OPTIONS")
  23. c.Header("Access-Control-Allow-Headers", "authorization, origin, content-type, accept")
  24. c.Header("Allow", "HEAD,GET,POST,PUT,PATCH,DELETE,OPTIONS")
  25. c.Header("Content-Type", "application/json")
  26. c.AbortWithStatus(200)
  27. }
  28. }
  29. //安全中间件
  30. //要来保障数据安全的头部
  31. func Secure(c *gin.Context){
  32. c.Header("Access-Control-Allow-Origin", "*")
  33. c.Header("X-Frame-Options", "DENY")
  34. c.Header("X-Content-Type-Options", "nosniff")
  35. c.Header("X-XSS-Protection", "1; mode=block")
  36. if c.Request.TLS != nil {
  37. c.Header("Strict-Transport-Security", "max-age=31536000")
  38. }
  39. //也可以考虑添加一个安全代理的头部
  40. //c.Header("Content-Security-Policy", "script-src 'self' https://cdnjs.cloudflare.com")
  41. }

建立文件夹和文件 aichat/router/router.go ,router.go 内容如下:

  1. package router
  2. import (
  3. "net/http"
  4. "aichat/service"
  5. "aichat/router/middleware"
  6. "github.com/gin-gonic/gin"
  7. )
  8. //初始化路由
  9. func InitRouter(g *gin.Engine){
  10. middlewares := []gin.HandlerFunc{}
  11. //中间件
  12. g.Use(gin.Recovery())
  13. g.Use(middleware.NoCache)
  14. g.Use(middleware.Options)
  15. g.Use(middleware.Secure)
  16. g.Use(middlewares...)
  17. //404处理
  18. g.NoRoute(func(c *gin.Context){
  19. c.String(http.StatusNotFound,"该路径不存在")
  20. })
  21. //健康检查中间件
  22. g.GET("/",service.Index)//主页
  23. g.GET("/chat",service.AiChat)//
  24. }

建立文件夹和文件 aichat/service/service.go ,service.go 内容如下:

  1. package service
  2. import (
  3. "github.com/tidwall/gjson"
  4. "github.com/gin-gonic/gin"
  5. "github.com/spf13/viper"
  6. "strconv"
  7. "log"
  8. "aichat/pkg/errno"
  9. . "aichat/handler"
  10. "aichat/model"
  11. )
  12. //首页
  13. func Index(c *gin.Context){
  14. html := `
  15. <!DOCTYPE html>
  16. <html lang="en">
  17. <head>
  18. <meta charset="UTF-8">
  19. <title>hello world</title>
  20. </head>
  21. <body>
  22. hello world
  23. </body>
  24. </html>
  25. `
  26. SendResponseHtml(c,nil,html)
  27. }
  28. //获取tuling接口回复
  29. func TulingAi(info string) (string,error) {
  30. api := viper.GetString("common.tuling.api")
  31. //发送http请求图灵api , body是http响应
  32. var body, resultErrs = HttpRequest(api,info,"POST")
  33. if resultErrs != nil {
  34. return "", errno.ApiServerError
  35. }
  36. return body, nil
  37. }
  38. //回复信息构造体
  39. type tlReply struct {
  40. code int
  41. Text string `json:"text"`
  42. }
  43. //聊天函数
  44. func AiChat(c *gin.Context){
  45. //获取聊天信息
  46. message := c.Query("message")
  47. if message == ""{
  48. SendResponse(c,errno.VALUEERROR,nil)
  49. return
  50. }
  51. var userId = "1"
  52. //图灵接口参数构造体
  53. var chattingInfo = model.BuildChatting(message,userId, viper.GetString("common.tuling.apikey"))
  54. log.Printf("chattingInfo: %+v\n",chattingInfo)
  55. // 参数构造体 转换成 字符串
  56. chatstr,err := model.ConvertJson(chattingInfo)
  57. if err != nil{
  58. SendResponse(c,errno.InternalServerError,nil)
  59. return
  60. }
  61. //调用图灵接口
  62. body,err := TulingAi(chatstr)
  63. if err != nil{
  64. SendResponse(c,errno.InternalServerError,nil)
  65. return
  66. }
  67. log.Printf("body: %+v\n",body)
  68. var results string
  69. // 使用gjson 获取返回结果的 resultType
  70. result := gjson.Get(body, "results.#.resultType")
  71. for key, name := range result.Array() {
  72. //如果 resultType 是 text格式
  73. if name.String() == "text"{
  74. //获取对应 key 的 values里的text ,就是图灵回复的文字
  75. getstring := "results."+strconv.Itoa(key)+".values.text"
  76. log.Printf("getstring: %+v\n",getstring)
  77. result_text := gjson.Get(body,getstring)
  78. results = result_text.String()
  79. }
  80. }
  81. SendResponse(c,nil,results)
  82. }

建立文件夹和文件 aichat/main.go ,main.go 内容如下:

  1. package main
  2. import (
  3. "aichat/config"
  4. "github.com/gin-gonic/gin"
  5. "github.com/spf13/viper"
  6. "log"
  7. "aichat/router"
  8. )
  9. func main() {
  10. if err := config.Init();err != nil{
  11. panic(err)
  12. }
  13. //设置gin模式
  14. gin.SetMode(viper.GetString("common.server.runmode"))
  15. //创建一个gin引擎
  16. g := gin.New()
  17. router.InitRouter(g)
  18. log.Printf("开始监听服务器地址: %s\n", viper.GetString("common.server.url"))
  19. if err := g.Run(viper.GetString("common.server.addr"));err != nil {
  20. log.Fatal("监听错误:", err)
  21. }
  22. }

初始化包

  1. [root@localhost aichat]# go mod init aichat
  2. go: creating new go.mod: module aichat

启动服务器

  1. [root@localhost aichat]# go run main.go
  2. [GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
  3. - using env: export GIN_MODE=release
  4. - using code: gin.SetMode(gin.ReleaseMode)
  5. [GIN-debug] GET / --> aichat/service.Index (5 handlers)
  6. [GIN-debug] GET /chat --> aichat/service.AiChat (5 handlers)
  7. [GIN-debug] Listening and serving HTTP on :6663

 

直接使用浏览器访问:

 

参考:https://blog.csdn.net/weixin_40165163/article/details/89044491

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/239351
推荐阅读
相关标签
  

闽ICP备14008679号