mobile version styled -ready for new version 2.0.1

This commit is contained in:
2025-10-22 18:37:08 +06:00
parent 344f763bb4
commit e37599d3ef
28 changed files with 4998 additions and 2224 deletions

421
serve/prompts.go Normal file
View File

@@ -0,0 +1,421 @@
package serve
import (
"encoding/json"
"fmt"
"html/template"
"net/http"
"os"
"strconv"
"strings"
"github.com/direct-dev-ru/linux-command-gpt/gpt"
"github.com/direct-dev-ru/linux-command-gpt/serve/templates"
)
// VerbosePrompt структура для промптов подробности
type VerbosePrompt struct {
Mode string
Name string
Description string
Content string
IsDefault bool
}
// handlePromptsPage обрабатывает страницу управления промптами
func handlePromptsPage(w http.ResponseWriter, r *http.Request) {
// Получаем домашнюю директорию пользователя
homeDir, err := os.UserHomeDir()
if err != nil {
http.Error(w, "Ошибка получения домашней директории", http.StatusInternalServerError)
return
}
// Создаем менеджер промптов (использует конфигурацию из config.AppConfig.PromptFolder)
pm := gpt.NewPromptManager(homeDir)
// Получаем язык из параметра запроса, если не указан - берем из файла
lang := r.URL.Query().Get("lang")
if lang == "" {
lang = pm.GetCurrentLanguage()
}
tmpl := templates.PromptsPageTemplate
t, err := template.New("prompts").Parse(tmpl)
if err != nil {
http.Error(w, "Ошибка шаблона", http.StatusInternalServerError)
return
}
// Создаем структуру с дополнительным полем IsDefault
type PromptWithDefault struct {
gpt.SystemPrompt
IsDefault bool
}
// Получаем текущий язык из файла
currentLang := pm.GetCurrentLanguage()
// Если язык не указан в URL, используем язык из файла
if lang == "" {
lang = currentLang
}
// Получаем системные промпты с учетом языка
systemPrompts := getSystemPromptsWithLang(pm.Prompts, lang)
var promptsWithDefault []PromptWithDefault
for _, prompt := range systemPrompts {
// Показываем только системные промпты (ID 1-5) на первой вкладке
if prompt.ID >= 1 && prompt.ID <= 5 {
// Проверяем, является ли промпт встроенным и неизмененным
isDefault := gpt.IsBuiltinPrompt(prompt)
promptsWithDefault = append(promptsWithDefault, PromptWithDefault{
SystemPrompt: prompt,
IsDefault: isDefault,
})
}
}
// Получаем промпты подробности из файла sys_prompts
verbosePrompts := getVerbosePromptsFromFile(pm.Prompts, lang)
data := struct {
Prompts []PromptWithDefault
VerbosePrompts []VerbosePrompt
Lang string
}{
Prompts: promptsWithDefault,
VerbosePrompts: verbosePrompts,
Lang: lang,
}
w.Header().Set("Content-Type", "text/html; charset=utf-8")
t.Execute(w, data)
}
// handleAddPrompt обрабатывает добавление нового промпта
func handleAddPrompt(w http.ResponseWriter, r *http.Request) {
if r.Method != "POST" {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
// Получаем домашнюю директорию пользователя
homeDir, err := os.UserHomeDir()
if err != nil {
http.Error(w, "Ошибка получения домашней директории", http.StatusInternalServerError)
return
}
// Создаем менеджер промптов (использует конфигурацию из config.AppConfig.PromptFolder)
pm := gpt.NewPromptManager(homeDir)
// Парсим JSON данные
var promptData struct {
Name string `json:"name"`
Description string `json:"description"`
Content string `json:"content"`
}
if err := json.NewDecoder(r.Body).Decode(&promptData); err != nil {
http.Error(w, "Ошибка парсинга JSON", http.StatusBadRequest)
return
}
// Добавляем промпт
if err := pm.AddPrompt(promptData.Name, promptData.Description, promptData.Content); err != nil {
http.Error(w, fmt.Sprintf("Ошибка добавления промпта: %v", err), http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusOK)
w.Write([]byte("Промпт успешно добавлен"))
}
// handleEditPrompt обрабатывает редактирование промпта
func handleEditPrompt(w http.ResponseWriter, r *http.Request) {
if r.Method != "PUT" {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
// Получаем ID из URL
idStr := strings.TrimPrefix(r.URL.Path, "/prompts/edit/")
id, err := strconv.Atoi(idStr)
if err != nil {
http.Error(w, "Неверный ID промпта", http.StatusBadRequest)
return
}
// Получаем домашнюю директорию пользователя
homeDir, err := os.UserHomeDir()
if err != nil {
http.Error(w, "Ошибка получения домашней директории", http.StatusInternalServerError)
return
}
// Создаем менеджер промптов (использует конфигурацию из config.AppConfig.PromptFolder)
pm := gpt.NewPromptManager(homeDir)
// Парсим JSON данные
var promptData struct {
Name string `json:"name"`
Description string `json:"description"`
Content string `json:"content"`
}
if err := json.NewDecoder(r.Body).Decode(&promptData); err != nil {
http.Error(w, "Ошибка парсинга JSON", http.StatusBadRequest)
return
}
// Обновляем промпт
if err := pm.UpdatePrompt(id, promptData.Name, promptData.Description, promptData.Content); err != nil {
http.Error(w, fmt.Sprintf("Ошибка обновления промпта: %v", err), http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusOK)
w.Write([]byte("Промпт успешно обновлен"))
}
// handleDeletePrompt обрабатывает удаление промпта
func handleDeletePrompt(w http.ResponseWriter, r *http.Request) {
if r.Method != "DELETE" {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
// Получаем ID из URL
idStr := strings.TrimPrefix(r.URL.Path, "/prompts/delete/")
id, err := strconv.Atoi(idStr)
if err != nil {
http.Error(w, "Неверный ID промпта", http.StatusBadRequest)
return
}
// Получаем домашнюю директорию пользователя
homeDir, err := os.UserHomeDir()
if err != nil {
http.Error(w, "Ошибка получения домашней директории", http.StatusInternalServerError)
return
}
// Создаем менеджер промптов (использует конфигурацию из config.AppConfig.PromptFolder)
pm := gpt.NewPromptManager(homeDir)
// Удаляем промпт
if err := pm.DeletePrompt(id); err != nil {
http.Error(w, fmt.Sprintf("Ошибка удаления промпта: %v", err), http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusOK)
w.Write([]byte("Промпт успешно удален"))
}
// handleRestorePrompt восстанавливает системный промпт к значению по умолчанию
func handleRestorePrompt(w http.ResponseWriter, r *http.Request) {
if r.Method != "POST" {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
// Получаем ID из URL
idStr := strings.TrimPrefix(r.URL.Path, "/prompts/restore/")
id, err := strconv.Atoi(idStr)
if err != nil {
http.Error(w, "Invalid prompt ID", http.StatusBadRequest)
return
}
// Получаем домашнюю директорию пользователя
homeDir, err := os.UserHomeDir()
if err != nil {
http.Error(w, "Ошибка получения домашней директории", http.StatusInternalServerError)
return
}
// Создаем менеджер промптов
pm := gpt.NewPromptManager(homeDir)
// Получаем текущий язык
currentLang := pm.GetCurrentLanguage()
// Получаем встроенный промпт для текущего языка
builtinPrompt := gpt.GetBuiltinPromptByIDAndLanguage(id, currentLang)
if builtinPrompt == nil {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusBadRequest)
json.NewEncoder(w).Encode(map[string]interface{}{
"success": false,
"error": "Промпт не найден в встроенных",
})
return
}
// Обновляем промпт в списке
for i, prompt := range pm.Prompts {
if prompt.ID == id {
pm.Prompts[i] = *builtinPrompt
break
}
}
// Сохраняем изменения
if err := pm.SaveAllPrompts(); err != nil {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusInternalServerError)
json.NewEncoder(w).Encode(map[string]interface{}{
"success": false,
"error": "Ошибка сохранения: " + err.Error(),
})
return
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]interface{}{
"success": true,
})
}
// handleRestoreVerbosePrompt восстанавливает verbose промпт к значению по умолчанию
func handleRestoreVerbosePrompt(w http.ResponseWriter, r *http.Request) {
if r.Method != "POST" {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
// Получаем режим из URL
mode := strings.TrimPrefix(r.URL.Path, "/prompts/restore-verbose/")
// Получаем домашнюю директорию пользователя
homeDir, err := os.UserHomeDir()
if err != nil {
http.Error(w, "Ошибка получения домашней директории", http.StatusInternalServerError)
return
}
// Создаем менеджер промптов
pm := gpt.NewPromptManager(homeDir)
// Получаем текущий язык
currentLang := pm.GetCurrentLanguage()
// Определяем ID по режиму
var id int
switch mode {
case "v":
id = 6
case "vv":
id = 7
case "vvv":
id = 8
default:
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusBadRequest)
json.NewEncoder(w).Encode(map[string]interface{}{
"success": false,
"error": "Неверный режим промпта",
})
return
}
// Получаем встроенный промпт для текущего языка
builtinPrompt := gpt.GetBuiltinPromptByIDAndLanguage(id, currentLang)
if builtinPrompt == nil {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusBadRequest)
json.NewEncoder(w).Encode(map[string]interface{}{
"success": false,
"error": "Промпт не найден в встроенных",
})
return
}
// Обновляем промпт в списке
for i, prompt := range pm.Prompts {
if prompt.ID == id {
pm.Prompts[i] = *builtinPrompt
break
}
}
// Сохраняем изменения
if err := pm.SaveAllPrompts(); err != nil {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusInternalServerError)
json.NewEncoder(w).Encode(map[string]interface{}{
"success": false,
"error": "Ошибка сохранения: " + err.Error(),
})
return
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]interface{}{
"success": true,
})
}
// handleSaveLang обрабатывает сохранение промптов при переключении языка
func handleSaveLang(w http.ResponseWriter, r *http.Request) {
if r.Method != "POST" {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
// Получаем домашнюю директорию пользователя
homeDir, err := os.UserHomeDir()
if err != nil {
http.Error(w, "Ошибка получения домашней директории", http.StatusInternalServerError)
return
}
// Создаем менеджер промптов
pm := gpt.NewPromptManager(homeDir)
// Парсим JSON данные
var langData struct {
Lang string `json:"lang"`
}
if err := json.NewDecoder(r.Body).Decode(&langData); err != nil {
http.Error(w, "Ошибка парсинга JSON", http.StatusBadRequest)
return
}
// Устанавливаем язык файла
pm.SetLanguage(langData.Lang)
// Переводим только встроенные промпты (по ID), а пользовательские оставляем как есть
var translatedPrompts []gpt.SystemPrompt
for _, p := range pm.Prompts {
// Проверяем, является ли промпт встроенным по ID (1-8)
if pm.IsDefaultPromptByID(p) {
// System (1-5) и Verbose (6-8)
if p.ID >= 1 && p.ID <= 5 {
translatedPrompts = append(translatedPrompts, translateSystemPrompt(p, langData.Lang))
} else if p.ID >= 6 && p.ID <= 8 {
translatedPrompts = append(translatedPrompts, translateVerbosePrompt(p, langData.Lang))
} else {
translatedPrompts = append(translatedPrompts, p)
}
} else {
// Пользовательские промпты (ID > 8) не трогаем
translatedPrompts = append(translatedPrompts, p)
}
}
// Обновляем в pm и сохраняем
pm.Prompts = translatedPrompts
if err := pm.SaveAllPrompts(); err != nil {
http.Error(w, fmt.Sprintf("Ошибка сохранения: %v", err), http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusOK)
w.Write([]byte("Промпты сохранены"))
}