Closed3

Neovim: plenary.curl で stream 処理

goropikarigoropikari

ollama へのリクエストが stream で飛んでくるので1行毎を buffer に都度送りたい

curl -s http://localhost:11434/api/generate -d '{
      "model": "codegemma",
      "prompt":"Hello!"
    }'
{"model":"codegemma","created_at":"2024-10-13T03:22:23.277732194Z","response":"Hello","done":false}
{"model":"codegemma","created_at":"2024-10-13T03:22:23.818230637Z","response":"!","done":false}
{"model":"codegemma","created_at":"2024-10-13T03:22:24.357831778Z","response":" 👋","done":false}
{"model":"codegemma","created_at":"2024-10-13T03:22:24.891041066Z","response":" It","done":false}
{"model":"codegemma","created_at":"2024-10-13T03:22:25.411833152Z","response":"'","done":false}
{"model":"codegemma","created_at":"2024-10-13T03:22:25.954475491Z","response":"s","done":false}
{"model":"codegemma","created_at":"2024-10-13T03:22:26.486324009Z","response":" nice","done":false}
{"model":"codegemma","created_at":"2024-10-13T03:22:27.00786642Z","response":" to","done":false}
{"model":"codegemma","created_at":"2024-10-13T03:22:27.383021173Z","response":" meet","done":false}
{"model":"codegemma","created_at":"2024-10-13T03:22:27.924946619Z","response":" you","done":false}
{"model":"codegemma","created_at":"2024-10-13T03:22:28.44119388Z","response":".","done":false}
{"model":"codegemma","created_at":"2024-10-13T03:22:28.82143907Z","response":" What","done":false}
{"model":"codegemma","created_at":"2024-10-13T03:22:29.358150899Z","response":" can","done":false}
{"model":"codegemma","created_at":"2024-10-13T03:22:29.889126231Z","response":" I","done":false}
{"model":"codegemma","created_at":"2024-10-13T03:22:30.422004398Z","response":" do","done":false}
{"model":"codegemma","created_at":"2024-10-13T03:22:30.939910817Z","response":" for","done":false}
{"model":"codegemma","created_at":"2024-10-13T03:22:31.442187757Z","response":" you","done":false}
{"model":"codegemma","created_at":"2024-10-13T03:22:31.949817234Z","response":" today","done":false}
{"model":"codegemma","created_at":"2024-10-13T03:22:32.332719691Z","response":"?","done":false}
{"model":"codegemma","created_at":"2024-10-13T03:22:32.857653405Z","response":" 😊","done":false}
{"model":"codegemma","created_at":"2024-10-13T03:22:33.383532691Z","response":"\u003c/","done":false}
{"model":"codegemma","created_at":"2024-10-13T03:22:33.887078247Z","response":"end","done":false}
{"model":"codegemma","created_at":"2024-10-13T03:22:34.272397572Z","response":"_","done":false}
{"model":"codegemma","created_at":"2024-10-13T03:22:34.670724455Z","response":"of","done":false}
{"model":"codegemma","created_at":"2024-10-13T03:22:35.190621273Z","response":"_","done":false}
{"model":"codegemma","created_at":"2024-10-13T03:22:35.71825778Z","response":"turn","done":false}
{"model":"codegemma","created_at":"2024-10-13T03:22:36.243699266Z","response":"\u003e","done":false}
{"model":"codegemma","created_at":"2024-10-13T03:22:36.777150246Z","response":"","done":true,"done_reason":"stop","context":[968,2997,235298,559,235298,15508,235313,1645,108,4521,149907,615,235298,559,235298,15508,235313,108,235322,2997,235298,559,235298,15508,235313,2516,108,4521,235341,169692,1165,235303,235256,4866,577,4664,692,235265,2439,798,590,749,604,692,3646,235336,44416,727,615,235298,559,235298,15508,235313],"total_duration":14165388199,"load_duration":49338759,"prompt_eval_count":28,"prompt_eval_duration":573189000,"eval_count":28,"eval_duration":13499366000}
goropikarigoropikari

stream 関数のなかで nvim_buf_set_lines を呼ぶためには schedule で包む必要がある

local curl = require("plenary.curl")
local log = require("plenary.log"):new()
log.level = "debug"

local bufnr = vim.api.nvim_create_buf(false, true)
vim.api.nvim_set_option_value("filetype", "markdown", { buf = bufnr })

local win_opts = {
	relative = "editor",
	width = math.floor(vim.o.columns * 0.7),
	height = math.floor(vim.o.lines / 2),
	col = math.floor((vim.o.columns - vim.o.columns * 0.7) / 2), -- 中央に配置
	row = math.floor(vim.o.lines * 0.1),
	border = "single", -- 枠線を付ける
	-- style = 'minimal',
	title = "Local LLM",
	title_pos = "center",
	style = "minimal",
}

vim.api.nvim_open_win(bufnr, false, win_opts)

curl.post({
	url = "http://localhost:11434/api/generate",
	stream = function(err, chunk)
		if chunk then
			local res = vim.json.decode(chunk)
			vim.schedule(function()
				local last_line_num = vim.api.nvim_buf_line_count(bufnr)
				local last_line_text = vim.api.nvim_buf_get_lines(bufnr, last_line_num - 1, last_line_num, false)[1]
				last_line_text = last_line_text .. res.response
				vim.api.nvim_buf_set_lines(bufnr, last_line_num - 1, -1, false, vim.split(last_line_text, "\n"))
				if res.done then
					vim.api.nvim_buf_set_lines(bufnr, -1, -1, false, { "", "----", "" })
				end
			end)
		end
	end,
	body = vim.json.encode({
		model = "codegemma",
		prompt = "Hello!",
	}),
})
このスクラップは2024/10/13にクローズされました