From 11141edcda9710520af9e02bb3df66ea75689658 Mon Sep 17 00:00:00 2001 From: "DESKTOP-V763RJ7\\Administrator" <835606593@qq.com> Date: Sun, 11 Jan 2026 16:16:27 +0800 Subject: [PATCH] =?UTF-8?q?feat=20=E4=BF=AE=E6=94=B9usn=E7=B1=BB=E5=9E=8B?= =?UTF-8?q?=E4=B8=BAstring?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- go.mod | 2 +- go.sum | 6 +- internal/ai/ai_client.go | 55 +++ internal/ai/ai_request.go | 82 ++++ internal/dao/model/questions.gen.go | 42 ++ internal/dao/model/users.gen.go | 11 +- internal/dao/query/gen.go | 24 +- internal/dao/query/questions.gen.go | 366 ++++++++++++++++++ internal/dao/query/users.gen.go | 6 +- internal/dao/repository/define.go | 21 + internal/dao/repository/questions.go | 83 ++++ internal/dao/repository/users.go | 22 +- internal/grpc_server/server/a_test.go | 11 + internal/grpc_server/server/server.go | 2 +- .../grpc_server/server/server_question.go | 156 ++++++++ .../server/server_question_temp.go | 161 ++++++++ internal/grpc_server/stream_client/gateway.go | 12 +- 17 files changed, 1019 insertions(+), 43 deletions(-) create mode 100644 internal/ai/ai_client.go create mode 100644 internal/ai/ai_request.go create mode 100644 internal/dao/model/questions.gen.go create mode 100644 internal/dao/query/questions.gen.go create mode 100644 internal/dao/repository/define.go create mode 100644 internal/dao/repository/questions.go create mode 100644 internal/grpc_server/server/a_test.go create mode 100644 internal/grpc_server/server/server_question.go create mode 100644 internal/grpc_server/server/server_question_temp.go diff --git a/go.mod b/go.mod index 4ecb652..ce1daa9 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module git.hlsq.asia/mmorpg/service-user go 1.23.1 require ( - git.hlsq.asia/mmorpg/service-common v0.0.0-20260108144540-69e82ec0fe77 + git.hlsq.asia/mmorpg/service-common v0.0.0-20260110153008-0be254c6a298 github.com/judwhite/go-svc v1.2.1 google.golang.org/grpc v1.71.1 google.golang.org/protobuf v1.36.9 diff --git a/go.sum b/go.sum index a6d5d96..1cfc19f 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +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-20260107061047-e02e56781e78 h1:4CP8w5jHDOdN7hym8YrtioxNDd7PS2WcZDrO6dtY344= -git.hlsq.asia/mmorpg/service-common v0.0.0-20260107061047-e02e56781e78/go.mod h1:xv6m1I2jUA6mudKVznygpnzMoshBQarthHD1QnkW4qc= -git.hlsq.asia/mmorpg/service-common v0.0.0-20260108144540-69e82ec0fe77 h1:39SVfV3+uysM25P+dSnJMvtJJI9l2aZ+/n/ooTdHqxk= -git.hlsq.asia/mmorpg/service-common v0.0.0-20260108144540-69e82ec0fe77/go.mod h1:xv6m1I2jUA6mudKVznygpnzMoshBQarthHD1QnkW4qc= +git.hlsq.asia/mmorpg/service-common v0.0.0-20260110153008-0be254c6a298 h1:zKQC0gqQfP9sUVYs7OsoHSrzdk379u6aenko6rMx1go= +git.hlsq.asia/mmorpg/service-common v0.0.0-20260110153008-0be254c6a298/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 new file mode 100644 index 0000000..35153c2 --- /dev/null +++ b/internal/ai/ai_client.go @@ -0,0 +1,55 @@ +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 new file mode 100644 index 0000000..8c37496 --- /dev/null +++ b/internal/ai/ai_request.go @@ -0,0 +1,82 @@ +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 new file mode 100644 index 0000000..d30d358 --- /dev/null +++ b/internal/dao/model/questions.gen.go @@ -0,0 +1,42 @@ +// 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/model/users.gen.go b/internal/dao/model/users.gen.go index b2f7841..5e0a675 100644 --- a/internal/dao/model/users.gen.go +++ b/internal/dao/model/users.gen.go @@ -5,9 +5,10 @@ package model import ( + "time" + "git.hlsq.asia/mmorpg/service-common/utils" "gorm.io/gorm" - "time" ) const TableNameUser = "users" @@ -15,7 +16,7 @@ const TableNameUser = "users" // User mapped from table type User struct { ID uint64 `gorm:"column:id;primaryKey;autoIncrement:true" json:"id"` - Sn int64 `gorm:"column:sn;not null;comment:业务唯一编号" json:"sn"` // 业务唯一编号 + Sn string `gorm:"column:sn;not null;comment:业务唯一编号" json:"sn"` // 业务唯一编号 Name string `gorm:"column:name;not null" json:"name"` Phone string `gorm:"column:phone;not null" json:"phone"` CreatedAt time.Time `gorm:"column:created_at;not null" json:"created_at"` @@ -28,10 +29,10 @@ func (*User) TableName() string { return TableNameUser } -// auto sn +// Auto sn func (m *User) BeforeCreate(_ *gorm.DB) error { - if m.Sn == 0 { - m.Sn = utils.SnowflakeInstance().Generate().Int64() + 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 d067772..4adcef8 100644 --- a/internal/dao/query/gen.go +++ b/internal/dao/query/gen.go @@ -17,23 +17,26 @@ import ( func Use(db *gorm.DB, opts ...gen.DOOption) *Query { return &Query{ - db: db, - User: newUser(db, opts...), + db: db, + Question: newQuestion(db, opts...), + User: newUser(db, opts...), } } type Query struct { db *gorm.DB - User user + Question question + User user } func (q *Query) Available() bool { return q.db != nil } func (q *Query) clone(db *gorm.DB) *Query { return &Query{ - db: db, - User: q.User.clone(db), + db: db, + Question: q.Question.clone(db), + User: q.User.clone(db), } } @@ -47,18 +50,21 @@ func (q *Query) WriteDB() *Query { func (q *Query) ReplaceDB(db *gorm.DB) *Query { return &Query{ - db: db, - User: q.User.replaceDB(db), + db: db, + Question: q.Question.replaceDB(db), + User: q.User.replaceDB(db), } } type queryCtx struct { - User *userDo + Question *questionDo + User *userDo } func (q *Query) WithContext(ctx context.Context) *queryCtx { return &queryCtx{ - User: q.User.WithContext(ctx), + Question: q.Question.WithContext(ctx), + User: q.User.WithContext(ctx), } } diff --git a/internal/dao/query/questions.gen.go b/internal/dao/query/questions.gen.go new file mode 100644 index 0000000..3c0f23b --- /dev/null +++ b/internal/dao/query/questions.gen.go @@ -0,0 +1,366 @@ +// 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" + "git.hlsq.asia/mmorpg/service-user/internal/dao/model" + + "gorm.io/gorm" + "gorm.io/gorm/clause" + "gorm.io/gorm/schema" + + "gorm.io/gen" + "gorm.io/gen/field" + + "gorm.io/plugin/dbresolver" +) + +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/query/users.gen.go b/internal/dao/query/users.gen.go index fb76e6c..a14728d 100644 --- a/internal/dao/query/users.gen.go +++ b/internal/dao/query/users.gen.go @@ -27,7 +27,7 @@ func newUser(db *gorm.DB, opts ...gen.DOOption) user { tableName := _user.userDo.TableName() _user.ALL = field.NewAsterisk(tableName) _user.ID = field.NewUint64(tableName, "id") - _user.Sn = field.NewInt64(tableName, "sn") + _user.Sn = field.NewString(tableName, "sn") _user.Name = field.NewString(tableName, "name") _user.Phone = field.NewString(tableName, "phone") _user.CreatedAt = field.NewTime(tableName, "created_at") @@ -44,7 +44,7 @@ type user struct { ALL field.Asterisk ID field.Uint64 - Sn field.Int64 // 业务唯一编号 + Sn field.String // 业务唯一编号 Name field.String Phone field.String CreatedAt field.Time @@ -67,7 +67,7 @@ func (u user) As(alias string) *user { func (u *user) updateTableName(table string) *user { u.ALL = field.NewAsterisk(table) u.ID = field.NewUint64(table, "id") - u.Sn = field.NewInt64(table, "sn") + u.Sn = field.NewString(table, "sn") u.Name = field.NewString(table, "name") u.Phone = field.NewString(table, "phone") u.CreatedAt = field.NewTime(table, "created_at") diff --git a/internal/dao/repository/define.go b/internal/dao/repository/define.go new file mode 100644 index 0000000..47b13cf --- /dev/null +++ b/internal/dao/repository/define.go @@ -0,0 +1,21 @@ +package repository + +import ( + "fmt" + "git.hlsq.asia/mmorpg/service-common/db/mysql" +) + +var dbName mysql.DBName = "user_db" + +var ( + cacheBySn = "c:%v:s:%v" + userCacheByPhone = "c:user:p:%v" +) + +func keyCacheBySn(sn string, tableName string) string { + return fmt.Sprintf(cacheBySn, tableName, sn) +} + +func keyUserCacheByPhone(phone string) string { + return fmt.Sprintf(userCacheByPhone, phone) +} diff --git a/internal/dao/repository/questions.go b/internal/dao/repository/questions.go new file mode 100644 index 0000000..ff34911 --- /dev/null +++ b/internal/dao/repository/questions.go @@ -0,0 +1,83 @@ +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/dao/repository/users.go b/internal/dao/repository/users.go index 20d9e1c..287d6af 100644 --- a/internal/dao/repository/users.go +++ b/internal/dao/repository/users.go @@ -2,7 +2,6 @@ package repository import ( "context" - "fmt" "git.hlsq.asia/mmorpg/service-common/db/mysql" "git.hlsq.asia/mmorpg/service-common/db/redis" "git.hlsq.asia/mmorpg/service-user/internal/dao/model" @@ -10,11 +9,6 @@ import ( "time" ) -var ( - cacheBySn = "c:user:s:%v" - cacheByPhone = "c:user:p:%v" -) - type UserDao struct { ctx context.Context query *query.Query @@ -24,7 +18,7 @@ type UserDao struct { func NewUserDao(ctx context.Context, cache ...*redis.CacheClient) *UserDao { dao := &UserDao{ ctx: ctx, - query: query.Use(mysql.GetDB("user_db")), + query: query.Use(mysql.GetDB(dbName)), } if len(cache) > 0 { dao.cache = cache[0] @@ -44,17 +38,17 @@ func (d *UserDao) Updates(user *model.User) error { Updates(user) if info.RowsAffected > 0 { if d.cache != nil { - d.cache.Del(d.ctx, fmt.Sprintf(cacheBySn, user.Sn)) - d.cache.Del(d.ctx, fmt.Sprintf(cacheByPhone, user.Phone)) + d.cache.Del(d.ctx, keyCacheBySn(user.Sn, user.TableName())) + d.cache.Del(d.ctx, keyUserCacheByPhone(user.Phone)) } } return info.Error } -func (d *UserDao) FindBySn(sn int64) (*model.User, error) { +func (d *UserDao) FindBySn(sn string) (*model.User, error) { if d.cache != nil { var user model.User - if ok := d.cache.Get(d.ctx, fmt.Sprintf(cacheBySn, sn), &user); ok { + if ok := d.cache.Get(d.ctx, keyCacheBySn(sn, user.TableName()), &user); ok { return &user, nil } } @@ -65,7 +59,7 @@ func (d *UserDao) FindBySn(sn int64) (*model.User, error) { return nil, err } if d.cache != nil { - d.cache.Set(d.ctx, fmt.Sprintf(cacheBySn, sn), first, 5*time.Minute) + d.cache.Set(d.ctx, keyCacheBySn(sn, first.TableName()), first, 5*time.Minute) } return first, nil } @@ -73,7 +67,7 @@ func (d *UserDao) FindBySn(sn int64) (*model.User, error) { func (d *UserDao) FindByPhone(phone string) (*model.User, error) { if d.cache != nil { var user model.User - if ok := d.cache.Get(d.ctx, fmt.Sprintf(cacheByPhone, phone), &user); ok { + if ok := d.cache.Get(d.ctx, keyUserCacheByPhone(phone), &user); ok { return &user, nil } } @@ -84,7 +78,7 @@ func (d *UserDao) FindByPhone(phone string) (*model.User, error) { return nil, err } if d.cache != nil { - d.cache.Set(d.ctx, fmt.Sprintf(cacheByPhone, phone), first, 5*time.Minute) + d.cache.Set(d.ctx, keyUserCacheByPhone(phone), first, 5*time.Minute) } return first, nil } diff --git a/internal/grpc_server/server/a_test.go b/internal/grpc_server/server/a_test.go new file mode 100644 index 0000000..60bdfda --- /dev/null +++ b/internal/grpc_server/server/a_test.go @@ -0,0 +1,11 @@ +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.go b/internal/grpc_server/server/server.go index c221f93..c502595 100644 --- a/internal/grpc_server/server/server.go +++ b/internal/grpc_server/server/server.go @@ -24,7 +24,7 @@ func (s *Server) Login(ctx context.Context, req *grpc_pb.LoginReq) (*grpc_pb.Log if err := userDao.Create(user); err != nil { return nil, err } - user.Name = fmt.Sprintf("user_%d", user.Sn) + user.Name = fmt.Sprintf("user_%v", user.Sn) _ = userDao.Updates(user) } else { return nil, err diff --git a/internal/grpc_server/server/server_question.go b/internal/grpc_server/server/server_question.go new file mode 100644 index 0000000..402c559 --- /dev/null +++ b/internal/grpc_server/server/server_question.go @@ -0,0 +1,156 @@ +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/ss/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 new file mode 100644 index 0000000..5ed1349 --- /dev/null +++ b/internal/grpc_server/server/server_question_temp.go @@ -0,0 +1,161 @@ +package server + +// +//import ( +// "bytes" +// "context" +// "encoding/json" +// "git.hlsq.asia/mmorpg/service-common/log" +// "git.hlsq.asia/mmorpg/service-common/proto/ss/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 index a47cf81..c43e22b 100644 --- a/internal/grpc_server/stream_client/gateway.go +++ b/internal/grpc_server/stream_client/gateway.go @@ -1,9 +1,9 @@ package stream_client import ( - "common/log" - "common/net/grpc/service" "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" @@ -23,7 +23,7 @@ type gatewayStream struct { stream grpc.ClientStream } -func findGatewayBySID(sid int64, fun GatewayFun) (*gatewayStream, error) { +func findGatewayBySID(sid string, fun GatewayFun) (*gatewayStream, error) { key := gatewayKey(sid, fun) if v, ok := gatewayServer.Load(key); ok { @@ -54,7 +54,7 @@ func findGatewayBySID(sid int64, fun GatewayFun) (*gatewayStream, error) { return ss, nil } -func SendMessageToGateway(sid int64, fun GatewayFun, msg proto.Message, re ...bool) error { +func SendMessageToGateway(sid string, fun GatewayFun, msg proto.Message, re ...bool) error { ss, err := findGatewayBySID(sid, fun) if err != nil { return err @@ -79,6 +79,6 @@ func SendMessageToGateway(sid int64, fun GatewayFun, msg proto.Message, re ...bo return nil } -func gatewayKey(sid int64, fun GatewayFun) string { - return strconv.FormatInt(sid, 10) + "-" + strconv.Itoa(int(fun)) +func gatewayKey(sid string, fun GatewayFun) string { + return sid + "-" + strconv.Itoa(int(fun)) }