package serve import ( "fmt" "html/template" "net/http" "strconv" "strings" "github.com/direct-dev-ru/linux-command-gpt/config" "github.com/direct-dev-ru/linux-command-gpt/gpt" "github.com/direct-dev-ru/linux-command-gpt/serve/templates" "github.com/direct-dev-ru/linux-command-gpt/validation" "github.com/russross/blackfriday/v2" ) // ExecutePageData содержит данные для страницы выполнения type ExecutePageData struct { Title string Header string CurrentPrompt string SystemOptions []SystemPromptOption ResultSection template.HTML VerboseButtons template.HTML ActionButtons template.HTML // Поля конфигурации для валидации MaxUserMessageLength int } // SystemPromptOption представляет опцию системного промпта type SystemPromptOption struct { ID int Name string Description string } // ExecuteResultData содержит результат выполнения type ExecuteResultData struct { Success bool Command string Explanation string Error string Model string Elapsed float64 Verbose string } // handleExecutePage обрабатывает страницу выполнения func handleExecutePage(w http.ResponseWriter, r *http.Request) { switch r.Method { case http.MethodGet: // Показываем форму showExecuteForm(w) case http.MethodPost: // Обрабатываем выполнение handleExecuteRequest(w, r) default: http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) } } // showExecuteForm показывает форму выполнения func showExecuteForm(w http.ResponseWriter) { // Получаем системные промпты pm := gpt.NewPromptManager(config.AppConfig.PromptFolder) var systemOptions []SystemPromptOption for i := 1; i <= 5; i++ { prompt, err := pm.GetPromptByID(i) if err == nil { systemOptions = append(systemOptions, SystemPromptOption{ ID: prompt.ID, Name: prompt.Name, Description: prompt.Description, }) } } data := ExecutePageData{ Title: "Выполнение запроса", Header: "Выполнение запроса", CurrentPrompt: "", SystemOptions: systemOptions, ResultSection: template.HTML(""), VerboseButtons: template.HTML(""), ActionButtons: template.HTML(""), MaxUserMessageLength: config.AppConfig.Validation.MaxUserMessageLength, } w.Header().Set("Content-Type", "text/html; charset=utf-8") templates.ExecutePageTemplate.Execute(w, data) } // handleExecuteRequest обрабатывает запрос на выполнение func handleExecuteRequest(w http.ResponseWriter, r *http.Request) { // Парсим форму prompt := r.FormValue("prompt") systemIDStr := r.FormValue("system_id") verbose := r.FormValue("verbose") // Получаем системные промпты pm := gpt.NewPromptManager(config.AppConfig.PromptFolder) if prompt == "" { http.Error(w, "Prompt is required", http.StatusBadRequest) return } // Валидация длины пользовательского сообщения if err := validation.ValidateUserMessage(prompt); err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } systemID := 1 if systemIDStr != "" { if id, err := strconv.Atoi(systemIDStr); err == nil && id >= 1 && id <= 5 { systemID = id } } // Получаем системный промпт systemPrompt, err := pm.GetPromptByID(systemID) if err != nil { http.Error(w, "Failed to get system prompt", http.StatusInternalServerError) return } // Валидация длины системного промпта if err := validation.ValidateSystemPrompt(systemPrompt.Content); err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } // Создаем GPT клиент gpt3 := gpt.NewGpt3( config.AppConfig.ProviderType, config.AppConfig.Host, config.AppConfig.JwtToken, config.AppConfig.Model, systemPrompt.Content, 0.01, 120, ) // Debug вывод для основного запроса PrintWebDebugInfo("EXECUTE", prompt, systemPrompt.Content, config.AppConfig.Model, 120) // Выполняем запрос response, elapsed := getCommand(*gpt3, prompt) var result ExecuteResultData if response == "" { result = ExecuteResultData{ Success: false, Error: "Failed to get response from AI", } } else { result = ExecuteResultData{ Success: true, Command: response, Model: config.AppConfig.Model, Elapsed: elapsed, } } // Если запрошено подробное объяснение if verbose != "" { level := len(verbose) verbosePrompt := gpt.GetVerbosePromptByLevel(level) // Debug вывод для verbose запроса PrintWebVerboseDebugInfo("VERBOSE", prompt, verbosePrompt, config.AppConfig.Model, level, 120) explanation, err := getDetailedExplanation(prompt, verbose, 120) if err == nil { // Конвертируем Markdown в HTML explanationHTML := blackfriday.Run([]byte(explanation)) result.Explanation = string(explanationHTML) result.Verbose = verbose } } // Получаем системные промпты для dropdown var systemOptions []SystemPromptOption for i := 1; i <= 5; i++ { prompt, err := pm.GetPromptByID(i) if err == nil { systemOptions = append(systemOptions, SystemPromptOption{ ID: prompt.ID, Name: prompt.Name, Description: prompt.Description, }) } } data := ExecutePageData{ Title: "Результат выполнения", Header: "Результат выполнения", CurrentPrompt: prompt, SystemOptions: systemOptions, ResultSection: template.HTML(formatResultSection(result)), VerboseButtons: template.HTML(formatVerboseButtons(result)), ActionButtons: template.HTML(formatActionButtons(result)), MaxUserMessageLength: config.AppConfig.Validation.MaxUserMessageLength, } w.Header().Set("Content-Type", "text/html; charset=utf-8") templates.ExecutePageTemplate.Execute(w, data) } // formatResultSection форматирует секцию результата func formatResultSection(result ExecuteResultData) string { if !result.Success { return fmt.Sprintf(`