Merge branch 'main' into for-dev
This commit is contained in:
commit
76285dc0e4
@ -6,4 +6,8 @@ const (
|
||||
|
||||
func EnocunterMsgInit(m msg) {
|
||||
m[ErrEaLinkInstert] = "路遇添加成功,但关联毛茸茸失败"
|
||||
}
|
||||
}
|
||||
|
||||
func EncounterMsgUserInit(m msg) {
|
||||
m[ErrEaLinkInstert] = "路遇上传成功啦。但是不小心让毛茸茸跑丢了 /(ㄒoㄒ)/~~"
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ func init() {
|
||||
// INGO
|
||||
ErrMsgForUser = make(msg)
|
||||
AnimalMsgUserInit(ErrMsgForUser)
|
||||
EncounterMsgUserInit(ErrMsgForUser)
|
||||
}
|
||||
|
||||
func GeneralMsgInit(m msg) {
|
||||
|
@ -71,4 +71,7 @@ const (
|
||||
|
||||
// GLM 部分
|
||||
ErrorsGlmClientInitFail string = "GLM Client 初始化失败"
|
||||
|
||||
// ES 部分
|
||||
ErrorsInitConnFail string = "初始化 Elasticsearch 连接失败"
|
||||
)
|
||||
|
@ -9,10 +9,10 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/casbin/casbin/v2"
|
||||
"github.com/elastic/go-elasticsearch/v8"
|
||||
"github.com/yankeguo/zhipu"
|
||||
"go.uber.org/zap"
|
||||
"gorm.io/gorm"
|
||||
|
||||
)
|
||||
|
||||
var (
|
||||
@ -46,6 +46,9 @@ var (
|
||||
|
||||
// GLM 全局客户端
|
||||
GlmClient *zhipu.Client
|
||||
|
||||
// ES 全局客户端
|
||||
ElasticClient *elasticsearch.Client
|
||||
)
|
||||
|
||||
func init() {
|
||||
@ -61,3 +64,20 @@ func init() {
|
||||
log.Fatal(my_errors.ErrorsBasePath)
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
// 1. 初始化程序根目录
|
||||
if curPath, err := os.Getwd(); err == nil {
|
||||
// 路径进行处理,兼容单元测试程序启动时的奇怪路径
|
||||
if len(os.Args) > 1 && strings.HasPrefix(os.Args[1], "-test") {
|
||||
// 替换 \ 为 /,然后移除 /test 及其后的内容
|
||||
curPath = strings.ReplaceAll(curPath, "\\", "/")
|
||||
parts := strings.Split(curPath, "/test")
|
||||
BasePath = parts[0]
|
||||
} else {
|
||||
BasePath = curPath
|
||||
}
|
||||
} else {
|
||||
log.Fatal(my_errors.ErrorsBasePath)
|
||||
}
|
||||
}
|
||||
|
@ -154,8 +154,8 @@ func (a *Animals) Create(context *gin.Context) {
|
||||
avatar := photos[0]
|
||||
avatarWidth := variable.ConfigYml.GetFloat64("FileUploadSetting.AvatarWidth")
|
||||
|
||||
srcPath := filepath.Join(variable.BasePath, variable.ConfigYml.GetString("FileUploadSetting.UploadFileSavePath"), "catsPhotos", "hum_"+userId, avatar)
|
||||
dstPath := filepath.Join(variable.BasePath, variable.ConfigYml.GetString("FileUploadSetting.UploadFileSavePath"), "catsAvatar", avatar)
|
||||
srcPath := filepath.Join(variable.ConfigYml.GetString("FileUploadSetting.UploadFileSavePath"), "catsPhotos", "hum_"+userId, avatar)
|
||||
dstPath := filepath.Join(variable.ConfigYml.GetString("FileUploadSetting.UploadFileSavePath"), "catsAvatar", avatar)
|
||||
avatarHeight, err := upload_file.ResizeImage(srcPath, dstPath, int(avatarWidth))
|
||||
if err != nil {
|
||||
response.Fail(context, consts.FilesUploadFailCode, consts.FilesUploadFailMsg, "")
|
||||
@ -215,8 +215,8 @@ func (a *Animals) Create(context *gin.Context) {
|
||||
// STAGE-3
|
||||
if anm_id, ok := model.CreateAnimalFactory("").InsertDate(context); ok {
|
||||
// 转移 photos 到 anm;采用 rename dir 的方式
|
||||
oldName := filepath.Join(variable.BasePath, variable.ConfigYml.GetString("FileUploadSetting.UploadFileSavePath"), "catsPhotos", "hum_"+userId)
|
||||
newName := filepath.Join(variable.BasePath, variable.ConfigYml.GetString("FileUploadSetting.UploadFileSavePath"), "catsPhotos", "anm_"+strconv.FormatInt(anm_id, 10))
|
||||
oldName := filepath.Join(variable.ConfigYml.GetString("FileUploadSetting.UploadFileSavePath"), "catsPhotos", "hum_"+userId)
|
||||
newName := filepath.Join(variable.ConfigYml.GetString("FileUploadSetting.UploadFileSavePath"), "catsPhotos", "anm_"+strconv.FormatInt(anm_id, 10))
|
||||
err := os.Rename(oldName, newName)
|
||||
if err != nil {
|
||||
// TODO 特殊返回,成功了一半?或者需要清空原有的操作?不过感觉这一步几乎不会出错。
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
"catface/app/global/variable"
|
||||
"catface/app/http/validator/core/data_transfer"
|
||||
"catface/app/model"
|
||||
"catface/app/model_es"
|
||||
"catface/app/service/encounter/curd"
|
||||
"catface/app/service/upload_file"
|
||||
"catface/app/utils/response"
|
||||
@ -25,8 +26,8 @@ func (e *Encounters) Create(context *gin.Context) {
|
||||
avatar := photos[0]
|
||||
avatarWidth := variable.ConfigYml.GetFloat64("FileUploadSetting.AvatarWidth")
|
||||
|
||||
srcPath := filepath.Join(variable.BasePath, variable.ConfigYml.GetString("FileUploadSetting.UploadFileSavePath"), "encounterPhotos", "hum_"+userId, avatar)
|
||||
dstPath := filepath.Join(variable.BasePath, variable.ConfigYml.GetString("FileUploadSetting.UploadFileSavePath"), "encounterAvatar", avatar)
|
||||
srcPath := filepath.Join(variable.ConfigYml.GetString("FileUploadSetting.UploadFileSavePath"), "encounterPhotos", "hum_"+userId, avatar)
|
||||
dstPath := filepath.Join(variable.ConfigYml.GetString("FileUploadSetting.UploadFileSavePath"), "encounterAvatar", avatar)
|
||||
avatarHeight, err := upload_file.ResizeImage(srcPath, dstPath, int(avatarWidth))
|
||||
if err != nil {
|
||||
response.Fail(context, consts.FilesUploadFailCode, consts.FilesUploadFailMsg, "")
|
||||
@ -67,14 +68,21 @@ func (e *Encounters) Create(context *gin.Context) {
|
||||
// STAGE -3: Real Insert - 1: ENC
|
||||
animals_id := data_transfer.GetFloat64Slice(context, "animals_id") // 由于是 Slice 就交给 EAlink 内部遍历时处理。
|
||||
// Real Insert - 2: EA LINK
|
||||
if encounter_id, ok := model.CreateEncounterFactory("").InsertDate(context); ok && encounter_id > 0 {
|
||||
if !model.CreateEncounterAnimalLinkFactory("").Insert(int64(encounter_id), animals_id) {
|
||||
response.Fail(context, errcode.ErrEaLinkInstert, errcode.ErrMsg[errcode.ErrEaLinkInstert], "")
|
||||
return
|
||||
if encounter, ok := model.CreateEncounterFactory("").InsertDate(context); ok {
|
||||
// 2: EA Links; // TIP 感觉直接使用 go 会直接且清晰。
|
||||
go model.CreateEncounterAnimalLinkFactory("").Insert(encounter.Id, animals_id)
|
||||
// if !model.CreateEncounterAnimalLinkFactory("").Insert(int64(encounter_id), animals_id) {
|
||||
// response.Fail(context, errcode.ErrEaLinkInstert, errcode.ErrMsg[errcode.ErrEaLinkInstert], errcode.ErrMsgForUser[errcode.ErrEaLinkInstert])
|
||||
// return
|
||||
// }
|
||||
|
||||
// 3. ES speed
|
||||
if level := int(context.GetFloat64(consts.ValidatorPrefix + "level")); level > 1 {
|
||||
go model_es.CreateEncounterESFactory(&encounter).InsertDocument()
|
||||
}
|
||||
|
||||
response.Success(context, consts.CurdStatusOkMsg, gin.H{
|
||||
"encounter_id": encounter_id,
|
||||
"encounter_id": encounter.Id,
|
||||
})
|
||||
} else {
|
||||
response.Fail(context, consts.CurdCreatFailCode, consts.CurdCreatFailMsg+", 新增错误", "")
|
||||
|
40
app/http/controller/web/search_controller.go
Normal file
40
app/http/controller/web/search_controller.go
Normal file
@ -0,0 +1,40 @@
|
||||
package web
|
||||
|
||||
import (
|
||||
"catface/app/global/consts"
|
||||
"catface/app/model"
|
||||
"catface/app/model_es"
|
||||
"catface/app/utils/response"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type Search struct {
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: 全局搜索:AnmName + Encounter
|
||||
* @param {*gin.Context} context
|
||||
* @return {*}
|
||||
*/
|
||||
func (s *Search) SearchAll(context *gin.Context) {
|
||||
query := context.GetString(consts.ValidatorPrefix + "query")
|
||||
|
||||
var animals []model.Animal
|
||||
var encounters []model.Encounter
|
||||
|
||||
// 1. Animal Name // TODO 增加字段的过滤,看前端了。
|
||||
animals = model.CreateAnimalFactory("").ShowByName(query)
|
||||
|
||||
// 2. Encounter
|
||||
encounterIds, _ := model_es.CreateEncounterESFactory(nil).QueryDocumentsMatchAll(query)
|
||||
|
||||
if len(encounterIds) > 0 {
|
||||
encounters = model.CreateEncounterFactory("").ShowByIDs(encounterIds)
|
||||
}
|
||||
|
||||
response.Success(context, consts.CurdStatusOkMsg, gin.H{
|
||||
"animals": animals,
|
||||
"encounters": encounters,
|
||||
})
|
||||
}
|
@ -19,7 +19,7 @@ type Upload struct {
|
||||
func (u *Upload) StartUpload(context *gin.Context) {
|
||||
// TODO 如果之后要存储到 Linux 服务器上特殊路径下,就需要修改这里。
|
||||
dir_name := context.GetString(consts.ValidatorPrefix + "dir_name")
|
||||
savePath := filepath.Join(variable.BasePath, variable.ConfigYml.GetString("FileUploadSetting.UploadFileSavePath"), dir_name)
|
||||
savePath := filepath.Join(variable.ConfigYml.GetString("FileUploadSetting.UploadFileSavePath"), dir_name)
|
||||
|
||||
if r, finnalSavePath := upload_file.Upload(context, savePath); r == true {
|
||||
response.Success(context, consts.CurdStatusOkMsg, finnalSavePath)
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
"catface/app/http/validator/web/encounter"
|
||||
"catface/app/http/validator/web/encounter_like"
|
||||
"catface/app/http/validator/web/nlp"
|
||||
"catface/app/http/validator/web/search"
|
||||
"catface/app/http/validator/web/users"
|
||||
)
|
||||
|
||||
@ -81,4 +82,8 @@ func WebRegisterValidator() {
|
||||
// TAG NLP
|
||||
key = consts.ValidatorPrefix + "NlpTitle"
|
||||
containers.Set(key, nlp.Title{})
|
||||
|
||||
// TAG Search
|
||||
key = consts.ValidatorPrefix + "SearchAll"
|
||||
containers.Set(key, search.SearchAll{})
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ type Create struct {
|
||||
AnimalsId []int `form:"animals_id" json:"animals_id" binding:"required"`
|
||||
Title string `form:"title" json:"title" binding:"required"`
|
||||
Content string `form:"content" json:"content"`
|
||||
Level int `form:"level" json:"level"`
|
||||
|
||||
// Avatar string `form:"avatar" json:"avatar"`
|
||||
Photos []string `form:"photos" json:"photos"` // INFO 如果 Photo 为空,那就选取 Animals 的 Avatar
|
||||
|
30
app/http/validator/web/search/searchAll.go
Normal file
30
app/http/validator/web/search/searchAll.go
Normal file
@ -0,0 +1,30 @@
|
||||
package search
|
||||
|
||||
import (
|
||||
"catface/app/global/consts"
|
||||
"catface/app/http/controller/web"
|
||||
"catface/app/http/validator/core/data_transfer"
|
||||
"catface/app/utils/response"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type SearchAll struct {
|
||||
Query string `form:"query" json:"query"`
|
||||
}
|
||||
|
||||
func (s SearchAll) CheckParams(context *gin.Context) {
|
||||
if err := context.ShouldBind(&s); err != nil {
|
||||
response.ValidatorError(context, err)
|
||||
return
|
||||
}
|
||||
|
||||
extraAddBindDataContext := data_transfer.DataAddContext(s, consts.ValidatorPrefix, context)
|
||||
if extraAddBindDataContext == nil {
|
||||
response.ErrorSystem(context, "Animal Create 表单验证器json化失败", "")
|
||||
} else {
|
||||
// 验证完成,调用控制器,并将验证器成员(字段)递给控制器,保持上下文数据一致性
|
||||
(&web.Search{}).SearchAll(extraAddBindDataContext)
|
||||
}
|
||||
|
||||
}
|
@ -44,18 +44,22 @@ func (e *Encounter) TableName() string {
|
||||
return "encounters"
|
||||
}
|
||||
|
||||
func (e *Encounter) InsertDate(c *gin.Context) (int64, bool) {
|
||||
var tmp Encounter
|
||||
/**
|
||||
* @description:
|
||||
* @param {*gin.Context} c
|
||||
* @return {*} 返回创建的绑定对象,之后 model_es 的利用。
|
||||
*/
|
||||
func (e *Encounter) InsertDate(c *gin.Context) (tmp Encounter, ok bool) {
|
||||
if err := data_bind.ShouldBindFormDataToModel(c, &tmp); err == nil {
|
||||
if res := e.Create(&tmp); res.Error == nil {
|
||||
return tmp.Id, true
|
||||
return tmp, true
|
||||
} else {
|
||||
variable.ZapLog.Error("Encounter 数据新增出错", zap.Error(res.Error))
|
||||
}
|
||||
} else {
|
||||
variable.ZapLog.Error("Encounter 数据绑定出错", zap.Error(err))
|
||||
}
|
||||
return 0, false
|
||||
return tmp, false
|
||||
}
|
||||
|
||||
func formatEncounterList(rows *gorm.DB) (temp []EncounterList, err error) {
|
||||
@ -169,6 +173,20 @@ func (e *Encounter) ShowByID(id int64) (temp *Encounter, err error) {
|
||||
// return
|
||||
}
|
||||
|
||||
func (e *Encounter) ShowByIDs(ids []int64, attrs ...string) (temp []Encounter) {
|
||||
db := e.DB.Table(e.TableName())
|
||||
|
||||
if len(attrs) > 0 {
|
||||
db = db.Select(attrs)
|
||||
}
|
||||
|
||||
err := db.Where("id in (?)", ids).Find(&temp).Error
|
||||
if err != nil {
|
||||
variable.ZapLog.Error("Encounter ShowByIDs Error", zap.Error(err))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: 过去 1 个月,发送过路遇表的 ids,同时去重。
|
||||
* @param {*} user_id
|
||||
|
@ -141,17 +141,17 @@ func testInsertDeworming() {
|
||||
}
|
||||
|
||||
func insertData() {
|
||||
// testInsertSterilzation()
|
||||
// fmt.Println("testInsertSterilzation success.")
|
||||
testInsertSterilzation()
|
||||
fmt.Println("testInsertSterilzation success.")
|
||||
|
||||
// testInsertBreed()
|
||||
// fmt.Println("testInsertBreed success.")
|
||||
testInsertBreed()
|
||||
fmt.Println("testInsertBreed success.")
|
||||
|
||||
// testInsertStatus()
|
||||
// fmt.Println("testInsertStatus success.")
|
||||
testInsertStatus()
|
||||
fmt.Println("testInsertStatus success.")
|
||||
|
||||
// testInsertAnmGender()
|
||||
// fmt.Println("testInsertAnmGender success.")
|
||||
testInsertAnmGender()
|
||||
fmt.Println("testInsertAnmGender success.")
|
||||
|
||||
testInsertVaccination()
|
||||
fmt.Println("testInsertVaccination success.")
|
||||
@ -163,7 +163,8 @@ func insertData() {
|
||||
func main() {
|
||||
// 1.
|
||||
dsn := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=True&loc=Local",
|
||||
"root", "Havocantelope412#", "113.44.68.213", "3306", "hav_cats") // ATT MySQL
|
||||
// "root", "Havocantelope412#", "113.44.68.213", "3306", "hav_cats") // ATT MySQL dsn := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=True&loc=Local",
|
||||
"root", "havocantelope412", "127.0.0.1", "3306", "hav_cats") // ATT MySQL
|
||||
fmt.Println("dsn:", dsn)
|
||||
dbMySQL, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
|
||||
if err != nil {
|
||||
|
225
app/model_es/encounter.go
Normal file
225
app/model_es/encounter.go
Normal file
@ -0,0 +1,225 @@
|
||||
package model_es
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"catface/app/global/variable"
|
||||
"catface/app/model"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/elastic/go-elasticsearch/v8"
|
||||
"github.com/elastic/go-elasticsearch/v8/esapi"
|
||||
)
|
||||
|
||||
func CreateEncounterESFactory(encounter *model.Encounter) *Encounter {
|
||||
if encounter == nil { // UPDATE 这样写好丑。
|
||||
return &Encounter{}
|
||||
}
|
||||
|
||||
// 我把数值绑定到了工厂创建当中。
|
||||
return &Encounter{
|
||||
Id: encounter.Id,
|
||||
Title: encounter.Title,
|
||||
Content: encounter.Content,
|
||||
Tags: encounter.TagsSlice, // TODO 暂时没有对此字段的查询。
|
||||
}
|
||||
}
|
||||
|
||||
// INFO 存储能够作为索引存在的数据。
|
||||
type Encounter struct {
|
||||
Id int64 `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Content string `json:"content"`
|
||||
Tags []string `json:"tags"`
|
||||
}
|
||||
|
||||
func (e *Encounter) IndexName() string {
|
||||
return "catface_encounters"
|
||||
}
|
||||
|
||||
func (e *Encounter) InsertDocument() error {
|
||||
ctx := context.Background()
|
||||
|
||||
// 将结构体转换为 JSON 字符串
|
||||
data, err := json.Marshal(e)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 创建请求
|
||||
req := esapi.IndexRequest{
|
||||
Index: e.IndexName(),
|
||||
DocumentID: fmt.Sprintf("%d", e.Id),
|
||||
Body: bytes.NewReader(data),
|
||||
Refresh: "true",
|
||||
}
|
||||
|
||||
// 发送请求
|
||||
res, err := req.Do(ctx, variable.ElasticClient)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
if res.IsError() {
|
||||
var e map[string]interface{}
|
||||
if err := json.NewDecoder(res.Body).Decode(&e); err != nil {
|
||||
return fmt.Errorf("error parsing the response body: %s", err)
|
||||
} else {
|
||||
return fmt.Errorf("[%s] %s: %s",
|
||||
res.Status(),
|
||||
e["error"].(map[string]interface{})["type"],
|
||||
e["error"].(map[string]interface{})["reason"],
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// TODO 改正,仿 Insert
|
||||
func (e *Encounter) UpdateDocument(client *elasticsearch.Client, encounter *Encounter) error {
|
||||
ctx := context.Background()
|
||||
|
||||
// 将结构体转换为 JSON 字符串
|
||||
data, err := json.Marshal(map[string]interface{}{
|
||||
"doc": encounter,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 创建请求
|
||||
req := esapi.UpdateRequest{
|
||||
Index: encounter.IndexName(),
|
||||
DocumentID: fmt.Sprintf("%d", encounter.Id),
|
||||
Body: bytes.NewReader(data),
|
||||
Refresh: "true",
|
||||
}
|
||||
|
||||
// 发送请求
|
||||
res, err := req.Do(ctx, client)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
if res.IsError() {
|
||||
var e map[string]interface{}
|
||||
if err := json.NewDecoder(res.Body).Decode(&e); err != nil {
|
||||
return fmt.Errorf("error parsing the response body: %s", err)
|
||||
} else {
|
||||
return fmt.Errorf("[%s] %s: %s",
|
||||
res.Status(),
|
||||
e["error"].(map[string]interface{})["type"],
|
||||
e["error"].(map[string]interface{})["reason"],
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: 粗略地包含各种关键词匹配,
|
||||
* @param {*elasticsearch.Client} client
|
||||
* @param {string} query
|
||||
* @return {*} 对应 Encounter 的 id,然后交给 MySQL 来查询详细的信息?
|
||||
*/
|
||||
func (e *Encounter) QueryDocumentsMatchAll(query string) ([]int64, error) {
|
||||
ctx := context.Background()
|
||||
|
||||
// 创建查询请求
|
||||
req := esapi.SearchRequest{ // UPDATE 同时实现查询高亮?
|
||||
Index: []string{e.IndexName()},
|
||||
Body: strings.NewReader(fmt.Sprintf(`{
|
||||
"_source": ["id"],
|
||||
"query": {
|
||||
"bool": {
|
||||
"should": [
|
||||
{
|
||||
"match": {
|
||||
"title": "%s"
|
||||
}
|
||||
},
|
||||
{
|
||||
"match": {
|
||||
"content": "%s"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}`, query, query)),
|
||||
}
|
||||
|
||||
// 发送请求
|
||||
res, err := req.Do(ctx, variable.ElasticClient)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
if res.IsError() {
|
||||
var e map[string]interface{}
|
||||
if err := json.NewDecoder(res.Body).Decode(&e); err != nil {
|
||||
return nil, fmt.Errorf("error parsing the response body: %s", err)
|
||||
} else {
|
||||
return nil, fmt.Errorf("[%s] %s: %s",
|
||||
res.Status(),
|
||||
e["error"].(map[string]interface{})["type"],
|
||||
e["error"].(map[string]interface{})["reason"],
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// 解析响应
|
||||
var r map[string]interface{}
|
||||
if err := json.NewDecoder(res.Body).Decode(&r); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 提取命中结果
|
||||
hits, ok := r["hits"].(map[string]interface{})["hits"].([]interface{})
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("error extracting hits from response")
|
||||
}
|
||||
|
||||
fmt.Println(hits)
|
||||
|
||||
// 转换为 id 切片
|
||||
var ids []int64
|
||||
for _, hit := range hits {
|
||||
hitMap := hit.(map[string]interface{})["_source"].(map[string]interface{})
|
||||
id := int64(hitMap["id"].(float64))
|
||||
ids = append(ids, id)
|
||||
}
|
||||
|
||||
return ids, nil
|
||||
|
||||
// // 转换为 Encounter 切片
|
||||
// var encounters []*Encounter
|
||||
// for _, hit := range hits {
|
||||
// hitMap := hit.(map[string]interface{})
|
||||
// source := hitMap["_source"].(map[string]interface{})
|
||||
|
||||
// // TIP 将 []interface{} 转换为 []string
|
||||
// tagsInterface := source["tags"].([]interface{})
|
||||
// tags := make([]string, len(tagsInterface))
|
||||
// for i, tag := range tagsInterface {
|
||||
// tags[i] = tag.(string)
|
||||
// }
|
||||
|
||||
// encounter := &Encounter{
|
||||
// Id: int64(source["id"].(float64)),
|
||||
// Title: source["title"].(string),
|
||||
// Content: source["content"].(string),
|
||||
// Tags: tags,
|
||||
// }
|
||||
// encounters = append(encounters, encounter)
|
||||
// }
|
||||
|
||||
// return encounters, nil
|
||||
}
|
@ -44,8 +44,9 @@ func Upload(context *gin.Context, savePath string) (r bool, finnalSavePath inter
|
||||
}
|
||||
|
||||
// 文件上传可以设置按照 xxx年-xx月 格式存储
|
||||
// INFO 但这个 returnPath 我还基本没有用到。
|
||||
func generateYearMonthPath(savePathPre string) (string, string) {
|
||||
returnPath := variable.BasePath + variable.ConfigYml.GetString("FileUploadSetting.UploadFileReturnPath")
|
||||
returnPath := variable.BasePath + variable.ConfigYml.GetString("FileUploadSetting.UploadFileReturnPath") // UPDATE 因为没用到,所以就先不调整了。
|
||||
curYearMonth := time.Now().In(time.Local).Format("2006_01")
|
||||
newSavePathPre := filepath.Join(savePathPre, curYearMonth)
|
||||
newReturnPathPre := filepath.Join(returnPath, curYearMonth)
|
||||
|
@ -16,6 +16,7 @@ import (
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/elastic/go-elasticsearch/v8"
|
||||
"github.com/yankeguo/zhipu"
|
||||
)
|
||||
|
||||
@ -120,4 +121,13 @@ func init() {
|
||||
log.Fatal(my_errors.ErrorsGlmClientInitFail + err.Error())
|
||||
}
|
||||
|
||||
|
||||
// 12. ES 客户端启动
|
||||
variable.ElasticClient, err = elasticsearch.NewClient(elasticsearch.Config{
|
||||
Addresses: []string{variable.ConfigYml.GetString("ElasticSearch.Addr")},
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatal(my_errors.ErrorsInitConnFail + err.Error())
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ Redis:
|
||||
|
||||
Logs:
|
||||
GinLogName: "/store/logs/gin.log" #设置 gin 框架的接口访问日志
|
||||
GoSkeletonLogName: "/store/logs/skeleton.log" #设置GoSkeleton项目骨架运行时日志文件名,注意该名称不要与上一条重复 ,避免和 gin 框架的日志掺杂一起,造成混乱。
|
||||
GoSkeletonLogName: "/store/logs/skeleton.log" #设置GoSkeleton项目骨架运行时日志文件名,注意该名称不要与上一条重复 ,避免和 gin 框架的日志掺杂一起,造成混乱。
|
||||
TextFormat: "json" #记录日志的格式,参数选项:console、json , console 表示一般的文本格式
|
||||
TimePrecision: "millisecond" #记录日志时,相关的时间精度,该参数选项:second 、 millisecond , 分别表示 秒 和 毫秒 ,默认为毫秒级别
|
||||
MaxSize: 10 #每个日志的最大尺寸(以MB为单位), 超过该值,系统将会自动进行切割
|
||||
@ -56,11 +56,12 @@ SnowFlake:
|
||||
SnowFlakeMachineId: 2 #如果本项目同时部署在多台机器,并且需要同时使用该算法,请为每一台机器设置不同的ID,区间范围: [0,1023]
|
||||
|
||||
FileUploadSetting:
|
||||
Size: 32 #设置上传文件的最大值,单位:M,注意: 如果go前置nginx服务器,nginx 默认限制文件上传大小为 50 M ,用户上传文件限制还需要继续修改 nginx 配置
|
||||
UploadFileField: "file" #post上传文件时,表单的键名
|
||||
UploadFileSavePath: "/public/nginx/" #上传文件保存在路径, 该路径与 BasePath 进行拼接使用
|
||||
UploadFileReturnPath: "" # 文件上后返回的路径,由于程序会自动创建软连接,自动将资源定位到实际路径,所有资源的访问入口建议都从public开始
|
||||
AllowMimeType: #允许的文件mime类型列表
|
||||
Size: 32 # 设置上传文件的最大值,单位:M,注意: 如果go前置nginx服务器,nginx 默认限制文件上传大小为 50 M ,用户上传文件限制还需要继续修改 nginx 配置
|
||||
UploadFileField: "file" # post上传文件时,表单的键名
|
||||
# TODO 为了方便后续兼容服务器上的 Nginx,直接采取绝对路径,
|
||||
UploadFileSavePath: "D:/.File Data/GoProject/catface_back/public/nginx" # 上传文件保存在路径, 该路径与 BasePath 进行拼接使用
|
||||
UploadFileReturnPath: "" # 文件上后返回的路径,由于程序会自动创建软连接,自动将资源定位到实际路径,所有资源的访问入口建议都从public开始
|
||||
AllowMimeType: #允许的文件mime类型列表
|
||||
- "image/jpeg" #jpg、jpeg图片格式
|
||||
- "image/png" #png图片格式
|
||||
# - "image/x-icon" #ico图片
|
||||
@ -155,7 +156,14 @@ Glm:
|
||||
ApiKey: "0cf510ebc01599dba2a593069c1bdfbc.nQBQ4skP8xBh7ijU"
|
||||
DefaultModel: "glm-4-flash"
|
||||
|
||||
|
||||
# qiNiu 云存储配置
|
||||
QiNiu:
|
||||
AccessKey: "bI1MpHUBA9OCg4uSJkuJRmScuCJfOlbePe8fCENo"
|
||||
SecretKey: "UP5-GmSmAYNbMlSb6LYLuKZ-fT35nlEzGvOKKm9S"
|
||||
SecretKey: "UP5-GmSmAYNbMlSb6LYLuKZ-fT35nlEzGvOKKm9S"
|
||||
|
||||
ElasticSearch:
|
||||
Addr: "http://localhost:9200"
|
||||
UserName: "elastic"
|
||||
Password: ""
|
||||
|
||||
|
@ -5,7 +5,8 @@ Gormv2: # 只针对 gorm 操作数据库有效
|
||||
IsInitGlobalGormMysql: 1 # 随项目启动为gorm db初始化一个全局 variable.GormDbMysql(完全等于*gorm.Db),正确配置数据库,该值必须设置为: 1
|
||||
SlowThreshold: 30 # 慢 SQL 阈值(sql执行时间超过此时间单位(秒),就会触发系统日志记录)
|
||||
Write:
|
||||
Host: "113.44.68.213"
|
||||
# Host: "113.44.68.213"
|
||||
Host: "127.0.0.1"
|
||||
DataBase: "hav_cats"
|
||||
Port: 3306
|
||||
Prefix: "tb_" # 目前没有用到该配置项
|
||||
|
@ -149,6 +149,11 @@ func InitWebRouter() *gin.Engine {
|
||||
{
|
||||
nlp.POST("title", validatorFactory.Create(consts.ValidatorPrefix+"NlpTitle"))
|
||||
}
|
||||
|
||||
search := backend.Group("search")
|
||||
{
|
||||
search.GET("", validatorFactory.Create(consts.ValidatorPrefix+"SearchAll"))
|
||||
}
|
||||
// }
|
||||
}
|
||||
|
||||
|
50
test/es/encounter_test.go
Normal file
50
test/es/encounter_test.go
Normal file
@ -0,0 +1,50 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"catface/app/global/variable"
|
||||
"catface/app/model"
|
||||
"catface/app/model_es"
|
||||
_ "catface/bootstrap"
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestEncounterEs(t *testing.T) {
|
||||
// 示例数据
|
||||
encounterOri := &model.Encounter{
|
||||
BaseModel: model.BaseModel{
|
||||
Id: 4,
|
||||
},
|
||||
Title: "猪皮伤势轻,需静养猪皮伤势轻,需静养",
|
||||
Content: "猪皮被带到医院检查了,拍片结果显示损伤不严重,静养即可自愈。建议这段时间不要折腾他,让老登好好休息。",
|
||||
TagsSlice: []string{"猪皮", "脚伤", "骗保"},
|
||||
}
|
||||
|
||||
encounter := model_es.CreateEncounterESFactory(encounterOri)
|
||||
|
||||
// 插入文档
|
||||
// if err := encounter.InsertDocument(); err != nil {
|
||||
// t.Fatalf("插入文档时出错: %s", err)
|
||||
// }
|
||||
go encounter.InsertDocument()
|
||||
|
||||
// // 更新文档
|
||||
// encounter.Content = "更新: 猪皮被带到医院检查了,拍片结果显示损伤不严重,静养即可自愈。建议这段时间不要折腾他,让老登好好休息。"
|
||||
// if err := encounter.UpdateDocument(variable.ElasticClient, encounter); err != nil {
|
||||
// t.Fatalf("更新文档时出错: %s", err)
|
||||
// }
|
||||
|
||||
// 查询文档
|
||||
encounters, err := encounter.QueryDocumentsMatchAll(variable.ElasticClient, "猪皮")
|
||||
if err != nil {
|
||||
t.Fatalf("查询文档时出错: %s", err)
|
||||
}
|
||||
|
||||
// for _, e := range encounters {
|
||||
// fmt.Printf("ID: %d, 标题: %s, 内容: %s, 标签: %v\n", e.Id, e.Title, e.Content, e.Tags)
|
||||
// }
|
||||
|
||||
for _, e := range encounters {
|
||||
fmt.Printf("ID: %d\n", e)
|
||||
}
|
||||
}
|
@ -13,7 +13,7 @@ func InitElastic() {
|
||||
var err error
|
||||
ElasticClient, err = elasticsearch.NewClient(elasticsearch.Config{
|
||||
// Addresses: []string{"http://113.44.68.213:9200"},
|
||||
Addresses: []string{"http://127.0.0.1:9200"},
|
||||
Addresses: []string{"http://localhost:9200"}, // TIP 用 localhost 可以,127.0.0.1 无效...
|
||||
// Username: "elastic",
|
||||
// Password: "U8n61yn*Sp4Kvbuqo_K8",
|
||||
})
|
||||
|
@ -15,7 +15,8 @@ var DB *gorm.DB
|
||||
|
||||
func Init() {
|
||||
dsn := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=True&loc=Local",
|
||||
"root", "Havocantelope412#", "113.44.68.213", "3306", "hav_cats") // danger MySQL
|
||||
"root", "havocantelope412", "127.0.0.1", "3306", "hav_cats") // ATT MySQL
|
||||
|
||||
fmt.Println("dsn:", dsn)
|
||||
dbMySQL, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
|
||||
if err != nil {
|
||||
|
Loading…
x
Reference in New Issue
Block a user