You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

ai_model_manage.go 30 kB

2 years ago
2 years ago
3 years ago
3 years ago
3 years ago
2 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006
  1. package repo
  2. import (
  3. "archive/zip"
  4. "encoding/json"
  5. "errors"
  6. "fmt"
  7. "net/http"
  8. "net/url"
  9. "path"
  10. "regexp"
  11. "strings"
  12. "code.gitea.io/gitea/models"
  13. "code.gitea.io/gitea/modules/context"
  14. "code.gitea.io/gitea/modules/log"
  15. "code.gitea.io/gitea/modules/notification"
  16. "code.gitea.io/gitea/modules/setting"
  17. "code.gitea.io/gitea/modules/storage"
  18. "code.gitea.io/gitea/services/cloudbrain/resource"
  19. uuid "github.com/satori/go.uuid"
  20. )
  21. const (
  22. Model_prefix = "aimodels/"
  23. tplModelManageIndex = "repo/modelmanage/index"
  24. tplModelManageDownload = "repo/modelmanage/download"
  25. tplModelInfo = "repo/modelmanage/showinfo"
  26. MODEL_LATEST = 1
  27. MODEL_NOT_LATEST = 0
  28. MODEL_MAX_SIZE = 1024 * 1024 * 1024
  29. STATUS_COPY_MODEL = 1
  30. STATUS_FINISHED = 0
  31. STATUS_ERROR = 2
  32. )
  33. func saveModelByParameters(jobId string, versionName string, name string, version string, label string, description string, engine int, ctx *context.Context) (string, error) {
  34. aiTask, err := models.GetCloudbrainByJobIDAndVersionName(jobId, versionName)
  35. if err != nil {
  36. aiTask, err = models.GetRepoCloudBrainByJobID(ctx.Repo.Repository.ID, jobId)
  37. if err != nil {
  38. log.Info("query task error." + err.Error())
  39. return "", err
  40. } else {
  41. log.Info("query gpu train task.")
  42. }
  43. }
  44. uuid := uuid.NewV4()
  45. id := uuid.String()
  46. modelPath := id
  47. var lastNewModelId string
  48. var modelSize int64
  49. log.Info("find task name:" + aiTask.JobName)
  50. aimodels := models.QueryModelByName(name, aiTask.RepoID)
  51. if len(aimodels) > 0 {
  52. for _, model := range aimodels {
  53. if model.Version == version {
  54. return "", errors.New(ctx.Tr("repo.model.manage.create_error"))
  55. }
  56. if model.New == MODEL_LATEST {
  57. lastNewModelId = model.ID
  58. }
  59. }
  60. }
  61. cloudType := aiTask.Type
  62. modelSelectedFile := ctx.Query("modelSelectedFile")
  63. //download model zip //train type
  64. if aiTask.ComputeResource == models.NPUResource {
  65. cloudType = models.TypeCloudBrainTwo
  66. } else if aiTask.ComputeResource == models.GPUResource {
  67. cloudType = models.TypeCloudBrainOne
  68. spec, err := resource.GetCloudbrainSpec(aiTask.ID)
  69. if err == nil {
  70. flaverName := "GPU: " + fmt.Sprint(spec.AccCardsNum) + "*" + spec.AccCardType + ",CPU: " + fmt.Sprint(spec.CpuCores) + "," + ctx.Tr("cloudbrain.memory") + ": " + fmt.Sprint(spec.MemGiB) + "GB," + ctx.Tr("cloudbrain.shared_memory") + ": " + fmt.Sprint(spec.ShareMemGiB) + "GB"
  71. aiTask.FlavorName = flaverName
  72. }
  73. }
  74. accuracy := make(map[string]string)
  75. accuracy["F1"] = ""
  76. accuracy["Recall"] = ""
  77. accuracy["Accuracy"] = ""
  78. accuracy["Precision"] = ""
  79. accuracyJson, _ := json.Marshal(accuracy)
  80. log.Info("accuracyJson=" + string(accuracyJson))
  81. aiTask.ContainerIp = ""
  82. aiTaskJson, _ := json.Marshal(aiTask)
  83. model := &models.AiModelManage{
  84. ID: id,
  85. Version: version,
  86. VersionCount: len(aimodels) + 1,
  87. Label: label,
  88. Name: name,
  89. Description: description,
  90. New: MODEL_LATEST,
  91. Type: cloudType,
  92. Path: modelPath,
  93. Size: modelSize,
  94. AttachmentId: aiTask.Uuid,
  95. RepoId: aiTask.RepoID,
  96. UserId: ctx.User.ID,
  97. CodeBranch: aiTask.BranchName,
  98. CodeCommitID: aiTask.CommitID,
  99. Engine: int64(engine),
  100. TrainTaskInfo: string(aiTaskJson),
  101. Accuracy: string(accuracyJson),
  102. Status: STATUS_COPY_MODEL,
  103. }
  104. err = models.SaveModelToDb(model)
  105. if err != nil {
  106. return "", err
  107. }
  108. if len(lastNewModelId) > 0 {
  109. //udpate status and version count
  110. models.ModifyModelNewProperty(lastNewModelId, MODEL_NOT_LATEST, 0)
  111. }
  112. var units []models.RepoUnit
  113. var deleteUnitTypes []models.UnitType
  114. units = append(units, models.RepoUnit{
  115. RepoID: ctx.Repo.Repository.ID,
  116. Type: models.UnitTypeModelManage,
  117. Config: &models.ModelManageConfig{
  118. EnableModelManage: true,
  119. },
  120. })
  121. deleteUnitTypes = append(deleteUnitTypes, models.UnitTypeModelManage)
  122. models.UpdateRepositoryUnits(ctx.Repo.Repository, units, deleteUnitTypes)
  123. go asyncToCopyModel(aiTask, id, modelSelectedFile)
  124. log.Info("save model end.")
  125. notification.NotifyOtherTask(ctx.User, ctx.Repo.Repository, id, name, models.ActionCreateNewModelTask)
  126. return id, nil
  127. }
  128. func asyncToCopyModel(aiTask *models.Cloudbrain, id string, modelSelectedFile string) {
  129. if aiTask.ComputeResource == models.NPUResource {
  130. modelPath, modelSize, err := downloadModelFromCloudBrainTwo(id, aiTask.JobName, "", aiTask.TrainUrl, modelSelectedFile)
  131. if err != nil {
  132. updateStatus(id, 0, STATUS_ERROR, modelPath, err.Error())
  133. log.Info("download model from CloudBrainTwo faild." + err.Error())
  134. } else {
  135. updateStatus(id, modelSize, STATUS_FINISHED, modelPath, "")
  136. }
  137. } else if aiTask.ComputeResource == models.GPUResource {
  138. modelPath, modelSize, err := downloadModelFromCloudBrainOne(id, aiTask.JobName, "", aiTask.TrainUrl, modelSelectedFile)
  139. if err != nil {
  140. updateStatus(id, 0, STATUS_ERROR, modelPath, err.Error())
  141. log.Info("download model from CloudBrainOne faild." + err.Error())
  142. } else {
  143. updateStatus(id, modelSize, STATUS_FINISHED, modelPath, "")
  144. }
  145. }
  146. }
  147. func updateStatus(id string, modelSize int64, status int, modelPath string, statusDesc string) {
  148. if len(statusDesc) > 400 {
  149. statusDesc = statusDesc[0:400]
  150. }
  151. err := models.ModifyModelStatus(id, modelSize, status, modelPath, statusDesc)
  152. if err != nil {
  153. log.Info("update status error." + err.Error())
  154. }
  155. }
  156. func SaveNewNameModel(ctx *context.Context) {
  157. if !ctx.Repo.CanWrite(models.UnitTypeModelManage) {
  158. ctx.Error(403, ctx.Tr("repo.model_noright"))
  159. return
  160. }
  161. name := ctx.Query("name")
  162. if name == "" {
  163. ctx.Error(500, fmt.Sprintf("name or version is null."))
  164. return
  165. }
  166. aimodels := models.QueryModelByName(name, ctx.Repo.Repository.ID)
  167. if len(aimodels) > 0 {
  168. ctx.Error(500, ctx.Tr("repo.model_rename"))
  169. return
  170. }
  171. SaveModel(ctx)
  172. ctx.Status(200)
  173. log.Info("save model end.")
  174. }
  175. func SaveModel(ctx *context.Context) {
  176. if !ctx.Repo.CanWrite(models.UnitTypeModelManage) {
  177. ctx.Error(403, ctx.Tr("repo.model_noright"))
  178. return
  179. }
  180. log.Info("save model start.")
  181. JobId := ctx.Query("jobId")
  182. VersionName := ctx.Query("versionName")
  183. name := ctx.Query("name")
  184. version := ctx.Query("version")
  185. label := ctx.Query("label")
  186. description := ctx.Query("description")
  187. engine := ctx.QueryInt("engine")
  188. modelSelectedFile := ctx.Query("modelSelectedFile")
  189. log.Info("engine=" + fmt.Sprint(engine) + " modelSelectedFile=" + modelSelectedFile)
  190. re := map[string]string{
  191. "code": "-1",
  192. }
  193. if JobId == "" || VersionName == "" {
  194. re["msg"] = "JobId or VersionName is null."
  195. ctx.JSON(200, re)
  196. return
  197. }
  198. if modelSelectedFile == "" {
  199. re["msg"] = "Not selected model file."
  200. ctx.JSON(200, re)
  201. return
  202. }
  203. if name == "" || version == "" {
  204. re["msg"] = "name or version is null."
  205. ctx.JSON(200, re)
  206. return
  207. }
  208. id, err := saveModelByParameters(JobId, VersionName, name, version, label, description, engine, ctx)
  209. if err != nil {
  210. log.Info("save model error." + err.Error())
  211. re["msg"] = err.Error()
  212. } else {
  213. re["code"] = "0"
  214. re["id"] = id
  215. }
  216. ctx.JSON(200, re)
  217. log.Info("save model end.")
  218. }
  219. func downloadModelFromCloudBrainTwo(modelUUID string, jobName string, parentDir string, trainUrl string, modelSelectedFile string) (string, int64, error) {
  220. objectkey := strings.TrimPrefix(path.Join(setting.TrainJobModelPath, jobName, setting.OutPutPath, parentDir), "/")
  221. if trainUrl != "" {
  222. objectkey = strings.Trim(trainUrl[len(setting.Bucket)+1:], "/")
  223. }
  224. prefix := objectkey + "/"
  225. filterFiles := strings.Split(modelSelectedFile, ";")
  226. Files := make([]string, 0)
  227. for _, shortFile := range filterFiles {
  228. Files = append(Files, prefix+shortFile)
  229. }
  230. totalSize := storage.ObsGetFilesSize(setting.Bucket, Files)
  231. if float64(totalSize) > setting.MaxModelSize*MODEL_MAX_SIZE {
  232. return "", 0, errors.New("Cannot create model, as model is exceed " + fmt.Sprint(setting.MaxModelSize) + "G.")
  233. }
  234. modelDbResult, err := storage.GetOneLevelAllObjectUnderDir(setting.Bucket, objectkey, "")
  235. log.Info("bucket=" + setting.Bucket + " objectkey=" + objectkey)
  236. if err != nil {
  237. log.Info("get TrainJobListModel failed:", err)
  238. return "", 0, err
  239. }
  240. if len(modelDbResult) == 0 {
  241. return "", 0, errors.New("Cannot create model, as model is empty.")
  242. }
  243. destKeyNamePrefix := Model_prefix + models.AttachmentRelativePath(modelUUID) + "/"
  244. size, err := storage.ObsCopyManyFile(setting.Bucket, prefix, setting.Bucket, destKeyNamePrefix, filterFiles)
  245. dataActualPath := setting.Bucket + "/" + destKeyNamePrefix
  246. return dataActualPath, size, nil
  247. }
  248. func downloadModelFromCloudBrainOne(modelUUID string, jobName string, parentDir string, trainUrl string, modelSelectedFile string) (string, int64, error) {
  249. modelActualPath := storage.GetMinioPath(jobName, "/model/")
  250. log.Info("modelActualPath=" + modelActualPath)
  251. modelSrcPrefix := setting.CBCodePathPrefix + jobName + "/model/"
  252. destKeyNamePrefix := Model_prefix + models.AttachmentRelativePath(modelUUID) + "/"
  253. bucketName := setting.Attachment.Minio.Bucket
  254. log.Info("destKeyNamePrefix=" + destKeyNamePrefix + " modelSrcPrefix=" + modelSrcPrefix + " bucket=" + bucketName)
  255. filterFiles := strings.Split(modelSelectedFile, ";")
  256. Files := make([]string, 0)
  257. for _, shortFile := range filterFiles {
  258. Files = append(Files, modelSrcPrefix+shortFile)
  259. }
  260. totalSize := storage.MinioGetFilesSize(bucketName, Files)
  261. if float64(totalSize) > setting.MaxModelSize*MODEL_MAX_SIZE {
  262. return "", 0, errors.New("Cannot create model, as model is exceed " + fmt.Sprint(setting.MaxModelSize) + "G.")
  263. }
  264. size, err := storage.MinioCopyFiles(bucketName, modelSrcPrefix, destKeyNamePrefix, filterFiles)
  265. if err == nil {
  266. dataActualPath := bucketName + "/" + destKeyNamePrefix
  267. return dataActualPath, size, nil
  268. } else {
  269. return "", 0, nil
  270. }
  271. }
  272. func DeleteModel(ctx *context.Context) {
  273. log.Info("delete model start.")
  274. id := ctx.Query("id")
  275. err := deleteModelByID(ctx, id)
  276. if err != nil {
  277. re := map[string]string{
  278. "code": "-1",
  279. }
  280. re["msg"] = err.Error()
  281. ctx.JSON(200, re)
  282. } else {
  283. ctx.JSON(200, map[string]string{
  284. "code": "0",
  285. })
  286. }
  287. }
  288. func deleteModelByID(ctx *context.Context, id string) error {
  289. log.Info("delete model start. id=" + id)
  290. model, err := models.QueryModelById(id)
  291. if !isCanDelete(ctx, model.UserId) {
  292. return errors.New(ctx.Tr("repo.model_noright"))
  293. }
  294. if err == nil {
  295. log.Info("bucket=" + setting.Bucket + " path=" + model.Path)
  296. if strings.HasPrefix(model.Path, setting.Bucket+"/"+Model_prefix) {
  297. err := storage.ObsRemoveObject(setting.Bucket, model.Path[len(setting.Bucket)+1:])
  298. if err != nil {
  299. log.Info("Failed to delete model. id=" + id)
  300. return err
  301. }
  302. }
  303. err = models.DeleteModelById(id)
  304. if err == nil { //find a model to change new
  305. aimodels := models.QueryModelByName(model.Name, model.RepoId)
  306. if model.New == MODEL_LATEST {
  307. if len(aimodels) > 0 {
  308. //udpate status and version count
  309. models.ModifyModelNewProperty(aimodels[0].ID, MODEL_LATEST, len(aimodels))
  310. }
  311. } else {
  312. for _, tmpModel := range aimodels {
  313. if tmpModel.New == MODEL_LATEST {
  314. models.ModifyModelNewProperty(tmpModel.ID, MODEL_LATEST, len(aimodels))
  315. break
  316. }
  317. }
  318. }
  319. }
  320. }
  321. return err
  322. }
  323. func QueryModelByParameters(repoId int64, page int) ([]*models.AiModelManage, int64, error) {
  324. return models.QueryModel(&models.AiModelQueryOptions{
  325. ListOptions: models.ListOptions{
  326. Page: page,
  327. PageSize: setting.UI.IssuePagingNum,
  328. },
  329. RepoID: repoId,
  330. Type: -1,
  331. New: MODEL_LATEST,
  332. Status: -1,
  333. })
  334. }
  335. func DownloadMultiModelFile(ctx *context.Context) {
  336. log.Info("DownloadMultiModelFile start.")
  337. id := ctx.Query("id")
  338. log.Info("id=" + id)
  339. task, err := models.QueryModelById(id)
  340. if err != nil {
  341. log.Error("no such model!", err.Error())
  342. ctx.ServerError("no such model:", err)
  343. return
  344. }
  345. if !isOper(ctx, task.UserId) {
  346. ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
  347. return
  348. }
  349. path := Model_prefix + models.AttachmentRelativePath(id) + "/"
  350. if task.Type == models.TypeCloudBrainTwo {
  351. downloadFromCloudBrainTwo(path, task, ctx, id)
  352. } else if task.Type == models.TypeCloudBrainOne {
  353. downloadFromCloudBrainOne(path, task, ctx, id)
  354. }
  355. }
  356. func MinioDownloadManyFile(path string, ctx *context.Context, returnFileName string, allFile []storage.FileInfo) {
  357. ctx.Resp.Header().Set("Content-Disposition", "attachment; filename="+url.QueryEscape(returnFileName))
  358. ctx.Resp.Header().Set("Content-Type", "application/octet-stream")
  359. w := zip.NewWriter(ctx.Resp)
  360. defer w.Close()
  361. for _, oneFile := range allFile {
  362. if oneFile.IsDir {
  363. log.Info("zip dir name:" + oneFile.FileName)
  364. } else {
  365. log.Info("zip file name:" + oneFile.FileName)
  366. fDest, err := w.Create(oneFile.FileName)
  367. if err != nil {
  368. log.Info("create zip entry error, download file failed: %s\n", err.Error())
  369. ctx.ServerError("download file failed:", err)
  370. return
  371. }
  372. log.Info("minio file path=" + (path + oneFile.FileName))
  373. body, err := storage.Attachments.DownloadAFile(setting.Attachment.Minio.Bucket, path+oneFile.FileName)
  374. if err != nil {
  375. log.Info("download file failed: %s\n", err.Error())
  376. ctx.ServerError("download file failed:", err)
  377. return
  378. } else {
  379. defer body.Close()
  380. p := make([]byte, 1024)
  381. var readErr error
  382. var readCount int
  383. // 读取对象内容
  384. for {
  385. readCount, readErr = body.Read(p)
  386. if readCount > 0 {
  387. fDest.Write(p[:readCount])
  388. }
  389. if readErr != nil {
  390. break
  391. }
  392. }
  393. }
  394. }
  395. }
  396. }
  397. func downloadFromCloudBrainOne(path string, task *models.AiModelManage, ctx *context.Context, id string) {
  398. allFile, err := storage.GetAllObjectByBucketAndPrefixMinio(setting.Attachment.Minio.Bucket, path)
  399. if err == nil {
  400. //count++
  401. models.ModifyModelDownloadCount(id)
  402. returnFileName := task.Name + "_" + task.Version + ".zip"
  403. MinioDownloadManyFile(path, ctx, returnFileName, allFile)
  404. } else {
  405. log.Info("error,msg=" + err.Error())
  406. ctx.ServerError("no file to download.", err)
  407. }
  408. }
  409. func ObsDownloadManyFile(path string, ctx *context.Context, returnFileName string, allFile []storage.FileInfo) {
  410. ctx.Resp.Header().Set("Content-Disposition", "attachment; filename="+url.QueryEscape(returnFileName))
  411. ctx.Resp.Header().Set("Content-Type", "application/octet-stream")
  412. w := zip.NewWriter(ctx.Resp)
  413. defer w.Close()
  414. for _, oneFile := range allFile {
  415. if oneFile.IsDir {
  416. log.Info("zip dir name:" + oneFile.FileName)
  417. } else {
  418. log.Info("zip file name:" + oneFile.FileName)
  419. fDest, err := w.Create(oneFile.FileName)
  420. if err != nil {
  421. log.Info("create zip entry error, download file failed: %s\n", err.Error())
  422. ctx.ServerError("download file failed:", err)
  423. return
  424. }
  425. body, err := storage.ObsDownloadAFile(setting.Bucket, path+oneFile.FileName)
  426. if err != nil {
  427. log.Info("download file failed: %s\n", err.Error())
  428. ctx.ServerError("download file failed:", err)
  429. return
  430. } else {
  431. defer body.Close()
  432. p := make([]byte, 1024)
  433. var readErr error
  434. var readCount int
  435. // 读取对象内容
  436. for {
  437. readCount, readErr = body.Read(p)
  438. if readCount > 0 {
  439. fDest.Write(p[:readCount])
  440. }
  441. if readErr != nil {
  442. break
  443. }
  444. }
  445. }
  446. }
  447. }
  448. }
  449. func downloadFromCloudBrainTwo(path string, task *models.AiModelManage, ctx *context.Context, id string) {
  450. allFile, err := storage.GetAllObjectByBucketAndPrefix(setting.Bucket, path)
  451. if err == nil {
  452. //count++
  453. models.ModifyModelDownloadCount(id)
  454. returnFileName := task.Name + "_" + task.Version + ".zip"
  455. ObsDownloadManyFile(path, ctx, returnFileName, allFile)
  456. } else {
  457. log.Info("error,msg=" + err.Error())
  458. ctx.ServerError("no file to download.", err)
  459. }
  460. }
  461. func QueryTrainJobVersionList(ctx *context.Context) {
  462. log.Info("query train job version list. start.")
  463. JobID := ctx.Query("jobId")
  464. if JobID == "" {
  465. JobID = ctx.Query("JobId")
  466. }
  467. VersionListTasks, count, err := models.QueryModelTrainJobVersionList(JobID)
  468. log.Info("query return count=" + fmt.Sprint(count))
  469. if err != nil {
  470. ctx.ServerError("QueryTrainJobList:", err)
  471. } else {
  472. ctx.JSON(200, VersionListTasks)
  473. }
  474. }
  475. func QueryTrainJobList(ctx *context.Context) {
  476. log.Info("query train job list. start.")
  477. repoId := ctx.QueryInt64("repoId")
  478. VersionListTasks, count, err := models.QueryModelTrainJobList(repoId)
  479. log.Info("query return count=" + fmt.Sprint(count))
  480. if err != nil {
  481. ctx.ServerError("QueryTrainJobList:", err)
  482. } else {
  483. ctx.JSON(200, VersionListTasks)
  484. }
  485. }
  486. func QueryTrainModelFileById(ctx *context.Context) ([]storage.FileInfo, error) {
  487. JobID := ctx.Query("jobId")
  488. VersionListTasks, count, err := models.QueryModelTrainJobVersionList(JobID)
  489. if err == nil {
  490. if count == 1 {
  491. task := VersionListTasks[0]
  492. jobName := task.JobName
  493. taskType := task.Type
  494. VersionName := task.VersionName
  495. modelDbResult, err := getModelFromObjectSave(jobName, taskType, VersionName)
  496. return modelDbResult, err
  497. }
  498. }
  499. log.Info("get TypeCloudBrainTwo TrainJobListModel failed:", err)
  500. return nil, errors.New("Not found task.")
  501. }
  502. func getModelFromObjectSave(jobName string, taskType int, VersionName string) ([]storage.FileInfo, error) {
  503. if taskType == models.TypeCloudBrainTwo {
  504. objectkey := path.Join(setting.TrainJobModelPath, jobName, setting.OutPutPath, VersionName) + "/"
  505. modelDbResult, err := storage.GetAllObjectByBucketAndPrefix(setting.Bucket, objectkey)
  506. log.Info("bucket=" + setting.Bucket + " objectkey=" + objectkey)
  507. if err != nil {
  508. log.Info("get TypeCloudBrainTwo TrainJobListModel failed:", err)
  509. return nil, err
  510. } else {
  511. return modelDbResult, nil
  512. }
  513. } else if taskType == models.TypeCloudBrainOne {
  514. modelSrcPrefix := setting.CBCodePathPrefix + jobName + "/model/"
  515. bucketName := setting.Attachment.Minio.Bucket
  516. modelDbResult, err := storage.GetAllObjectByBucketAndPrefixMinio(bucketName, modelSrcPrefix)
  517. if err != nil {
  518. log.Info("get TypeCloudBrainOne TrainJobListModel failed:", err)
  519. return nil, err
  520. } else {
  521. return modelDbResult, nil
  522. }
  523. }
  524. return nil, errors.New("Not support.")
  525. }
  526. func QueryTrainModelList(ctx *context.Context) {
  527. log.Info("query train job list. start.")
  528. jobName := ctx.Query("jobName")
  529. taskType := ctx.QueryInt("type")
  530. VersionName := ctx.Query("versionName")
  531. if VersionName == "" {
  532. VersionName = ctx.Query("VersionName")
  533. }
  534. modelDbResult, err := getModelFromObjectSave(jobName, taskType, VersionName)
  535. if err != nil {
  536. log.Info("get TypeCloudBrainTwo TrainJobListModel failed:", err)
  537. ctx.JSON(200, "")
  538. } else {
  539. ctx.JSON(200, modelDbResult)
  540. return
  541. }
  542. }
  543. func DownloadSingleModelFile(ctx *context.Context) {
  544. log.Info("DownloadSingleModelFile start.")
  545. id := ctx.Params(":ID")
  546. parentDir := ctx.Query("parentDir")
  547. fileName := ctx.Query("fileName")
  548. path := Model_prefix + models.AttachmentRelativePath(id) + "/" + parentDir + fileName
  549. task, err := models.QueryModelById(id)
  550. if err != nil {
  551. log.Error("no such model!", err.Error())
  552. ctx.ServerError("no such model:", err)
  553. return
  554. }
  555. if !isOper(ctx, task.UserId) {
  556. ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
  557. return
  558. }
  559. if task.Type == models.TypeCloudBrainTwo {
  560. if setting.PROXYURL != "" {
  561. body, err := storage.ObsDownloadAFile(setting.Bucket, path)
  562. if err != nil {
  563. log.Info("download error.")
  564. } else {
  565. //count++
  566. models.ModifyModelDownloadCount(id)
  567. defer body.Close()
  568. ctx.Resp.Header().Set("Content-Disposition", "attachment; filename="+fileName)
  569. ctx.Resp.Header().Set("Content-Type", "application/octet-stream")
  570. p := make([]byte, 1024)
  571. var readErr error
  572. var readCount int
  573. // 读取对象内容
  574. for {
  575. readCount, readErr = body.Read(p)
  576. if readCount > 0 {
  577. ctx.Resp.Write(p[:readCount])
  578. //fmt.Printf("%s", p[:readCount])
  579. }
  580. if readErr != nil {
  581. break
  582. }
  583. }
  584. }
  585. } else {
  586. url, err := storage.GetObsCreateSignedUrlByBucketAndKey(setting.Bucket, path)
  587. if err != nil {
  588. log.Error("GetObsCreateSignedUrl failed: %v", err.Error(), ctx.Data["msgID"])
  589. ctx.ServerError("GetObsCreateSignedUrl", err)
  590. return
  591. }
  592. //count++
  593. models.ModifyModelDownloadCount(id)
  594. http.Redirect(ctx.Resp, ctx.Req.Request, url, http.StatusMovedPermanently)
  595. }
  596. } else if task.Type == models.TypeCloudBrainOne {
  597. log.Info("start to down load minio file.")
  598. url, err := storage.Attachments.PresignedGetURL(path, fileName)
  599. if err != nil {
  600. log.Error("Get minio get SignedUrl failed: %v", err.Error(), ctx.Data["msgID"])
  601. ctx.ServerError("Get minio get SignedUrl failed", err)
  602. return
  603. }
  604. models.ModifyModelDownloadCount(id)
  605. http.Redirect(ctx.Resp, ctx.Req.Request, url, http.StatusMovedPermanently)
  606. }
  607. }
  608. func ShowModelInfo(ctx *context.Context) {
  609. ctx.Data["ID"] = ctx.Query("id")
  610. ctx.Data["name"] = ctx.Query("name")
  611. ctx.Data["isModelManage"] = true
  612. ctx.Data["ModelManageAccess"] = ctx.Repo.CanWrite(models.UnitTypeModelManage)
  613. ctx.HTML(200, tplModelInfo)
  614. }
  615. func QueryModelById(ctx *context.Context) {
  616. id := ctx.Query("id")
  617. model, err := models.QueryModelById(id)
  618. if err == nil {
  619. model.IsCanOper = isOper(ctx, model.UserId)
  620. model.IsCanDelete = isCanDelete(ctx, model.UserId)
  621. removeIpInfo(model)
  622. ctx.JSON(http.StatusOK, model)
  623. } else {
  624. ctx.JSON(http.StatusNotFound, nil)
  625. }
  626. }
  627. func ShowSingleModel(ctx *context.Context) {
  628. name := ctx.Query("name")
  629. log.Info("Show single ModelInfo start.name=" + name)
  630. models := models.QueryModelByName(name, ctx.Repo.Repository.ID)
  631. userIds := make([]int64, len(models))
  632. for i, model := range models {
  633. model.IsCanOper = isOper(ctx, model.UserId)
  634. model.IsCanDelete = isCanDelete(ctx, model.UserId)
  635. userIds[i] = model.UserId
  636. }
  637. userNameMap := queryUserName(userIds)
  638. for _, model := range models {
  639. removeIpInfo(model)
  640. value := userNameMap[model.UserId]
  641. if value != nil {
  642. model.UserName = value.Name
  643. model.UserRelAvatarLink = value.RelAvatarLink()
  644. }
  645. }
  646. ctx.JSON(http.StatusOK, models)
  647. }
  648. func removeIpInfo(model *models.AiModelManage) {
  649. reg, _ := regexp.Compile(`[[:digit:]]{1,3}\.[[:digit:]]{1,3}\.[[:digit:]]{1,3}\.[[:digit:]]{1,3}`)
  650. taskInfo := model.TrainTaskInfo
  651. taskInfo = reg.ReplaceAllString(taskInfo, "")
  652. model.TrainTaskInfo = taskInfo
  653. }
  654. func queryUserName(intSlice []int64) map[int64]*models.User {
  655. keys := make(map[int64]string)
  656. uniqueElements := []int64{}
  657. for _, entry := range intSlice {
  658. if _, value := keys[entry]; !value {
  659. keys[entry] = ""
  660. uniqueElements = append(uniqueElements, entry)
  661. }
  662. }
  663. result := make(map[int64]*models.User)
  664. userLists, err := models.GetUsersByIDs(uniqueElements)
  665. if err == nil {
  666. for _, user := range userLists {
  667. result[user.ID] = user
  668. }
  669. }
  670. return result
  671. }
  672. func ShowOneVersionOtherModel(ctx *context.Context) {
  673. repoId := ctx.Repo.Repository.ID
  674. name := ctx.Query("name")
  675. aimodels := models.QueryModelByName(name, repoId)
  676. userIds := make([]int64, len(aimodels))
  677. for i, model := range aimodels {
  678. model.IsCanOper = isOper(ctx, model.UserId)
  679. model.IsCanDelete = isCanDelete(ctx, model.UserId)
  680. userIds[i] = model.UserId
  681. }
  682. userNameMap := queryUserName(userIds)
  683. for _, model := range aimodels {
  684. removeIpInfo(model)
  685. value := userNameMap[model.UserId]
  686. if value != nil {
  687. model.UserName = value.Name
  688. model.UserRelAvatarLink = value.RelAvatarLink()
  689. }
  690. }
  691. if len(aimodels) > 0 {
  692. ctx.JSON(200, aimodels[1:])
  693. } else {
  694. ctx.JSON(200, aimodels)
  695. }
  696. }
  697. func SetModelCount(ctx *context.Context) {
  698. repoId := ctx.Repo.Repository.ID
  699. Type := -1
  700. _, count, _ := models.QueryModel(&models.AiModelQueryOptions{
  701. ListOptions: models.ListOptions{
  702. Page: 1,
  703. PageSize: 2,
  704. },
  705. RepoID: repoId,
  706. Type: Type,
  707. New: MODEL_LATEST,
  708. Status: -1,
  709. })
  710. ctx.Data["MODEL_COUNT"] = count
  711. }
  712. func ShowModelTemplate(ctx *context.Context) {
  713. ctx.Data["isModelManage"] = true
  714. repoId := ctx.Repo.Repository.ID
  715. SetModelCount(ctx)
  716. ctx.Data["ModelManageAccess"] = ctx.Repo.CanWrite(models.UnitTypeModelManage)
  717. _, trainCount, _ := models.QueryModelTrainJobList(repoId)
  718. log.Info("query train count=" + fmt.Sprint(trainCount))
  719. ctx.Data["TRAIN_COUNT"] = trainCount
  720. ctx.HTML(200, tplModelManageIndex)
  721. }
  722. func isQueryRight(ctx *context.Context) bool {
  723. if ctx.Repo.Repository.IsPrivate {
  724. if ctx.Repo.CanRead(models.UnitTypeModelManage) || ctx.User.IsAdmin || ctx.Repo.IsAdmin() || ctx.Repo.IsOwner() {
  725. return true
  726. }
  727. return false
  728. } else {
  729. return true
  730. }
  731. }
  732. func isCanDelete(ctx *context.Context, modelUserId int64) bool {
  733. if ctx.User == nil {
  734. return false
  735. }
  736. if ctx.User.IsAdmin || ctx.User.ID == modelUserId {
  737. return true
  738. }
  739. if ctx.Repo.IsOwner() {
  740. return true
  741. }
  742. return false
  743. }
  744. func isOper(ctx *context.Context, modelUserId int64) bool {
  745. if ctx.User == nil {
  746. return false
  747. }
  748. if ctx.User.IsAdmin || ctx.User.ID == modelUserId {
  749. return true
  750. }
  751. return false
  752. }
  753. func ShowModelPageInfo(ctx *context.Context) {
  754. log.Info("ShowModelInfo start.")
  755. if !isQueryRight(ctx) {
  756. ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
  757. return
  758. }
  759. page := ctx.QueryInt("page")
  760. if page <= 0 {
  761. page = 1
  762. }
  763. pageSize := ctx.QueryInt("pageSize")
  764. if pageSize <= 0 {
  765. pageSize = setting.UI.IssuePagingNum
  766. }
  767. repoId := ctx.Repo.Repository.ID
  768. Type := -1
  769. modelResult, count, err := models.QueryModel(&models.AiModelQueryOptions{
  770. ListOptions: models.ListOptions{
  771. Page: page,
  772. PageSize: pageSize,
  773. },
  774. RepoID: repoId,
  775. Type: Type,
  776. New: MODEL_LATEST,
  777. Status: -1,
  778. })
  779. if err != nil {
  780. ctx.ServerError("Cloudbrain", err)
  781. return
  782. }
  783. userIds := make([]int64, len(modelResult))
  784. for i, model := range modelResult {
  785. model.IsCanOper = isOper(ctx, model.UserId)
  786. model.IsCanDelete = isCanDelete(ctx, model.UserId)
  787. userIds[i] = model.UserId
  788. }
  789. userNameMap := queryUserName(userIds)
  790. for _, model := range modelResult {
  791. removeIpInfo(model)
  792. value := userNameMap[model.UserId]
  793. if value != nil {
  794. model.UserName = value.Name
  795. model.UserRelAvatarLink = value.RelAvatarLink()
  796. }
  797. }
  798. mapInterface := make(map[string]interface{})
  799. mapInterface["data"] = modelResult
  800. mapInterface["count"] = count
  801. ctx.JSON(http.StatusOK, mapInterface)
  802. }
  803. func ModifyModel(id string, description string) error {
  804. err := models.ModifyModelDescription(id, description)
  805. if err == nil {
  806. log.Info("modify success.")
  807. } else {
  808. log.Info("Failed to modify.id=" + id + " desc=" + description + " error:" + err.Error())
  809. }
  810. return err
  811. }
  812. func ModifyModelInfo(ctx *context.Context) {
  813. log.Info("modify model start.")
  814. id := ctx.Query("id")
  815. description := ctx.Query("description")
  816. task, err := models.QueryModelById(id)
  817. if err != nil {
  818. log.Error("no such model!", err.Error())
  819. ctx.ServerError("no such model:", err)
  820. return
  821. }
  822. if !isOper(ctx, task.UserId) {
  823. ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
  824. //ctx.ServerError("no right.", errors.New(ctx.Tr("repo.model_noright")))
  825. return
  826. }
  827. err = ModifyModel(id, description)
  828. if err != nil {
  829. log.Info("modify error," + err.Error())
  830. ctx.ServerError("error.", err)
  831. } else {
  832. ctx.JSON(200, "success")
  833. }
  834. }
  835. func QueryModelListForPredict(ctx *context.Context) {
  836. repoId := ctx.Repo.Repository.ID
  837. modelResult, count, err := models.QueryModel(&models.AiModelQueryOptions{
  838. ListOptions: models.ListOptions{
  839. Page: -1,
  840. PageSize: -1,
  841. },
  842. RepoID: repoId,
  843. Type: ctx.QueryInt("type"),
  844. New: -1,
  845. Status: 0,
  846. })
  847. if err != nil {
  848. ctx.ServerError("Cloudbrain", err)
  849. return
  850. }
  851. log.Info("query return count=" + fmt.Sprint(count))
  852. nameList := make([]string, 0)
  853. nameMap := make(map[string][]*models.AiModelManage)
  854. for _, model := range modelResult {
  855. removeIpInfo(model)
  856. if _, value := nameMap[model.Name]; !value {
  857. models := make([]*models.AiModelManage, 0)
  858. models = append(models, model)
  859. nameMap[model.Name] = models
  860. nameList = append(nameList, model.Name)
  861. } else {
  862. nameMap[model.Name] = append(nameMap[model.Name], model)
  863. }
  864. }
  865. mapInterface := make(map[string]interface{})
  866. mapInterface["nameList"] = nameList
  867. mapInterface["nameMap"] = nameMap
  868. ctx.JSON(http.StatusOK, mapInterface)
  869. }
  870. func QueryModelFileForPredict(ctx *context.Context) {
  871. id := ctx.Query("id")
  872. if id == "" {
  873. id = ctx.Query("ID")
  874. }
  875. ctx.JSON(http.StatusOK, QueryModelFileByID(id))
  876. }
  877. func QueryModelFileByID(id string) []storage.FileInfo {
  878. model, err := models.QueryModelById(id)
  879. if err == nil {
  880. if model.Type == models.TypeCloudBrainTwo {
  881. prefix := model.Path[len(setting.Bucket)+1:]
  882. fileinfos, _ := storage.GetAllObjectByBucketAndPrefix(setting.Bucket, prefix)
  883. return fileinfos
  884. } else if model.Type == models.TypeCloudBrainOne {
  885. prefix := model.Path[len(setting.Attachment.Minio.Bucket)+1:]
  886. fileinfos, _ := storage.GetAllObjectByBucketAndPrefixMinio(setting.Attachment.Minio.Bucket, prefix)
  887. return fileinfos
  888. }
  889. } else {
  890. log.Error("no such model!", err.Error())
  891. }
  892. return nil
  893. }
  894. func QueryOneLevelModelFile(ctx *context.Context) {
  895. id := ctx.Query("id")
  896. if id == "" {
  897. id = ctx.Query("ID")
  898. }
  899. parentDir := ctx.Query("parentDir")
  900. model, err := models.QueryModelById(id)
  901. if err != nil {
  902. log.Error("no such model!", err.Error())
  903. ctx.ServerError("no such model:", err)
  904. return
  905. }
  906. if model.Type == models.TypeCloudBrainTwo {
  907. log.Info("TypeCloudBrainTwo list model file.")
  908. prefix := model.Path[len(setting.Bucket)+1:]
  909. fileinfos, _ := storage.GetOneLevelAllObjectUnderDir(setting.Bucket, prefix, parentDir)
  910. if fileinfos == nil {
  911. fileinfos = make([]storage.FileInfo, 0)
  912. }
  913. ctx.JSON(http.StatusOK, fileinfos)
  914. } else if model.Type == models.TypeCloudBrainOne {
  915. log.Info("TypeCloudBrainOne list model file.")
  916. prefix := model.Path[len(setting.Attachment.Minio.Bucket)+1:]
  917. fileinfos, _ := storage.GetOneLevelAllObjectUnderDirMinio(setting.Attachment.Minio.Bucket, prefix, parentDir)
  918. if fileinfos == nil {
  919. fileinfos = make([]storage.FileInfo, 0)
  920. }
  921. ctx.JSON(http.StatusOK, fileinfos)
  922. }
  923. }