go aiサーバの構築
13502 ワード
aiインタフェース申請:http://www.tuling123.com
使用するサードパーティ製パッケージは次のとおりです.
ディレクトリ構造は以下の通りである:プロジェクトルートディレクトリは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の内容は次のとおりです.
フォルダとファイルaichat/config/configを作成する.go ,config.goの内容は以下の通りです.
フォルダとファイルを作成するgo ,handler.goの内容は以下の通りです.
フォルダaichat/logsを作成してログファイルを保存し、logsフォルダの権限0777
フォルダとファイルaichat/model/chaterを作成します.go ,chater.goの内容は以下の通りです.
フォルダとファイルaichat/pkg/errno/codeを作成します.go ,code.goの内容は以下の通りです.
フォルダとファイルaichat/pkg/errno/errnoを作成します.go ,errno.goの内容は以下の通りです.
フォルダとファイルaichat/router/middleware/headerを作成します.go ,header.goの内容は以下の通りです.
フォルダとファイルaichat/router/routerを作成します.go ,router.goの内容は以下の通りです.
フォルダとファイルaichat/service/serviceを作成します.go ,service.goの内容は以下の通りです.
フォルダとファイルを作成します.go ,main.goの内容は以下の通りです.
初期化パッケージ
サーバの起動
ブラウザを直接使用してアクセスするには、次の手順に従います.
参照先:https://blog.csdn.net/weixin_40165163/article/details/89044491
使用するサードパーティ製パッケージは次のとおりです.
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
ブラウザを直接使用してアクセスするには、次の手順に従います.
参照先:https://blog.csdn.net/weixin_40165163/article/details/89044491