package server import ( "bytes" "fmt" "gskaro-v1/internal/llm" "net/http" "time" ) type llmLogEntry struct { Model string Prompt string Answer string Timestamp time.Time PromptTokens int AnswerTokens int } var llmHistory []llmLogEntry // ----------------------------- // LLM Console // ----------------------------- func llmConsoleHandler(w http.ResponseWriter, r *http.Request) { if r.Header.Get("HX-Request") != "true" { fmt.Fprintf(w, ` LLM Console
Текущая модель:
`) renderConsole(w) fmt.Fprintf(w, `
`) return } renderConsole(w) } func renderConsole(w http.ResponseWriter) { fmt.Fprintf(w, `

LLM Console

Текущая модель: %s


Ожидание ответа...
`, llm.ActiveModel) } // ----------------------------- // Список моделей // ----------------------------- func llmModelsHandler(w http.ResponseWriter, r *http.Request) { host := r.URL.Query().Get("host") if host == "" { fmt.Fprintf(w, `

Подключение к Ollama

`) return } models, err := llm.GetModelsFromHost(host) if err != nil { fmt.Fprintf(w, `

Ошибка подключения: %s

`, err) return } fmt.Fprintf(w, `

Модели на %s

`, host) fmt.Fprintf(w, `
`) fmt.Fprintf(w, ``, host) fmt.Fprintf(w, ``) fmt.Fprintf(w, ``) fmt.Fprintf(w, `
`) } // ----------------------------- // Выбор модели // ----------------------------- func llmSelectHandler(w http.ResponseWriter, r *http.Request) { host := r.FormValue("host") model := r.FormValue("model") if host != "" { llm.ActiveHost = host } if model != "" { llm.ActiveModel = model } if r.Header.Get("HX-Request") == "true" { w.Header().Set("HX-Redirect", "/api/llm/console") return } http.Redirect(w, r, "/api/llm/console", http.StatusSeeOther) } // ----------------------------- // Запрос к модели // ----------------------------- func llmQueryHandler(w http.ResponseWriter, r *http.Request) { prompt := r.FormValue("prompt") if prompt == "" { fmt.Fprintf(w, "

Пустой запрос.

") return } client := &llm.OllamaClient{ Host: llm.ActiveHost, Model: llm.ActiveModel, } var answerBuf bytes.Buffer var promptTokens, answerTokens int err := client.Stream(prompt, func(chunk string, meta *llm.OllamaGenerateResponse) { answerBuf.WriteString(chunk) if meta != nil { promptTokens = meta.PromptEvalCount answerTokens = meta.EvalCount } }) if err != nil { fmt.Fprintf(w, "

Ошибка: %s

", err) return } resp := answerBuf.String() llmHistory = append(llmHistory, llmLogEntry{ Model: llm.ActiveModel, Prompt: prompt, Answer: resp, Timestamp: time.Now(), PromptTokens: promptTokens, AnswerTokens: answerTokens, }) fmt.Fprintf(w, "
%s
", resp) } // ----------------------------- // Статус // ----------------------------- func llmStatusHandler(w http.ResponseWriter, r *http.Request) { resp, err := http.Get(llm.ActiveHost + "/api/tags") if err != nil { fmt.Fprintf(w, ` Ollama: offline   Модель: %s `, llm.ActiveModel) return } resp.Body.Close() fmt.Fprintf(w, ` Ollama: online   Модель: %s `, llm.ActiveModel) } // ----------------------------- // История // ----------------------------- func llmHistoryHandler(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "

LLM History

") if len(llmHistory) == 0 { fmt.Fprintf(w, "

Пока пусто.

") return } fmt.Fprintf(w, ``) }