routes.go 34 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418
  1. package server
  2. import (
  3. "context"
  4. "encoding/json"
  5. "errors"
  6. "fmt"
  7. "io"
  8. "io/fs"
  9. "log/slog"
  10. "math"
  11. "net"
  12. "net/http"
  13. "net/netip"
  14. "os"
  15. "os/signal"
  16. "path/filepath"
  17. "reflect"
  18. "runtime"
  19. "strconv"
  20. "strings"
  21. "sync"
  22. "syscall"
  23. "time"
  24. "github.com/gin-contrib/cors"
  25. "github.com/gin-gonic/gin"
  26. "golang.org/x/exp/slices"
  27. "ollama.com/api"
  28. "ollama.com/gpu"
  29. "ollama.com/llm"
  30. "ollama.com/openai"
  31. "ollama.com/parser"
  32. "ollama.com/version"
  33. )
  34. var mode string = gin.DebugMode
  35. type Server struct {
  36. addr net.Addr
  37. }
  38. func init() {
  39. switch mode {
  40. case gin.DebugMode:
  41. case gin.ReleaseMode:
  42. case gin.TestMode:
  43. default:
  44. mode = gin.DebugMode
  45. }
  46. gin.SetMode(mode)
  47. }
  48. var loaded struct {
  49. mu sync.Mutex
  50. llama *llm.LlamaServer
  51. expireTimer *time.Timer
  52. model string
  53. adapters []string
  54. projectors []string
  55. *api.Options
  56. }
  57. var defaultSessionDuration = 5 * time.Minute
  58. func unload() {
  59. if loaded.llama != nil {
  60. loaded.llama.Close()
  61. }
  62. loaded.llama = nil
  63. loaded.model = ""
  64. loaded.adapters = nil
  65. loaded.projectors = nil
  66. loaded.Options = nil
  67. }
  68. // load a model into memory if it is not already loaded, it is up to the caller to lock loaded.mu before calling this function
  69. func load(c *gin.Context, model *Model, opts api.Options, sessionDuration time.Duration) error {
  70. ctx, cancel := context.WithTimeout(c, 10*time.Second)
  71. defer cancel()
  72. needLoad := loaded.llama == nil || // is there a model loaded?
  73. loaded.model != model.ModelPath || // has the base model changed?
  74. !reflect.DeepEqual(loaded.adapters, model.AdapterPaths) || // have the adapters changed?
  75. !reflect.DeepEqual(loaded.projectors, model.ProjectorPaths) || // have the adapters changed?
  76. !reflect.DeepEqual(loaded.Options.Runner, opts.Runner) || // have the runner options changed?
  77. loaded.llama.Ping(ctx) != nil
  78. if needLoad {
  79. if loaded.llama != nil {
  80. slog.Info("changing loaded model")
  81. unload()
  82. }
  83. llama, err := llm.NewLlamaServer(model.ModelPath, model.AdapterPaths, model.ProjectorPaths, opts)
  84. if err != nil {
  85. // some older models are not compatible with newer versions of llama.cpp
  86. // show a generalized compatibility error until there is a better way to
  87. // check for model compatibility
  88. if errors.Is(llm.ErrUnsupportedFormat, err) || strings.Contains(err.Error(), "failed to load model") {
  89. err = fmt.Errorf("%v: this model may be incompatible with your version of Ollama. If you previously pulled this model, try updating it by running `ollama pull %s`", err, model.ShortName)
  90. }
  91. return err
  92. }
  93. loaded.model = model.ModelPath
  94. loaded.adapters = model.AdapterPaths
  95. loaded.projectors = model.ProjectorPaths
  96. loaded.llama = llama
  97. loaded.Options = &opts
  98. if err = llama.WaitUntilRunning(); err != nil {
  99. slog.Error("error loading llama server", "error", err)
  100. unload()
  101. return err
  102. }
  103. }
  104. if loaded.expireTimer == nil {
  105. loaded.expireTimer = time.AfterFunc(sessionDuration, func() {
  106. loaded.mu.Lock()
  107. defer loaded.mu.Unlock()
  108. unload()
  109. })
  110. }
  111. loaded.expireTimer.Reset(sessionDuration)
  112. return nil
  113. }
  114. func modelOptions(model *Model, requestOpts map[string]interface{}) (api.Options, error) {
  115. opts := api.DefaultOptions()
  116. if err := opts.FromMap(model.Options); err != nil {
  117. return api.Options{}, err
  118. }
  119. if err := opts.FromMap(requestOpts); err != nil {
  120. return api.Options{}, err
  121. }
  122. return opts, nil
  123. }
  124. func isSupportedImageType(image []byte) bool {
  125. contentType := http.DetectContentType(image)
  126. allowedTypes := []string{"image/jpeg", "image/jpg", "image/png"}
  127. return slices.Contains(allowedTypes, contentType)
  128. }
  129. func GenerateHandler(c *gin.Context) {
  130. loaded.mu.Lock()
  131. defer loaded.mu.Unlock()
  132. checkpointStart := time.Now()
  133. var req api.GenerateRequest
  134. err := c.ShouldBindJSON(&req)
  135. switch {
  136. case errors.Is(err, io.EOF):
  137. c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "missing request body"})
  138. return
  139. case err != nil:
  140. c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": err.Error()})
  141. return
  142. }
  143. // validate the request
  144. switch {
  145. case req.Model == "":
  146. c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "model is required"})
  147. return
  148. case len(req.Format) > 0 && req.Format != "json":
  149. c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "format must be json"})
  150. return
  151. case req.Raw && (req.Template != "" || req.System != "" || len(req.Context) > 0):
  152. c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "raw mode does not support template, system, or context"})
  153. return
  154. }
  155. for _, img := range req.Images {
  156. if !isSupportedImageType(img) {
  157. c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "unsupported image format"})
  158. return
  159. }
  160. }
  161. model, err := GetModel(req.Model)
  162. if err != nil {
  163. var pErr *fs.PathError
  164. if errors.As(err, &pErr) {
  165. c.JSON(http.StatusNotFound, gin.H{"error": fmt.Sprintf("model '%s' not found, try pulling it first", req.Model)})
  166. return
  167. }
  168. c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
  169. return
  170. }
  171. if model.IsEmbedding() {
  172. c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "embedding models do not support generate"})
  173. return
  174. }
  175. opts, err := modelOptions(model, req.Options)
  176. if err != nil {
  177. if errors.Is(err, api.ErrInvalidOpts) {
  178. c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
  179. return
  180. }
  181. c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
  182. return
  183. }
  184. var sessionDuration time.Duration
  185. if req.KeepAlive == nil {
  186. sessionDuration = getDefaultSessionDuration()
  187. } else {
  188. sessionDuration = req.KeepAlive.Duration
  189. }
  190. if err := load(c, model, opts, sessionDuration); err != nil {
  191. c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
  192. return
  193. }
  194. // an empty request loads the model
  195. // note: for a short while template was used in lieu
  196. // of `raw` mode so we need to check for it too
  197. if req.Prompt == "" && req.Template == "" && req.System == "" {
  198. c.JSON(http.StatusOK, api.GenerateResponse{
  199. CreatedAt: time.Now().UTC(),
  200. Model: req.Model,
  201. Done: true,
  202. })
  203. return
  204. }
  205. checkpointLoaded := time.Now()
  206. var prompt string
  207. switch {
  208. case req.Raw:
  209. prompt = req.Prompt
  210. case req.Prompt != "":
  211. if req.Template == "" {
  212. req.Template = model.Template
  213. }
  214. if req.System == "" {
  215. req.System = model.System
  216. }
  217. slog.Debug("generate handler", "prompt", req.Prompt)
  218. slog.Debug("generate handler", "template", req.Template)
  219. slog.Debug("generate handler", "system", req.System)
  220. var sb strings.Builder
  221. for i := range req.Images {
  222. fmt.Fprintf(&sb, "[img-%d] ", i)
  223. }
  224. sb.WriteString(req.Prompt)
  225. p, err := Prompt(req.Template, req.System, sb.String(), "", true)
  226. if err != nil {
  227. c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
  228. return
  229. }
  230. sb.Reset()
  231. if req.Context != nil {
  232. prev, err := loaded.llama.Detokenize(c.Request.Context(), req.Context)
  233. if err != nil {
  234. c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
  235. return
  236. }
  237. sb.WriteString(prev)
  238. }
  239. sb.WriteString(p)
  240. prompt = sb.String()
  241. }
  242. slog.Debug("generate handler", "prompt", prompt)
  243. ch := make(chan any)
  244. var generated strings.Builder
  245. go func() {
  246. defer close(ch)
  247. fn := func(r llm.CompletionResponse) {
  248. // Update model expiration
  249. loaded.expireTimer.Reset(sessionDuration)
  250. // Build up the full response
  251. if _, err := generated.WriteString(r.Content); err != nil {
  252. ch <- gin.H{"error": err.Error()}
  253. return
  254. }
  255. resp := api.GenerateResponse{
  256. Model: req.Model,
  257. CreatedAt: time.Now().UTC(),
  258. Done: r.Done,
  259. Response: r.Content,
  260. Metrics: api.Metrics{
  261. PromptEvalCount: r.PromptEvalCount,
  262. PromptEvalDuration: r.PromptEvalDuration,
  263. EvalCount: r.EvalCount,
  264. EvalDuration: r.EvalDuration,
  265. },
  266. }
  267. if r.Done {
  268. resp.TotalDuration = time.Since(checkpointStart)
  269. resp.LoadDuration = checkpointLoaded.Sub(checkpointStart)
  270. if !req.Raw {
  271. p, err := Prompt(req.Template, req.System, req.Prompt, generated.String(), false)
  272. if err != nil {
  273. c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
  274. return
  275. }
  276. // TODO (jmorganca): encode() should not strip special tokens
  277. tokens, err := loaded.llama.Tokenize(c.Request.Context(), p)
  278. if err != nil {
  279. ch <- gin.H{"error": err.Error()}
  280. return
  281. }
  282. resp.Context = append(req.Context, tokens...)
  283. }
  284. }
  285. ch <- resp
  286. }
  287. var images []llm.ImageData
  288. for i := range req.Images {
  289. images = append(images, llm.ImageData{
  290. ID: i,
  291. Data: req.Images[i],
  292. })
  293. }
  294. // Start prediction
  295. req := llm.CompletionRequest{
  296. Prompt: prompt,
  297. Format: req.Format,
  298. Images: images,
  299. Options: opts,
  300. }
  301. if err := loaded.llama.Completion(c.Request.Context(), req, fn); err != nil {
  302. ch <- gin.H{"error": err.Error()}
  303. }
  304. }()
  305. if req.Stream != nil && !*req.Stream {
  306. // Accumulate responses into the final response
  307. var final api.GenerateResponse
  308. var sb strings.Builder
  309. for resp := range ch {
  310. switch r := resp.(type) {
  311. case api.GenerateResponse:
  312. sb.WriteString(r.Response)
  313. final = r
  314. case gin.H:
  315. if errorMsg, ok := r["error"].(string); ok {
  316. c.JSON(http.StatusInternalServerError, gin.H{"error": errorMsg})
  317. return
  318. } else {
  319. c.JSON(http.StatusInternalServerError, gin.H{"error": "unexpected error format in response"})
  320. return
  321. }
  322. default:
  323. c.JSON(http.StatusInternalServerError, gin.H{"error": "unexpected error"})
  324. return
  325. }
  326. }
  327. final.Response = sb.String()
  328. c.JSON(http.StatusOK, final)
  329. return
  330. }
  331. streamResponse(c, ch)
  332. }
  333. func getDefaultSessionDuration() time.Duration {
  334. if t, exists := os.LookupEnv("OLLAMA_KEEP_ALIVE"); exists {
  335. v, err := strconv.Atoi(t)
  336. if err != nil {
  337. d, err := time.ParseDuration(t)
  338. if err != nil {
  339. return defaultSessionDuration
  340. }
  341. if d < 0 {
  342. return time.Duration(math.MaxInt64)
  343. }
  344. return d
  345. }
  346. d := time.Duration(v) * time.Second
  347. if d < 0 {
  348. return time.Duration(math.MaxInt64)
  349. }
  350. return d
  351. }
  352. return defaultSessionDuration
  353. }
  354. func EmbeddingsHandler(c *gin.Context) {
  355. loaded.mu.Lock()
  356. defer loaded.mu.Unlock()
  357. var req api.EmbeddingRequest
  358. err := c.ShouldBindJSON(&req)
  359. switch {
  360. case errors.Is(err, io.EOF):
  361. c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "missing request body"})
  362. return
  363. case err != nil:
  364. c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": err.Error()})
  365. return
  366. }
  367. if req.Model == "" {
  368. c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "model is required"})
  369. return
  370. }
  371. model, err := GetModel(req.Model)
  372. if err != nil {
  373. var pErr *fs.PathError
  374. if errors.As(err, &pErr) {
  375. c.JSON(http.StatusNotFound, gin.H{"error": fmt.Sprintf("model '%s' not found, try pulling it first", req.Model)})
  376. return
  377. }
  378. c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
  379. return
  380. }
  381. opts, err := modelOptions(model, req.Options)
  382. if err != nil {
  383. if errors.Is(err, api.ErrInvalidOpts) {
  384. c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
  385. return
  386. }
  387. c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
  388. return
  389. }
  390. var sessionDuration time.Duration
  391. if req.KeepAlive == nil {
  392. sessionDuration = getDefaultSessionDuration()
  393. } else {
  394. sessionDuration = req.KeepAlive.Duration
  395. }
  396. if err := load(c, model, opts, sessionDuration); err != nil {
  397. c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
  398. return
  399. }
  400. // an empty request loads the model
  401. if req.Prompt == "" {
  402. c.JSON(http.StatusOK, api.EmbeddingResponse{Embedding: []float64{}})
  403. return
  404. }
  405. embedding, err := loaded.llama.Embedding(c.Request.Context(), req.Prompt)
  406. if err != nil {
  407. slog.Info(fmt.Sprintf("embedding generation failed: %v", err))
  408. c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to generate embedding"})
  409. return
  410. }
  411. resp := api.EmbeddingResponse{
  412. Embedding: embedding,
  413. }
  414. c.JSON(http.StatusOK, resp)
  415. }
  416. func PullModelHandler(c *gin.Context) {
  417. var req api.PullRequest
  418. err := c.ShouldBindJSON(&req)
  419. switch {
  420. case errors.Is(err, io.EOF):
  421. c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "missing request body"})
  422. return
  423. case err != nil:
  424. c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": err.Error()})
  425. return
  426. }
  427. var model string
  428. if req.Model != "" {
  429. model = req.Model
  430. } else if req.Name != "" {
  431. model = req.Name
  432. } else {
  433. c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "model is required"})
  434. return
  435. }
  436. ch := make(chan any)
  437. go func() {
  438. defer close(ch)
  439. fn := func(r api.ProgressResponse) {
  440. ch <- r
  441. }
  442. regOpts := &registryOptions{
  443. Insecure: req.Insecure,
  444. }
  445. ctx, cancel := context.WithCancel(c.Request.Context())
  446. defer cancel()
  447. if err := PullModel(ctx, model, regOpts, fn); err != nil {
  448. ch <- gin.H{"error": err.Error()}
  449. }
  450. }()
  451. if req.Stream != nil && !*req.Stream {
  452. waitForStream(c, ch)
  453. return
  454. }
  455. streamResponse(c, ch)
  456. }
  457. func PushModelHandler(c *gin.Context) {
  458. var req api.PushRequest
  459. err := c.ShouldBindJSON(&req)
  460. switch {
  461. case errors.Is(err, io.EOF):
  462. c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "missing request body"})
  463. return
  464. case err != nil:
  465. c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": err.Error()})
  466. return
  467. }
  468. var model string
  469. if req.Model != "" {
  470. model = req.Model
  471. } else if req.Name != "" {
  472. model = req.Name
  473. } else {
  474. c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "model is required"})
  475. return
  476. }
  477. ch := make(chan any)
  478. go func() {
  479. defer close(ch)
  480. fn := func(r api.ProgressResponse) {
  481. ch <- r
  482. }
  483. regOpts := &registryOptions{
  484. Insecure: req.Insecure,
  485. }
  486. ctx, cancel := context.WithCancel(c.Request.Context())
  487. defer cancel()
  488. if err := PushModel(ctx, model, regOpts, fn); err != nil {
  489. ch <- gin.H{"error": err.Error()}
  490. }
  491. }()
  492. if req.Stream != nil && !*req.Stream {
  493. waitForStream(c, ch)
  494. return
  495. }
  496. streamResponse(c, ch)
  497. }
  498. func CreateModelHandler(c *gin.Context) {
  499. var req api.CreateRequest
  500. err := c.ShouldBindJSON(&req)
  501. switch {
  502. case errors.Is(err, io.EOF):
  503. c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "missing request body"})
  504. return
  505. case err != nil:
  506. c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": err.Error()})
  507. return
  508. }
  509. var model string
  510. if req.Model != "" {
  511. model = req.Model
  512. } else if req.Name != "" {
  513. model = req.Name
  514. } else {
  515. c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "model is required"})
  516. return
  517. }
  518. if err := ParseModelPath(model).Validate(); err != nil {
  519. c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": err.Error()})
  520. return
  521. }
  522. if req.Path == "" && req.Modelfile == "" {
  523. c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "path or modelfile are required"})
  524. return
  525. }
  526. var modelfile io.Reader = strings.NewReader(req.Modelfile)
  527. if req.Path != "" && req.Modelfile == "" {
  528. mf, err := os.Open(req.Path)
  529. if err != nil {
  530. c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("error reading modelfile: %s", err)})
  531. return
  532. }
  533. defer mf.Close()
  534. modelfile = mf
  535. }
  536. commands, err := parser.Parse(modelfile)
  537. if err != nil {
  538. c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": err.Error()})
  539. return
  540. }
  541. ch := make(chan any)
  542. go func() {
  543. defer close(ch)
  544. fn := func(resp api.ProgressResponse) {
  545. ch <- resp
  546. }
  547. ctx, cancel := context.WithCancel(c.Request.Context())
  548. defer cancel()
  549. if err := CreateModel(ctx, model, filepath.Dir(req.Path), req.Quantization, commands, fn); err != nil {
  550. ch <- gin.H{"error": err.Error()}
  551. }
  552. }()
  553. if req.Stream != nil && !*req.Stream {
  554. waitForStream(c, ch)
  555. return
  556. }
  557. streamResponse(c, ch)
  558. }
  559. func DeleteModelHandler(c *gin.Context) {
  560. var req api.DeleteRequest
  561. err := c.ShouldBindJSON(&req)
  562. switch {
  563. case errors.Is(err, io.EOF):
  564. c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "missing request body"})
  565. return
  566. case err != nil:
  567. c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": err.Error()})
  568. return
  569. }
  570. var model string
  571. if req.Model != "" {
  572. model = req.Model
  573. } else if req.Name != "" {
  574. model = req.Name
  575. } else {
  576. c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "model is required"})
  577. return
  578. }
  579. if err := DeleteModel(model); err != nil {
  580. if os.IsNotExist(err) {
  581. c.JSON(http.StatusNotFound, gin.H{"error": fmt.Sprintf("model '%s' not found", model)})
  582. } else {
  583. c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
  584. }
  585. return
  586. }
  587. manifestsPath, err := GetManifestPath()
  588. if err != nil {
  589. c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
  590. return
  591. }
  592. if err := PruneDirectory(manifestsPath); err != nil {
  593. c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
  594. return
  595. }
  596. c.JSON(http.StatusOK, nil)
  597. }
  598. func ShowModelHandler(c *gin.Context) {
  599. var req api.ShowRequest
  600. err := c.ShouldBindJSON(&req)
  601. switch {
  602. case errors.Is(err, io.EOF):
  603. c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "missing request body"})
  604. return
  605. case err != nil:
  606. c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": err.Error()})
  607. return
  608. }
  609. if req.Model != "" {
  610. // noop
  611. } else if req.Name != "" {
  612. req.Model = req.Name
  613. } else {
  614. c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "model is required"})
  615. return
  616. }
  617. resp, err := GetModelInfo(req)
  618. if err != nil {
  619. if os.IsNotExist(err) {
  620. c.JSON(http.StatusNotFound, gin.H{"error": fmt.Sprintf("model '%s' not found", req.Model)})
  621. } else {
  622. c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
  623. }
  624. return
  625. }
  626. c.JSON(http.StatusOK, resp)
  627. }
  628. func GetModelInfo(req api.ShowRequest) (*api.ShowResponse, error) {
  629. model, err := GetModel(req.Model)
  630. if err != nil {
  631. return nil, err
  632. }
  633. modelDetails := api.ModelDetails{
  634. ParentModel: model.ParentModel,
  635. Format: model.Config.ModelFormat,
  636. Family: model.Config.ModelFamily,
  637. Families: model.Config.ModelFamilies,
  638. ParameterSize: model.Config.ModelType,
  639. QuantizationLevel: model.Config.FileType,
  640. }
  641. if req.System != "" {
  642. model.System = req.System
  643. }
  644. if req.Template != "" {
  645. model.Template = req.Template
  646. }
  647. msgs := make([]api.Message, 0)
  648. for _, msg := range model.Messages {
  649. msgs = append(msgs, api.Message{Role: msg.Role, Content: msg.Content})
  650. }
  651. resp := &api.ShowResponse{
  652. License: strings.Join(model.License, "\n"),
  653. System: model.System,
  654. Template: model.Template,
  655. Details: modelDetails,
  656. Messages: msgs,
  657. }
  658. var params []string
  659. cs := 30
  660. for k, v := range model.Options {
  661. switch val := v.(type) {
  662. case []interface{}:
  663. for _, nv := range val {
  664. params = append(params, fmt.Sprintf("%-*s %#v", cs, k, nv))
  665. }
  666. default:
  667. params = append(params, fmt.Sprintf("%-*s %#v", cs, k, v))
  668. }
  669. }
  670. resp.Parameters = strings.Join(params, "\n")
  671. for k, v := range req.Options {
  672. if _, ok := req.Options[k]; ok {
  673. model.Options[k] = v
  674. }
  675. }
  676. mf, err := ShowModelfile(model)
  677. if err != nil {
  678. return nil, err
  679. }
  680. resp.Modelfile = mf
  681. return resp, nil
  682. }
  683. func ListModelsHandler(c *gin.Context) {
  684. models := make([]api.ModelResponse, 0)
  685. manifestsPath, err := GetManifestPath()
  686. if err != nil {
  687. c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
  688. return
  689. }
  690. modelResponse := func(modelName string) (api.ModelResponse, error) {
  691. model, err := GetModel(modelName)
  692. if err != nil {
  693. return api.ModelResponse{}, err
  694. }
  695. modelDetails := api.ModelDetails{
  696. Format: model.Config.ModelFormat,
  697. Family: model.Config.ModelFamily,
  698. Families: model.Config.ModelFamilies,
  699. ParameterSize: model.Config.ModelType,
  700. QuantizationLevel: model.Config.FileType,
  701. }
  702. return api.ModelResponse{
  703. Model: model.ShortName,
  704. Name: model.ShortName,
  705. Size: model.Size,
  706. Digest: model.Digest,
  707. Details: modelDetails,
  708. }, nil
  709. }
  710. walkFunc := func(path string, info os.FileInfo, _ error) error {
  711. if !info.IsDir() {
  712. path, tag := filepath.Split(path)
  713. model := strings.Trim(strings.TrimPrefix(path, manifestsPath), string(os.PathSeparator))
  714. modelPath := strings.Join([]string{model, tag}, ":")
  715. canonicalModelPath := strings.ReplaceAll(modelPath, string(os.PathSeparator), "/")
  716. resp, err := modelResponse(canonicalModelPath)
  717. if err != nil {
  718. slog.Info(fmt.Sprintf("skipping file: %s", canonicalModelPath))
  719. // nolint: nilerr
  720. return nil
  721. }
  722. resp.ModifiedAt = info.ModTime()
  723. models = append(models, resp)
  724. }
  725. return nil
  726. }
  727. if err := filepath.Walk(manifestsPath, walkFunc); err != nil {
  728. c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
  729. return
  730. }
  731. c.JSON(http.StatusOK, api.ListResponse{Models: models})
  732. }
  733. func CopyModelHandler(c *gin.Context) {
  734. var req api.CopyRequest
  735. err := c.ShouldBindJSON(&req)
  736. switch {
  737. case errors.Is(err, io.EOF):
  738. c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "missing request body"})
  739. return
  740. case err != nil:
  741. c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": err.Error()})
  742. return
  743. }
  744. if req.Source == "" || req.Destination == "" {
  745. c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "source add destination are required"})
  746. return
  747. }
  748. if err := ParseModelPath(req.Destination).Validate(); err != nil {
  749. c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": err.Error()})
  750. return
  751. }
  752. if err := CopyModel(req.Source, req.Destination); err != nil {
  753. if os.IsNotExist(err) {
  754. c.JSON(http.StatusNotFound, gin.H{"error": fmt.Sprintf("model '%s' not found", req.Source)})
  755. } else {
  756. c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
  757. }
  758. return
  759. }
  760. }
  761. func HeadBlobHandler(c *gin.Context) {
  762. path, err := GetBlobsPath(c.Param("digest"))
  763. if err != nil {
  764. c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": err.Error()})
  765. return
  766. }
  767. if _, err := os.Stat(path); err != nil {
  768. c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"error": fmt.Sprintf("blob %q not found", c.Param("digest"))})
  769. return
  770. }
  771. c.Status(http.StatusOK)
  772. }
  773. func CreateBlobHandler(c *gin.Context) {
  774. path, err := GetBlobsPath(c.Param("digest"))
  775. if err != nil {
  776. c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": err.Error()})
  777. return
  778. }
  779. _, err = os.Stat(path)
  780. switch {
  781. case errors.Is(err, os.ErrNotExist):
  782. // noop
  783. case err != nil:
  784. c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
  785. return
  786. default:
  787. c.Status(http.StatusOK)
  788. return
  789. }
  790. layer, err := NewLayer(c.Request.Body, "")
  791. if err != nil {
  792. c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
  793. return
  794. }
  795. if layer.Digest != c.Param("digest") {
  796. c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("digest mismatch, expected %q, got %q", c.Param("digest"), layer.Digest)})
  797. return
  798. }
  799. if _, err := layer.Commit(); err != nil {
  800. c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
  801. return
  802. }
  803. c.Status(http.StatusCreated)
  804. }
  805. var defaultAllowOrigins = []string{
  806. "localhost",
  807. "127.0.0.1",
  808. "0.0.0.0",
  809. }
  810. func isLocalIP(ip netip.Addr) bool {
  811. if interfaces, err := net.Interfaces(); err == nil {
  812. for _, iface := range interfaces {
  813. addrs, err := iface.Addrs()
  814. if err != nil {
  815. continue
  816. }
  817. for _, a := range addrs {
  818. if parsed, _, err := net.ParseCIDR(a.String()); err == nil {
  819. if parsed.String() == ip.String() {
  820. return true
  821. }
  822. }
  823. }
  824. }
  825. }
  826. return false
  827. }
  828. func allowedHost(host string) bool {
  829. if host == "" || host == "localhost" {
  830. return true
  831. }
  832. if hostname, err := os.Hostname(); err == nil && host == hostname {
  833. return true
  834. }
  835. var tlds = []string{
  836. "localhost",
  837. "local",
  838. "internal",
  839. }
  840. // check if the host is a local TLD
  841. for _, tld := range tlds {
  842. if strings.HasSuffix(host, "."+tld) {
  843. return true
  844. }
  845. }
  846. return false
  847. }
  848. func allowedHostsMiddleware(addr net.Addr) gin.HandlerFunc {
  849. return func(c *gin.Context) {
  850. if addr == nil {
  851. c.Next()
  852. return
  853. }
  854. if addr, err := netip.ParseAddrPort(addr.String()); err == nil && !addr.Addr().IsLoopback() {
  855. c.Next()
  856. return
  857. }
  858. host, _, err := net.SplitHostPort(c.Request.Host)
  859. if err != nil {
  860. host = c.Request.Host
  861. }
  862. if addr, err := netip.ParseAddr(host); err == nil {
  863. if addr.IsLoopback() || addr.IsPrivate() || addr.IsUnspecified() || isLocalIP(addr) {
  864. c.Next()
  865. return
  866. }
  867. }
  868. if allowedHost(host) {
  869. c.Next()
  870. return
  871. }
  872. c.AbortWithStatus(http.StatusForbidden)
  873. }
  874. }
  875. func (s *Server) GenerateRoutes() http.Handler {
  876. config := cors.DefaultConfig()
  877. config.AllowWildcard = true
  878. config.AllowBrowserExtensions = true
  879. if allowedOrigins := strings.Trim(os.Getenv("OLLAMA_ORIGINS"), "\"'"); allowedOrigins != "" {
  880. config.AllowOrigins = strings.Split(allowedOrigins, ",")
  881. }
  882. for _, allowOrigin := range defaultAllowOrigins {
  883. config.AllowOrigins = append(config.AllowOrigins,
  884. fmt.Sprintf("http://%s", allowOrigin),
  885. fmt.Sprintf("https://%s", allowOrigin),
  886. fmt.Sprintf("http://%s:*", allowOrigin),
  887. fmt.Sprintf("https://%s:*", allowOrigin),
  888. )
  889. }
  890. r := gin.Default()
  891. r.Use(
  892. cors.New(config),
  893. allowedHostsMiddleware(s.addr),
  894. )
  895. r.POST("/api/pull", PullModelHandler)
  896. r.POST("/api/generate", GenerateHandler)
  897. r.POST("/api/chat", ChatHandler)
  898. r.POST("/api/embeddings", EmbeddingsHandler)
  899. r.POST("/api/create", CreateModelHandler)
  900. r.POST("/api/push", PushModelHandler)
  901. r.POST("/api/copy", CopyModelHandler)
  902. r.DELETE("/api/delete", DeleteModelHandler)
  903. r.POST("/api/show", ShowModelHandler)
  904. r.POST("/api/blobs/:digest", CreateBlobHandler)
  905. r.HEAD("/api/blobs/:digest", HeadBlobHandler)
  906. // Compatibility endpoints
  907. r.POST("/v1/chat/completions", openai.Middleware(), ChatHandler)
  908. for _, method := range []string{http.MethodGet, http.MethodHead} {
  909. r.Handle(method, "/", func(c *gin.Context) {
  910. c.String(http.StatusOK, "Ollama is running")
  911. })
  912. r.Handle(method, "/api/tags", ListModelsHandler)
  913. r.Handle(method, "/api/version", func(c *gin.Context) {
  914. c.JSON(http.StatusOK, gin.H{"version": version.Version})
  915. })
  916. }
  917. return r
  918. }
  919. func Serve(ln net.Listener) error {
  920. level := slog.LevelInfo
  921. if debug := os.Getenv("OLLAMA_DEBUG"); debug != "" {
  922. level = slog.LevelDebug
  923. }
  924. handler := slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{
  925. Level: level,
  926. AddSource: true,
  927. ReplaceAttr: func(_ []string, attr slog.Attr) slog.Attr {
  928. if attr.Key == slog.SourceKey {
  929. source := attr.Value.Any().(*slog.Source)
  930. source.File = filepath.Base(source.File)
  931. }
  932. return attr
  933. },
  934. })
  935. slog.SetDefault(slog.New(handler))
  936. blobsDir, err := GetBlobsPath("")
  937. if err != nil {
  938. return err
  939. }
  940. if err := fixBlobs(blobsDir); err != nil {
  941. return err
  942. }
  943. if noprune := os.Getenv("OLLAMA_NOPRUNE"); noprune == "" {
  944. // clean up unused layers and manifests
  945. if err := PruneLayers(); err != nil {
  946. return err
  947. }
  948. manifestsPath, err := GetManifestPath()
  949. if err != nil {
  950. return err
  951. }
  952. if err := PruneDirectory(manifestsPath); err != nil {
  953. return err
  954. }
  955. }
  956. s := &Server{addr: ln.Addr()}
  957. r := s.GenerateRoutes()
  958. slog.Info(fmt.Sprintf("Listening on %s (version %s)", ln.Addr(), version.Version))
  959. srvr := &http.Server{
  960. Handler: r,
  961. }
  962. // listen for a ctrl+c and stop any loaded llm
  963. signals := make(chan os.Signal, 1)
  964. signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM)
  965. go func() {
  966. <-signals
  967. unload()
  968. gpu.Cleanup()
  969. os.Exit(0)
  970. }()
  971. if err := llm.Init(); err != nil {
  972. return fmt.Errorf("unable to initialize llm library %w", err)
  973. }
  974. if runtime.GOOS == "linux" { // TODO - windows too
  975. // check compatibility to log warnings
  976. if _, err := gpu.CheckVRAM(); err != nil {
  977. slog.Info(err.Error())
  978. }
  979. }
  980. return srvr.Serve(ln)
  981. }
  982. func waitForStream(c *gin.Context, ch chan interface{}) {
  983. c.Header("Content-Type", "application/json")
  984. for resp := range ch {
  985. switch r := resp.(type) {
  986. case api.ProgressResponse:
  987. if r.Status == "success" {
  988. c.JSON(http.StatusOK, r)
  989. return
  990. }
  991. case gin.H:
  992. if errorMsg, ok := r["error"].(string); ok {
  993. c.JSON(http.StatusInternalServerError, gin.H{"error": errorMsg})
  994. return
  995. } else {
  996. c.JSON(http.StatusInternalServerError, gin.H{"error": "unexpected error format in progress response"})
  997. return
  998. }
  999. default:
  1000. c.JSON(http.StatusInternalServerError, gin.H{"error": "unexpected progress response"})
  1001. return
  1002. }
  1003. }
  1004. c.JSON(http.StatusInternalServerError, gin.H{"error": "unexpected end of progress response"})
  1005. }
  1006. func streamResponse(c *gin.Context, ch chan any) {
  1007. c.Header("Content-Type", "application/x-ndjson")
  1008. c.Stream(func(w io.Writer) bool {
  1009. val, ok := <-ch
  1010. if !ok {
  1011. return false
  1012. }
  1013. bts, err := json.Marshal(val)
  1014. if err != nil {
  1015. slog.Info(fmt.Sprintf("streamResponse: json.Marshal failed with %s", err))
  1016. return false
  1017. }
  1018. // Delineate chunks with new-line delimiter
  1019. bts = append(bts, '\n')
  1020. if _, err := w.Write(bts); err != nil {
  1021. slog.Info(fmt.Sprintf("streamResponse: w.Write failed with %s", err))
  1022. return false
  1023. }
  1024. return true
  1025. })
  1026. }
  1027. // ChatPrompt builds up a prompt from a series of messages for the currently `loaded` model
  1028. func chatPrompt(ctx context.Context, template string, messages []api.Message, numCtx int) (string, error) {
  1029. encode := func(s string) ([]int, error) {
  1030. return loaded.llama.Tokenize(ctx, s)
  1031. }
  1032. prompt, err := ChatPrompt(template, messages, numCtx, encode)
  1033. if err != nil {
  1034. return "", err
  1035. }
  1036. return prompt, nil
  1037. }
  1038. func ChatHandler(c *gin.Context) {
  1039. loaded.mu.Lock()
  1040. defer loaded.mu.Unlock()
  1041. checkpointStart := time.Now()
  1042. var req api.ChatRequest
  1043. err := c.ShouldBindJSON(&req)
  1044. switch {
  1045. case errors.Is(err, io.EOF):
  1046. c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "missing request body"})
  1047. return
  1048. case err != nil:
  1049. c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": err.Error()})
  1050. return
  1051. }
  1052. // validate the request
  1053. switch {
  1054. case req.Model == "":
  1055. c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "model is required"})
  1056. return
  1057. case len(req.Format) > 0 && req.Format != "json":
  1058. c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "format must be json"})
  1059. return
  1060. }
  1061. model, err := GetModel(req.Model)
  1062. if err != nil {
  1063. var pErr *fs.PathError
  1064. if errors.As(err, &pErr) {
  1065. c.JSON(http.StatusNotFound, gin.H{"error": fmt.Sprintf("model '%s' not found, try pulling it first", req.Model)})
  1066. return
  1067. }
  1068. c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
  1069. return
  1070. }
  1071. if model.IsEmbedding() {
  1072. c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "embedding models do not support chat"})
  1073. return
  1074. }
  1075. opts, err := modelOptions(model, req.Options)
  1076. if err != nil {
  1077. if errors.Is(err, api.ErrInvalidOpts) {
  1078. c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
  1079. return
  1080. }
  1081. c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
  1082. return
  1083. }
  1084. var sessionDuration time.Duration
  1085. if req.KeepAlive == nil {
  1086. sessionDuration = getDefaultSessionDuration()
  1087. } else {
  1088. sessionDuration = req.KeepAlive.Duration
  1089. }
  1090. if err := load(c, model, opts, sessionDuration); err != nil {
  1091. c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
  1092. return
  1093. }
  1094. checkpointLoaded := time.Now()
  1095. // if the first message is not a system message, then add the model's default system message
  1096. if len(req.Messages) > 0 && req.Messages[0].Role != "system" {
  1097. req.Messages = append([]api.Message{
  1098. {
  1099. Role: "system",
  1100. Content: model.System,
  1101. },
  1102. }, req.Messages...)
  1103. }
  1104. prompt, err := chatPrompt(c.Request.Context(), model.Template, req.Messages, opts.NumCtx)
  1105. if err != nil {
  1106. c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
  1107. return
  1108. }
  1109. // an empty request loads the model
  1110. if len(req.Messages) == 0 || prompt == "" {
  1111. resp := api.ChatResponse{
  1112. CreatedAt: time.Now().UTC(),
  1113. Model: req.Model,
  1114. Done: true,
  1115. Message: api.Message{Role: "assistant"},
  1116. }
  1117. c.JSON(http.StatusOK, resp)
  1118. return
  1119. }
  1120. // only send images that are in the prompt
  1121. var i int
  1122. var images []llm.ImageData
  1123. for _, m := range req.Messages {
  1124. for _, img := range m.Images {
  1125. if !isSupportedImageType(img) {
  1126. c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "unsupported image format"})
  1127. return
  1128. }
  1129. if strings.Contains(prompt, fmt.Sprintf("[img-%d]", i)) {
  1130. images = append(images, llm.ImageData{Data: img, ID: i})
  1131. }
  1132. i += 1
  1133. }
  1134. }
  1135. slog.Debug("chat handler", "prompt", prompt, "images", len(images))
  1136. ch := make(chan any)
  1137. go func() {
  1138. defer close(ch)
  1139. fn := func(r llm.CompletionResponse) {
  1140. // Update model expiration
  1141. loaded.expireTimer.Reset(sessionDuration)
  1142. resp := api.ChatResponse{
  1143. Model: req.Model,
  1144. CreatedAt: time.Now().UTC(),
  1145. Message: api.Message{Role: "assistant", Content: r.Content},
  1146. Done: r.Done,
  1147. Metrics: api.Metrics{
  1148. PromptEvalCount: r.PromptEvalCount,
  1149. PromptEvalDuration: r.PromptEvalDuration,
  1150. EvalCount: r.EvalCount,
  1151. EvalDuration: r.EvalDuration,
  1152. },
  1153. }
  1154. if r.Done {
  1155. resp.TotalDuration = time.Since(checkpointStart)
  1156. resp.LoadDuration = checkpointLoaded.Sub(checkpointStart)
  1157. }
  1158. ch <- resp
  1159. }
  1160. if err := loaded.llama.Completion(c.Request.Context(), llm.CompletionRequest{
  1161. Prompt: prompt,
  1162. Format: req.Format,
  1163. Images: images,
  1164. Options: opts,
  1165. }, fn); err != nil {
  1166. ch <- gin.H{"error": err.Error()}
  1167. }
  1168. }()
  1169. if req.Stream != nil && !*req.Stream {
  1170. // Accumulate responses into the final response
  1171. var final api.ChatResponse
  1172. var sb strings.Builder
  1173. for resp := range ch {
  1174. switch r := resp.(type) {
  1175. case api.ChatResponse:
  1176. sb.WriteString(r.Message.Content)
  1177. final = r
  1178. case gin.H:
  1179. if errorMsg, ok := r["error"].(string); ok {
  1180. c.JSON(http.StatusInternalServerError, gin.H{"error": errorMsg})
  1181. return
  1182. } else {
  1183. c.JSON(http.StatusInternalServerError, gin.H{"error": "unexpected error format in response"})
  1184. return
  1185. }
  1186. default:
  1187. c.JSON(http.StatusInternalServerError, gin.H{"error": "unexpected error"})
  1188. return
  1189. }
  1190. }
  1191. final.Message = api.Message{Role: "assistant", Content: sb.String()}
  1192. c.JSON(http.StatusOK, final)
  1193. return
  1194. }
  1195. streamResponse(c, ch)
  1196. }