Compare commits

..

2 Commits

Author SHA1 Message Date
2ab29d1e02 合併 2023-05-11 07:50:56 +08:00
69973202e0 服務器狀態 2023-04-29 19:16:03 +08:00
9 changed files with 376 additions and 27 deletions

View File

@@ -38,6 +38,7 @@ POST | /api/{name} | 篩選:創建新對象
- [ ] /api/models/{model_id} [#模型詳情](#模型詳情)
- [ ] /api/images/{image_id} [#圖片詳情](#圖片詳情)
- [ ] /api/params/{params_id} [#參數詳情](#參數詳情)
- [ ] /api/server/{server_id} [#服務詳情](#服務詳情)
詳情接口-請求方式:
@@ -200,38 +201,38 @@ GET /api/images
列表视图:(输出控制)
Method | URL | Info | Status
-------|--------------------------------|-----------------------------------|--------
GET | /api/images | 标准顺序查询 | ok
GET | /api/images?page=1&pageSize=20 | 指定页码和指定分页大小 | ok
Method | URL | Info
-------|--------------------------------|----------------------------------
GET | /api/images | 标准顺序查询
GET | /api/images?page=1&pageSize=20 | 指定页码和指定分页大小
DELETE | /api/images/{image_id} | 刪除指定圖片
筛选规则:(数据过滤)
Method | URL | Info | Statu
-------|--------------------------------|-----------------------------------|--------
GET | /api/images?user=1234 | 筛选指定某用户发表的图片 |
GET | /api/images?choice=1234 | 筛选指定精选集下的图片 |
GET | /api/images?like=1234 | 筛选指定用户点赞的图片 |
GET | /api/images?tag=1234 | 筛选含有指定标签的图片 |
GET | /api/images?tag=1234,1235 | 筛选含有多个标签之一的图片(并集) |
GET | /api/images?tag=1234&tag=1235 | 筛选含有指定多个标签的图片(交集) |
GET | /api/images?user=1234&tag=123 | 筛选指定用户的指定标签图片(交集) |
GET | /api/images?date=20220214+ | 时间范围(之后) |
GET | /api/images?date=20220214- | 时间范围(之前) |
GET | /api/images?date=2022~2023 | 时间范围(之间) |
Method | URL | Info
-------|--------------------------------|----------------------------------
GET | /api/images?user=1234 | 筛选指定某用户发表的图片
GET | /api/images?choice=1234 | 筛选指定精选集下的图片
GET | /api/images?like=1234 | 筛选指定用户点赞的图片
GET | /api/images?tag=1234 | 筛选含有指定标签的图片
GET | /api/images?tag=1234,1235 | 筛选含有多个标签之一的图片(并集)
GET | /api/images?tag=1234&tag=1235 | 筛选含有指定多个标签的图片(交集)
GET | /api/images?user=1234&tag=123 | 筛选指定用户的指定标签图片(交集)
GET | /api/images?date=20220214+ | 时间范围(之后)
GET | /api/images?date=20220214- | 时间范围(之前)
GET | /api/images?date=2022~2023 | 时间范围(之间)
排序规则:(权重强化)
Method | URL | Info | Status
-------|--------------------------------|-----------------------------------|--------
GET | /api/images?similar=1234 | 根据指定图片的相似图片(指定图片ID) | ok
GET | /api/images?sort=date+ | 排序规则(相似图片查询时此项无效) |
GET | /api/images?sort=like | 根据用户偏好推荐(指定用户的偏好) |
GET | /api/images?sort=history | 根据浏览记录推荐(指定用户的记录) |
GET | /api/images?sort=choice | 根据精选集推荐(指定精选集ID,取一组权重) |
Method | URL | Info
-------|--------------------------------|----------------------------------
GET | /api/images?similar=1234 | 根据指定图片的相似图片(指定图片ID)
GET | /api/images?sort=date+ | 排序规则(相似图片查询时此项无效)
GET | /api/images?sort=like | 根据用户偏好推荐(指定用户的偏好)
GET | /api/images?sort=history | 根据浏览记录推荐(指定用户的记录)
GET | /api/images?sort=choice | 根据精选集推荐(指定精选集ID,取一组权重)
* 注意, 筛选规则为多条件取交集, 单条件的复数取并集
* 权重强化属于排序规则而非过滤规则
@@ -257,7 +258,7 @@ GET /api/models
篩選規則:(數據過濾)
Method | URL | Info
-------|--------------------------------|------------------
-------|--------------------------------|----------------------------------
GET | /api/models | 獲取所有模型
GET | /api/models?user=1234 | 僅取指定用戶的(按用戶ID過濾)
GET | /api/models?tag=xxx | 按標籤分類篩選

View File

@@ -61,7 +61,9 @@ func init() {
CREATE TABLE IF NOT EXISTS users(
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT,
email TEXT,
password TEXT,
slat TEXT,
created_at TEXT,
updated_at TEXT
);

View File

@@ -21,6 +21,29 @@ type Model struct {
UserID int `json:"user_id"`
}
func (model *Model) SendToTrain() error {
db, err := configs.GetDB()
if err != nil {
log.Println(err)
return err
}
defer db.Close()
stmt, err := db.Prepare("UPDATE models SET status = ?, progress = ?, updated_at = ? WHERE id = ?")
if err != nil {
log.Println(err)
return err
}
defer stmt.Close()
_, err = stmt.Exec(model.Status, model.Progress, model.UpdatedAt, model.ID)
if err != nil {
log.Println(err)
return err
}
// TODO: 創建一個新線程管理訓練任務
// 將任務放入隊列中, 將自動回調更新任務狀態
return nil
}
func (model *Model) Create() error {
db, err := configs.GetDB()
if err != nil {

141
models/Server.go Normal file
View File

@@ -0,0 +1,141 @@
package models
import (
"log"
"main/configs"
)
type Server struct {
ID int `json:"id"`
Name string `json:"name"`
Type string `json:"type"` // (訓練|推理)
IP string `json:"ip"`
Port int `json:"port"`
Username string `json:"username"`
Password string `json:"password"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
}
func (server *Server) Create() error {
db, err := configs.GetDB()
if err != nil {
log.Println(err)
return err
}
defer db.Close()
stmt, err := db.Prepare("INSERT INTO servers(name, ip, port, username, password, created_at, updated_at) values(?, ?, ?, ?, ?, ?, ?)")
if err != nil {
log.Println(err)
return err
}
defer stmt.Close()
result, err := stmt.Exec(server.Name, server.IP, server.Port, server.Username, server.Password, server.CreatedAt, server.UpdatedAt)
if err != nil {
log.Println(err)
return err
}
id, err := result.LastInsertId()
if err != nil {
return err
}
server.ID = int(id)
return nil
}
func (server *Server) Delete() error {
db, err := configs.GetDB()
if err != nil {
log.Println(err)
return err
}
defer db.Close()
stmt, err := db.Prepare("DELETE FROM servers WHERE id = ?")
if err != nil {
log.Println(err)
return err
}
defer stmt.Close()
_, err = stmt.Exec(server.ID)
if err != nil {
log.Println(err)
return err
}
return nil
}
func (server *Server) Update() error {
db, err := configs.GetDB()
if err != nil {
log.Println(err)
return err
}
defer db.Close()
stmt, err := db.Prepare("UPDATE servers SET name = ?, ip = ?, port = ?, username = ?, password = ?, updated_at = ? WHERE id = ?")
if err != nil {
log.Println(err)
return err
}
defer stmt.Close()
_, err = stmt.Exec(server.Name, server.IP, server.Port, server.Username, server.Password, server.UpdatedAt, server.ID)
if err != nil {
log.Println(err)
return err
}
return nil
}
func (server *Server) Get() error {
db, err := configs.GetDB()
if err != nil {
log.Println(err)
return err
}
defer db.Close()
err = db.QueryRow("SELECT id, name, ip, port, username, password, created_at, updated_at FROM servers WHERE id = ?", server.ID).Scan(&server.ID, &server.Name, &server.IP, &server.Port, &server.Username, &server.Password, &server.CreatedAt, &server.UpdatedAt)
if err != nil {
log.Println(err)
return err
}
return nil
}
func QueryServers(page int, pagesize int) (servers []interface{}) {
db, err := configs.GetDB()
if err != nil {
log.Println(err)
return
}
defer db.Close()
rows, err := db.Query("SELECT id, name, ip, port, username, password, created_at, updated_at FROM servers ORDER BY id DESC LIMIT ?, ?", page*pagesize, pagesize)
if err != nil {
log.Println(err)
return
}
defer rows.Close()
for rows.Next() {
server := Server{}
err := rows.Scan(&server.ID, &server.Name, &server.IP, &server.Port, &server.Username, &server.Password, &server.CreatedAt, &server.UpdatedAt)
if err != nil {
log.Println(err)
continue
}
servers = append(servers, server)
}
return
}
func CountServers() (count int) {
db, err := configs.GetDB()
if err != nil {
log.Println(err)
return
}
defer db.Close()
err = db.QueryRow("SELECT COUNT(*) FROM servers").Scan(&count)
if err != nil {
log.Println(err)
return
}
return
}

View File

@@ -3,6 +3,9 @@ package models
import (
"log"
"main/configs"
"net/http"
"strconv"
"time"
)
type Task struct {
@@ -16,6 +19,49 @@ type Task struct {
UserID int `json:"user_id"`
}
// 推理任務
func startInferenceTask(task *Task) {
// 獲取一臺可用的 GPU 資源
// ...
// 執行推理任務
// ...
// 更新任務狀態
task.Status = "running"
task.Progress = 0
task.Update()
// 監聽任務狀態
for {
// 延遲 1 秒
time.Sleep(1 * time.Second)
// 查詢任務狀態
resp, err := http.Get("http://localhost:5000/api/v1/tasks/" + strconv.Itoa(task.ID))
if err != nil {
log.Println(err)
continue
}
defer resp.Body.Close()
// 解析任務狀態
// ...
// 更新任務狀態
task.Progress = 100
task.Status = "success"
task.Update()
// 任務結束判定
if task.Progress == 100 {
break
}
}
}
func (task *Task) Create() error {
db, err := configs.GetDB()
if err != nil {

View File

@@ -9,6 +9,8 @@ type User struct {
ID int `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
Password string `json:"password"`
Slat string `json:"slat"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
}
@@ -136,3 +138,43 @@ func (user *User) GetByEmail() error {
}
return nil
}
func QueryUsers(page, pagesize int) (list []interface{}) {
db, err := configs.GetDB()
if err != nil {
log.Println(err)
return
}
defer db.Close()
rows, err := db.Query("SELECT id, name, email, created_at, updated_at FROM users LIMIT ?, ?", (page-1)*pagesize, pagesize)
if err != nil {
log.Println(err)
return
}
defer rows.Close()
for rows.Next() {
var user User
err := rows.Scan(&user.ID, &user.Name, &user.Email, &user.CreatedAt, &user.UpdatedAt)
if err != nil {
log.Println(err)
return
}
list = append(list, user)
}
return
}
func CountUsers() (count int) {
db, err := configs.GetDB()
if err != nil {
log.Println(err)
return
}
defer db.Close()
err = db.QueryRow("SELECT COUNT(*) FROM users").Scan(&count)
if err != nil {
log.Println(err)
return
}
return
}

View File

@@ -81,18 +81,44 @@ func ModelItemGet(w http.ResponseWriter, r *http.Request) {
}
func ModelItemPatch(w http.ResponseWriter, r *http.Request) {
var model models.Model
// 取出原始数据
model := models.Model{ID: utils.ParamInt(mux.Vars(r)["id"], 0)}
if err := model.Get(); err != nil {
w.WriteHeader(http.StatusNotFound)
return
}
// 取出更新数据
var model_new models.Model
body, err := ioutil.ReadAll(r.Body)
if err != nil {
log.Println(err)
return
}
defer r.Body.Close()
if err = json.Unmarshal(body, &model); err != nil {
if err = json.Unmarshal(body, &model_new); err != nil {
log.Println(err)
return
}
model.ID = utils.ParamInt(mux.Vars(r)["id"], 0)
// 字段不爲空且不等於原始數據時更新
if model_new.Name != "" && model_new.Name != model.Name {
model.Name = model_new.Name
}
if model_new.Type != "" && model_new.Type != model.Type {
model.Type = model_new.Type
}
if model_new.Status != "" && model_new.Status != model.Status {
model.Status = model_new.Status
// 如果狀態被改變爲 ready, 將模型發送到訓練隊列
if model.Status == "ready" {
model.SendToTrain()
}
}
if model_new.Image != "" && model_new.Image != model.Image {
model.Image = model_new.Image
}
model.Update()
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.Write(utils.ToJSON(model))

50
routers/servers.go Normal file
View File

@@ -0,0 +1,50 @@
package routers
import (
"main/models"
"main/utils"
"net/http"
"github.com/gorilla/mux"
)
func ServersGet(w http.ResponseWriter, r *http.Request) {
var listview models.ListView
listview.Page = utils.ParamInt(r.URL.Query().Get("page"), 1)
listview.PageSize = utils.ParamInt(r.URL.Query().Get("pageSize"), 10)
listview.List = models.QueryServers(listview.Page, listview.PageSize)
listview.Total = models.CountServers()
listview.Next = listview.Page*listview.PageSize < listview.Total
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.Write(listview.ToJSON())
}
func ServersPost(w http.ResponseWriter, r *http.Request) {
var server models.Server
server.Create()
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.Write(utils.ToJSON(server))
}
func ServersItemGet(w http.ResponseWriter, r *http.Request) {
server := models.Server{ID: utils.ParamInt(mux.Vars(r)["id"], 0)}
server.Get()
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.Write(utils.ToJSON(server))
}
func ServersItemPatch(w http.ResponseWriter, r *http.Request) {
server := models.Server{ID: utils.ParamInt(mux.Vars(r)["id"], 0)}
server.Get()
server.Update()
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.Write(utils.ToJSON(server))
}
func ServersItemDelete(w http.ResponseWriter, r *http.Request) {
server := models.Server{ID: utils.ParamInt(mux.Vars(r)["id"], 0)}
server.Get()
server.Delete()
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.Write(utils.ToJSON(server))
}

18
routers/users.go Normal file
View File

@@ -0,0 +1,18 @@
package routers
import (
"main/models"
"main/utils"
"net/http"
)
func UsersGet(w http.ResponseWriter, r *http.Request) {
var listview models.ListView
listview.Page = utils.ParamInt(r.URL.Query().Get("page"), 1)
listview.PageSize = utils.ParamInt(r.URL.Query().Get("pageSize"), 10)
listview.List = models.QueryUsers(listview.Page, listview.PageSize)
listview.Total = models.CountUsers()
listview.Next = listview.Page*listview.PageSize < listview.Total
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.Write(listview.ToJSON())
}