From b8e5aba27c59c554cff8994a2c04107d275db05e Mon Sep 17 00:00:00 2001 From: "DESKTOP-V763RJ7\\Administrator" <835606593@qq.com> Date: Mon, 12 Jan 2026 16:53:48 +0800 Subject: [PATCH] =?UTF-8?q?feat=20=E6=8B=86=E5=87=BAqgdzs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- go.mod | 4 +- go.sum | 4 +- internal/ai/ai_client.go | 55 --- internal/ai/ai_request.go | 82 ---- internal/dao/model/questions.gen.go | 42 -- internal/dao/query/gen.go | 24 +- internal/dao/query/questions.gen.go | 367 ------------------ internal/dao/repository/questions.go | 83 ---- internal/grpc_server/server/a_test.go | 11 - .../grpc_server/server/server_question.go | 156 -------- .../server/server_question_temp.go | 161 -------- internal/grpc_server/stream_client/gateway.go | 84 ---- 12 files changed, 13 insertions(+), 1060 deletions(-) delete mode 100644 internal/ai/ai_client.go delete mode 100644 internal/ai/ai_request.go delete mode 100644 internal/dao/model/questions.gen.go delete mode 100644 internal/dao/query/questions.gen.go delete mode 100644 internal/dao/repository/questions.go delete mode 100644 internal/grpc_server/server/a_test.go delete mode 100644 internal/grpc_server/server/server_question.go delete mode 100644 internal/grpc_server/server/server_question_temp.go delete mode 100644 internal/grpc_server/stream_client/gateway.go diff --git a/go.mod b/go.mod index 44c4cec..3e3aa31 100644 --- a/go.mod +++ b/go.mod @@ -3,10 +3,9 @@ module git.hlsq.asia/mmorpg/service-user go 1.23.1 require ( - git.hlsq.asia/mmorpg/service-common v0.0.0-20260112040622-d433cd03a956 + git.hlsq.asia/mmorpg/service-common v0.0.0-20260112082258-b1e7d33940d7 github.com/judwhite/go-svc v1.2.1 google.golang.org/grpc v1.71.1 - google.golang.org/protobuf v1.36.9 gorm.io/gen v0.3.27 gorm.io/gorm v1.31.1 gorm.io/plugin/dbresolver v1.6.2 @@ -81,6 +80,7 @@ require ( golang.org/x/tools v0.35.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb // indirect + google.golang.org/protobuf v1.36.9 // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect gorm.io/datatypes v1.2.4 // indirect diff --git a/go.sum b/go.sum index e9e8c86..4d8b631 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= -git.hlsq.asia/mmorpg/service-common v0.0.0-20260112040622-d433cd03a956 h1:UfdH/8hH1MOnWzsMEvI8e31O7u5IJO5NaJjgK+BR1iY= -git.hlsq.asia/mmorpg/service-common v0.0.0-20260112040622-d433cd03a956/go.mod h1:xv6m1I2jUA6mudKVznygpnzMoshBQarthHD1QnkW4qc= +git.hlsq.asia/mmorpg/service-common v0.0.0-20260112082258-b1e7d33940d7 h1:C3quCA54dyFgmlCVgJXx+0rNqa+JZgGggdotbvHAsnA= +git.hlsq.asia/mmorpg/service-common v0.0.0-20260112082258-b1e7d33940d7/go.mod h1:xv6m1I2jUA6mudKVznygpnzMoshBQarthHD1QnkW4qc= github.com/BurntSushi/toml v1.2.0 h1:Rt8g24XnyGTyglgET/PRUNlrUeu9F5L+7FilkXfZgs0= github.com/BurntSushi/toml v1.2.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= diff --git a/internal/ai/ai_client.go b/internal/ai/ai_client.go deleted file mode 100644 index 35153c2..0000000 --- a/internal/ai/ai_client.go +++ /dev/null @@ -1,55 +0,0 @@ -package ai - -import ( - "git.hlsq.asia/mmorpg/service-common/log" -) - -type Client struct { - enableSearch bool // 是否开启搜索 - searchStrategy string // 搜索策略(开了搜索才生效) - temperature float32 // 采样温度 -} - -func NewAIClient(enableSearch bool, searchStrategy string, temperature float32) *Client { - return &Client{ - enableSearch: enableSearch, - searchStrategy: searchStrategy, - temperature: temperature, - } -} - -func (c *Client) RequestAI(prompt []string, cb func(content string, i int) error) error { - inToken, outToken := int32(0), int32(0) - messages := make([]Message, 0) - for i, step := range prompt { - messages = append(messages, Message{ - Role: "user", - Content: step, - }) - r, err := request("deepseek-v3.2", Parameters{ - EnableSearch: c.enableSearch, - SearchOptions: SearchOptions{ - SearchStrategy: c.searchStrategy, - }, - ResultFormat: "message", - Temperature: c.temperature, - }, messages) - if err != nil { - return err - } - inToken += r.Usage.InputTokens - outToken += r.Usage.OutputTokens - if len(r.Output.Choices) == 0 { - log.Infof("AI response err, r: %#+v", r) - return err - } else { - messages = append(messages, r.Output.Choices[0].Message) - } - log.Infof("AI 回答 %v: %v", i, r.Output.Choices[0].Message.Content) - if err = cb(r.Output.Choices[0].Message.Content, i); err != nil { - return err - } - } - log.Infof("AI finished, use token: in-%v out-%v", inToken, outToken) - return nil -} diff --git a/internal/ai/ai_request.go b/internal/ai/ai_request.go deleted file mode 100644 index 8c37496..0000000 --- a/internal/ai/ai_request.go +++ /dev/null @@ -1,82 +0,0 @@ -package ai - -import ( - "bytes" - "encoding/json" - "io" - "net/http" -) - -type Message struct { - Role string `json:"role"` - Content string `json:"content"` -} - -type Input struct { - Messages []Message `json:"messages"` -} - -type Parameters struct { - EnableSearch bool `json:"enable_search,omitempty"` - SearchOptions SearchOptions `json:"search_options,omitempty"` - ResultFormat string `json:"result_format,omitempty"` - Temperature float32 `json:"temperature,omitempty"` -} - -type SearchOptions struct { - SearchStrategy string `json:"search_strategy"` -} - -type RequestBody struct { - Model string `json:"model"` - Input Input `json:"input"` - Parameters Parameters `json:"parameters"` -} - -type ResponseBody struct { - Output struct { - Choices []struct { - Message Message `json:"message"` - FinishReason string `json:"finish_reason"` - } `json:"choices"` - } `json:"output"` - Usage struct { - InputTokens int32 `json:"input_tokens"` - OutputTokens int32 `json:"output_tokens"` - TotalTokens int32 `json:"total_tokens"` - } `json:"usage"` -} - -func request(model string, parameters Parameters, messages []Message) (*ResponseBody, error) { - requestBody := RequestBody{ - Model: model, - Input: Input{ - Messages: messages, - }, - Parameters: parameters, - } - jsonData, _ := json.Marshal(requestBody) - - req, err := http.NewRequest("POST", "https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation", bytes.NewBuffer(jsonData)) - if err != nil { - return nil, err - } - req.Header.Set("Authorization", "Bearer "+"sk-4daf94ad2fa94288b198d2a1d8924cef") - req.Header.Set("Content-Type", "application/json") - - resp, err := (&http.Client{}).Do(req) - if err != nil { - return nil, err - } - defer resp.Body.Close() - - body, err := io.ReadAll(resp.Body) - if err != nil { - return nil, err - } - var res ResponseBody - if err = json.Unmarshal(body, &res); err != nil { - return nil, err - } - return &res, nil -} diff --git a/internal/dao/model/questions.gen.go b/internal/dao/model/questions.gen.go deleted file mode 100644 index d30d358..0000000 --- a/internal/dao/model/questions.gen.go +++ /dev/null @@ -1,42 +0,0 @@ -// Code generated by gorm.io/gen. DO NOT EDIT. -// Code generated by gorm.io/gen. DO NOT EDIT. -// Code generated by gorm.io/gen. DO NOT EDIT. - -package model - -import ( - "time" - - "git.hlsq.asia/mmorpg/service-common/utils" - "gorm.io/gorm" -) - -const TableNameQuestion = "questions" - -// Question mapped from table -type Question struct { - ID uint64 `gorm:"column:id;primaryKey;autoIncrement:true" json:"id"` - Sn string `gorm:"column:sn;not null;comment:业务唯一编号" json:"sn"` // 业务唯一编号 - Question string `gorm:"column:question;not null;comment:题干" json:"question"` // 题干 - Options string `gorm:"column:options;not null;comment:选项" json:"options"` // 选项 - Answer string `gorm:"column:answer;not null;comment:答案" json:"answer"` // 答案 - Explanation string `gorm:"column:explanation;not null;comment:解析" json:"explanation"` // 解析 - Difficulty int32 `gorm:"column:difficulty;not null;comment:难度分 0 - 100" json:"difficulty"` // 难度分 0 - 100 - Category string `gorm:"column:category;not null;comment:分类" json:"category"` // 分类 - CreatedAt time.Time `gorm:"column:created_at;not null" json:"created_at"` - UpdatedAt time.Time `gorm:"column:updated_at;not null" json:"updated_at"` - DeletedAt gorm.DeletedAt `gorm:"column:deleted_at" json:"deleted_at"` -} - -// TableName Question's table name -func (*Question) TableName() string { - return TableNameQuestion -} - -// Auto sn -func (m *Question) BeforeCreate(_ *gorm.DB) error { - if m.Sn == "" { - m.Sn = utils.SnowflakeInstance().Generate().String() - } - return nil -} diff --git a/internal/dao/query/gen.go b/internal/dao/query/gen.go index 4adcef8..d067772 100644 --- a/internal/dao/query/gen.go +++ b/internal/dao/query/gen.go @@ -17,26 +17,23 @@ import ( func Use(db *gorm.DB, opts ...gen.DOOption) *Query { return &Query{ - db: db, - Question: newQuestion(db, opts...), - User: newUser(db, opts...), + db: db, + User: newUser(db, opts...), } } type Query struct { db *gorm.DB - Question question - User user + User user } func (q *Query) Available() bool { return q.db != nil } func (q *Query) clone(db *gorm.DB) *Query { return &Query{ - db: db, - Question: q.Question.clone(db), - User: q.User.clone(db), + db: db, + User: q.User.clone(db), } } @@ -50,21 +47,18 @@ func (q *Query) WriteDB() *Query { func (q *Query) ReplaceDB(db *gorm.DB) *Query { return &Query{ - db: db, - Question: q.Question.replaceDB(db), - User: q.User.replaceDB(db), + db: db, + User: q.User.replaceDB(db), } } type queryCtx struct { - Question *questionDo - User *userDo + User *userDo } func (q *Query) WithContext(ctx context.Context) *queryCtx { return &queryCtx{ - Question: q.Question.WithContext(ctx), - User: q.User.WithContext(ctx), + User: q.User.WithContext(ctx), } } diff --git a/internal/dao/query/questions.gen.go b/internal/dao/query/questions.gen.go deleted file mode 100644 index 97e41f2..0000000 --- a/internal/dao/query/questions.gen.go +++ /dev/null @@ -1,367 +0,0 @@ -// Code generated by gorm.io/gen. DO NOT EDIT. -// Code generated by gorm.io/gen. DO NOT EDIT. -// Code generated by gorm.io/gen. DO NOT EDIT. - -package query - -import ( - "context" - - "gorm.io/gorm" - "gorm.io/gorm/clause" - "gorm.io/gorm/schema" - - "gorm.io/gen" - "gorm.io/gen/field" - - "gorm.io/plugin/dbresolver" - - "git.hlsq.asia/mmorpg/service-user/internal/dao/model" -) - -func newQuestion(db *gorm.DB, opts ...gen.DOOption) question { - _question := question{} - - _question.questionDo.UseDB(db, opts...) - _question.questionDo.UseModel(&model.Question{}) - - tableName := _question.questionDo.TableName() - _question.ALL = field.NewAsterisk(tableName) - _question.ID = field.NewUint64(tableName, "id") - _question.Sn = field.NewString(tableName, "sn") - _question.Question = field.NewString(tableName, "question") - _question.Options = field.NewString(tableName, "options") - _question.Answer = field.NewString(tableName, "answer") - _question.Explanation = field.NewString(tableName, "explanation") - _question.Difficulty = field.NewInt32(tableName, "difficulty") - _question.Category = field.NewString(tableName, "category") - _question.CreatedAt = field.NewTime(tableName, "created_at") - _question.UpdatedAt = field.NewTime(tableName, "updated_at") - _question.DeletedAt = field.NewField(tableName, "deleted_at") - - _question.fillFieldMap() - - return _question -} - -type question struct { - questionDo questionDo - - ALL field.Asterisk - ID field.Uint64 - Sn field.String // 业务唯一编号 - Question field.String // 题干 - Options field.String // 选项 - Answer field.String // 答案 - Explanation field.String // 解析 - Difficulty field.Int32 // 难度分 0 - 100 - Category field.String // 分类 - CreatedAt field.Time - UpdatedAt field.Time - DeletedAt field.Field - - fieldMap map[string]field.Expr -} - -func (q question) Table(newTableName string) *question { - q.questionDo.UseTable(newTableName) - return q.updateTableName(newTableName) -} - -func (q question) As(alias string) *question { - q.questionDo.DO = *(q.questionDo.As(alias).(*gen.DO)) - return q.updateTableName(alias) -} - -func (q *question) updateTableName(table string) *question { - q.ALL = field.NewAsterisk(table) - q.ID = field.NewUint64(table, "id") - q.Sn = field.NewString(table, "sn") - q.Question = field.NewString(table, "question") - q.Options = field.NewString(table, "options") - q.Answer = field.NewString(table, "answer") - q.Explanation = field.NewString(table, "explanation") - q.Difficulty = field.NewInt32(table, "difficulty") - q.Category = field.NewString(table, "category") - q.CreatedAt = field.NewTime(table, "created_at") - q.UpdatedAt = field.NewTime(table, "updated_at") - q.DeletedAt = field.NewField(table, "deleted_at") - - q.fillFieldMap() - - return q -} - -func (q *question) WithContext(ctx context.Context) *questionDo { return q.questionDo.WithContext(ctx) } - -func (q question) TableName() string { return q.questionDo.TableName() } - -func (q question) Alias() string { return q.questionDo.Alias() } - -func (q question) Columns(cols ...field.Expr) gen.Columns { return q.questionDo.Columns(cols...) } - -func (q *question) GetFieldByName(fieldName string) (field.OrderExpr, bool) { - _f, ok := q.fieldMap[fieldName] - if !ok || _f == nil { - return nil, false - } - _oe, ok := _f.(field.OrderExpr) - return _oe, ok -} - -func (q *question) fillFieldMap() { - q.fieldMap = make(map[string]field.Expr, 11) - q.fieldMap["id"] = q.ID - q.fieldMap["sn"] = q.Sn - q.fieldMap["question"] = q.Question - q.fieldMap["options"] = q.Options - q.fieldMap["answer"] = q.Answer - q.fieldMap["explanation"] = q.Explanation - q.fieldMap["difficulty"] = q.Difficulty - q.fieldMap["category"] = q.Category - q.fieldMap["created_at"] = q.CreatedAt - q.fieldMap["updated_at"] = q.UpdatedAt - q.fieldMap["deleted_at"] = q.DeletedAt -} - -func (q question) clone(db *gorm.DB) question { - q.questionDo.ReplaceConnPool(db.Statement.ConnPool) - return q -} - -func (q question) replaceDB(db *gorm.DB) question { - q.questionDo.ReplaceDB(db) - return q -} - -type questionDo struct{ gen.DO } - -func (q questionDo) Debug() *questionDo { - return q.withDO(q.DO.Debug()) -} - -func (q questionDo) WithContext(ctx context.Context) *questionDo { - return q.withDO(q.DO.WithContext(ctx)) -} - -func (q questionDo) ReadDB() *questionDo { - return q.Clauses(dbresolver.Read) -} - -func (q questionDo) WriteDB() *questionDo { - return q.Clauses(dbresolver.Write) -} - -func (q questionDo) Session(config *gorm.Session) *questionDo { - return q.withDO(q.DO.Session(config)) -} - -func (q questionDo) Clauses(conds ...clause.Expression) *questionDo { - return q.withDO(q.DO.Clauses(conds...)) -} - -func (q questionDo) Returning(value interface{}, columns ...string) *questionDo { - return q.withDO(q.DO.Returning(value, columns...)) -} - -func (q questionDo) Not(conds ...gen.Condition) *questionDo { - return q.withDO(q.DO.Not(conds...)) -} - -func (q questionDo) Or(conds ...gen.Condition) *questionDo { - return q.withDO(q.DO.Or(conds...)) -} - -func (q questionDo) Select(conds ...field.Expr) *questionDo { - return q.withDO(q.DO.Select(conds...)) -} - -func (q questionDo) Where(conds ...gen.Condition) *questionDo { - return q.withDO(q.DO.Where(conds...)) -} - -func (q questionDo) Order(conds ...field.Expr) *questionDo { - return q.withDO(q.DO.Order(conds...)) -} - -func (q questionDo) Distinct(cols ...field.Expr) *questionDo { - return q.withDO(q.DO.Distinct(cols...)) -} - -func (q questionDo) Omit(cols ...field.Expr) *questionDo { - return q.withDO(q.DO.Omit(cols...)) -} - -func (q questionDo) Join(table schema.Tabler, on ...field.Expr) *questionDo { - return q.withDO(q.DO.Join(table, on...)) -} - -func (q questionDo) LeftJoin(table schema.Tabler, on ...field.Expr) *questionDo { - return q.withDO(q.DO.LeftJoin(table, on...)) -} - -func (q questionDo) RightJoin(table schema.Tabler, on ...field.Expr) *questionDo { - return q.withDO(q.DO.RightJoin(table, on...)) -} - -func (q questionDo) Group(cols ...field.Expr) *questionDo { - return q.withDO(q.DO.Group(cols...)) -} - -func (q questionDo) Having(conds ...gen.Condition) *questionDo { - return q.withDO(q.DO.Having(conds...)) -} - -func (q questionDo) Limit(limit int) *questionDo { - return q.withDO(q.DO.Limit(limit)) -} - -func (q questionDo) Offset(offset int) *questionDo { - return q.withDO(q.DO.Offset(offset)) -} - -func (q questionDo) Scopes(funcs ...func(gen.Dao) gen.Dao) *questionDo { - return q.withDO(q.DO.Scopes(funcs...)) -} - -func (q questionDo) Unscoped() *questionDo { - return q.withDO(q.DO.Unscoped()) -} - -func (q questionDo) Create(values ...*model.Question) error { - if len(values) == 0 { - return nil - } - return q.DO.Create(values) -} - -func (q questionDo) CreateInBatches(values []*model.Question, batchSize int) error { - return q.DO.CreateInBatches(values, batchSize) -} - -// Save : !!! underlying implementation is different with GORM -// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values) -func (q questionDo) Save(values ...*model.Question) error { - if len(values) == 0 { - return nil - } - return q.DO.Save(values) -} - -func (q questionDo) First() (*model.Question, error) { - if result, err := q.DO.First(); err != nil { - return nil, err - } else { - return result.(*model.Question), nil - } -} - -func (q questionDo) Take() (*model.Question, error) { - if result, err := q.DO.Take(); err != nil { - return nil, err - } else { - return result.(*model.Question), nil - } -} - -func (q questionDo) Last() (*model.Question, error) { - if result, err := q.DO.Last(); err != nil { - return nil, err - } else { - return result.(*model.Question), nil - } -} - -func (q questionDo) Find() ([]*model.Question, error) { - result, err := q.DO.Find() - return result.([]*model.Question), err -} - -func (q questionDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.Question, err error) { - buf := make([]*model.Question, 0, batchSize) - err = q.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error { - defer func() { results = append(results, buf...) }() - return fc(tx, batch) - }) - return results, err -} - -func (q questionDo) FindInBatches(result *[]*model.Question, batchSize int, fc func(tx gen.Dao, batch int) error) error { - return q.DO.FindInBatches(result, batchSize, fc) -} - -func (q questionDo) Attrs(attrs ...field.AssignExpr) *questionDo { - return q.withDO(q.DO.Attrs(attrs...)) -} - -func (q questionDo) Assign(attrs ...field.AssignExpr) *questionDo { - return q.withDO(q.DO.Assign(attrs...)) -} - -func (q questionDo) Joins(fields ...field.RelationField) *questionDo { - for _, _f := range fields { - q = *q.withDO(q.DO.Joins(_f)) - } - return &q -} - -func (q questionDo) Preload(fields ...field.RelationField) *questionDo { - for _, _f := range fields { - q = *q.withDO(q.DO.Preload(_f)) - } - return &q -} - -func (q questionDo) FirstOrInit() (*model.Question, error) { - if result, err := q.DO.FirstOrInit(); err != nil { - return nil, err - } else { - return result.(*model.Question), nil - } -} - -func (q questionDo) FirstOrCreate() (*model.Question, error) { - if result, err := q.DO.FirstOrCreate(); err != nil { - return nil, err - } else { - return result.(*model.Question), nil - } -} - -func (q questionDo) FindByPage(offset int, limit int) (result []*model.Question, count int64, err error) { - result, err = q.Offset(offset).Limit(limit).Find() - if err != nil { - return - } - - if size := len(result); 0 < limit && 0 < size && size < limit { - count = int64(size + offset) - return - } - - count, err = q.Offset(-1).Limit(-1).Count() - return -} - -func (q questionDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) { - count, err = q.Count() - if err != nil { - return - } - - err = q.Offset(offset).Limit(limit).Scan(result) - return -} - -func (q questionDo) Scan(result interface{}) (err error) { - return q.DO.Scan(result) -} - -func (q questionDo) Delete(models ...*model.Question) (result gen.ResultInfo, err error) { - return q.DO.Delete(models) -} - -func (q *questionDo) withDO(do gen.Dao) *questionDo { - q.DO = *do.(*gen.DO) - return q -} diff --git a/internal/dao/repository/questions.go b/internal/dao/repository/questions.go deleted file mode 100644 index ff34911..0000000 --- a/internal/dao/repository/questions.go +++ /dev/null @@ -1,83 +0,0 @@ -package repository - -import ( - "context" - "git.hlsq.asia/mmorpg/service-common/db/mysql" - "git.hlsq.asia/mmorpg/service-common/db/redis" - "git.hlsq.asia/mmorpg/service-common/utils" - "git.hlsq.asia/mmorpg/service-user/internal/dao/model" - "git.hlsq.asia/mmorpg/service-user/internal/dao/query" - "gorm.io/gorm" - "time" -) - -type QuestionDao struct { - ctx context.Context - query *query.Query - cache *redis.CacheClient -} - -func NewQuestionDao(ctx context.Context, cache ...*redis.CacheClient) *QuestionDao { - dao := &QuestionDao{ - ctx: ctx, - query: query.Use(mysql.GetDB(dbName)), - } - if len(cache) > 0 { - dao.cache = cache[0] - } - return dao -} - -func (d *QuestionDao) Create(question *model.Question) error { - err := d.query.Question.WithContext(d.ctx). - Create(question) - return err -} - -func (d *QuestionDao) FindByRandom() (*model.Question, error) { - count, err := d.query.Question.WithContext(d.ctx).Count() - if err != nil { - return nil, err - } - if count == 0 { - return nil, gorm.ErrRecordNotFound - } - first, err := d.query.Question.WithContext(d.ctx). - Offset(utils.RandInt(0, int(count-1))). - First() - if err != nil { - return nil, err - } - return first, nil -} - -func (d *QuestionDao) FindBySn(sn string) (*model.Question, error) { - if d.cache != nil { - var question model.Question - if ok := d.cache.Get(d.ctx, keyCacheBySn(sn, question.TableName()), &question); ok { - return &question, nil - } - } - first, err := d.query.Question.WithContext(d.ctx). - Where(d.query.Question.Sn.Eq(sn)). - First() - if err != nil { - return nil, err - } - if d.cache != nil { - d.cache.Set(d.ctx, keyCacheBySn(sn, first.TableName()), first, 5*time.Minute) - } - return first, nil -} - -func (d *QuestionDao) FindCategory() ([]string, error) { - var categories []string - err := d.query.Question.WithContext(d.ctx). - Select(d.query.Question.Category). - Distinct(). - Scan(&categories) - if err != nil { - return nil, err - } - return categories, nil -} diff --git a/internal/grpc_server/server/a_test.go b/internal/grpc_server/server/a_test.go deleted file mode 100644 index 60bdfda..0000000 --- a/internal/grpc_server/server/a_test.go +++ /dev/null @@ -1,11 +0,0 @@ -package server - -import ( - "fmt" - "testing" -) - -func TestName(t *testing.T) { - - t.Logf("step: %v", fmt.Sprintf("aa %v bb", []string{"1", "2"})) -} diff --git a/internal/grpc_server/server/server_question.go b/internal/grpc_server/server/server_question.go deleted file mode 100644 index 8746ab7..0000000 --- a/internal/grpc_server/server/server_question.go +++ /dev/null @@ -1,156 +0,0 @@ -package server - -import ( - "context" - "encoding/json" - "fmt" - "git.hlsq.asia/mmorpg/service-common/db/redis" - "git.hlsq.asia/mmorpg/service-common/log" - "git.hlsq.asia/mmorpg/service-common/proto/rs/grpc_pb" - "git.hlsq.asia/mmorpg/service-user/internal/ai" - "git.hlsq.asia/mmorpg/service-user/internal/dao/model" - "git.hlsq.asia/mmorpg/service-user/internal/dao/repository" - "time" -) - -//var prompt = []string{` -//你是一个微信小游戏的内容策划,请生成 %v 道“每日趣味题”,要求: -//- 避免敏感、争议或超纲内容 -//- 每次从 [动物冷知识, 科学趣理, 语言陷阱, 历史轶事, 地理奇观, 数学谜题, 艺术人文, 综合杂学] 中**随机选一个类型** -//- 确保选项有迷惑性,解析有趣 -//- 绝对要避免重复,现在的时间是:%v -//- 输出格式为 JSON 数组,不要任何解释、不要Markdown、不要任何其他字符: -// [{ -// "question": "题目文本", // 简洁,30字以内 -// "options": ["A. 选项1", "B. 选项2", "C. 选项3", "D. 选项4"], // 提供4个选项(A/B/C/D),其中仅1个正确 -// "answer": "C", // 答案 -// "explanation": "解析文本", // 200字以内,尽量幽默有趣 -// "category": "分类", // 只能从上面列出的类型中选择 -// "difficulty": 100, // 难度分 0 - 100 -// }] -//`} - -var prompt = []string{` -你是一个微信小游戏的内容策划,我需要生成“每日趣味题”,要求: -- 避免敏感、争议或超纲内容 -- 确保选项有迷惑性,解析有趣 -- 绝对要避免重复,现在的时间是:%v -- 这些是我目前的分类:%v -- 输出格式为 JSON 数组,不要任何解释、不要Markdown、不要任何其他字符: - [{ - "question": "题目文本", // 简洁,30字以内 - "options": ["A. 选项1", "B. 选项2", "C. 选项3", "D. 选项4"], // 提供4个选项(A/B/C/D),其中仅1个正确 - "answer": "C", // 答案 - "explanation": "解析文本", // 200字以内,尽量幽默有趣 - "category": "分类", // 尽量从上述分类中选择,你也可以增加,但是命名风格要类似 - "difficulty": 100, // 难度分 0 - 100 - }] -如果你准备好了,请回答”好的“,不要有其他任何字符 -`, ` -请帮我生成 %v 道,只允许回答 JSON 数组: -`, ` -请继续生成 %v 道,只允许回答 JSON 数组: -`, ` -请继续生成 %v 道,只允许回答 JSON 数组: -`, ` -请继续生成 %v 道,只允许回答 JSON 数组: -`, ` -请继续生成 %v 道,只允许回答 JSON 数组: -`} - -type Question struct { - Question string `json:"question"` // 题干 - Options []string `json:"options"` // 选项 - Answer string `json:"answer"` // 答案 - Explanation string `json:"explanation"` // 解析 - Category string `json:"category"` // 分类 - Difficulty int32 `json:"difficulty"` // 难度分 -} - -func (s *Server) GenerateQuestion(ctx context.Context, req *grpc_pb.GenerateQuestionReq) (*grpc_pb.GenerateQuestionResp, error) { - category, err := repository.NewQuestionDao(ctx).FindCategory() - if err != nil { - log.Errorf("GenerateQuestion FindCategory error: %v", err) - return nil, err - } - question := make([]*Question, 0) - err = ai.NewAIClient(false, "", 0.9). - RequestAI( - []string{ - fmt.Sprintf(prompt[0], time.Now().Format("2006-01-02 15:04:05"), category), - fmt.Sprintf(prompt[1], req.Num, req.Category), - fmt.Sprintf(prompt[2], req.Num), - fmt.Sprintf(prompt[3], req.Num), - fmt.Sprintf(prompt[4], req.Num), - fmt.Sprintf(prompt[5], req.Num), - }, - func(content string, i int) error { - if i == 0 { - return nil - } - step := make([]*Question, 0) - if err := json.Unmarshal([]byte(content), &step); err != nil { - log.Errorf("RequestAI json.Unmarshal error: %v, data: %v", err, content) - return err - } - question = append(question, step...) - return nil - }, - ) - if err != nil { - log.Errorf("RequestAI error: %v", err) - return nil, err - } - - questionDao := repository.NewQuestionDao(ctx, redis.GetCacheClient()) - for _, q := range question { - marshal, _ := json.Marshal(q.Options) - if err = questionDao.Create(&model.Question{ - Question: q.Question, - Options: string(marshal), - Answer: q.Answer, - Explanation: q.Explanation, - Category: q.Category, - Difficulty: q.Difficulty, - }); err != nil { - log.Errorf("GenerateQuestion Create error: %v", err) - return nil, err - } - } - return nil, nil -} - -func (s *Server) GetQuestion(ctx context.Context, req *grpc_pb.GetQuestionReq) (*grpc_pb.GetQuestionResp, error) { - question, err := repository.NewQuestionDao(ctx).FindByRandom() - if err != nil { - log.Errorf("GetQuestion error: %v", err) - return nil, err - } - options := make([]string, 0) - if err = json.Unmarshal([]byte(question.Options), &options); err != nil { - log.Errorf("GetQuestion json.Unmarshal error: %v, data: %v", err, question.Options) - return nil, err - } - return &grpc_pb.GetQuestionResp{ - Sn: question.Sn, - Question: question.Question, - Options: options, - }, nil -} - -func (s *Server) AnswerQuestion(ctx context.Context, req *grpc_pb.AnswerQuestionReq) (*grpc_pb.AnswerQuestionResp, error) { - question, err := repository.NewQuestionDao(ctx).FindBySn(req.Sn) - if err != nil { - log.Errorf("AnswerQuestion error: %v", err) - return nil, err - } - options := make([]string, 0) - if err = json.Unmarshal([]byte(question.Options), &options); err != nil { - log.Errorf("AnswerQuestion json.Unmarshal error: %v, data: %v", err, question.Options) - return nil, err - } - return &grpc_pb.AnswerQuestionResp{ - Answer: question.Answer, - Explanation: question.Explanation, - }, nil -} diff --git a/internal/grpc_server/server/server_question_temp.go b/internal/grpc_server/server/server_question_temp.go deleted file mode 100644 index a7365f7..0000000 --- a/internal/grpc_server/server/server_question_temp.go +++ /dev/null @@ -1,161 +0,0 @@ -package server - -// -//import ( -// "bytes" -// "context" -// "encoding/json" -// "git.hlsq.asia/mmorpg/service-common/log" -// "git.hlsq.asia/mmorpg/service-common/proto/rs/grpc_pb" -// "io" -// "net/http" -//) -// -//var question = []string{ -// "本次对话 数据来源必须:东方财富,巨潮资讯,官网,数据截止:自上市至2025年第3季度\n帮我查询一下京东方科技集团股份有限公司公司的所有财报数量", -// "帮我从东方财富 / 巨潮资讯 / 官网这三个来源整理一下重大事项公告的数量,按照三个维度划分( 并购重组公告披露,关联交易公告,对外投资公告)", -// "帮我从东方财富 / 巨潮资讯 / 官网这三个来源整理一下投资者关系活动,按照三个维度划分( 年度业绩说明次数, 投资者调研次数,接待机构数量)", -// "帮我查询一下ESG与治理的信息各个维度评分评级", -// "帮我查询一下这个公司监管合规信息,综合评估一下本年度监管合规(信披评分,公司治理,内控合规,ESG表现,财务合规,业务运营合规,股东与投资者权益保护合规,合规风险管理)百分制", -// "将本次对话的所有内容总结和完整的装入这个结构体生成json对象数据返回,注意:必须以json(markdown代码)的形式返回,并且只输出json即可不用输出其它说明,下面内容就是结构体: \n// CompanyComplianceScore 公司合规评分\ntype CompanyComplianceScore struct {\n\tInformationDisclosureRating string `json:\"informationDisclosureRating\" bson:\"information_disclosure_rating\" comment:\"信息披露评级\"`//获取交易所的信披评级,如A/B/C等\n\tRegularReportFrequencyCount *RegularReportFrequency `json:\"regularReportFrequency\" bson:\"regular_report_frequency\" comment:\"定期报告披露频次\"`\n\tMajorAnnouncementCount *MajorAnnouncementCount `json:\"majorAnnouncementCount\" bson:\"major_announcement_count\" comment:\"重大事项公告\"`\n\tInvestorRelationsActivity *InvestorRelationsActivity `json:\"InvestorRelationsActivity\" bson:\"investor_relations_activity\" comment:\"投资者关系活动\"`\n\tEsgReport *EsgReport `json:\"esgReport\" bson:\"esg_report\" comment:\"ESG与治理\"`\n\tDisclosureScore float64 `json:\"disclosureScore\" bson:\"disclosure_score\" comment:\"信息披露专项评分\"`\n\tCorporateGovernanceScore float64 `json:\"corporateGovernanceScore\" bson:\"corporate_governance_score\" comment:\"公司治理评分\"`\n\tInternalControlCompliance float64 `json:\"internalControlCompliance\" bson:\"internal_control_compliance\" comment:\"内控合规评分\"`\n\tEsgPerformanceScore float64 `json:\"esgPerformanceScore\" bson:\"esg_performance_score\" comment:\"ESG表现评分\"`\n\tFinancialComplianceScore float64 `json:\"financialComplianceScore\" bson:\"financial_compliance_score\" comment:\"财务合规评分\"`\n\tBusinessOperationCompliance float64 `json:\"businessOperationCompliance\" bson:\"business_operation_compliance\" comment:\"业务运营合规评分\"`\n\tShareholderRightsCompliance float64 `json:\"shareholderRightsCompliance\" bson:\"shareholder_rights_compliance\" comment:\"股东权益保护合规评分\"`\n\tComplianceRiskManagement float64 `json:\"complianceRiskManagement\" bson:\"compliance_risk_management\" comment:\"合规风险管理评分\"`\n\tOverallComprehensiveScore float64 `json:\"overallComprehensiveScore\" bson:\"overall_comprehensive_score\" comment:\"综合评分\"`\n}\n\n// RegularReportFrequency 定期报告披露频次\ntype RegularReportFrequency struct {\n\tAnnualReportCount int `json:\"annualReportCount\" bson:\"annual_report_count\" comment:\"年报数量\"`\n\tSemiAnnualReportCount int `json:\"semiAnnualReportCount\" bson:\"semi_annual_report_count\" comment:\"半年报数量\"`\n\tQuarterlyReportCount int `json:\"quarterlyReportCount\" bson:\"quarterly_report_count\" comment:\"季度报告数量\"`\n\tTotalReportCount int `json:\"totalReportCount\" bson:\"total_report_count\" comment:\"报告总数\"`\n}\n\n// MajorAnnouncementCount 重大事项公告\ntype MajorAnnouncementCount struct {\n\tMnaAnnouncementCount int `json:\"mnaAnnouncementCount\" bson:\"mna_announcement_count\" comment:\"并购重组公告数量\"`\n\tRelatedTransactionCount int `json:\"relatedTransactionCount\" bson:\"related_transaction_count\" comment:\"关联交易公告数量\"`\n\tForeignInvestmentCount int `json:\"foreignInvestmentCount\" bson:\"foreign_investment_count\" comment:\"对外投资公告数量\"`\n}\n\n// InvestorRelationsActivity 投资者关系活动\ntype InvestorRelationsActivity struct {\n\tAnnualPerformanceBriefings int `json:\"annualPerformanceBriefings\" bson:\"annual_performance_briefings\" comment:\"年度业绩说明次数\"`\n\tInvestorResearchCount int `json:\"investorResearchCount\" bson:\"investor_research_count\" comment:\"投资者调研次数\"`\n\tInstitutionsReceivedCount int `json:\"institutionsReceivedCount\" bson:\"institutions_received_count\" comment:\"接待机构数量\"`\n}\n\n// EsgReport ESG与治理\ntype EsgReport struct {\n\tEsgOverallScore float64 `json:\"esgOverallScore\" bson:\"esg_overall_score\" comment:\"ESG综合评分\"`//通过【上海华证指数信息服务有限公司】披露的公司ESG评级,例如BBB,不允许返回分数\n\tEnvironmentalScore float64 `json:\"environmentalScore\" bson:\"environmental_score\" comment:\"环境评分\"`\n\tSocialScore float64 `json:\"socialScore\" bson:\"social_score\" comment:\"社会评分\"`\n\tGovernanceScore float64 `json:\"governanceScore\" bson:\"governance_score\" comment:\"治理评分\"`\n}", -//} -// -//type Message struct { -// Role string `json:"role"` -// Content string `json:"content"` -//} -// -//type Input struct { -// Messages []Message `json:"messages"` -//} -// -//type Parameters struct { -// EnableSearch bool `json:"enable_search"` -// ResultFormat string `json:"result_format"` -// SearchOptions SearchOptions `json:"search_options"` -//} -// -//type SearchOptions struct { -// SearchStrategy string `json:"search_strategy"` -//} -// -//type RequestBody struct { -// Model string `json:"model"` -// Input Input `json:"input"` -// Parameters Parameters `json:"parameters"` -//} -// -//type ResponseBody struct { -// Output struct { -// Choices []struct { -// Message Message `json:"message"` -// FinishReason string `json:"finish_reason"` -// } `json:"choices"` -// } `json:"output"` -// Usage struct { -// InputTokens int32 `json:"input_tokens"` -// OutputTokens int32 `json:"output_tokens"` -// TotalTokens int32 `json:"total_tokens"` -// } `json:"usage"` -//} -// -//func (s *Server) GenerateQuestion(ctx context.Context, req *grpc_pb.GenerateQuestionReq) (*grpc_pb.GenerateQuestionResp, error) { -// inToken, outToken := int32(0), int32(0) -// -// messages := make([]Message, 0) -// for i, step := range question { -// messages = append(messages, newUserMessage(step)) -// -// //chatCompletion, err := client.Chat.Completions.New( -// // context.Background(), openai.ChatCompletionNewParams{ -// // Messages: messages, -// // Model: "qwen3-max", -// // }, -// //) -// //if err != nil { -// // return nil, err -// //} -// r, err := request(messages) -// if err != nil { -// return nil, err -// } -// inToken += r.Usage.InputTokens -// outToken += r.Usage.OutputTokens -// log.Infof("回答 %v:%v", i, r) -// //break -// messages = append(messages, r.Output.Choices[0].Message) -// -// //log.Infof("回答 %v:%v", i, chatCompletion.Choices[0].Message.Content) -// //messages = append(messages, openai.AssistantMessage(chatCompletion.Choices[0].Message.Content)) -// } -// log.Infof("返回:%v", messages[len(messages)-1].Content) -// //log.Infof("消耗token:%v %v, 费用:%v", inToken, outToken, float64(inToken)/1000*0.0032+float64(outToken)/1000*0.0128) -// log.Infof("消耗token:%v %v, 费用:%v", inToken, outToken, float64(inToken)/1000*0.002+float64(outToken)/1000*0.003) -// -// //chatCompletion, err := client.Chat.Completions.New( -// // context.Background(), openai.ChatCompletionNewParams{ -// // Messages: []openai.ChatCompletionMessageParamUnion{ -// // openai.UserMessage("你能做什么"), -// // }, -// // Model: "qwen3-max", -// // }, -// //) -// //if err != nil { -// // return nil, err -// //} -// //for i, choice := range chatCompletion.Choices { -// // log.Infof("chatCompletion %v: %#+v \n", i, choice) -// //} -// //log.Infof("返回:%v", chatCompletion.Choices[0].Message.Content) -// return nil, nil -//} -// -//func newUserMessage(content string) Message { -// return Message{ -// Role: "user", -// Content: content, -// } -//} -// -//func request(messages []Message) (*ResponseBody, error) { -// client := &http.Client{} -// requestBody := RequestBody{ -// //Model: "qwen3-max", -// Model: "deepseek-v3.2", -// Input: Input{ -// Messages: messages, -// }, -// Parameters: Parameters{ -// EnableSearch: true, -// SearchOptions: SearchOptions{ -// SearchStrategy: "max", -// }, -// -// ResultFormat: "message", -// }, -// } -// jsonData, _ := json.Marshal(requestBody) -// -// req, err := http.NewRequest("POST", "https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation", bytes.NewBuffer(jsonData)) -// if err != nil { -// return nil, err -// } -// req.Header.Set("Authorization", "Bearer "+"sk-4daf94ad2fa94288b198d2a1d8924cef") -// req.Header.Set("Content-Type", "application/json") -// -// resp, err := client.Do(req) -// if err != nil { -// return nil, err -// } -// defer resp.Body.Close() -// -// body, err := io.ReadAll(resp.Body) -// if err != nil { -// return nil, err -// } -// var res ResponseBody -// if err = json.Unmarshal(body, &res); err != nil { -// return nil, err -// } -// return &res, nil -//} diff --git a/internal/grpc_server/stream_client/gateway.go b/internal/grpc_server/stream_client/gateway.go deleted file mode 100644 index c43e22b..0000000 --- a/internal/grpc_server/stream_client/gateway.go +++ /dev/null @@ -1,84 +0,0 @@ -package stream_client - -import ( - "context" - "git.hlsq.asia/mmorpg/service-common/log" - "git.hlsq.asia/mmorpg/service-common/net/grpc/service" - "google.golang.org/grpc" - "google.golang.org/protobuf/proto" - "strconv" - "sync" -) - -type GatewayFun int - -const ( - FunToClient GatewayFun = iota -) - -var gatewayServer sync.Map // map[string]*gatewayStream - -type gatewayStream struct { - mu sync.Mutex - stream grpc.ClientStream -} - -func findGatewayBySID(sid string, fun GatewayFun) (*gatewayStream, error) { - key := gatewayKey(sid, fun) - - if v, ok := gatewayServer.Load(key); ok { - return v.(*gatewayStream), nil - } - - client, err := service.GatewayNewClient(sid) - if err != nil { - log.Errorf("findGatewayBySID cannot find client: %v", err) - return nil, err - } - var stream grpc.ClientStream - switch fun { - case FunToClient: - stream, err = client.ToClient(context.Background()) - } - if err != nil { - log.Errorf("findGatewayBySID %v err: %v, sid: %v", fun, err, sid) - return nil, err - } - - ss := &gatewayStream{stream: stream} - if actual, loaded := gatewayServer.LoadOrStore(key, ss); loaded { - go func() { _ = stream.CloseSend() }() - return actual.(*gatewayStream), nil - } - - return ss, nil -} - -func SendMessageToGateway(sid string, fun GatewayFun, msg proto.Message, re ...bool) error { - ss, err := findGatewayBySID(sid, fun) - if err != nil { - return err - } - - ss.mu.Lock() - err = ss.stream.SendMsg(msg) - ss.mu.Unlock() - - if err != nil { - key := gatewayKey(sid, fun) - if v, ok := gatewayServer.Load(key); ok && v == ss { - gatewayServer.Delete(key) - _ = ss.stream.CloseSend() - } - // 如果没有标识本次是重试的,就重试一次(默认重试) - if re == nil || !re[0] { - return SendMessageToGateway(sid, fun, msg, true) - } - return err - } - return nil -} - -func gatewayKey(sid string, fun GatewayFun) string { - return sid + "-" + strconv.Itoa(int(fun)) -}