作者 yangfu

初始化

正在显示 74 个修改的文件 包含 4756 行增加0 行删除

要显示太多修改。

为保证性能只显示 74 of 74+ 个文件。

.git*
.idea*
... ...
# Compiled Object codefiles, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
*.test
.log
.idea
.vscode
.gitkeep
app.log
go.sum
lastupdate.tmp
*.log
public/
logs/
cmd/discuss/api/etc/core.local.yaml
... ...
# Su Enterprise System Module(素天下企业平台系统模块)
## 功能简介
企业平台系统模块包含模块,用户管理、应用管理、组织架构设置、通知公告、系统设置、系统日志
\ No newline at end of file
... ...
.PHONY: model
model:
goctl model mysql ddl -s .\cmd\ep\chat\deploy\database\table.sql -d cmd/ep/chat
.PHONY: api
api:
goctl api go -api .\cmd\ep\chat\dsl\core.api -dir cmd/ep/chat/api -style go_zero
.PHONY: swagger
swagger:
goctl api plugin -plugin goctl-swagger="swagger -filename core.json" -api .\cmd\ep\chat\dsl\core.api -dir .\cmd\ep\chat\generate
.PHONY: build
build:
docker build -f cmd/ep/chat/deploy/docker/Dockerfile -t sumicro/chat:1.0.0 .
... ...
package main
import (
"flag"
"fmt"
"github.com/zeromicro/go-zero/core/logx"
"github.com/zeromicro/go-zero/rest/httpx"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/internal/pkg/db"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/internal/pkg/domain"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/pkg/xerr"
"net/http"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/api/internal/config"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/api/internal/handler"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/api/internal/svc"
"github.com/zeromicro/go-zero/core/conf"
"github.com/zeromicro/go-zero/rest"
)
var configFile = flag.String("f", "etc/core.yaml", "the config file")
func main() {
flag.Parse()
var c config.Config
conf.MustLoad(*configFile, &c)
// 系统设置
systemSetup(c)
// 服务初始化
opts := make([]rest.RunOption, 0)
opts = append(opts, rest.WithCustomCors(func(header http.Header) {
header.Set("Access-Control-Allow-Headers", "*")
}, func(writer http.ResponseWriter) {
}))
opts = append(opts, rest.WithUnauthorizedCallback(func(w http.ResponseWriter, r *http.Request, err error) {
if err != nil {
logx.Debugf("unauthorized: %s \n", err.Error())
}
httpx.WriteJson(w, http.StatusUnauthorized, xerr.Error(xerr.TokenExpireError, err.Error()))
return
}))
server := rest.MustNewServer(c.RestConf, opts...)
defer server.Stop()
ctx := svc.NewServiceContext(c)
handler.RegisterHandlers(server, ctx)
// 数据迁移
if c.Migrate {
db.Migrate(ctx.DB)
}
fmt.Printf("Starting server at %s:%d...\n", c.Host, c.Port)
server.Start()
}
func systemSetup(c config.Config) {
// 初始化Domain里面的配置
domain.ProjectName = c.Name
// 系统错误应答包装
httpx.SetErrorHandlerCtx(xerr.ErrorHandlerCtx)
// 系统成功应答包装
httpx.SetOkHandler(xerr.OkHandlerCtx)
}
... ...
Name: sumicro-chat
Host: 0.0.0.0
Port: 8080
Verbose: false
Migrate: true
Timeout: 30000
LogRequest: true # 记录详细请求日志
Log:
#Mode: file
Encoding: plain
Level: debug # info
MaxSize: 1 # 2MB
TimeFormat: 2006-01-02 15:04:05
Rotation: size
MaxContentLength: 10240
SystemAuth:
AccessSecret: su-platform
AccessExpire: 360000
Redis:
Host: 127.0.0.1:6379
Type: node
Pass:
DB:
DataSource: host=114.55.200.59 user=postgres password=eagle1010 dbname=su_enterprise_platform port=31543 sslmode=disable TimeZone=Asia/Shanghai
... ...
package config
import (
"github.com/zeromicro/go-zero/core/stores/redis"
"github.com/zeromicro/go-zero/rest"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/pkg/config"
)
type Config struct {
rest.RestConf
config.Config
Redis redis.RedisConf `json:",optional"`
SystemAuth config.Auth
}
... ...
package chat
import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/api/internal/logic/chat"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/api/internal/svc"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/api/internal/types"
)
func ChatModelsHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.ChatModelsRequest
if err := httpx.Parse(r, &req); err != nil {
httpx.ErrorCtx(r.Context(), w, err)
return
}
l := chat.NewChatModelsLogic(r.Context(), svcCtx)
resp, err := l.ChatModels(&req)
if err != nil {
httpx.ErrorCtx(r.Context(), w, err)
} else {
httpx.OkJsonCtx(r.Context(), w, resp)
}
}
}
... ...
package chat
import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/api/internal/logic/chat"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/api/internal/svc"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/api/internal/types"
)
func ChatSessionConversationHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.ChatSessionConversationRequest
if err := httpx.Parse(r, &req); err != nil {
httpx.ErrorCtx(r.Context(), w, err)
return
}
l := chat.NewChatSessionConversationLogic(r.Context(), svcCtx)
resp, err := l.ChatSessionConversation(w, r, &req)
if err != nil {
httpx.ErrorCtx(r.Context(), w, err)
} else {
httpx.OkJsonCtx(r.Context(), w, resp)
}
}
}
... ...
package chat
import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/api/internal/logic/chat"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/api/internal/svc"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/api/internal/types"
)
func ChatSessionConversationWsHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.ChatSessionConversationRequestWs
if err := httpx.Parse(r, &req); err != nil {
httpx.ErrorCtx(r.Context(), w, err)
return
}
l := chat.NewChatSessionConversationWsLogic(r.Context(), svcCtx)
resp, err := l.ChatSessionConversationWs(w, r, &req)
if err != nil {
httpx.ErrorCtx(r.Context(), w, err)
} else {
httpx.OkJsonCtx(r.Context(), w, resp)
}
}
}
... ...
package chat
import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/api/internal/logic/chat"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/api/internal/svc"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/api/internal/types"
)
func ChatSessionDeleteHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.ChatSessionDeleteRequest
if err := httpx.Parse(r, &req); err != nil {
httpx.ErrorCtx(r.Context(), w, err)
return
}
l := chat.NewChatSessionDeleteLogic(r.Context(), svcCtx)
resp, err := l.ChatSessionDelete(&req)
if err != nil {
httpx.ErrorCtx(r.Context(), w, err)
} else {
httpx.OkJsonCtx(r.Context(), w, resp)
}
}
}
... ...
package chat
import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/api/internal/logic/chat"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/api/internal/svc"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/api/internal/types"
)
func ChatSessionGetHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.ChatSessionGetRequest
if err := httpx.Parse(r, &req); err != nil {
httpx.ErrorCtx(r.Context(), w, err)
return
}
l := chat.NewChatSessionGetLogic(r.Context(), svcCtx)
resp, err := l.ChatSessionGet(&req)
if err != nil {
httpx.ErrorCtx(r.Context(), w, err)
} else {
httpx.OkJsonCtx(r.Context(), w, resp)
}
}
}
... ...
package chat
import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/api/internal/logic/chat"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/api/internal/svc"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/api/internal/types"
)
func ChatSessionRecordsHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.ChatSessionRecordsRequest
if err := httpx.Parse(r, &req); err != nil {
httpx.ErrorCtx(r.Context(), w, err)
return
}
l := chat.NewChatSessionRecordsLogic(r.Context(), svcCtx)
resp, err := l.ChatSessionRecords(&req)
if err != nil {
httpx.ErrorCtx(r.Context(), w, err)
} else {
httpx.OkJsonCtx(r.Context(), w, resp)
}
}
}
... ...
package chat
import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/api/internal/logic/chat"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/api/internal/svc"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/api/internal/types"
)
func ChatSessionSaveHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.ChatSessionSaveRequest
if err := httpx.Parse(r, &req); err != nil {
httpx.ErrorCtx(r.Context(), w, err)
return
}
l := chat.NewChatSessionSaveLogic(r.Context(), svcCtx)
resp, err := l.ChatSessionSave(&req)
if err != nil {
httpx.ErrorCtx(r.Context(), w, err)
} else {
httpx.OkJsonCtx(r.Context(), w, resp)
}
}
}
... ...
package chat
import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/api/internal/logic/chat"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/api/internal/svc"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/api/internal/types"
)
func ChatSessionSearchHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.ChatSessionSearchRequest
if err := httpx.Parse(r, &req); err != nil {
httpx.ErrorCtx(r.Context(), w, err)
return
}
l := chat.NewChatSessionSearchLogic(r.Context(), svcCtx)
resp, err := l.ChatSessionSearch(&req)
if err != nil {
httpx.ErrorCtx(r.Context(), w, err)
} else {
httpx.OkJsonCtx(r.Context(), w, resp)
}
}
}
... ...
package chat
import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/api/internal/logic/chat"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/api/internal/svc"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/api/internal/types"
)
func ChatSessionUpdateHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.ChatSessionUpdateRequest
if err := httpx.Parse(r, &req); err != nil {
httpx.ErrorCtx(r.Context(), w, err)
return
}
l := chat.NewChatSessionUpdateLogic(r.Context(), svcCtx)
resp, err := l.ChatSessionUpdate(&req)
if err != nil {
httpx.ErrorCtx(r.Context(), w, err)
} else {
httpx.OkJsonCtx(r.Context(), w, resp)
}
}
}
... ...
// Code generated by goctl. DO NOT EDIT.
package handler
import (
"net/http"
chat "gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/api/internal/handler/chat"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/api/internal/svc"
"github.com/zeromicro/go-zero/rest"
)
func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
server.AddRoutes(
rest.WithMiddlewares(
[]rest.Middleware{serverCtx.LogRequest},
[]rest.Route{
{
Method: http.MethodGet,
Path: "/chat/session/:id",
Handler: chat.ChatSessionGetHandler(serverCtx),
},
{
Method: http.MethodPost,
Path: "/chat/session",
Handler: chat.ChatSessionSaveHandler(serverCtx),
},
{
Method: http.MethodDelete,
Path: "/chat/session/:id",
Handler: chat.ChatSessionDeleteHandler(serverCtx),
},
{
Method: http.MethodPut,
Path: "/chat/session/:id",
Handler: chat.ChatSessionUpdateHandler(serverCtx),
},
{
Method: http.MethodPost,
Path: "/chat/session/search",
Handler: chat.ChatSessionSearchHandler(serverCtx),
},
{
Method: http.MethodPost,
Path: "/chat/session/conversation",
Handler: chat.ChatSessionConversationHandler(serverCtx),
},
{
Method: http.MethodGet,
Path: "/chat/session/conversation",
Handler: chat.ChatSessionConversationWsHandler(serverCtx),
},
{
Method: http.MethodPost,
Path: "/chat/session/records",
Handler: chat.ChatSessionRecordsHandler(serverCtx),
},
{
Method: http.MethodGet,
Path: "/chat/models",
Handler: chat.ChatModelsHandler(serverCtx),
},
}...,
),
rest.WithJwt(serverCtx.Config.SystemAuth.AccessSecret),
rest.WithPrefix("/v1"),
)
}
... ...
package chat
import (
"context"
"github.com/samber/lo"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/internal/pkg/domain"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/api/internal/svc"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/api/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type ChatModelsLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewChatModelsLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ChatModelsLogic {
return &ChatModelsLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *ChatModelsLogic) ChatModels(req *types.ChatModelsRequest) (resp *types.ChatModelsResponse, err error) {
var models = make([]types.Model, 0)
lo.ForEach(domain.DefaultChatModels, func(item *domain.ChatModel, index int) {
models = append(models, types.Model{
Id: item.Id,
Name: item.Name,
Logo: item.Logo,
Code: item.Code,
})
})
resp = &types.ChatModelsResponse{
List: models,
}
return
}
... ...
package chat
import (
"context"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/internal/pkg/domain"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/system/open"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/pkg/ai"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/pkg/contextdata"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/pkg/transaction"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/pkg/xerr"
"net/http"
"time"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/api/internal/svc"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/api/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type ChatSessionConversationLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewChatSessionConversationLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ChatSessionConversationLogic {
return &ChatSessionConversationLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *ChatSessionConversationLogic) ChatSessionConversation(w http.ResponseWriter, r *http.Request, req *types.ChatSessionConversationRequest) (resp *types.ChatSessionConversationResponse, err error) {
var (
conn = l.svcCtx.DefaultDBConn()
dm *domain.ChatSessionRecord
token = contextdata.GetUserTokenFromCtx(l.ctx)
session *domain.ChatSession
user open.User
model *domain.ChatModel
ok bool
beginUnix = time.Now().UnixMilli()
)
if session, err = l.svcCtx.ChatSessionRepository.FindOne(l.ctx, conn, req.SessionId); err != nil {
return nil, xerr.NewErrMsgErr("会话不存在", err)
}
if user, err = l.svcCtx.SystemOpen.User(l.ctx, conn, token.UserId); err != nil {
return nil, xerr.NewErrMsgErr("用户不存在", err)
}
if user.Id != session.UserId {
return nil, xerr.NewErrMsgErr("无权限", err)
}
if model, ok = domain.DefaultChatModels.Match(req.ModelId); !ok {
return nil, xerr.NewErrMsgErr("模型不存在", err)
}
dm = &domain.ChatSessionRecord{
CompanyId: token.CompanyId,
UserId: token.UserId,
SessionId: req.SessionId,
ModelId: req.ModelId,
Author: NewDomainUser(user),
ContentType: req.ContentType,
ProblemText: req.Text,
Metadata: domain.Metadata{},
Cost: 0,
Status: domain.Processing,
}
var answer string
var channel = make(chan string, 5)
// 异步访问AI接口
go func() {
// 异步访问AI接口
answer, err = Conversation(model, req.Text, channel)
}()
for {
if _, ok = <-channel; !ok {
break
}
}
if err != nil {
return nil, xerr.NewErrMsgErr("AI模型异常,稍后再试", err)
}
// 记录
dm.AnswerText = answer
dm.Cost = time.Now().UnixMilli() - beginUnix
dm.Status = domain.FinishedSuccess
if err = transaction.UseTrans(l.ctx, l.svcCtx.DB, func(ctx context.Context, conn transaction.Conn) error {
dm, err = l.svcCtx.ChatSessionRecordRepository.Insert(l.ctx, conn, dm)
return err
}, true); err != nil {
return nil, xerr.NewErrMsg("保存失败")
}
record := NewTypesChatRecord(dm, user)
resp = &types.ChatSessionConversationResponse{
Record: &record,
Parts: make([]string, 0),
Finished: true,
}
return
}
func Conversation(m *domain.ChatModel, text string, channel chan string) (answer string, err error) {
switch m.Id {
// 星火3.5
case 1, 2, 3:
answer, err = ai.ChatGPT(m.Code, m.Config.AppKey, text, channel)
case 4:
answer, err = ai.Spark(m.Config.AppId, m.Config.AppKey, m.Config.AppSecret, text, channel)
}
if err != nil {
return "", err
}
return
}
... ...
package chat
import (
"context"
"github.com/gorilla/websocket"
"github.com/zeromicro/go-zero/core/fx"
"github.com/zeromicro/go-zero/rest/httpx"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/internal/pkg/domain"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/system/open"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/pkg/contextdata"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/pkg/transaction"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/pkg/xerr"
"net/http"
"time"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/api/internal/svc"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/api/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type ChatSessionConversationWsLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewChatSessionConversationWsLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ChatSessionConversationWsLogic {
return &ChatSessionConversationWsLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *ChatSessionConversationWsLogic) ChatSessionConversationWs(w http.ResponseWriter, r *http.Request, req *types.ChatSessionConversationRequestWs) (resp *types.ChatSessionConversationResponse, err error) {
var (
conn = l.svcCtx.DefaultDBConn()
dm *domain.ChatSessionRecord
token = contextdata.GetUserTokenFromCtx(l.ctx)
session *domain.ChatSession
user open.User
model *domain.ChatModel
ok bool
)
if session, err = l.svcCtx.ChatSessionRepository.FindOne(l.ctx, conn, req.SessionId); err != nil {
return nil, xerr.NewErrMsgErr("会话不存在", err)
}
if user, err = l.svcCtx.SystemOpen.User(l.ctx, conn, token.UserId); err != nil {
return nil, xerr.NewErrMsgErr("用户不存在", err)
}
if user.Id != session.UserId {
return nil, xerr.NewErrMsgErr("无权限", err)
}
if model, ok = domain.DefaultChatModels.Match(req.ModelId); !ok {
return nil, xerr.NewErrMsgErr("模型不存在", err)
}
var answer string
var upgrader = websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
CheckOrigin: func(r *http.Request) bool {
return true
},
}
var wsconn *websocket.Conn
wsconn, err = upgrader.Upgrade(w, r, nil)
if err != nil {
httpx.ErrorCtx(r.Context(), w, err)
return
}
defer func() {
wsconn.Close()
}()
for {
var text []byte
_, text, err = wsconn.ReadMessage()
if err != nil {
break
}
var beginUnix = time.Now().UnixMilli()
var channel = make(chan string, 5)
dm = &domain.ChatSessionRecord{
CompanyId: token.CompanyId,
UserId: token.UserId,
SessionId: req.SessionId,
ModelId: req.ModelId,
Author: NewDomainUser(user),
ContentType: req.ContentType,
ProblemText: string(text),
Metadata: domain.Metadata{},
Cost: 0,
Status: domain.Processing,
}
fx.Parallel(func() {
// 异步访问AI接口
answer, err = Conversation(model, string(text), channel)
}, func() {
for {
var v string
if v, ok = <-channel; ok {
if err = wsconn.WriteJSON(types.ChatSessionConversationResponse{Parts: []string{v}, Finished: false}); err != nil {
//httpx.ErrorCtx(r.Context(), w, err)
dm.Status = domain.FinishedFail
break
}
} else {
dm.Status = domain.FinishedSuccess
break
}
}
return
})
// 记录
dm.AnswerText = answer
dm.Cost = time.Now().UnixMilli() - beginUnix
if err = transaction.UseTrans(l.ctx, l.svcCtx.DB, func(ctx context.Context, conn transaction.Conn) error {
dm, err = l.svcCtx.ChatSessionRecordRepository.Insert(l.ctx, conn, dm)
return err
}, true); err != nil {
return nil, xerr.NewErrMsg("保存失败")
}
record := NewTypesChatRecord(dm, user)
if err = wsconn.WriteJSON(types.ChatSessionConversationResponse{Record: &record, Finished: true}); err != nil {
return
}
}
if err != nil {
return nil, xerr.NewErrMsgErr("AI模型异常,稍后再试", err)
}
return
}
... ...
package chat
import (
"context"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/internal/pkg/domain"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/pkg/contextdata"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/pkg/transaction"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/pkg/xerr"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/api/internal/svc"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/api/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type ChatSessionDeleteLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewChatSessionDeleteLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ChatSessionDeleteLogic {
return &ChatSessionDeleteLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *ChatSessionDeleteLogic) ChatSessionDelete(req *types.ChatSessionDeleteRequest) (resp *types.ChatSessionDeleteResponse, err error) {
var (
conn = l.svcCtx.DefaultDBConn()
dm *domain.ChatSession
token = contextdata.GetUserTokenFromCtx(l.ctx)
)
if dm, err = l.svcCtx.ChatSessionRepository.FindOne(l.ctx, conn, req.Id); err != nil {
return nil, xerr.NewErrMsgErr("不存在", err)
}
if dm.UserId != token.UserId {
return nil, xerr.NewErrMsgErr("无权限", err)
}
if err = transaction.UseTrans(l.ctx, l.svcCtx.DB, func(ctx context.Context, conn transaction.Conn) error {
if dm, err = l.svcCtx.ChatSessionRepository.Delete(l.ctx, conn, dm); err != nil {
return err
}
return nil
}, true); err != nil {
return nil, xerr.NewErrMsgErr("移除失败", err)
}
return
}
... ...
package chat
import (
"context"
"github.com/samber/lo"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/internal/pkg/domain"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/system/open"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/pkg/contextdata"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/pkg/xerr"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/api/internal/svc"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/api/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type ChatSessionGetLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewChatSessionGetLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ChatSessionGetLogic {
return &ChatSessionGetLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *ChatSessionGetLogic) ChatSessionGet(req *types.ChatSessionGetRequest) (resp *types.ChatSessionGetResponse, err error) {
var (
conn = l.svcCtx.DefaultDBConn()
dm *domain.ChatSession
records []*domain.ChatSessionRecord
token = contextdata.GetUserTokenFromCtx(l.ctx)
user open.User
)
// 货号唯一
if dm, err = l.svcCtx.ChatSessionRepository.FindOne(l.ctx, conn, req.Id); err != nil {
return nil, xerr.NewErrMsgErr("不存在", err)
}
if user, err = l.svcCtx.SystemOpen.User(l.ctx, conn, dm.UserId); err != nil {
return nil, xerr.NewErrMsgErr("用户不存在", err)
}
if _, records, err = l.svcCtx.ChatSessionRecordRepository.FindByCompanyUser(l.ctx, conn, token.CompanyId, token.UserId, domain.NewQueryOptions().MustWithKV("sessionId", dm.Id)); err != nil {
return nil, xerr.NewErr(err)
}
var typesRecords []types.Record
lo.ForEach(records, func(item *domain.ChatSessionRecord, index int) {
typesRecords = append(typesRecords, NewTypesChatRecord(item, user))
})
resp = &types.ChatSessionGetResponse{
ChatSession: NewTypesChatSession(dm),
Records: typesRecords,
}
return
}
func NewTypesChatRecord(item *domain.ChatSessionRecord, user open.User) types.Record {
model, ok := domain.DefaultChatModels.Match(item.ModelId)
var typesModel *types.Model
if !ok {
typesModel = &types.Model{}
} else {
typesModel = &types.Model{
Name: model.Name,
Id: model.Id,
Logo: model.Logo,
}
}
return types.Record{
Id: item.Id,
SessionId: item.SessionId,
GroupId: item.Group,
Author: NewTypesUser(user),
Model: typesModel,
ContentType: item.ContentType,
ProblemText: item.ProblemText,
AnswerText: item.AnswerText,
Status: item.Status,
CreateAt: item.CreatedAt,
}
}
func NewTypesUser(user open.User) *types.User {
if user.Id == 0 && user.Name == "" {
return nil
}
return &types.User{
Id: user.Id,
Name: user.Name,
}
}
func NewDomainUser(user open.User) domain.User {
if user.Id == 0 && user.Name == "" {
return domain.User{}
}
return domain.User{
Id: user.Id,
Name: user.Name,
}
}
... ...
package chat
import (
"context"
"github.com/samber/lo"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/internal/pkg/domain"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/system/open"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/pkg/contextdata"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/pkg/tool"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/pkg/xerr"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/api/internal/svc"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/api/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type ChatSessionRecordsLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewChatSessionRecordsLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ChatSessionRecordsLogic {
return &ChatSessionRecordsLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *ChatSessionRecordsLogic) ChatSessionRecords(req *types.ChatSessionRecordsRequest) (resp *types.ChatSessionRecordsResponse, err error) {
var (
conn = l.svcCtx.DefaultDBConn()
//chatSession *domain.ChatSession
records []*domain.ChatSessionRecord
token = contextdata.GetUserTokenFromCtx(l.ctx)
user open.User
total int64
)
queryOptions := domain.NewQueryOptions().MustWithKV("sessionId", req.SessionId)
if req.Page > 0 && req.Size > 0 {
queryOptions.WithOffsetLimit(req.Page, req.Size)
}
if total, records, err = l.svcCtx.ChatSessionRecordRepository.FindByCompanyUser(l.ctx, conn, token.CompanyId, token.UserId, queryOptions); err != nil {
return nil, xerr.NewErr(err)
}
var typesRecords []types.Record
var lazyUser = tool.NewLazyLoadService(l.svcCtx.SystemOpen.User)
lo.ForEach(records, func(item *domain.ChatSessionRecord, index int) {
user, _ = lazyUser.Load(l.ctx, conn, item.UserId)
typesRecords = append(typesRecords, NewTypesChatRecord(item, user))
})
resp = &types.ChatSessionRecordsResponse{
Records: typesRecords,
Total: total,
}
return
}
... ...
package chat
import (
"context"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/internal/pkg/domain"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/pkg/contextdata"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/pkg/transaction"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/pkg/xerr"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/api/internal/svc"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/api/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type ChatSessionSaveLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewChatSessionSaveLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ChatSessionSaveLogic {
return &ChatSessionSaveLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *ChatSessionSaveLogic) ChatSessionSave(req *types.ChatSessionSaveRequest) (resp *types.ChatSessionSaveResponse, err error) {
var (
dm *domain.ChatSession
token = contextdata.GetUserTokenFromCtx(l.ctx)
)
dm = NewDomainChatSession(token, req.ChatSession)
if err = transaction.UseTrans(l.ctx, l.svcCtx.DB, func(ctx context.Context, conn transaction.Conn) error {
dm, err = l.svcCtx.ChatSessionRepository.Insert(l.ctx, conn, dm)
return err
}, true); err != nil {
return nil, xerr.NewErrMsg("保存失败")
}
resp = &types.ChatSessionSaveResponse{}
return
}
func NewDomainChatSession(token contextdata.UserToken, item types.ChatSessionItem) *domain.ChatSession {
title := item.Title
if item.Title == "" {
title = "新对话窗口"
}
return &domain.ChatSession{
CompanyId: token.CompanyId,
UserId: token.UserId,
Title: title,
Abstract: title,
}
}
func NewTypesChatSession(item *domain.ChatSession) types.ChatSessionItem {
return types.ChatSessionItem{
Id: item.Id,
Title: item.Title,
Abstract: item.Abstract,
CreatedAt: item.CreatedAt,
}
}
... ...
package chat
import (
"context"
"fmt"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/internal/pkg/domain"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/api/internal/svc"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/api/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type ChatSessionSearchLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewChatSessionSearchLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ChatSessionSearchLogic {
return &ChatSessionSearchLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *ChatSessionSearchLogic) ChatSessionSearch(req *types.ChatSessionSearchRequest) (resp *types.ChatSessionSearchResponse, err error) {
var (
conn = l.svcCtx.DefaultDBConn()
dms []*domain.ChatSession
total int64
)
queryOptions := domain.NewQueryOptions().
WithKV("title", fmt.Sprintf("%%%v%%", req.Title))
if req.Page != 0 && req.Size != 0 {
queryOptions.WithOffsetLimit(req.Page, req.Size)
}
total, dms, err = l.svcCtx.ChatSessionRepository.Find(l.ctx, conn, queryOptions)
list := make([]types.ChatSessionItem, 0)
for i := range dms {
list = append(list, NewTypesChatSession(dms[i]))
}
resp = &types.ChatSessionSearchResponse{
List: list,
Total: total,
}
return
}
... ...
package chat
import (
"context"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/internal/pkg/domain"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/pkg/contextdata"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/pkg/transaction"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/pkg/xerr"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/api/internal/svc"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/api/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type ChatSessionUpdateLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewChatSessionUpdateLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ChatSessionUpdateLogic {
return &ChatSessionUpdateLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *ChatSessionUpdateLogic) ChatSessionUpdate(req *types.ChatSessionUpdateRequest) (resp *types.ChatSessionUpdateResponse, err error) {
var (
conn = l.svcCtx.DefaultDBConn()
dm *domain.ChatSession
token = contextdata.GetUserTokenFromCtx(l.ctx)
)
if dm, err = l.svcCtx.ChatSessionRepository.FindOne(l.ctx, conn, req.Id); err != nil {
return nil, xerr.NewErrMsgErr("不存在", err)
}
if dm.UserId != token.UserId {
return nil, xerr.NewErrMsgErr("无权限", err)
}
// 赋值
dm.Title = req.ChatSession.Title
dm.Abstract = req.ChatSession.Abstract
// 更新
if err = transaction.UseTrans(l.ctx, l.svcCtx.DB, func(ctx context.Context, conn transaction.Conn) error {
dm, err = l.svcCtx.ChatSessionRepository.UpdateWithVersion(l.ctx, conn, dm)
return err
}, true); err != nil {
return nil, xerr.NewErrMsg("更新失败")
}
resp = &types.ChatSessionUpdateResponse{}
return
}
... ...
package svc
import (
"github.com/zeromicro/go-zero/core/stores/redis"
"github.com/zeromicro/go-zero/rest"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/api/internal/config"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/internal/pkg/db/repository"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/internal/pkg/domain"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/system/open"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/pkg/cache"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/pkg/database"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/pkg/middleware"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/pkg/transaction"
"gorm.io/gorm"
)
type ServiceContext struct {
Config config.Config
LogRequest rest.Middleware
Redis *redis.Redis
DB *gorm.DB
ChatSessionRepository domain.ChatSessionRepository
ChatSessionRecordRepository domain.ChatSessionRecordRepository
SystemOpen open.SystemOpen
}
func NewServiceContext(c config.Config) *ServiceContext {
db := database.OpenGormPGDB(c.DB.DataSource, c.Log.Mode)
mlCache := cache.NewMultiLevelCache([]string{c.Redis.Host}, c.Redis.Pass)
redis, _ := redis.NewRedis(redis.RedisConf{Host: c.Redis.Host, Pass: c.Redis.Pass, Type: "node"})
return &ServiceContext{
Config: c,
DB: db,
Redis: redis,
LogRequest: middleware.NewLogRequestMiddleware(c.LogRequest).Handle,
ChatSessionRepository: repository.NewChatSessionRepository(cache.NewCachedRepository(mlCache)),
ChatSessionRecordRepository: repository.NewChatSessionRecordRepository(cache.NewCachedRepository(mlCache)),
SystemOpen: open.NewSystemOpen(c.Redis),
}
}
func (svc *ServiceContext) DefaultDBConn() transaction.Conn {
return transaction.NewTransactionContext(svc.DB)
}
... ...
// Code generated by goctl. DO NOT EDIT.
package types
type ChatSessionGetRequest struct {
Id int64 `path:"id"`
}
type ChatSessionGetResponse struct {
ChatSession ChatSessionItem `json:"session"`
Records []Record `json:"records"`
}
type ChatSessionSaveRequest struct {
ChatSession ChatSessionItem `json:"session"`
}
type ChatSessionSaveResponse struct {
}
type ChatSessionDeleteRequest struct {
Id int64 `path:"id"`
}
type ChatSessionDeleteResponse struct {
}
type ChatSessionUpdateRequest struct {
Id int64 `path:"id"`
ChatSession ChatSessionItem `json:"session"`
}
type ChatSessionUpdateResponse struct {
}
type ChatSessionSearchRequest struct {
Page int `json:"page,optional"`
Size int `json:"size,optional"`
Title string `json:"title,optional"` // 按标题搜索
}
type ChatSessionSearchResponse struct {
List []ChatSessionItem `json:"list"`
Total int64 `json:"total"`
}
type ChatSessionItem struct {
Id int64 `json:"id,optional,omitempty"` // 唯一标识
Title string `json:"title,optional,omitempty"` // 会话标题
Abstract string `json:"abstract,optional,omitempty"` // 摘要
CreatedAt int64 `json:"createdAt,optional,omitempty"` // 创建时间
}
type ChatModelsRequest struct {
}
type ChatModelsResponse struct {
List []Model `json:"list"`
}
type Model struct {
Id int64 `json:"id"` // 模型ID
Name string `json:"name"` // 模型名称
Code string `json:"code"` // 模型编码
Logo string `json:"logo"` // 模型LOGO地址
}
type ChatSessionRecordsRequest struct {
Page int `json:"page,optional"`
Size int `json:"size,optional"`
SessionId int64 `json:"sessionId"`
}
type ChatSessionRecordsResponse struct {
Records []Record `json:"list"`
Total int64 `json:"total"`
}
type ChatSessionConversationRequest struct {
SessionId int64 `json:"sessionId"` // 会话ID
ModelId int64 `json:"modelId"` // 模型ID
ContentType string `json:"contentType"` // 内容类型 文本:text (图片:image 文档:document)
Text string `json:"text"` // 内容文本
FileUrl string `json:"fileUrl,optional"` // 文件地址
}
type ChatSessionConversationResponse struct {
Record *Record `json:"record,omitempty"`
Parts []string `json:"parts"`
Finished bool `json:"finished"`
}
type ChatSessionConversationRequestWs struct {
SessionId int64 `form:"sessionId"` // 会话ID
ModelId int64 `form:"modelId"` // 模型ID
ContentType string `form:"contentType"` // 内容类型 文本:text (图片:image 文档:document)
Text string `form:"text"` // 内容文本
}
type Record struct {
Id int64 `json:"id"` // 记录ID
SessionId int64 `json:"sessionId"` // 会话ID
GroupId int64 `json:"groupId"` // 分组ID
ModelId int64 `json:"modelId,omitempty"` // 模型ID
AuthorId int64 `json:"authorId,omitempty"` // 作者ID
Author *User `json:"author,omitempty"` // 提问人
Model *Model `json:"model,omitempty"` // 应答人
ContentType string `json:"contentType"` // 内容类型 文本:text (图片:image 文档:document)
ProblemText string `json:"problemText"` // 问题文本
AnswerText string `json:"answerText"` // 回答文本
Status string `json:"status"` // 状态 处理中:processing 超时:finished_timeout 结束成功:finished_fail 结束失败:finished_success
CreateAt int64 `json:"createAt"` // 创建时间
}
type Content struct {
ContentType string `json:"contentType"` // 内容类型 文本:text (图片:image 文档:document)
Parts []string `json:"parts"` // 内容
}
type User struct {
Id int64 `json:"id"` // 用ID
Name string `json:"name"` // 名称
Avatar string `json:"avatar"` // 头像
}
... ...
CREATE TABLE `chat_session`
(
`id` int(0) NOT NULL COMMENT '唯一标识',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
CREATE TABLE `chat_session_record`
(
`id` int(0) NOT NULL COMMENT '唯一标识',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
CREATE TABLE `chat_model`
(
`id` int(0) NOT NULL COMMENT '唯一标识',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
... ...
FROM golang:1.19-alpine as builder
# Define the project name | 定义项目名称
ARG PROJECT=core
ARG PROJECTCODE=chat
WORKDIR /build
COPY . .
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories
RUN apk update --no-cache && apk add --no-cache tzdata
RUN go env -w GO111MODULE=on \
&& go env -w GOPROXY=https://goproxy.cn,direct \
&& go env -w CGO_ENABLED=0 \
&& go env \
&& go mod tidy \
&& cd cmd/ep/${PROJECTCODE}/api \
&& go build -ldflags="-s -w" -o /build/api/${PROJECT} ${PROJECT}.go
FROM alpine:latest
# Define the project name | 定义项目名称
ARG PROJECT=core
ARG PROJECTCODE=chat
# Define the config file name | 定义配置文件名
ARG CONFIG_FILE=core.yaml
# Define the author | 定义作者
ARG AUTHOR=785409885@qq.com
LABEL org.opencontainers.image.authors=${AUTHOR}
WORKDIR /app
ENV PROJECT=${PROJECT}
ENV CONFIG_FILE=${CONFIG_FILE}
ENV TZ Asia/Shanghai
COPY --from=builder /usr/share/zoneinfo/Asia/Shanghai /usr/share/zoneinfo/Asia/Shanghai
COPY --from=builder /build/api/${PROJECT} ./
COPY --from=builder /build/cmd/ep/${PROJECTCODE}/api/etc/${CONFIG_FILE} ./etc/
EXPOSE 8080
ENTRYPOINT ./${PROJECT} -f etc/${CONFIG_FILE}
\ No newline at end of file
... ...
#!/bin/bash
export PATH=/root/local/bin:$PATH
kubectl -n mmm-suplus-test get pods | grep -q sumifcc-discuss
if [ "$?" == "1" ];then
kubectl create -f /tmp/test/sumifcc-discuss/sumifcc-discuss.yaml --record
kubectl -n mmm-suplus-test get svc | grep -q sumifcc-discuss
if [ "$?" == "0" ];then
echo "sumifcc-discuss service install success!"
else
echo "sumifcc-discuss service install fail!"
fi
kubectl -n mmm-suplus-test get pods | grep -q sumifcc-discuss
if [ "$?" == "0" ];then
echo "sumifcc-discuss deployment install success!"
else
echo "sumifcc-discuss deployment install fail!"
fi
else
kubectl delete -f /tmp/test/sumifcc-discuss/sumifcc-discuss.yaml
kubectl -n mmm-suplus-test get svc | grep -q sumifcc-discuss
while [ "$?" == "0" ]
do
kubectl -n mmm-suplus-test get svc | grep -q sumifcc-discuss
done
kubectl -n mmm-suplus-test get pods | grep -q sumifcc-discuss
while [ "$?" == "0" ]
do
kubectl -n mmm-suplus-test get pods | grep -q sumifcc-discuss
done
kubectl create -f /tmp/test/sumifcc-discuss/sumifcc-discuss.yaml --record
kubectl -n mmm-suplus-test get svc | grep -q sumifcc-discuss
if [ "$?" == "0" ];then
echo "sumifcc-discuss service update success!"
else
echo "sumifcc-discuss service update fail!"
fi
kubectl -n mmm-suplus-test get pods | grep -q sumifcc-discuss
if [ "$?" == "0" ];then
echo "sumifcc-discuss deployment update success!"
else
echo "sumifcc-discuss deployment update fail!"
fi
fi
\ No newline at end of file
... ...
apiVersion: v1
kind: ConfigMap
metadata:
name: sumicro-chat-config-dev
data:
core.yaml: |
Name: sumicro-chat-dev
Host: 0.0.0.0
Port: 8080
Verbose: false
Migrate: true
Timeout: 30000
LogRequest: true # 记录详细请求日志
Log:
#Mode: file
Encoding: plain
Level: debug # info
MaxSize: 1 # 2MB
TimeFormat: 2006-01-02 15:04:05
Rotation: size
MaxContentLength: 10240
SystemAuth:
AccessSecret: su-platform
AccessExpire: 360000
Redis:
Host: 192.168.0.243:6379
Type: node
Pass:
DB:
DataSource: host=114.55.200.59 user=postgres password=eagle1010 dbname=su_enterprise_platform port=31543 sslmode=disable TimeZone=Asia/Shanghai
---
apiVersion: v1
kind: Service
metadata:
name: sumicro-chat
namespace: mmm-suplus-test
labels:
k8s-app: sumicro-chat
spec:
ports:
- name: "http"
port: 80
targetPort: 8080
- name: "https"
port: 443
targetPort: 443
selector:
k8s-app: sumicro-chat
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: sumicro-chat
namespace: mmm-suplus-test
labels:
k8s-app: sumicro-chat
spec:
replicas: 1
template:
metadata:
labels:
k8s-app: sumicro-chat
spec:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- preference: {}
weight: 100
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- cn-hangzhou.i-bp1djh1xn7taumbue1ze
containers:
- name: sumicro-chat
image: 192.168.0.243:5000/mmm/sumicro-chat:dev
imagePullPolicy: Always
ports:
- containerPort: 8080
- containerPort: 443
volumeMounts:
- mountPath: /opt/logs
name: accesslogs
- mountPath: /app/etc
name: config-volume
env:
- name: LOG_LEVEL
value: "debug"
- name: LOG_FILE
value: "true"
volumes:
- name: accesslogs
emptyDir: {}
- name: config-volume
configMap:
name: sumicro-chat-config-dev
... ...
#!/bin/bash
export PATH=/root/local/bin:$PATH
kubectl -n mmm-suplus-test get pods | grep -q sumifcc-discuss
if [ "$?" == "1" ];then
kubectl create -f /tmp/test/sumifcc-discuss/sumifcc-discuss.yaml --record
kubectl -n mmm-suplus-test get svc | grep -q sumifcc-discuss
if [ "$?" == "0" ];then
echo "sumifcc-discuss service install success!"
else
echo "sumifcc-discuss service install fail!"
fi
kubectl -n mmm-suplus-test get pods | grep -q sumifcc-discuss
if [ "$?" == "0" ];then
echo "sumifcc-discuss deployment install success!"
else
echo "sumifcc-discuss deployment install fail!"
fi
else
kubectl delete -f /tmp/test/sumifcc-discuss/sumifcc-discuss.yaml
kubectl -n mmm-suplus-test get svc | grep -q sumifcc-discuss
while [ "$?" == "0" ]
do
kubectl -n mmm-suplus-test get svc | grep -q sumifcc-discuss
done
kubectl -n mmm-suplus-test get pods | grep -q sumifcc-discuss
while [ "$?" == "0" ]
do
kubectl -n mmm-suplus-test get pods | grep -q sumifcc-discuss
done
kubectl create -f /tmp/test/sumifcc-discuss/sumifcc-discuss.yaml --record
kubectl -n mmm-suplus-test get svc | grep -q sumifcc-discuss
if [ "$?" == "0" ];then
echo "sumifcc-discuss service update success!"
else
echo "sumifcc-discuss service update fail!"
fi
kubectl -n mmm-suplus-test get pods | grep -q sumifcc-discuss
if [ "$?" == "0" ];then
echo "sumifcc-discuss deployment update success!"
else
echo "sumifcc-discuss deployment update fail!"
fi
fi
\ No newline at end of file
... ...
apiVersion: v1
kind: ConfigMap
metadata:
name: sumicro-chat-config-prd
data:
config.yml: |
Name: sumicro-chat-prd
Host: 0.0.0.0
Port: 8080
Verbose: false
Migrate: true
Timeout: 30000
LogRequest: true # 记录详细请求日志
Log:
#Mode: file
Encoding: plain
Level: debug # info
MaxSize: 1 # 2MB
TimeFormat: 2006-01-02 15:04:05
Rotation: size
MaxContentLength: 10240
SystemAuth:
AccessSecret: su-platform
AccessExpire: 360000
Redis:
Host: 192.168.0.243:6379
Type: node
Pass:
DB:
DataSource: host=114.55.200.59 user=postgres password=eagle1010 dbname=su_enterprise_platform port=31543 sslmode=disable TimeZone=Asia/Shanghai
---
apiVersion: v1
kind: Service
metadata:
name: sumicro-chat
namespace: mmm-suplus-test
labels:
k8s-app: sumicro-chat
spec:
ports:
- name: "http"
port: 80
targetPort: 8080
- name: "https"
port: 443
targetPort: 443
selector:
k8s-app: sumicro-chat
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: sumicro-chat
namespace: mmm-suplus-test
labels:
k8s-app: sumicro-chat
spec:
replicas: 1
template:
metadata:
labels:
k8s-app: sumicro-chat
spec:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- preference: {}
weight: 100
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- cn-hangzhou.i-bp1djh1xn7taumbue1ze
containers:
- name: sumicro-chat
image: 192.168.0.243:5000/mmm/sumicro-chat:dev
imagePullPolicy: Always
ports:
- containerPort: 8080
- containerPort: 443
volumeMounts:
- mountPath: /opt/logs
name: accesslogs
- mountPath: /app/etc
name: config-volume
env:
- name: LOG_LEVEL
value: "debug"
- name: LOG_FILE
value: "true"
volumes:
- name: accesslogs
emptyDir: {}
- name: config-volume
configMap:
name: sumicro-chat-config-prd
... ...
## 1、准备工作
在开始之前,我们需要准备一些东西:
* Docker:这是一个用于容器化应用程序的开源平台。
## 2、准备Nginx配置文件
完整的配置文件见**nginx.conf**,其核心部分如下:
```conf
server {
listen 80; # 监听80端口,用于HTTP请求
location / {
proxy_pass https://api.openai.com/; # 反向代理到https://api.openai.com/这个地址
proxy_ssl_server_name on; # 开启代理SSL服务器名称验证,确保SSL连接的安全性
proxy_set_header Host api.openai.com; # 设置代理请求头中的Host字段为api.openai.com
chunked_transfer_encoding off; # 禁用分块编码传输,避免可能的代理问题
proxy_buffering off; # 禁用代理缓存,避免数据传输延迟
proxy_cache off; # 禁用代理缓存,确保实时获取最新的数据
#proxy_set_header X-Forwarded-For $remote_addr; # 将客户端真实IP添加到代理请求头中的X-Forwarded-For字段中,用于记录客户端真实IP
}
}
```
## 3、启动服务
### 3.1、docker run
```
docker run -itd -p 80:80 -v $PWD/nginx.conf:/etc/nginx/nginx.conf --name my-nginx nginx
```
### 3.2、docker compose up
```
docker compose up -d
```
## 4、应用
```python
# Note: you need to be using OpenAI Python v0.27.0 for the code below to work
import openai
openai.api_key = api_key
openai.api_base = "your_proxy_url" # 代理地址,如“http://www.test.com/v1”
openai.ChatCompletion.create(
model="gpt-3.5-turbo",
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Who won the world series in 2020?"},
{"role": "assistant", "content": "The Los Angeles Dodgers won the World Series in 2020."},
{"role": "user", "content": "Where was it played?"}
]
)
```
... ...
services:
proxy:
image: nginx
volumes:
- "$PWD/nginx.conf:/etc/nginx/nginx.conf"
ports:
- "80:80"
- "443:443"
restart: unless-stopped
... ...
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
# include /etc/nginx/conf.d/*.conf;
server {
listen 80;
location / {
proxy_pass https://api.openai.com/;
proxy_ssl_server_name on;
proxy_set_header Host api.openai.com;
chunked_transfer_encoding off;
proxy_buffering off;
proxy_cache off;
proxy_set_header X-Forwarded-For $remote_addr;
}
}
}
... ...
syntax = "v1"
import "core/session.api"
\ No newline at end of file
... ...
syntax = "v1"
// 后台接口
@server(
prefix: v1
group: chat
middleware: LogRequest
jwt: SystemAuth
)
service Core {
@doc "聊天会话-详情"
@handler chatSessionGet
get /chat/session/:id (ChatSessionGetRequest) returns (ChatSessionGetResponse)
@doc "聊天会话-保存"
@handler chatSessionSave
post /chat/session (ChatSessionSaveRequest) returns (ChatSessionSaveResponse)
@doc "聊天会话-删除"
@handler chatSessionDelete
delete /chat/session/:id (ChatSessionDeleteRequest) returns (ChatSessionDeleteResponse)
@doc "聊天会话-更新"
@handler chatSessionUpdate
put /chat/session/:id (ChatSessionUpdateRequest) returns (ChatSessionUpdateResponse)
@doc "聊天会话-搜索"
@handler chatSessionSearch
post /chat/session/search (ChatSessionSearchRequest) returns (ChatSessionSearchResponse)
@doc "聊天会话-对话"
@handler chatSessionConversation
post /chat/session/conversation (ChatSessionConversationRequest) returns (ChatSessionConversationResponse)
@doc "聊天会话-对话"
@handler chatSessionConversationWs
get /chat/session/conversation (ChatSessionConversationRequestWs) returns (ChatSessionConversationResponse)
@doc "聊天会话-对话记录列表"
@handler chatSessionRecords
post /chat/session/records (ChatSessionRecordsRequest) returns (ChatSessionRecordsResponse)
@doc "模型列表"
@handler chatModels
get /chat/models (ChatModelsRequest) returns (ChatModelsResponse)
}
type (
ChatSessionGetRequest {
Id int64 `path:"id"`
}
ChatSessionGetResponse {
ChatSession ChatSessionItem `json:"session"`
Records []Record `json:"records"`
}
ChatSessionSaveRequest {
ChatSession ChatSessionItem `json:"session"`
}
ChatSessionSaveResponse {}
ChatSessionDeleteRequest {
Id int64 `path:"id"`
}
ChatSessionDeleteResponse {}
ChatSessionUpdateRequest {
Id int64 `path:"id"`
ChatSession ChatSessionItem `json:"session"`
}
ChatSessionUpdateResponse {}
ChatSessionSearchRequest {
Page int `json:"page,optional"`
Size int `json:"size,optional"`
Title string `json:"title,optional"` // 按标题搜索
}
ChatSessionSearchResponse{
List []ChatSessionItem `json:"list"`
Total int64 `json:"total"`
}
ChatSessionItem {
Id int64 `json:"id,optional,omitempty"` // 唯一标识
Title string `json:"title,optional,omitempty"` // 会话标题
Abstract string `json:"abstract,optional,omitempty"` // 摘要
CreatedAt int64 `json:"createdAt,optional,omitempty"` // 创建时间
}
)
// 模型列表
type(
ChatModelsRequest{
}
ChatModelsResponse{
List []Model `json:"list"`
}
Model{
Id int64 `json:"id"` // 模型ID
Name string `json:"name"` // 模型名称
Code string `json:"code"` // 模型编码
Logo string `json:"logo"` // 模型LOGO地址
}
)
// 聊天会话-记录列表
type(
ChatSessionRecordsRequest{
Page int `json:"page,optional"`
Size int `json:"size,optional"`
SessionId int64 `json:"sessionId"`
}
ChatSessionRecordsResponse{
Records []Record `json:"list"`
Total int64 `json:"total"`
}
)
// 聊天会话-对话
type(
ChatSessionConversationRequest{
SessionId int64 `json:"sessionId"` // 会话ID
ModelId int64 `json:"modelId"` // 模型ID
ContentType string `json:"contentType"` // 内容类型 文本:text (图片:image 文档:document)
Text string `json:"text"` // 内容文本
FileUrl string `json:"fileUrl,optional"` // 文件地址
}
ChatSessionConversationResponse{
Record *Record `json:"record,omitempty"`
Parts []string `json:"parts"`
Finished bool `json:"finished"`
}
ChatSessionConversationRequestWs{
SessionId int64 `form:"sessionId"` // 会话ID
ModelId int64 `form:"modelId"` // 模型ID
ContentType string `form:"contentType"` // 内容类型 文本:text (图片:image 文档:document)
Text string `form:"text"` // 内容文本
}
Record{
Id int64 `json:"id"` // 记录ID
SessionId int64 `json:"sessionId"` // 会话ID
GroupId int64 `json:"groupId"` // 分组ID
ModelId int64 `json:"modelId,omitempty"` // 模型ID
AuthorId int64 `json:"authorId,omitempty"` // 作者ID
Author *User `json:"author,omitempty"` // 提问人
Model *Model `json:"model,omitempty"` // 应答人
ContentType string `json:"contentType"` // 内容类型 文本:text (图片:image 文档:document)
ProblemText string `json:"problemText"` // 问题文本
AnswerText string `json:"answerText"` // 回答文本
Status string `json:"status"` // 状态 处理中:processing 超时:finished_timeout 结束成功:finished_fail 结束失败:finished_success
CreateAt int64 `json:"createAt"` // 创建时间
}
Content{
ContentType string `json:"contentType"` // 内容类型 文本:text (图片:image 文档:document)
Parts []string `json:"parts"` // 内容
}
User {
Id int64 `json:"id"` // 用ID
Name string `json:"name"` // 名称
Avatar string `json:"avatar"` // 头像
}
)
\ No newline at end of file
... ...
{
"swagger": "2.0",
"info": {
"title": "",
"version": ""
},
"schemes": [
"http",
"https"
],
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"paths": {
"v1/chat/models": {
"get": {
"summary": "模型列表",
"operationId": "chatModels",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/ChatModelsResponse"
}
}
},
"requestBody": {},
"tags": [
"chat"
]
}
},
"v1/chat/session": {
"post": {
"summary": "聊天会话-保存",
"operationId": "chatSessionSave",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/ChatSessionSaveResponse"
}
}
},
"parameters": [
{
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/ChatSessionSaveRequest"
}
}
],
"requestBody": {},
"tags": [
"chat"
]
}
},
"v1/chat/session/conversation": {
"get": {
"summary": "聊天会话-对话",
"operationId": "chatSessionConversation",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/ChatSessionConversationResponse"
}
}
},
"parameters": [
{
"name": "sessionId",
"description": " 会话ID",
"in": "query",
"required": true,
"type": "integer",
"format": "int64"
},
{
"name": "modelId",
"description": " 模型ID",
"in": "query",
"required": true,
"type": "integer",
"format": "int64"
},
{
"name": "contentType",
"description": " 内容类型 文本:text (图片:image 文档:document)",
"in": "query",
"required": true,
"type": "string"
},
{
"name": "text",
"description": " 内容文本",
"in": "query",
"required": true,
"type": "string"
},
{
"name": "fileUrl",
"description": " 文件地址",
"in": "query",
"required": true,
"type": "string"
}
],
"requestBody": {},
"tags": [
"chat"
]
}
},
"v1/chat/session/records": {
"get": {
"summary": "聊天会话-对话记录列表",
"operationId": "chatSessionRecords",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/ChatSessionRecordsResponse"
}
}
},
"parameters": [
{
"name": "page",
"in": "query",
"required": false,
"type": "integer",
"format": "int32"
},
{
"name": "size",
"in": "query",
"required": false,
"type": "integer",
"format": "int32"
},
{
"name": "sessionId",
"in": "query",
"required": true,
"type": "integer",
"format": "int64"
}
],
"requestBody": {},
"tags": [
"chat"
]
}
},
"v1/chat/session/search": {
"post": {
"summary": "聊天会话-搜索",
"operationId": "chatSessionSearch",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/ChatSessionSearchResponse"
}
}
},
"parameters": [
{
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/ChatSessionSearchRequest"
}
}
],
"requestBody": {},
"tags": [
"chat"
]
}
},
"v1/chat/session/{id}": {
"get": {
"summary": "聊天会话-详情",
"operationId": "chatSessionGet",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/ChatSessionGetResponse"
}
}
},
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"type": "string"
}
],
"requestBody": {},
"tags": [
"chat"
]
},
"delete": {
"summary": "聊天会话-删除",
"operationId": "chatSessionDelete",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/ChatSessionDeleteResponse"
}
}
},
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"type": "string"
},
{
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/ChatSessionDeleteRequest"
}
}
],
"requestBody": {},
"tags": [
"chat"
]
},
"put": {
"summary": "聊天会话-更新",
"operationId": "chatSessionUpdate",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/ChatSessionUpdateResponse"
}
}
},
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"type": "string"
},
{
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/ChatSessionUpdateRequest"
}
}
],
"requestBody": {},
"tags": [
"chat"
]
}
}
},
"definitions": {
"ChatModelsRequest": {
"type": "object",
"title": "ChatModelsRequest"
},
"ChatModelsResponse": {
"type": "object",
"properties": {
"list": {
"type": "array",
"items": {
"$ref": "#/definitions/Model"
}
}
},
"title": "ChatModelsResponse",
"required": [
"list"
]
},
"ChatSessionConversationRequest": {
"type": "object",
"properties": {
"sessionId": {
"type": "integer",
"format": "int64",
"description": " 会话ID"
},
"modelId": {
"type": "integer",
"format": "int64",
"description": " 模型ID"
},
"contentType": {
"type": "string",
"description": " 内容类型 文本:text (图片:image 文档:document)"
},
"text": {
"type": "string",
"description": " 内容文本"
},
"fileUrl": {
"type": "string",
"description": " 文件地址"
}
},
"title": "ChatSessionConversationRequest",
"required": [
"sessionId",
"modelId",
"contentType",
"text",
"fileUrl"
]
},
"ChatSessionConversationResponse": {
"type": "object",
"title": "ChatSessionConversationResponse"
},
"ChatSessionDeleteRequest": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"format": "int64"
}
},
"title": "ChatSessionDeleteRequest",
"required": [
"id"
]
},
"ChatSessionDeleteResponse": {
"type": "object",
"title": "ChatSessionDeleteResponse"
},
"ChatSessionGetRequest": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"format": "int64"
}
},
"title": "ChatSessionGetRequest",
"required": [
"id"
]
},
"ChatSessionGetResponse": {
"type": "object",
"properties": {
"session": {
"$ref": "#/definitions/ChatSessionItem"
},
"records": {
"type": "array",
"items": {
"$ref": "#/definitions/Record"
}
}
},
"title": "ChatSessionGetResponse",
"required": [
"session",
"records"
]
},
"ChatSessionItem": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"format": "int64",
"description": " 唯一标识"
},
"title": {
"type": "string",
"description": " 会话标题"
},
"abstract": {
"type": "string",
"description": " 摘要"
},
"createdAt": {
"type": "integer",
"format": "int64",
"description": " 创建时间"
}
},
"title": "ChatSessionItem",
"required": [
"id",
"title",
"abstract",
"createdAt"
]
},
"ChatSessionRecordsRequest": {
"type": "object",
"properties": {
"page": {
"type": "integer",
"format": "int32"
},
"size": {
"type": "integer",
"format": "int32"
},
"sessionId": {
"type": "integer",
"format": "int64"
}
},
"title": "ChatSessionRecordsRequest",
"required": [
"sessionId"
]
},
"ChatSessionRecordsResponse": {
"type": "object",
"properties": {
"list": {
"type": "array",
"items": {
"$ref": "#/definitions/Record"
}
},
"total": {
"type": "integer",
"format": "int64"
}
},
"title": "ChatSessionRecordsResponse",
"required": [
"list",
"total"
]
},
"ChatSessionSaveRequest": {
"type": "object",
"properties": {
"session": {
"$ref": "#/definitions/ChatSessionItem"
}
},
"title": "ChatSessionSaveRequest",
"required": [
"session"
]
},
"ChatSessionSaveResponse": {
"type": "object",
"title": "ChatSessionSaveResponse"
},
"ChatSessionSearchRequest": {
"type": "object",
"properties": {
"page": {
"type": "integer",
"format": "int32"
},
"size": {
"type": "integer",
"format": "int32"
},
"title": {
"type": "string",
"description": " 按标题搜索"
}
},
"title": "ChatSessionSearchRequest"
},
"ChatSessionSearchResponse": {
"type": "object",
"properties": {
"list": {
"type": "array",
"items": {
"$ref": "#/definitions/ChatSessionItem"
}
},
"total": {
"type": "integer",
"format": "int64"
}
},
"title": "ChatSessionSearchResponse",
"required": [
"list",
"total"
]
},
"ChatSessionUpdateRequest": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"format": "int64"
},
"session": {
"$ref": "#/definitions/ChatSessionItem"
}
},
"title": "ChatSessionUpdateRequest",
"required": [
"id",
"session"
]
},
"ChatSessionUpdateResponse": {
"type": "object",
"title": "ChatSessionUpdateResponse"
},
"Content": {
"type": "object",
"properties": {
"contentType": {
"type": "string",
"description": " 内容类型 文本:text (图片:image 文档:document)"
},
"parts": {
"type": "array",
"items": {
"type": "string"
},
"description": " 内容"
}
},
"title": "Content",
"required": [
"contentType",
"parts"
]
},
"Model": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"format": "int64",
"description": " 模型ID"
},
"name": {
"type": "string",
"description": " 模型名称"
},
"code": {
"type": "string",
"description": " 模型编码"
},
"logo": {
"type": "string",
"description": " 模型LOGO地址"
}
},
"title": "Model",
"required": [
"id",
"name",
"code",
"logo"
]
},
"Record": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"format": "int64",
"description": " 记录ID"
},
"sessionId": {
"type": "integer",
"format": "int64",
"description": " 会话ID"
},
"groupId": {
"type": "integer",
"format": "int64",
"description": " 分组ID"
},
"modelId": {
"type": "integer",
"format": "int64",
"description": " 模型ID"
},
"authorId": {
"type": "integer",
"format": "int64",
"description": " 作者ID"
},
"author": {
"$ref": "#/definitions/User",
"description": " 提问人"
},
"model": {
"$ref": "#/definitions/Model",
"description": " 应答人"
},
"contentType": {
"type": "string",
"description": " 内容类型 文本:text (图片:image 文档:document)"
},
"problemText": {
"type": "string",
"description": " 问题文本"
},
"answerText": {
"type": "string",
"description": " 回答文本"
},
"status": {
"type": "string",
"description": " 状态 处理中:processing 超时:finished_timeout 结束成功:finished_fail 结束失败:finished_success"
},
"createAt": {
"type": "integer",
"format": "int64",
"description": " 创建时间"
}
},
"title": "Record",
"required": [
"id",
"sessionId",
"groupId",
"modelId",
"authorId",
"author",
"model",
"contentType",
"problemText",
"answerText",
"status",
"createAt"
]
},
"User": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"format": "int64",
"description": " 用ID"
},
"name": {
"type": "string",
"description": " 名称"
},
"avatar": {
"type": "string",
"description": " 头像"
}
},
"title": "User",
"required": [
"id",
"name",
"avatar"
]
}
},
"securityDefinitions": {
"apiKey": {
"type": "apiKey",
"description": "Enter JWT Bearer token **_only_**",
"name": "Authorization",
"in": "header"
}
},
"security": [
{
"apiKey": []
}
]
}
... ...
syntax = "v1"
info(
title: "xx实例"
desc: "xx实例"
author: "author"
email: "email"
version: "v1"
)
@server(
prefix: v1
group: chat_model
jwt: JwtAuth
)
service Core {
@doc "详情"
@handler chat_modelGet
get /chat_model/:id (ChatModelGetRequest) returns (ChatModelGetResponse)
@doc "保存"
@handler chat_modelSave
post /chat_model (ChatModelSaveRequest) returns (ChatModelSaveResponse)
@doc "删除"
@handler chat_modelDelete
delete /chat_model/:id (ChatModelDeleteRequest) returns (ChatModelDeleteResponse)
@doc "更新"
@handler chat_modelUpdate
put /chat_model/:id (ChatModelUpdateRequest) returns (ChatModelUpdateResponse)
@doc "搜索"
@handler chat_modelSearch
post /chat_model/search (ChatModelSearchRequest) returns (ChatModelSearchResponse)
}
type (
ChatModelGetRequest {
Id int64 `path:"id"`
}
ChatModelGetResponse {
ChatModel ChatModelItem `json:"chat_model"`
}
ChatModelSaveRequest {
ChatModel ChatModelItem `json:"chat_model"`
}
ChatModelSaveResponse {}
ChatModelDeleteRequest {
Id int64 `path:"id"`
}
ChatModelDeleteResponse {}
ChatModelUpdateRequest {
Id int64 `path:"id"`
ChatModel ChatModelItem `json:"chat_model"`
}
ChatModelUpdateResponse {}
ChatModelSearchRequest {
Page int `json:"page"`
Size int `json:"size"`
}
ChatModelSearchResponse{
List []ChatModelItem `json:"list"`
Total int64 `json:"total"`
}
ChatModelItem {
}
)
// logic CRUD
// Save
//var (
// conn = l.svcCtx.DefaultDBConn()
// dm *domain.ChatModel
//)
//// 唯一判断
//dm = NewDomainChatModel(req.ChatModel)
//if err = transaction.UseTrans(l.ctx, l.svcCtx.DB, func(ctx context.Context, conn transaction.Conn) error {
// dm, err = l.svcCtx.ChatModelRepository.Insert(l.ctx, conn, dm)
// return err
//}, true); err != nil {
// return nil, xerr.NewErrMsg("保存失败")
//}
////resp = &types.ChatModelSaveResponse{}
//return
//func NewDomainChatModel(item types.ChatModelItem) *domain.ChatModel {
// return &domain.ChatModel{
// }
//}
//
//func NewTypesChatModel(item *domain.ChatModel) types.ChatModelItem {
// return types.ChatModelItem{
// Id: item.Id,
// }
//}
// Get
//var (
// conn = l.svcCtx.DefaultDBConn()
// dm *domain.ChatModel
//)
//// 货号唯一
//if dm, err = l.svcCtx.ChatModelRepository.FindOne(l.ctx, conn, req.Id); err != nil {
// return nil, xerr.NewErrMsgErr("不存在", err)
//}
//resp = &types.ChatModelGetResponse{
// ChatModel: NewTypesChatModel(dm),
//}
//return
// Delete
//var (
// conn = l.svcCtx.DefaultDBConn()
// dm *domain.ChatModel
//)
//if dm, err = l.svcCtx.ChatModelRepository.FindOne(l.ctx, conn, req.Id); err != nil {
// return nil, xerr.NewErrMsgErr("不存在", err)
//}
//if err = transaction.UseTrans(l.ctx, l.svcCtx.DB, func(ctx context.Context, conn transaction.Conn) error {
// if dm, err = l.svcCtx.ChatModelRepository.Delete(l.ctx, conn, dm); err != nil {
// return err
// }
// return nil
//}, true); err != nil {
// return nil, xerr.NewErrMsgErr("移除失败", err)
//}
//return
// Search
//var (
// conn = l.svcCtx.DefaultDBConn()
// dms []*domain.ChatModel
// total int64
//)
//
//queryOptions := domain.NewQueryOptions().WithOffsetLimit(req.Page, req.Size).
// WithKV("", "")
//total, dms, err = l.svcCtx.ChatModelRepository.Find(l.ctx, conn, queryOptions)
//list := make([]types.ChatModelItem, 0)
//for i := range dms {
// list = append(list, NewTypesChatModel(dms[i]))
//}
//resp = &types.ChatModelSearchResponse{
// List: list,
// Total: total,
//}
//return
// Update
//var (
// conn = l.svcCtx.DefaultDBConn()
// dm *domain.ChatModel
//)
//if dm, err = l.svcCtx.ChatModelRepository.FindOne(l.ctx, conn, req.Id); err != nil {
// return nil, xerr.NewErrMsgErr("不存在", err)
//}
//// 不可编辑判断
//// 赋值
//// 更新
//if err = transaction.UseTrans(l.ctx, l.svcCtx.DB, func(ctx context.Context, conn transaction.Conn) error {
// dm, err = l.svcCtx.ChatModelRepository.UpdateWithVersion(l.ctx, conn, dm)
// return err
//}, true); err != nil {
// return nil, xerr.NewErrMsg("更新失败")
//}
//resp = &types.ChatModelUpdateResponse{}
//return
... ...
syntax = "v1"
info(
title: "xx实例"
desc: "xx实例"
author: "author"
email: "email"
version: "v1"
)
@server(
prefix: v1
group: chat_session
jwt: JwtAuth
)
service Core {
@doc "详情"
@handler chat_sessionGet
get /chat_session/:id (ChatSessionGetRequest) returns (ChatSessionGetResponse)
@doc "保存"
@handler chat_sessionSave
post /chat_session (ChatSessionSaveRequest) returns (ChatSessionSaveResponse)
@doc "删除"
@handler chat_sessionDelete
delete /chat_session/:id (ChatSessionDeleteRequest) returns (ChatSessionDeleteResponse)
@doc "更新"
@handler chat_sessionUpdate
put /chat_session/:id (ChatSessionUpdateRequest) returns (ChatSessionUpdateResponse)
@doc "搜索"
@handler chat_sessionSearch
post /chat_session/search (ChatSessionSearchRequest) returns (ChatSessionSearchResponse)
}
type (
ChatSessionGetRequest {
Id int64 `path:"id"`
}
ChatSessionGetResponse {
ChatSession ChatSessionItem `json:"chat_session"`
}
ChatSessionSaveRequest {
ChatSession ChatSessionItem `json:"chat_session"`
}
ChatSessionSaveResponse {}
ChatSessionDeleteRequest {
Id int64 `path:"id"`
}
ChatSessionDeleteResponse {}
ChatSessionUpdateRequest {
Id int64 `path:"id"`
ChatSession ChatSessionItem `json:"chat_session"`
}
ChatSessionUpdateResponse {}
ChatSessionSearchRequest {
Page int `json:"page"`
Size int `json:"size"`
}
ChatSessionSearchResponse{
List []ChatSessionItem `json:"list"`
Total int64 `json:"total"`
}
ChatSessionItem {
}
)
// logic CRUD
// Save
//var (
// conn = l.svcCtx.DefaultDBConn()
// dm *domain.ChatSession
//)
//// 唯一判断
//dm = NewDomainChatSession(req.ChatSession)
//if err = transaction.UseTrans(l.ctx, l.svcCtx.DB, func(ctx context.Context, conn transaction.Conn) error {
// dm, err = l.svcCtx.ChatSessionRepository.Insert(l.ctx, conn, dm)
// return err
//}, true); err != nil {
// return nil, xerr.NewErrMsg("保存失败")
//}
////resp = &types.ChatSessionSaveResponse{}
//return
//func NewDomainChatSession(item types.ChatSessionItem) *domain.ChatSession {
// return &domain.ChatSession{
// }
//}
//
//func NewTypesChatSession(item *domain.ChatSession) types.ChatSessionItem {
// return types.ChatSessionItem{
// Id: item.Id,
// }
//}
// Get
//var (
// conn = l.svcCtx.DefaultDBConn()
// dm *domain.ChatSession
//)
//// 货号唯一
//if dm, err = l.svcCtx.ChatSessionRepository.FindOne(l.ctx, conn, req.Id); err != nil {
// return nil, xerr.NewErrMsgErr("不存在", err)
//}
//resp = &types.ChatSessionGetResponse{
// ChatSession: NewTypesChatSession(dm),
//}
//return
// Delete
//var (
// conn = l.svcCtx.DefaultDBConn()
// dm *domain.ChatSession
//)
//if dm, err = l.svcCtx.ChatSessionRepository.FindOne(l.ctx, conn, req.Id); err != nil {
// return nil, xerr.NewErrMsgErr("不存在", err)
//}
//if err = transaction.UseTrans(l.ctx, l.svcCtx.DB, func(ctx context.Context, conn transaction.Conn) error {
// if dm, err = l.svcCtx.ChatSessionRepository.Delete(l.ctx, conn, dm); err != nil {
// return err
// }
// return nil
//}, true); err != nil {
// return nil, xerr.NewErrMsgErr("移除失败", err)
//}
//return
// Search
//var (
// conn = l.svcCtx.DefaultDBConn()
// dms []*domain.ChatSession
// total int64
//)
//
//queryOptions := domain.NewQueryOptions().WithOffsetLimit(req.Page, req.Size).
// WithKV("", "")
//total, dms, err = l.svcCtx.ChatSessionRepository.Find(l.ctx, conn, queryOptions)
//list := make([]types.ChatSessionItem, 0)
//for i := range dms {
// list = append(list, NewTypesChatSession(dms[i]))
//}
//resp = &types.ChatSessionSearchResponse{
// List: list,
// Total: total,
//}
//return
// Update
//var (
// conn = l.svcCtx.DefaultDBConn()
// dm *domain.ChatSession
//)
//if dm, err = l.svcCtx.ChatSessionRepository.FindOne(l.ctx, conn, req.Id); err != nil {
// return nil, xerr.NewErrMsgErr("不存在", err)
//}
//// 不可编辑判断
//// 赋值
//// 更新
//if err = transaction.UseTrans(l.ctx, l.svcCtx.DB, func(ctx context.Context, conn transaction.Conn) error {
// dm, err = l.svcCtx.ChatSessionRepository.UpdateWithVersion(l.ctx, conn, dm)
// return err
//}, true); err != nil {
// return nil, xerr.NewErrMsg("更新失败")
//}
//resp = &types.ChatSessionUpdateResponse{}
//return
... ...
syntax = "v1"
info(
title: "xx实例"
desc: "xx实例"
author: "author"
email: "email"
version: "v1"
)
@server(
prefix: v1
group: chat_session_record
jwt: JwtAuth
)
service Core {
@doc "详情"
@handler chat_session_recordGet
get /chat_session_record/:id (ChatSessionRecordGetRequest) returns (ChatSessionRecordGetResponse)
@doc "保存"
@handler chat_session_recordSave
post /chat_session_record (ChatSessionRecordSaveRequest) returns (ChatSessionRecordSaveResponse)
@doc "删除"
@handler chat_session_recordDelete
delete /chat_session_record/:id (ChatSessionRecordDeleteRequest) returns (ChatSessionRecordDeleteResponse)
@doc "更新"
@handler chat_session_recordUpdate
put /chat_session_record/:id (ChatSessionRecordUpdateRequest) returns (ChatSessionRecordUpdateResponse)
@doc "搜索"
@handler chat_session_recordSearch
post /chat_session_record/search (ChatSessionRecordSearchRequest) returns (ChatSessionRecordSearchResponse)
}
type (
ChatSessionRecordGetRequest {
Id int64 `path:"id"`
}
ChatSessionRecordGetResponse {
ChatSessionRecord ChatSessionRecordItem `json:"chat_session_record"`
}
ChatSessionRecordSaveRequest {
ChatSessionRecord ChatSessionRecordItem `json:"chat_session_record"`
}
ChatSessionRecordSaveResponse {}
ChatSessionRecordDeleteRequest {
Id int64 `path:"id"`
}
ChatSessionRecordDeleteResponse {}
ChatSessionRecordUpdateRequest {
Id int64 `path:"id"`
ChatSessionRecord ChatSessionRecordItem `json:"chat_session_record"`
}
ChatSessionRecordUpdateResponse {}
ChatSessionRecordSearchRequest {
Page int `json:"page"`
Size int `json:"size"`
}
ChatSessionRecordSearchResponse{
List []ChatSessionRecordItem `json:"list"`
Total int64 `json:"total"`
}
ChatSessionRecordItem {
}
)
// logic CRUD
// Save
//var (
// conn = l.svcCtx.DefaultDBConn()
// dm *domain.ChatSessionRecord
//)
//// 唯一判断
//dm = NewDomainChatSessionRecord(req.ChatSessionRecord)
//if err = transaction.UseTrans(l.ctx, l.svcCtx.DB, func(ctx context.Context, conn transaction.Conn) error {
// dm, err = l.svcCtx.ChatSessionRecordRepository.Insert(l.ctx, conn, dm)
// return err
//}, true); err != nil {
// return nil, xerr.NewErrMsg("保存失败")
//}
////resp = &types.ChatSessionRecordSaveResponse{}
//return
//func NewDomainChatSessionRecord(item types.ChatSessionRecordItem) *domain.ChatSessionRecord {
// return &domain.ChatSessionRecord{
// }
//}
//
//func NewTypesChatSessionRecord(item *domain.ChatSessionRecord) types.ChatSessionRecordItem {
// return types.ChatSessionRecordItem{
// Id: item.Id,
// }
//}
// Get
//var (
// conn = l.svcCtx.DefaultDBConn()
// dm *domain.ChatSessionRecord
//)
//// 货号唯一
//if dm, err = l.svcCtx.ChatSessionRecordRepository.FindOne(l.ctx, conn, req.Id); err != nil {
// return nil, xerr.NewErrMsgErr("不存在", err)
//}
//resp = &types.ChatSessionRecordGetResponse{
// ChatSessionRecord: NewTypesChatSessionRecord(dm),
//}
//return
// Delete
//var (
// conn = l.svcCtx.DefaultDBConn()
// dm *domain.ChatSessionRecord
//)
//if dm, err = l.svcCtx.ChatSessionRecordRepository.FindOne(l.ctx, conn, req.Id); err != nil {
// return nil, xerr.NewErrMsgErr("不存在", err)
//}
//if err = transaction.UseTrans(l.ctx, l.svcCtx.DB, func(ctx context.Context, conn transaction.Conn) error {
// if dm, err = l.svcCtx.ChatSessionRecordRepository.Delete(l.ctx, conn, dm); err != nil {
// return err
// }
// return nil
//}, true); err != nil {
// return nil, xerr.NewErrMsgErr("移除失败", err)
//}
//return
// Search
//var (
// conn = l.svcCtx.DefaultDBConn()
// dms []*domain.ChatSessionRecord
// total int64
//)
//
//queryOptions := domain.NewQueryOptions().WithOffsetLimit(req.Page, req.Size).
// WithKV("", "")
//total, dms, err = l.svcCtx.ChatSessionRecordRepository.Find(l.ctx, conn, queryOptions)
//list := make([]types.ChatSessionRecordItem, 0)
//for i := range dms {
// list = append(list, NewTypesChatSessionRecord(dms[i]))
//}
//resp = &types.ChatSessionRecordSearchResponse{
// List: list,
// Total: total,
//}
//return
// Update
//var (
// conn = l.svcCtx.DefaultDBConn()
// dm *domain.ChatSessionRecord
//)
//if dm, err = l.svcCtx.ChatSessionRecordRepository.FindOne(l.ctx, conn, req.Id); err != nil {
// return nil, xerr.NewErrMsgErr("不存在", err)
//}
//// 不可编辑判断
//// 赋值
//// 更新
//if err = transaction.UseTrans(l.ctx, l.svcCtx.DB, func(ctx context.Context, conn transaction.Conn) error {
// dm, err = l.svcCtx.ChatSessionRecordRepository.UpdateWithVersion(l.ctx, conn, dm)
// return err
//}, true); err != nil {
// return nil, xerr.NewErrMsg("更新失败")
//}
//resp = &types.ChatSessionRecordUpdateResponse{}
//return
... ...
syntax = "proto3";
option go_package ="./pb";
package pb;
message ChatModelGetReq {
int64 Id = 1;
}
message ChatModelGetResp{
ChatModelItem ChatModel = 1;
}
message ChatModelSaveReq {
}
message ChatModelSaveResp{
}
message ChatModelDeleteReq {
int64 Id = 1;
}
message ChatModelDeleteResp{
}
message ChatModelUpdateReq {
int64 Id = 1;
}
message ChatModelUpdateResp{
}
message ChatModelSearchReq {
int64 PageNumber = 1;
int64 PageSize = 2;
}
message ChatModelSearchResp{
repeated ChatModelItem List =1;
int64 Total =2;
}
message ChatModelItem {
}
service ChatModelService {
rpc ChatModelGet(ChatModelGetReq) returns(ChatModelGetResp);
rpc ChatModelSave(ChatModelSaveReq) returns(ChatModelSaveResp);
rpc ChatModelDelete(ChatModelDeleteReq) returns(ChatModelDeleteResp);
rpc ChatModelUpdate(ChatModelUpdateReq) returns(ChatModelUpdateResp);
rpc ChatModelSearch(ChatModelSearchReq) returns(ChatModelSearchResp);
}
... ...
syntax = "proto3";
option go_package ="./pb";
package pb;
message ChatSessionGetReq {
int64 Id = 1;
}
message ChatSessionGetResp{
ChatSessionItem ChatSession = 1;
}
message ChatSessionSaveReq {
}
message ChatSessionSaveResp{
}
message ChatSessionDeleteReq {
int64 Id = 1;
}
message ChatSessionDeleteResp{
}
message ChatSessionUpdateReq {
int64 Id = 1;
}
message ChatSessionUpdateResp{
}
message ChatSessionSearchReq {
int64 PageNumber = 1;
int64 PageSize = 2;
}
message ChatSessionSearchResp{
repeated ChatSessionItem List =1;
int64 Total =2;
}
message ChatSessionItem {
}
service ChatSessionService {
rpc ChatSessionGet(ChatSessionGetReq) returns(ChatSessionGetResp);
rpc ChatSessionSave(ChatSessionSaveReq) returns(ChatSessionSaveResp);
rpc ChatSessionDelete(ChatSessionDeleteReq) returns(ChatSessionDeleteResp);
rpc ChatSessionUpdate(ChatSessionUpdateReq) returns(ChatSessionUpdateResp);
rpc ChatSessionSearch(ChatSessionSearchReq) returns(ChatSessionSearchResp);
}
... ...
syntax = "proto3";
option go_package ="./pb";
package pb;
message ChatSessionRecordGetReq {
int64 Id = 1;
}
message ChatSessionRecordGetResp{
ChatSessionRecordItem ChatSessionRecord = 1;
}
message ChatSessionRecordSaveReq {
}
message ChatSessionRecordSaveResp{
}
message ChatSessionRecordDeleteReq {
int64 Id = 1;
}
message ChatSessionRecordDeleteResp{
}
message ChatSessionRecordUpdateReq {
int64 Id = 1;
}
message ChatSessionRecordUpdateResp{
}
message ChatSessionRecordSearchReq {
int64 PageNumber = 1;
int64 PageSize = 2;
}
message ChatSessionRecordSearchResp{
repeated ChatSessionRecordItem List =1;
int64 Total =2;
}
message ChatSessionRecordItem {
}
service ChatSessionRecordService {
rpc ChatSessionRecordGet(ChatSessionRecordGetReq) returns(ChatSessionRecordGetResp);
rpc ChatSessionRecordSave(ChatSessionRecordSaveReq) returns(ChatSessionRecordSaveResp);
rpc ChatSessionRecordDelete(ChatSessionRecordDeleteReq) returns(ChatSessionRecordDeleteResp);
rpc ChatSessionRecordUpdate(ChatSessionRecordUpdateReq) returns(ChatSessionRecordUpdateResp);
rpc ChatSessionRecordSearch(ChatSessionRecordSearchReq) returns(ChatSessionRecordSearchResp);
}
... ...
package db
import (
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/internal/pkg/db/models"
"gorm.io/gorm"
)
func Migrate(db *gorm.DB) {
db.AutoMigrate(
&models.ChatSession{},
&models.ChatSessionRecord{},
)
}
... ...
package models
import (
"fmt"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/internal/pkg/domain"
"gorm.io/gorm"
"gorm.io/plugin/soft_delete"
)
type ChatModel struct {
Id int64 // 唯一标识
CreatedAt int64
UpdatedAt int64
DeletedAt int64
Version int
IsDel soft_delete.DeletedAt `gorm:"softDelete:flag,DeletedAtField:DeletedAt"`
}
func (m *ChatModel) TableName() string {
return "chat.model"
}
func (m *ChatModel) BeforeCreate(tx *gorm.DB) (err error) {
// m.CreatedAt = time.Now().Unix()
// m.UpdatedAt = time.Now().Unix()
return
}
func (m *ChatModel) BeforeUpdate(tx *gorm.DB) (err error) {
// m.UpdatedAt = time.Now().Unix()
return
}
func (m *ChatModel) CacheKeyFunc() string {
if m.Id == 0 {
return ""
}
return fmt.Sprintf("%v:cache:%v:id:%v", domain.ProjectName, m.TableName(), m.Id)
}
func (m *ChatModel) CacheKeyFuncByObject(obj interface{}) string {
if v, ok := obj.(*ChatModel); ok {
return v.CacheKeyFunc()
}
return ""
}
func (m *ChatModel) CachePrimaryKeyFunc() string {
if len("") == 0 {
return ""
}
return fmt.Sprintf("%v:cache:%v:primarykey:%v", domain.ProjectName, m.TableName(), "key")
}
... ...
package models
import (
"fmt"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/internal/pkg/domain"
"gorm.io/gorm"
"gorm.io/plugin/soft_delete"
)
type ChatSession struct {
Id int64 // 唯一标识
CompanyId int64 // 公司ID
UserId int64 // 用户ID
Title string // 会话标题
Abstract string // 摘要
CreatedAt int64
UpdatedAt int64
DeletedAt int64
Version int
IsDel soft_delete.DeletedAt `gorm:"softDelete:flag,DeletedAtField:DeletedAt"`
}
func (m *ChatSession) TableName() string {
return "chat.session"
}
func (m *ChatSession) BeforeCreate(tx *gorm.DB) (err error) {
// m.CreatedAt = time.Now().Unix()
// m.UpdatedAt = time.Now().Unix()
return
}
func (m *ChatSession) BeforeUpdate(tx *gorm.DB) (err error) {
// m.UpdatedAt = time.Now().Unix()
return
}
func (m *ChatSession) CacheKeyFunc() string {
if m.Id == 0 {
return ""
}
return fmt.Sprintf("%v:cache:%v:id:%v", domain.ProjectName, m.TableName(), m.Id)
}
func (m *ChatSession) CacheKeyFuncByObject(obj interface{}) string {
if v, ok := obj.(*ChatSession); ok {
return v.CacheKeyFunc()
}
return ""
}
func (m *ChatSession) CachePrimaryKeyFunc() string {
if len("") == 0 {
return ""
}
return fmt.Sprintf("%v:cache:%v:primarykey:%v", domain.ProjectName, m.TableName(), "key")
}
... ...
package models
import (
"fmt"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/internal/pkg/domain"
"gorm.io/gorm"
"gorm.io/plugin/soft_delete"
)
type ChatSessionRecord struct {
Id int64 // 唯一标识
Group int64 // 分组(一个问题多次重复提问)
CompanyId int64 // 公司ID
UserId int64 // 用户ID
SessionId int64 // 会话ID
ModelId int64 // 选择模型ID
Author domain.User `gorm:"type:jsonb;serializer:json"` // 作者
ContentType string // 内容类型 文本:text (图片:image 文档:document)
ProblemText string // 问题文本
AnswerText string // 回答文本
Metadata domain.Metadata `gorm:"type:jsonb;serializer:json"` // 记录元数据
Cost int64 // 花费时间 单位毫秒
Status string // 状态 处理中:processing 超时:finished_timeout 结束成功:finished_fail 结束失败:finished_success
CreatedAt int64
UpdatedAt int64
DeletedAt int64
Version int
IsDel soft_delete.DeletedAt `gorm:"softDelete:flag,DeletedAtField:DeletedAt"`
}
func (m *ChatSessionRecord) TableName() string {
return "chat.session_record"
}
func (m *ChatSessionRecord) BeforeCreate(tx *gorm.DB) (err error) {
// m.CreatedAt = time.Now().Unix()
// m.UpdatedAt = time.Now().Unix()
return
}
func (m *ChatSessionRecord) BeforeUpdate(tx *gorm.DB) (err error) {
// m.UpdatedAt = time.Now().Unix()
return
}
func (m *ChatSessionRecord) CacheKeyFunc() string {
if m.Id == 0 {
return ""
}
return fmt.Sprintf("%v:cache:%v:id:%v", domain.ProjectName, m.TableName(), m.Id)
}
func (m *ChatSessionRecord) CacheKeyFuncByObject(obj interface{}) string {
if v, ok := obj.(*ChatSessionRecord); ok {
return v.CacheKeyFunc()
}
return ""
}
func (m *ChatSessionRecord) CachePrimaryKeyFunc() string {
if len("") == 0 {
return ""
}
return fmt.Sprintf("%v:cache:%v:primarykey:%v", domain.ProjectName, m.TableName(), "key")
}
... ...
package repository
import (
"context"
"github.com/jinzhu/copier"
"github.com/pkg/errors"
"github.com/tiptok/gocomm/pkg/cache"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/internal/pkg/db/models"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/internal/pkg/domain"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/pkg/transaction"
"gorm.io/gorm"
)
type ChatModelRepository struct {
*cache.CachedRepository
}
func (repository *ChatModelRepository) Insert(ctx context.Context, conn transaction.Conn, dm *domain.ChatModel) (*domain.ChatModel, error) {
var (
err error
m = &models.ChatModel{}
tx = conn.DB()
)
if m, err = repository.DomainModelToModel(dm); err != nil {
return nil, err
}
if tx = tx.Model(m).Save(m); tx.Error != nil {
return nil, tx.Error
}
dm.Id = m.Id
return repository.ModelToDomainModel(m)
}
func (repository *ChatModelRepository) Update(ctx context.Context, conn transaction.Conn, dm *domain.ChatModel) (*domain.ChatModel, error) {
var (
err error
m *models.ChatModel
tx = conn.DB()
)
if m, err = repository.DomainModelToModel(dm); err != nil {
return nil, err
}
queryFunc := func() (interface{}, error) {
tx = tx.Model(m).Updates(m)
return nil, tx.Error
}
if _, err = repository.Query(queryFunc, m.CacheKeyFunc()); err != nil {
return nil, err
}
return repository.ModelToDomainModel(m)
}
func (repository *ChatModelRepository) UpdateWithVersion(ctx context.Context, transaction transaction.Conn, dm *domain.ChatModel) (*domain.ChatModel, error) {
var (
err error
m *models.ChatModel
tx = transaction.DB()
)
if m, err = repository.DomainModelToModel(dm); err != nil {
return nil, err
}
oldVersion := dm.Version
m.Version += 1
queryFunc := func() (interface{}, error) {
tx = tx.Model(m).Select("*").Where("id = ?", m.Id).Where("version = ?", oldVersion).Updates(m)
if tx.RowsAffected == 0 {
return nil, domain.ErrUpdateFail
}
return nil, tx.Error
}
if _, err = repository.Query(queryFunc, m.CacheKeyFunc()); err != nil {
return nil, err
}
return repository.ModelToDomainModel(m)
}
func (repository *ChatModelRepository) Delete(ctx context.Context, conn transaction.Conn, dm *domain.ChatModel) (*domain.ChatModel, error) {
var (
tx = conn.DB()
m = &models.ChatModel{Id: dm.Id}
)
queryFunc := func() (interface{}, error) {
tx = tx.Where("id = ?", m.Id).Delete(m)
return m, tx.Error
}
if _, err := repository.Query(queryFunc, m.CacheKeyFunc()); err != nil {
return dm, err
}
return repository.ModelToDomainModel(m)
}
func (repository *ChatModelRepository) FindOne(ctx context.Context, conn transaction.Conn, id int64) (*domain.ChatModel, error) {
var (
err error
tx = conn.DB()
m = new(models.ChatModel)
)
queryFunc := func() (interface{}, error) {
tx = tx.Model(m).Where("id = ?", id).First(m)
if errors.Is(tx.Error, gorm.ErrRecordNotFound) {
return nil, domain.ErrNotFound
}
return m, tx.Error
}
cacheModel := new(models.ChatModel)
cacheModel.Id = id
if err = repository.QueryCache(cacheModel.CacheKeyFunc, m, queryFunc); err != nil {
return nil, err
}
return repository.ModelToDomainModel(m)
}
func (repository *ChatModelRepository) FindOneUnscoped(ctx context.Context, conn transaction.Conn, id int64) (*domain.ChatModel, error) {
var (
err error
tx = conn.DB()
m = new(models.ChatModel)
)
queryFunc := func() (interface{}, error) {
tx = tx.Model(m).Unscoped().Where("id = ?", id).First(m)
if errors.Is(tx.Error, gorm.ErrRecordNotFound) {
return nil, domain.ErrNotFound
}
return m, tx.Error
}
cacheModel := new(models.ChatModel)
cacheModel.Id = id
if err = repository.QueryCache(cacheModel.CacheKeyFunc, m, queryFunc); err != nil {
return nil, err
}
return repository.ModelToDomainModel(m)
}
func (repository *ChatModelRepository) Find(ctx context.Context, conn transaction.Conn, queryOptions map[string]interface{}) (int64, []*domain.ChatModel, error) {
var (
tx = conn.DB()
ms []*models.ChatModel
dms = make([]*domain.ChatModel, 0)
total int64
)
queryFunc := func() (interface{}, error) {
tx = tx.Model(&ms).Order("id desc")
if total, tx = transaction.PaginationAndCount(ctx, tx, queryOptions, &ms); tx.Error != nil {
return dms, tx.Error
}
return dms, nil
}
if _, err := repository.Query(queryFunc); err != nil {
return 0, nil, err
}
for _, item := range ms {
if dm, err := repository.ModelToDomainModel(item); err != nil {
return 0, dms, err
} else {
dms = append(dms, dm)
}
}
return total, dms, nil
}
func (repository *ChatModelRepository) ModelToDomainModel(from *models.ChatModel) (*domain.ChatModel, error) {
to := &domain.ChatModel{}
err := copier.Copy(to, from)
return to, err
}
func (repository *ChatModelRepository) DomainModelToModel(from *domain.ChatModel) (*models.ChatModel, error) {
to := &models.ChatModel{}
err := copier.Copy(to, from)
return to, err
}
func NewChatModelRepository(cache *cache.CachedRepository) domain.ChatModelRepository {
return &ChatModelRepository{CachedRepository: cache}
}
... ...
package repository
import (
"context"
"github.com/jinzhu/copier"
"github.com/pkg/errors"
"github.com/tiptok/gocomm/pkg/cache"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/internal/pkg/db/models"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/internal/pkg/domain"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/pkg/transaction"
"gorm.io/gorm"
)
type ChatSessionRecordRepository struct {
*cache.CachedRepository
}
func (repository *ChatSessionRecordRepository) Insert(ctx context.Context, conn transaction.Conn, dm *domain.ChatSessionRecord) (*domain.ChatSessionRecord, error) {
var (
err error
m = &models.ChatSessionRecord{}
tx = conn.DB()
)
if m, err = repository.DomainModelToModel(dm); err != nil {
return nil, err
}
if tx = tx.Model(m).Save(m); tx.Error != nil {
return nil, tx.Error
}
dm.Id = m.Id
return repository.ModelToDomainModel(m)
}
func (repository *ChatSessionRecordRepository) Update(ctx context.Context, conn transaction.Conn, dm *domain.ChatSessionRecord) (*domain.ChatSessionRecord, error) {
var (
err error
m *models.ChatSessionRecord
tx = conn.DB()
)
if m, err = repository.DomainModelToModel(dm); err != nil {
return nil, err
}
queryFunc := func() (interface{}, error) {
tx = tx.Model(m).Updates(m)
return nil, tx.Error
}
if _, err = repository.Query(queryFunc, m.CacheKeyFunc()); err != nil {
return nil, err
}
return repository.ModelToDomainModel(m)
}
func (repository *ChatSessionRecordRepository) UpdateWithVersion(ctx context.Context, transaction transaction.Conn, dm *domain.ChatSessionRecord) (*domain.ChatSessionRecord, error) {
var (
err error
m *models.ChatSessionRecord
tx = transaction.DB()
)
if m, err = repository.DomainModelToModel(dm); err != nil {
return nil, err
}
oldVersion := dm.Version
m.Version += 1
queryFunc := func() (interface{}, error) {
tx = tx.Model(m).Select("*").Where("id = ?", m.Id).Where("version = ?", oldVersion).Updates(m)
if tx.RowsAffected == 0 {
return nil, domain.ErrUpdateFail
}
return nil, tx.Error
}
if _, err = repository.Query(queryFunc, m.CacheKeyFunc()); err != nil {
return nil, err
}
return repository.ModelToDomainModel(m)
}
func (repository *ChatSessionRecordRepository) Delete(ctx context.Context, conn transaction.Conn, dm *domain.ChatSessionRecord) (*domain.ChatSessionRecord, error) {
var (
tx = conn.DB()
m = &models.ChatSessionRecord{Id: dm.Id}
)
queryFunc := func() (interface{}, error) {
tx = tx.Where("id = ?", m.Id).Delete(m)
return m, tx.Error
}
if _, err := repository.Query(queryFunc, m.CacheKeyFunc()); err != nil {
return dm, err
}
return repository.ModelToDomainModel(m)
}
func (repository *ChatSessionRecordRepository) FindOne(ctx context.Context, conn transaction.Conn, id int64) (*domain.ChatSessionRecord, error) {
var (
err error
tx = conn.DB()
m = new(models.ChatSessionRecord)
)
queryFunc := func() (interface{}, error) {
tx = tx.Model(m).Where("id = ?", id).First(m)
if errors.Is(tx.Error, gorm.ErrRecordNotFound) {
return nil, domain.ErrNotFound
}
return m, tx.Error
}
cacheModel := new(models.ChatSessionRecord)
cacheModel.Id = id
if err = repository.QueryCache(cacheModel.CacheKeyFunc, m, queryFunc); err != nil {
return nil, err
}
return repository.ModelToDomainModel(m)
}
func (repository *ChatSessionRecordRepository) FindOneUnscoped(ctx context.Context, conn transaction.Conn, id int64) (*domain.ChatSessionRecord, error) {
var (
err error
tx = conn.DB()
m = new(models.ChatSessionRecord)
)
queryFunc := func() (interface{}, error) {
tx = tx.Model(m).Unscoped().Where("id = ?", id).First(m)
if errors.Is(tx.Error, gorm.ErrRecordNotFound) {
return nil, domain.ErrNotFound
}
return m, tx.Error
}
cacheModel := new(models.ChatSessionRecord)
cacheModel.Id = id
if err = repository.QueryCache(cacheModel.CacheKeyFunc, m, queryFunc); err != nil {
return nil, err
}
return repository.ModelToDomainModel(m)
}
func (repository *ChatSessionRecordRepository) Find(ctx context.Context, conn transaction.Conn, queryOptions map[string]interface{}) (int64, []*domain.ChatSessionRecord, error) {
var (
tx = conn.DB()
ms []*models.ChatSessionRecord
dms = make([]*domain.ChatSessionRecord, 0)
total int64
)
queryFunc := func() (interface{}, error) {
tx = tx.Model(&ms).Order("id asc")
if total, tx = transaction.PaginationAndCount(ctx, tx, queryOptions, &ms); tx.Error != nil {
return dms, tx.Error
}
return dms, nil
}
if _, err := repository.Query(queryFunc); err != nil {
return 0, nil, err
}
for _, item := range ms {
if dm, err := repository.ModelToDomainModel(item); err != nil {
return 0, dms, err
} else {
dms = append(dms, dm)
}
}
return total, dms, nil
}
func (repository *ChatSessionRecordRepository) FindByCompanyUser(ctx context.Context, conn transaction.Conn, companyId, userId int64, queryOptions map[string]interface{}) (int64, []*domain.ChatSessionRecord, error) {
var (
tx = conn.DB()
ms []*models.ChatSessionRecord
dms = make([]*domain.ChatSessionRecord, 0)
total int64
)
queryFunc := func() (interface{}, error) {
tx = tx.Model(&ms).Order("id asc")
tx.Where("company_id = ?", companyId).Where("user_id = ?", userId)
if v, ok := queryOptions["sessionId"]; ok {
tx.Where("session_id =?", v)
}
if total, tx = transaction.PaginationAndCount(ctx, tx, queryOptions, &ms); tx.Error != nil {
return dms, tx.Error
}
return dms, nil
}
if _, err := repository.Query(queryFunc); err != nil {
return 0, nil, err
}
for _, item := range ms {
if dm, err := repository.ModelToDomainModel(item); err != nil {
return 0, dms, err
} else {
dms = append(dms, dm)
}
}
return total, dms, nil
}
func (repository *ChatSessionRecordRepository) ModelToDomainModel(from *models.ChatSessionRecord) (*domain.ChatSessionRecord, error) {
to := &domain.ChatSessionRecord{}
err := copier.Copy(to, from)
return to, err
}
func (repository *ChatSessionRecordRepository) DomainModelToModel(from *domain.ChatSessionRecord) (*models.ChatSessionRecord, error) {
to := &models.ChatSessionRecord{}
err := copier.Copy(to, from)
return to, err
}
func NewChatSessionRecordRepository(cache *cache.CachedRepository) domain.ChatSessionRecordRepository {
return &ChatSessionRecordRepository{CachedRepository: cache}
}
... ...
package repository
import (
"context"
"github.com/jinzhu/copier"
"github.com/pkg/errors"
"github.com/tiptok/gocomm/pkg/cache"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/internal/pkg/db/models"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/chat/internal/pkg/domain"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/pkg/transaction"
"gorm.io/gorm"
)
type ChatSessionRepository struct {
*cache.CachedRepository
}
func (repository *ChatSessionRepository) Insert(ctx context.Context, conn transaction.Conn, dm *domain.ChatSession) (*domain.ChatSession, error) {
var (
err error
m = &models.ChatSession{}
tx = conn.DB()
)
if m, err = repository.DomainModelToModel(dm); err != nil {
return nil, err
}
if tx = tx.Model(m).Save(m); tx.Error != nil {
return nil, tx.Error
}
dm.Id = m.Id
return repository.ModelToDomainModel(m)
}
func (repository *ChatSessionRepository) Update(ctx context.Context, conn transaction.Conn, dm *domain.ChatSession) (*domain.ChatSession, error) {
var (
err error
m *models.ChatSession
tx = conn.DB()
)
if m, err = repository.DomainModelToModel(dm); err != nil {
return nil, err
}
queryFunc := func() (interface{}, error) {
tx = tx.Model(m).Updates(m)
return nil, tx.Error
}
if _, err = repository.Query(queryFunc, m.CacheKeyFunc()); err != nil {
return nil, err
}
return repository.ModelToDomainModel(m)
}
func (repository *ChatSessionRepository) UpdateWithVersion(ctx context.Context, transaction transaction.Conn, dm *domain.ChatSession) (*domain.ChatSession, error) {
var (
err error
m *models.ChatSession
tx = transaction.DB()
)
if m, err = repository.DomainModelToModel(dm); err != nil {
return nil, err
}
oldVersion := dm.Version
m.Version += 1
queryFunc := func() (interface{}, error) {
tx = tx.Model(m).Select("*").Where("id = ?", m.Id).Where("version = ?", oldVersion).Updates(m)
if tx.RowsAffected == 0 {
return nil, domain.ErrUpdateFail
}
return nil, tx.Error
}
if _, err = repository.Query(queryFunc, m.CacheKeyFunc()); err != nil {
return nil, err
}
return repository.ModelToDomainModel(m)
}
func (repository *ChatSessionRepository) Delete(ctx context.Context, conn transaction.Conn, dm *domain.ChatSession) (*domain.ChatSession, error) {
var (
tx = conn.DB()
m = &models.ChatSession{Id: dm.Id}
)
queryFunc := func() (interface{}, error) {
tx = tx.Where("id = ?", m.Id).Delete(m)
return m, tx.Error
}
if _, err := repository.Query(queryFunc, m.CacheKeyFunc()); err != nil {
return dm, err
}
return repository.ModelToDomainModel(m)
}
func (repository *ChatSessionRepository) FindOne(ctx context.Context, conn transaction.Conn, id int64) (*domain.ChatSession, error) {
var (
err error
tx = conn.DB()
m = new(models.ChatSession)
)
queryFunc := func() (interface{}, error) {
tx = tx.Model(m).Where("id = ?", id).First(m)
if errors.Is(tx.Error, gorm.ErrRecordNotFound) {
return nil, domain.ErrNotFound
}
return m, tx.Error
}
cacheModel := new(models.ChatSession)
cacheModel.Id = id
if err = repository.QueryCache(cacheModel.CacheKeyFunc, m, queryFunc); err != nil {
return nil, err
}
return repository.ModelToDomainModel(m)
}
func (repository *ChatSessionRepository) FindOneUnscoped(ctx context.Context, conn transaction.Conn, id int64) (*domain.ChatSession, error) {
var (
err error
tx = conn.DB()
m = new(models.ChatSession)
)
queryFunc := func() (interface{}, error) {
tx = tx.Model(m).Unscoped().Where("id = ?", id).First(m)
if errors.Is(tx.Error, gorm.ErrRecordNotFound) {
return nil, domain.ErrNotFound
}
return m, tx.Error
}
cacheModel := new(models.ChatSession)
cacheModel.Id = id
if err = repository.QueryCache(cacheModel.CacheKeyFunc, m, queryFunc); err != nil {
return nil, err
}
return repository.ModelToDomainModel(m)
}
func (repository *ChatSessionRepository) Find(ctx context.Context, conn transaction.Conn, queryOptions map[string]interface{}) (int64, []*domain.ChatSession, error) {
var (
tx = conn.DB()
ms []*models.ChatSession
dms = make([]*domain.ChatSession, 0)
total int64
)
queryFunc := func() (interface{}, error) {
tx = tx.Model(&ms).Order("id desc")
if v, ok := queryOptions["title"]; ok {
tx.Where("title like ?", v)
}
if total, tx = transaction.PaginationAndCount(ctx, tx, queryOptions, &ms); tx.Error != nil {
return dms, tx.Error
}
return dms, nil
}
if _, err := repository.Query(queryFunc); err != nil {
return 0, nil, err
}
for _, item := range ms {
if dm, err := repository.ModelToDomainModel(item); err != nil {
return 0, dms, err
} else {
dms = append(dms, dm)
}
}
return total, dms, nil
}
func (repository *ChatSessionRepository) ModelToDomainModel(from *models.ChatSession) (*domain.ChatSession, error) {
to := &domain.ChatSession{}
err := copier.Copy(to, from)
return to, err
}
func (repository *ChatSessionRepository) DomainModelToModel(from *domain.ChatSession) (*models.ChatSession, error) {
to := &models.ChatSession{}
err := copier.Copy(to, from)
return to, err
}
func NewChatSessionRepository(cache *cache.CachedRepository) domain.ChatSessionRepository {
return &ChatSessionRepository{CachedRepository: cache}
}
... ...
package domain
import (
"context"
"github.com/samber/lo"
"github.com/sashabaranov/go-openai"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/pkg/transaction"
)
type ChatModel struct {
Id int64 `json:",omitempty"` // 唯一标识
Name string `json:",omitempty"`
Code string `json:",omitempty"`
Logo string `json:",omitempty"`
Config ModelConfig `json:",omitempty"`
CreatedAt int64 `json:",omitempty"`
UpdatedAt int64 `json:",omitempty"`
DeletedAt int64 `json:",omitempty"`
Version int `json:",omitempty"`
}
type ChatModelRepository interface {
Insert(ctx context.Context, conn transaction.Conn, dm *ChatModel) (*ChatModel, error)
Update(ctx context.Context, conn transaction.Conn, dm *ChatModel) (*ChatModel, error)
UpdateWithVersion(ctx context.Context, conn transaction.Conn, dm *ChatModel) (*ChatModel, error)
Delete(ctx context.Context, conn transaction.Conn, dm *ChatModel) (*ChatModel, error)
FindOne(ctx context.Context, conn transaction.Conn, id int64) (*ChatModel, error)
FindOneUnscoped(ctx context.Context, conn transaction.Conn, id int64) (*ChatModel, error)
Find(ctx context.Context, conn transaction.Conn, queryOptions map[string]interface{}) (int64, []*ChatModel, error)
}
type ChatModels []*ChatModel
func (list ChatModels) Match(id int64) (*ChatModel, bool) {
return lo.Find(list, func(item *ChatModel) bool {
if item.Id == id {
return true
}
return false
})
}
var DefaultChatModels ChatModels = []*ChatModel{
NewChatModels(1, "ChatGPT 4o", openai.GPT4o, "", NewModelConfig("", "sk-proj-0odTHgsYqzGpjPMWYuw2T3BlbkFJpaIsQ9I6j8kYc8P7l60H", "")),
NewChatModels(2, "ChatGPT 4-turbo", openai.GPT4Turbo, "", NewModelConfig("", "sk-proj-0odTHgsYqzGpjPMWYuw2T3BlbkFJpaIsQ9I6j8kYc8P7l60H", "")),
NewChatModels(3, "ChatGPT 3.5", openai.GPT3Dot5Turbo, "", NewModelConfig("", "sk-proj-0odTHgsYqzGpjPMWYuw2T3BlbkFJpaIsQ9I6j8kYc8P7l60H", "")),
NewChatModels(4, "星火大模型V3.5", "spark3.5", "", NewModelConfig("4fd8694e", "4a4081a20e9ba0fb1b9686ed93221989", "NTVkM2FjNzk2NzQ5MzBkNWMwYTUwNjAz")),
}
type ModelConfig struct {
AppId string
AppKey string
AppSecret string
}
func NewModelConfig(appid, appKey, appSecret string) ModelConfig {
return ModelConfig{
AppId: appid,
AppKey: appKey,
AppSecret: appSecret,
}
}
func NewChatModels(id int64, name, code string, logo string, config ModelConfig) *ChatModel {
return &ChatModel{
Id: id,
Name: name,
Code: code,
Logo: logo,
Config: config,
}
}
... ...
package domain
import (
"context"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/pkg/transaction"
)
type ChatSession struct {
Id int64 `json:",omitempty"` // 唯一标识
CompanyId int64 `json:",omitempty"` // 公司ID
UserId int64 `json:",omitempty"` // 用户ID
Title string `json:",omitempty"` // 会话标题
Abstract string `json:",omitempty"` // 摘要
CreatedAt int64 `json:",omitempty"`
UpdatedAt int64 `json:",omitempty"`
DeletedAt int64 `json:",omitempty"`
Version int `json:",omitempty"`
}
type ChatSessionRepository interface {
Insert(ctx context.Context, conn transaction.Conn, dm *ChatSession) (*ChatSession, error)
Update(ctx context.Context, conn transaction.Conn, dm *ChatSession) (*ChatSession, error)
UpdateWithVersion(ctx context.Context, conn transaction.Conn, dm *ChatSession) (*ChatSession, error)
Delete(ctx context.Context, conn transaction.Conn, dm *ChatSession) (*ChatSession, error)
FindOne(ctx context.Context, conn transaction.Conn, id int64) (*ChatSession, error)
FindOneUnscoped(ctx context.Context, conn transaction.Conn, id int64) (*ChatSession, error)
Find(ctx context.Context, conn transaction.Conn, queryOptions map[string]interface{}) (int64, []*ChatSession, error)
}
... ...
package domain
import (
"context"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/pkg/transaction"
)
type ChatSessionRecord struct {
Id int64 // 唯一标识
Group int64 // 分组(一个问题多次重复提问)
CompanyId int64 // 公司ID
UserId int64 // 用户ID
SessionId int64 // 会话ID
ModelId int64 // 选择模型ID
Author User // 作者
ContentType string // 内容类型 文本:text (图片:image 文档:document)
ProblemText string // 问题文本
AnswerText string // 回答文本
Metadata Metadata // 记录元数据
Cost int64 // 花费时间 单位毫秒
Status string // 状态 处理中:processing 超时:finished_timeout 结束成功:finished_fail 结束失败:finished_success
CreatedAt int64 `json:",omitempty"`
UpdatedAt int64 `json:",omitempty"`
DeletedAt int64 `json:",omitempty"`
Version int `json:",omitempty"`
}
const (
Processing = "processing"
FinishedTimeout = "finished_timeout"
FinishedFail = "finished_fail"
FinishedSuccess = "finished_success"
)
type User struct {
Id int64
Name string
Avatar string
Role string // 角色类型 用户:user 模型:model
}
type Metadata struct {
FailReason string // 失败原因
}
type ChatSessionRecordRepository interface {
Insert(ctx context.Context, conn transaction.Conn, dm *ChatSessionRecord) (*ChatSessionRecord, error)
Update(ctx context.Context, conn transaction.Conn, dm *ChatSessionRecord) (*ChatSessionRecord, error)
UpdateWithVersion(ctx context.Context, conn transaction.Conn, dm *ChatSessionRecord) (*ChatSessionRecord, error)
Delete(ctx context.Context, conn transaction.Conn, dm *ChatSessionRecord) (*ChatSessionRecord, error)
FindOne(ctx context.Context, conn transaction.Conn, id int64) (*ChatSessionRecord, error)
FindOneUnscoped(ctx context.Context, conn transaction.Conn, id int64) (*ChatSessionRecord, error)
Find(ctx context.Context, conn transaction.Conn, queryOptions map[string]interface{}) (int64, []*ChatSessionRecord, error)
FindByCompanyUser(ctx context.Context, conn transaction.Conn, companyId, userId int64, queryOptions map[string]interface{}) (int64, []*ChatSessionRecord, error)
}
... ...
package domain
import (
"context"
"fmt"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/pkg/transaction"
"reflect"
)
func OffsetLimit(page, size int) (offset int, limit int) {
if page == 0 {
page = 1
}
if size == 0 {
size = 20
}
offset = (page - 1) * size
limit = size
return
}
type QueryOptions map[string]interface{}
func NewQueryOptions() QueryOptions {
options := make(map[string]interface{})
return options
}
func (options QueryOptions) WithOffsetLimit(page, size int) QueryOptions {
offset, limit := OffsetLimit(page, size)
options["offset"] = offset
options["limit"] = limit
return options
}
func (options QueryOptions) WithKV(key string, value interface{}) QueryOptions {
if isEmptyOrZeroValue(value) {
return options
}
options[key] = value
return options
}
func isEmptyOrZeroValue(i interface{}) bool {
if i == nil {
return true // 如果接口为空,返回true
}
// 使用反射判断接口的值是否为零值
v := reflect.ValueOf(i)
switch v.Kind() {
case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice, reflect.String:
return v.Len() == 0
case reflect.Bool:
return !v.Bool()
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return v.Int() == 0
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return v.Uint() == 0
case reflect.Float32, reflect.Float64:
return v.Float() == 0
case reflect.Interface, reflect.Ptr:
return v.IsNil()
default:
return false // 其他类型默认不为空
}
}
func (options QueryOptions) MustWithKV(key string, value interface{}) QueryOptions {
options[key] = value
return options
}
func (options QueryOptions) Copy() QueryOptions {
newOptions := NewQueryOptions()
for k, v := range options {
newOptions[k] = v
}
return newOptions
}
type IndexQueryOptionFunc func() QueryOptions
// 自定义的一些查询条件
func (options QueryOptions) WithCountOnly() QueryOptions {
options["countOnly"] = true
return options
}
func (options QueryOptions) WithFindOnly() QueryOptions {
options["findOnly"] = true
return options
}
func LazyLoad[K comparable, T any](source map[K]T, ctx context.Context, conn transaction.Conn, k K, load func(context.Context, transaction.Conn, K) (T, error)) (T, error) {
if isEmptyOrZeroValue(k) {
var t T
return t, fmt.Errorf("empty key ‘%v’", k)
}
if v, ok := source[k]; ok {
return v, nil
}
if v, err := load(ctx, conn, k); err != nil {
return v, err
} else {
source[k] = v
return v, nil
}
}
func Values[T any, V any](list []T, each func(item T) V) []V {
var result []V
for _, item := range list {
value := each(item)
result = append(result, value)
}
return result
}
... ...
package domain
import (
"errors"
"github.com/zeromicro/go-zero/core/stores/sqlx"
)
var (
ErrNotFound = sqlx.ErrNotFound
ErrUpdateFail = errors.New("sql: no rows affected")
)
var ProjectName = "project"
... ...
.PHONY: model
model:
goctl model mysql ddl -s .\cmd\ep\system\deploy\database\table.sql -d cmd/ep/system
.PHONY: api
api:
goctl api go -api .\cmd\ep\system\dsl\core.api -dir cmd/ep/system/api -style go_zero
.PHONY: swagger
swagger:
goctl api plugin -plugin goctl-swagger="swagger -filename core.json" -api .\cmd\ep\system\dsl\core.api -dir .\cmd\ep\system\generate
.PHONY: build
build:
docker build -f cmd/ep/system/deploy/docker/Dockerfile -t sumicro/system:1.0.0 .
... ...
package main
import (
"flag"
"fmt"
"github.com/zeromicro/go-zero/core/logx"
"github.com/zeromicro/go-zero/rest/httpx"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/system/api/internal/config"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/system/api/internal/handler"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/system/api/internal/svc"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/system/internal/pkg/db"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/system/internal/pkg/domain"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/pkg/gateway/smslib"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/pkg/xerr"
"net/http"
"github.com/zeromicro/go-zero/core/conf"
"github.com/zeromicro/go-zero/rest"
)
var configFile = flag.String("f", "etc/core.yaml", "the config file")
func main() {
flag.Parse()
var c config.Config
conf.MustLoad(*configFile, &c)
// 系统设置
systemSetup(c)
// 服务初始化
opts := make([]rest.RunOption, 0)
opts = append(opts, rest.WithCustomCors(func(header http.Header) {
header.Set("Access-Control-Allow-Headers", "*")
}, func(writer http.ResponseWriter) {
}))
opts = append(opts, rest.WithUnauthorizedCallback(func(w http.ResponseWriter, r *http.Request, err error) {
if err != nil {
logx.Debugf("unauthorized: %s \n", err.Error())
}
httpx.WriteJson(w, http.StatusUnauthorized, xerr.Error(xerr.TokenExpireError, err.Error()))
return
}))
server := rest.MustNewServer(c.RestConf, opts...)
defer server.Stop()
ctx := svc.NewServiceContext(c)
handler.RegisterHandlers(server, ctx)
server.AddRoutes(RoutersOpenapi(ctx))
// 数据迁移
if c.Migrate {
db.Migrate(ctx.DB)
}
fmt.Printf("Starting server at %s:%d...\n", c.Host, c.Port)
server.Start()
}
func systemSetup(c config.Config) {
// 初始化Domain里面的配置
domain.ProjectName = c.Name
// 系统错误应答包装
httpx.SetErrorHandlerCtx(xerr.ErrorHandlerCtx)
// 系统成功应答包装
httpx.SetOkHandler(xerr.OkHandlerCtx)
}
func RoutersOpenapi(svc *svc.ServiceContext) []rest.Route {
return []rest.Route{
{
Method: http.MethodPost,
Path: "/openapi/sms/send-sms-code",
Handler: smslib.SendSmsCodeHandler(svc.SmsService),
},
}
}
... ...
Name: sumicro-system
Host: 0.0.0.0
Port: 8080
Verbose: false
Migrate: true
Timeout: 30000
LogRequest: true # 记录详细请求日志
Log:
#Mode: file
Encoding: plain
Level: debug # info
MaxSize: 1 # 2MB
TimeFormat: 2006-01-02 15:04:05
Rotation: size
MaxContentLength: 10240
SystemAuth:
AccessSecret: su-platform
AccessExpire: 360000
Redis:
Host: 127.0.0.1:6379
Type: node
Pass:
DB:
DataSource: host=114.55.200.59 user=postgres password=eagle1010 dbname=su_enterprise_platform port=31543 sslmode=disable TimeZone=Asia/Shanghai
... ...
package config
import (
"github.com/zeromicro/go-zero/core/stores/redis"
"github.com/zeromicro/go-zero/rest"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/pkg/config"
)
type Config struct {
rest.RestConf
config.Config
Redis redis.RedisConf `json:",optional"`
SystemAuth config.Auth
DebugSmsCode string `json:",optional,default=999512"`
}
... ...
package auth
import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/system/api/internal/logic/auth"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/system/api/internal/svc"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/system/api/internal/types"
)
func SystemAuthLoginHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.AuthLoginRequest
if err := httpx.Parse(r, &req); err != nil {
httpx.ErrorCtx(r.Context(), w, err)
return
}
l := auth.NewSystemAuthLoginLogic(r.Context(), svcCtx)
resp, err := l.SystemAuthLogin(&req)
if err != nil {
httpx.ErrorCtx(r.Context(), w, err)
} else {
httpx.OkJsonCtx(r.Context(), w, resp)
}
}
}
... ...
package auth
import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/system/api/internal/logic/auth"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/system/api/internal/svc"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/system/api/internal/types"
)
func SystemAuthRegisterHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.CompanyRegisterRequest
if err := httpx.Parse(r, &req); err != nil {
httpx.ErrorCtx(r.Context(), w, err)
return
}
l := auth.NewSystemAuthRegisterLogic(r.Context(), svcCtx)
resp, err := l.SystemAuthRegister(&req)
if err != nil {
httpx.ErrorCtx(r.Context(), w, err)
} else {
httpx.OkJsonCtx(r.Context(), w, resp)
}
}
}
... ...
package auth
import (
"gitlab.fjmaimaimai.com/allied-creation/su-micro/pkg/contextdata"
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/system/api/internal/logic/auth"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/system/api/internal/svc"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/system/api/internal/types"
)
func SystemAuthUserInfoHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.UserInfoRequest
if err := httpx.Parse(r, &req); err != nil {
httpx.ErrorCtx(r.Context(), w, err)
return
}
token := contextdata.GetUserTokenFromCtx(r.Context())
req.UserId = token.UserId
req.CompanyId = token.CompanyId
req.EmployeeId = token.EmployeeId
l := auth.NewSystemAuthUserInfoLogic(r.Context(), svcCtx)
resp, err := l.SystemAuthUserInfo(&req)
if err != nil {
httpx.ErrorCtx(r.Context(), w, err)
} else {
httpx.OkJsonCtx(r.Context(), w, resp)
}
}
}
... ...
package department
import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/system/api/internal/logic/department"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/system/api/internal/svc"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/system/api/internal/types"
)
func SystemDepartmentBatchDeleteHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.DepartmentBatchDeleteRequest
if err := httpx.Parse(r, &req); err != nil {
httpx.ErrorCtx(r.Context(), w, err)
return
}
l := department.NewSystemDepartmentBatchDeleteLogic(r.Context(), svcCtx)
resp, err := l.SystemDepartmentBatchDelete(&req)
if err != nil {
httpx.ErrorCtx(r.Context(), w, err)
} else {
httpx.OkJsonCtx(r.Context(), w, resp)
}
}
}
... ...
package department
import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/system/api/internal/logic/department"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/system/api/internal/svc"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/system/api/internal/types"
)
func SystemDepartmentDeleteHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.DepartmentDeleteRequest
if err := httpx.Parse(r, &req); err != nil {
httpx.ErrorCtx(r.Context(), w, err)
return
}
l := department.NewSystemDepartmentDeleteLogic(r.Context(), svcCtx)
resp, err := l.SystemDepartmentDelete(&req)
if err != nil {
httpx.ErrorCtx(r.Context(), w, err)
} else {
httpx.OkJsonCtx(r.Context(), w, resp)
}
}
}
... ...
package department
import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/system/api/internal/logic/department"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/system/api/internal/svc"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/system/api/internal/types"
)
func SystemDepartmentExportHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.DepartmentSearchRequest
if err := httpx.Parse(r, &req); err != nil {
httpx.ErrorCtx(r.Context(), w, err)
return
}
l := department.NewSystemDepartmentExportLogic(r.Context(), svcCtx)
resp, err := l.SystemDepartmentExport(&req)
if err != nil {
httpx.ErrorCtx(r.Context(), w, err)
} else {
httpx.OkJsonCtx(r.Context(), w, resp)
}
}
}
... ...
package department
import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/system/api/internal/logic/department"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/system/api/internal/svc"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/system/api/internal/types"
)
func SystemDepartmentGetHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.DepartmentGetRequest
if err := httpx.Parse(r, &req); err != nil {
httpx.ErrorCtx(r.Context(), w, err)
return
}
l := department.NewSystemDepartmentGetLogic(r.Context(), svcCtx)
resp, err := l.SystemDepartmentGet(&req)
if err != nil {
httpx.ErrorCtx(r.Context(), w, err)
} else {
httpx.OkJsonCtx(r.Context(), w, resp)
}
}
}
... ...
package department
import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/system/api/internal/logic/department"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/system/api/internal/svc"
"gitlab.fjmaimaimai.com/allied-creation/su-micro/cmd/ep/system/api/internal/types"
)
func SystemDepartmentImportHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.DepartmentImportRequest
if err := httpx.Parse(r, &req); err != nil {
httpx.ErrorCtx(r.Context(), w, err)
return
}
l := department.NewSystemDepartmentImportLogic(r.Context(), svcCtx)
resp, err := l.SystemDepartmentImport(&req)
if err != nil {
httpx.ErrorCtx(r.Context(), w, err)
} else {
httpx.OkJsonCtx(r.Context(), w, resp)
}
}
}
... ...