| 131 | } |
| 132 | } |
| 133 | func (i *imlLocalModelController) Deploy(ctx *gin.Context) { |
| 134 | |
| 135 | var input ai_local_dto.DeployInput |
| 136 | err := ctx.ShouldBindBodyWithJSON(&input) |
| 137 | if err != nil { |
| 138 | ctx.JSON(200, gin.H{ |
| 139 | "code": -1, "msg": err.Error(), "success": "fail", |
| 140 | }) |
| 141 | return |
| 142 | } |
| 143 | if input.Model == "" { |
| 144 | ctx.JSON(200, gin.H{ |
| 145 | "code": -1, "msg": "model is required", "success": "fail", |
| 146 | }) |
| 147 | return |
| 148 | } |
| 149 | |
| 150 | id := uuid.NewString() |
| 151 | p, err := i.module.Deploy(ctx, input.Model, id) |
| 152 | if err != nil { |
| 153 | ctx.JSON(200, gin.H{ |
| 154 | "code": -1, "msg": err.Error(), "success": "fail", |
| 155 | }) |
| 156 | return |
| 157 | } |
| 158 | done := make(chan struct{}) |
| 159 | // 启动一个 goroutine 监听客户端关闭连接 |
| 160 | go func() { |
| 161 | select { |
| 162 | case <-ctx.Writer.CloseNotify(): |
| 163 | |
| 164 | case <-done: |
| 165 | |
| 166 | } |
| 167 | ai_provider_local.CancelPipeline(input.Model, id) |
| 168 | }() |
| 169 | var complete int64 |
| 170 | var total int64 |
| 171 | ctx.Header("Content-Type", "text/plain; charset=utf-8") |
| 172 | ctx.Header("text-encoding", "chunked") |
| 173 | ctx.Stream(func(w io.Writer) bool { |
| 174 | msg, ok := <-p.Message() |
| 175 | if !ok { |
| 176 | return false |
| 177 | } |
| 178 | state := "download" |
| 179 | switch msg.Status { |
| 180 | case "verifying sha256 digest": |
| 181 | state = "deploy" |
| 182 | case "writing manifest": |
| 183 | state = "initializing" |
| 184 | case "removing any unused layers": |
| 185 | state = "initializing" |
| 186 | case "success": |
| 187 | state = "finish" |
| 188 | case "error": |
| 189 | state = "error" |
| 190 | } |