go aiサーバの構築

13502 ワード

aiインタフェース申請:http://www.tuling123.com
使用するサードパーティ製パッケージは次のとおりです.
github.com/gin-gonic/gin
github.com/spf13/viper
github.com/tidwall/gjson

 
ディレクトリ構造は以下の通りである:プロジェクトルートディレクトリはaichat aichatのディレクトリ構造├-conf#プロファイル統一保存ディレクトリ├-config.yaml#コンフィギュレーションファイル├-config#コンフィギュレーションファイルとコンフィギュレーションファイルの処理に特化したGo package|└-config.go├-handler#はMVCアーキテクチャのCに類似しており、入力を読み出し、実際の処理関数に処理フローを転送し、結果‖├-handlerを返す.├├——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の内容は次のとおりです.
common:
  #http://www.tuling123.com        
  tuling:
    apikey:         apikey
    api: http://openapi.tuling123.com/openapi/api/v2
  server: #     
    runmode: debug               #     , debug, release, test
    addr: :6663                  # HTTP    
    name: apiserver              # API Server   
    url: http://10.10.87.243:6663   # pingServer     API    ip:port
    max_ping_count: 10           # pingServer       

フォルダとファイルaichat/config/configを作成する.go ,config.goの内容は以下の通りです.
package config

import (
	"github.com/spf13/viper"
	"time"
	"os"
	"log"
)

// LogInfo        
func LogInfo() {
	file := "./logs/" + time.Now().Format("2006-01-02") + ".log"
	logFile, _ := os.OpenFile(file,os.O_RDWR| os.O_CREATE| os.O_APPEND, 0755)
	log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)
	log.SetOutput(logFile)
}

// Init          
func Init() error {
	//     
	if err := Config();err != nil{
		return err
	}

	//     
	LogInfo()
	return nil
}

// Config viper      
func Config() error{
	viper.AddConfigPath("conf")
	viper.SetConfigName("config")
	if err := viper.ReadInConfig();err != nil{
		return err
	}
	return nil
}


フォルダとファイルを作成するgo ,handler.goの内容は以下の通りです.
package handler

import (
	"bytes"
	"net/http"
	"io/ioutil"

	"github.com/gin-gonic/gin"

	"aichat/pkg/errno"
)

type Response struct {
	Code    int         `json:"code"`
	Message string      `json:"message"`
	Data    interface{} `json:"data"`
}

//  json   
func SendResponse(c *gin.Context,err error,data interface{}){
	code,message := errno.DecodeErr(err)

	//    http  ok
	c.JSON(http.StatusOK,Response{
		Code: code,
		Message:message,
		Data: data,
	})

}

//  html   
func SendResponseHtml(c *gin.Context,err error,data string){
	c.Header("Content-Type", "text/html; charset=utf-8")
	//    http  ok
	c.String(http.StatusOK,data)
}

//http  
func HttpRequest(api string,json string,method string) (string, error) {
	jsonStr := []byte(json)
	req, err := http.NewRequest(method, api, bytes.NewBuffer(jsonStr))
	req.Header.Set("Content-Type", "application/json") //  json    

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return "", errno.ApiServerError
	}
	defer resp.Body.Close()

	body, _ := ioutil.ReadAll(resp.Body)

	if !(resp.StatusCode == 200) {
		return "",  errno.ApiServerError
	}
	return string(body), nil
}

フォルダaichat/logsを作成してログファイルを保存し、logsフォルダの権限0777
フォルダとファイルaichat/model/chaterを作成します.go ,chater.goの内容は以下の通りです.
package model

import (
	"encoding/json"

	"aichat/pkg/errno"
)

/*
     json
{
	"reqType":0,
    "perception": {
        "inputText": {
            "text": "     "
        },
        "inputImage": {
            "url": "imageUrl"
        },
        "selfInfo": {
            "location": {
                "city": "  ",
                "province": "  ",
                "street": "   "
            }
        }
    },
    "userInfo": {
        "apiKey": "",
        "userId": ""
    }
}
*/

type Chatting struct {
	ReqType    int        `json:"reqType"`
	Perception Perception `json:"perception"`
	UserInfo   UserInfo   `json:"userInfo"`
}

type InputText struct {
	Text string `json:"text"`
}

type Perception struct {
	InputText InputText `json:"inputText"`
}

type UserInfo struct {
	ApiKey string `json:"apiKey"`
	UserId string `json:"userId"`
}
//             
func UpdateChatting(userId string, text string, chattingInfo Chatting) Chatting {
	chattingInfo.UserInfo.UserId = userId
	chattingInfo.Perception.InputText.Text = text
	return chattingInfo
}
//          
func BuildChatting(text string, userId string,appKey string) Chatting {
	chatting := Chatting{ReqType: 0}
	chatting.Perception = buildPerception(text)
	chatting.UserInfo = buildUserInfo(userId,appKey)
	return chatting
}
//   Perception
func buildPerception(text string) Perception {
	perception := Perception{buildInputText(text)}
	return perception
}
//   InputText
func buildInputText(text string) InputText {
	inputText := InputText{text}
	return inputText
}
//   UserInfo
func buildUserInfo(userId string,appKey string) UserInfo {
	return UserInfo{appKey, userId}
}

//         
func ConvertJson(chattingInfo Chatting) (string,error) {
	jsons, errs := json.Marshal(chattingInfo)
	if errs != nil {
		return "", errno.ModelError
	}
	return string(jsons),nil
}

フォルダとファイルaichat/pkg/errno/codeを作成します.go ,code.goの内容は以下の通りです.
package errno

var (
	// Common errors
	OK                  = &Errno{Code: 0, Message: "OK"}
	VALUEERROR        = &Errno{Code: -1, Message: "    "}

	InternalServerError = &Errno{Code: 10001, Message: "     "}
	ApiServerError = &Errno{Code: 20001, Message: "       "}
	ModelError = &Errno{Code: 30001, Message: "      "}
)

フォルダとファイルaichat/pkg/errno/errnoを作成します.go ,errno.goの内容は以下の通りです.
package errno

import "fmt"

type Errno struct {
	Code int
	Message string
}

//      
func (err Errno) Error() string{
	return err.Message
}

//   Err    
type Err struct {
	Code int
	Message string
	Err error
}

//     
func New(errno *Errno,err error) *Err{
	return &Err{Code:errno.Code,Message:errno.Message,Err:err}
}

//      
func (err *Err) Add(message string) error{
	err.Message += " " + message
	return err
}

//           
func (err * Err) Addf(format string,args...interface{}) error{
	err.Message += " " + fmt.Sprintf(format,args...)
	return err
}

//         
func (err *Err) Error() string{
	return fmt.Sprintf("Err - code: %d, message: %s, error: %s",err.Code,err.Message,err.Err)
}

//        ,      
func DecodeErr(err error) (int,string){
	if err == nil{
		return OK.Code,OK.Message
	}
	switch typed := err.(type) {
	case *Err:
		return typed.Code,typed.Message
	case *Errno:
		return typed.Code,typed.Message
	default:
	}
	return InternalServerError.Code,err.Error()
}

フォルダとファイルaichat/router/middleware/headerを作成します.go ,header.goの内容は以下の通りです.
package middleware

import (
	"net/http"
	"time"
	"github.com/gin-gonic/gin"
)

//         ,
//                  
func NoCache(c *gin.Context){
	c.Header("Cache-Control", "no-cache, no-store, max-age=0, must-revalidate, value")
	c.Header("Expires", "Thu, 01 Jan 1970 00:00:00 GMT")
	c.Header("Last-Modified", time.Now().UTC().Format(http.TimeFormat))
	c.Next()
}

//     
//                ,       
func Options(c *gin.Context){
	if c.Request.Method != "OPTIONS"{
		c.Next()
	}else{
		c.Header("Access-Control-Allow-Origin","*")
		c.Header("Access-Control-Allow-Methods", "GET,POST,PUT,PATCH,DELETE,OPTIONS")
		c.Header("Access-Control-Allow-Headers", "authorization, origin, content-type, accept")
		c.Header("Allow", "HEAD,GET,POST,PUT,PATCH,DELETE,OPTIONS")
		c.Header("Content-Type", "application/json")
		c.AbortWithStatus(200)
	}
}

//     
//           
func Secure(c *gin.Context){
	c.Header("Access-Control-Allow-Origin", "*")
	c.Header("X-Frame-Options", "DENY")
	c.Header("X-Content-Type-Options", "nosniff")
	c.Header("X-XSS-Protection", "1; mode=block")
	if c.Request.TLS != nil {
		c.Header("Strict-Transport-Security", "max-age=31536000")
	}

	//                
	//c.Header("Content-Security-Policy", "script-src 'self' https://cdnjs.cloudflare.com")
}

フォルダとファイルaichat/router/routerを作成します.go ,router.goの内容は以下の通りです.
package router

import (
	"net/http"
	"aichat/service"
	"aichat/router/middleware"
	"github.com/gin-gonic/gin"
)

//     
func InitRouter(g *gin.Engine){
	middlewares := []gin.HandlerFunc{}
	//   
	g.Use(gin.Recovery())
	g.Use(middleware.NoCache)
	g.Use(middleware.Options)
	g.Use(middleware.Secure)
	g.Use(middlewares...)

	//404  
	g.NoRoute(func(c *gin.Context){
		c.String(http.StatusNotFound,"      ")
	})
	//       
	g.GET("/",service.Index)//  
	g.GET("/chat",service.AiChat)//
}

フォルダとファイルaichat/service/serviceを作成します.go ,service.goの内容は以下の通りです.
package service

import (
	"github.com/tidwall/gjson"
	"github.com/gin-gonic/gin"
	"github.com/spf13/viper"
	"strconv"
	"log"

	"aichat/pkg/errno"
	. "aichat/handler"
	"aichat/model"
)

//  
func Index(c *gin.Context){
	html := `



    
    hello world


    hello world


`
	SendResponseHtml(c,nil,html)
}

//  tuling    
func TulingAi(info string) (string,error) {
	api := viper.GetString("common.tuling.api")

	//  http    api  , body http  
	var body, resultErrs = HttpRequest(api,info,"POST")
	if resultErrs != nil {
		return "", errno.ApiServerError
	}

	return body, nil
}

//       
type tlReply struct {
	code int
	Text string `json:"text"`
}

//    
func AiChat(c *gin.Context){
	//      
	message := c.Query("message")
	if message == ""{
		SendResponse(c,errno.VALUEERROR,nil)
		return
	}
	var userId = "1"
	//         
	var chattingInfo = model.BuildChatting(message,userId, viper.GetString("common.tuling.apikey"))
	log.Printf("chattingInfo: %+v
",chattingInfo) // chatstr,err := model.ConvertJson(chattingInfo) if err != nil{ SendResponse(c,errno.InternalServerError,nil) return } // body,err := TulingAi(chatstr) if err != nil{ SendResponse(c,errno.InternalServerError,nil) return } log.Printf("body: %+v
",body) var results string // gjson resultType result := gjson.Get(body, "results.#.resultType") for key, name := range result.Array() { // resultType text if name.String() == "text"{ // key values text , getstring := "results."+strconv.Itoa(key)+".values.text" log.Printf("getstring: %+v
",getstring) result_text := gjson.Get(body,getstring) results = result_text.String() } } SendResponse(c,nil,results) }

フォルダとファイルを作成します.go ,main.goの内容は以下の通りです.
package main

import (
	"aichat/config"
	"github.com/gin-gonic/gin"
	"github.com/spf13/viper"

	"log"

	"aichat/router"
)

func main() {
	if err := config.Init();err != nil{
		panic(err)
	}
	//  gin  
	gin.SetMode(viper.GetString("common.server.runmode"))

	//    gin  
	g := gin.New()

	router.InitRouter(g)
	log.Printf("         : %s
", viper.GetString("common.server.url")) if err := g.Run(viper.GetString("common.server.addr"));err != nil { log.Fatal(" :", err) } }

初期化パッケージ
[root@localhost aichat]# go mod init aichat
go: creating new go.mod: module aichat

サーバの起動
[root@localhost aichat]# go run main.go
[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
 - using env:	export GIN_MODE=release
 - using code:	gin.SetMode(gin.ReleaseMode)

[GIN-debug] GET    /                         --> aichat/service.Index (5 handlers)
[GIN-debug] GET    /chat                     --> aichat/service.AiChat (5 handlers)
[GIN-debug] Listening and serving HTTP on :6663

 
ブラウザを直接使用してアクセスするには、次の手順に従います.
go搭建ai服务器_第1张图片
 
go搭建ai服务器_第2张图片
参照先:https://blog.csdn.net/weixin_40165163/article/details/89044491