Compare commits

..

13 Commits

30 changed files with 116 additions and 1704 deletions

View File

@@ -1,32 +0,0 @@
# Goreleaser configuration version 2
version: 2
builds:
- id: lcg
binary: "lcg_{{ .Version }}"
goos:
- linux
- windows
- darwin
goarch:
- amd64
- arm64
env:
- CGO_ENABLED=0
ldflags:
- -s -w
- -X main.version={{.Version}}
- -X main.commit={{.Commit}}
- -X main.date={{.Date}}
main: .
dir: .
archives:
- id: lcg
ids:
- lcg
formats:
- binary
name_template: "{{ .Binary }}_{{ .Os }}_{{ .Arch }}"
files:
- "lcg_{{ .Version }}"

View File

@@ -1,36 +1,6 @@
CHANGELOG
=========
Версия 2.0.6 (2025-10-28)
=========================
## ✨ НОВОЕ И ИЗМЕНЕНО
- 🌐 Поддержка BasePath для всех веб‑роутов и шаблонов
- Новый параметр: `LCG_BASE_URL` (пример: `/lcg`) — префикс для всех страниц и API
- Обновлены редиректы и middleware с учетом BasePath
- 🧭 Кастомная страница 404 (красная тема), показывается для любого неизвестного пути под BasePath
- 📱 Улучшена мобильная верстка результатов — стиль карточек как в истории
- 🗂️ Человекочитаемые заголовки результатов: преобразование имени файла в «заголовок — дата время»
- 🗑️ Иконки удаления: единый бледно‑красный крест ✖ в результатах и истории
## 🐛 ИСПРАВЛЕНИЯ
- 🛡️ Исправлен просмотр/удаление файла при включенном BasePath (правильный разбор URL)
- 🧰 На старте сервера гарантируется создание `ResultFolder` и пустого `ResultHistory` (без 500)
- 🚧 Главная страница обрабатывается только по точному пути BasePath, а не по произвольным под‑путям
## ⚙️ КОНФИГУРАЦИЯ
- 🔍 Debug режим теперь включается и флагом `--debug`, и переменной `LCG_DEBUG=1|true`
- 🍪 Уточнена работа с `CookiePath`/`BasePath` в middleware
## 📚 ДОКУМЕНТАЦИЯ
- Обновлены `README.md`, `USAGE_GUIDE.md`, `API_GUIDE.md`, `REVERSE_PROXY_GUIDE.md` — добавлены примеры с BasePath и примечания к 404
---
Версия 2.0.1 (2025-10-22)
=========================

View File

@@ -1,52 +0,0 @@
# Git
.git
.gitignore
.gitattributes
# Build artifacts
dist/
*.exe
*.dll
*.so
*.dylib
lcg
go-lcg
# IDE
.idea/
.vscode/
*.swp
*.swo
*~
# Documentation
docs/
*.md
!README.md
# Tests
*_test.go
test_*.sh
# Deployment scripts
deploy/
shell-code/
kustomize/
# Temporary files
*.log
*.tmp
*.temp
# OS files
.DS_Store
Thumbs.db
# Go
vendor/
# Docker
Dockerfile*
docker-compose*.yml
.dockerignore

View File

@@ -1,15 +0,0 @@
# Временные файлы
*.log
*.tmp
*.temp
# IDE
.idea/
.vscode/
*.swp
*.swo
# OS files
.DS_Store
Thumbs.db

View File

@@ -1,78 +0,0 @@
# Multi-stage build для LCG с Ollama
FROM golang:1.24.6-alpine3.22 AS builder
WORKDIR /build
# Копируем файлы зависимостей
COPY go.mod go.sum ./
RUN go mod download
# Копируем исходный код
COPY . .
# Собираем бинарник
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-w -s -buildid=" -trimpath -o /build/lcg .
# Финальный образ с Ollama
FROM alpine:3.22
# Устанавливаем необходимые пакеты
RUN apk add --no-cache \
curl \
ca-certificates \
bash \
&& rm -rf /var/cache/apk/*
# Устанавливаем Ollama 0.9.5 (поддержка разных архитектур)
ARG TARGETARCH
RUN case ${TARGETARCH} in \
amd64) OLLAMA_ARCH=amd64 ;; \
arm64) OLLAMA_ARCH=arm64 ;; \
arm) OLLAMA_ARCH=arm64 ;; \
*) echo "Unsupported architecture: ${TARGETARCH}" && exit 1 ;; \
esac && \
curl -L https://github.com/ollama/ollama/releases/download/v0.9.5/ollama-linux-${OLLAMA_ARCH} -o /usr/local/bin/ollama \
&& chmod +x /usr/local/bin/ollama
# Создаем пользователя для запуска сервисов
RUN addgroup -g 1000 ollama && \
adduser -D -u 1000 -G ollama ollama && \
mkdir -p /home/ollama/.ollama && \
chown -R ollama:ollama /home/ollama
# Копируем бинарник lcg
COPY --from=builder /build/lcg /usr/local/bin/lcg
RUN chmod +x /usr/local/bin/lcg
# Копируем entrypoint скрипт
COPY --chmod=755 Dockerfiles/OllamaServer/entrypoint.sh /entrypoint.sh
# Создаем директории для данных
RUN mkdir -p /app/data/results /app/data/prompts /app/data/config \
&& chown -R ollama:ollama /app/data
# Настройки по умолчанию
ENV LCG_PROVIDER=ollama
ENV LCG_HOST=http://127.0.0.1:11434/
ENV LCG_MODEL=codegeex4
ENV LCG_RESULT_FOLDER=/app/data/results
ENV LCG_PROMPT_FOLDER=/app/data/prompts
ENV LCG_CONFIG_FOLDER=/app/data/config
ENV LCG_SERVER_HOST=0.0.0.0
ENV LCG_SERVER_PORT=8080
ENV LCG_SERVER_ALLOW_HTTP=true
ENV OLLAMA_HOST=0.0.0.0
ENV OLLAMA_PORT=11434
# Expose порты
EXPOSE 8080 11434
# Переключаемся на пользователя ollama
USER ollama
WORKDIR /home/ollama
# Запускаем entrypoint
ENTRYPOINT ["/entrypoint.sh"]
CMD []

View File

@@ -1,107 +0,0 @@
.PHONY: build build-podman run run-podman stop stop-podman logs logs-podman clean help
# Переменные
IMAGE_NAME = lcg-ollama
IMAGE_TAG = latest
CONTAINER_NAME = lcg-ollama
DOCKERFILE = Dockerfile
CONTEXT = ../..
help: ## Показать справку
@echo "Доступные команды:"
@echo " make build - Собрать Docker образ"
@echo " make build-podman - Собрать Podman образ"
@echo " make run - Запустить контейнер (Docker)"
@echo " make run-podman - Запустить контейнер (Podman)"
@echo " make stop - Остановить контейнер (Docker)"
@echo " make stop-podman - Остановить контейнер (Podman)"
@echo " make logs - Показать логи (Docker)"
@echo " make logs-podman - Показать логи (Podman)"
@echo " make clean - Удалить контейнер и образ"
@echo " make compose-up - Запустить через docker-compose"
@echo " make compose-down - Остановить docker-compose"
@echo " make podman-compose-up - Запустить через podman-compose"
@echo " make podman-compose-down - Остановить podman-compose"
build: ## Собрать Docker образ
docker build -f $(DOCKERFILE) -t $(IMAGE_NAME):$(IMAGE_TAG) $(CONTEXT)
@echo "Образ $(IMAGE_NAME):$(IMAGE_TAG) успешно собран"
build-podman: ## Собрать Podman образ
podman build -f $(DOCKERFILE) -t $(IMAGE_NAME):$(IMAGE_TAG) $(CONTEXT)
@echo "Образ $(IMAGE_NAME):$(IMAGE_TAG) успешно собран"
run: ## Запустить контейнер (Docker)
docker run -d \
--name $(CONTAINER_NAME) \
-p 8080:8080 \
-p 11434:11434 \
-v ollama-data:/home/ollama/.ollama \
-v lcg-results:/app/data/results \
-v lcg-prompts:/app/data/prompts \
-v lcg-config:/app/data/config \
$(IMAGE_NAME):$(IMAGE_TAG)
@echo "Контейнер $(CONTAINER_NAME) запущен"
run-podman: ## Запустить контейнер (Podman)
podman run -d \
--name $(CONTAINER_NAME) \
-p 8080:8080 \
-p 11434:11434 \
-v ollama-data:/home/ollama/.ollama \
-v lcg-results:/app/data/results \
-v lcg-prompts:/app/data/prompts \
-v lcg-config:/app/data/config \
$(IMAGE_NAME):$(IMAGE_TAG)
@echo "Контейнер $(CONTAINER_NAME) запущен"
stop: ## Остановить контейнер (Docker)
docker stop $(CONTAINER_NAME) || true
docker rm $(CONTAINER_NAME) || true
@echo "Контейнер $(CONTAINER_NAME) остановлен и удален"
stop-podman: ## Остановить контейнер (Podman)
podman stop $(CONTAINER_NAME) || true
podman rm $(CONTAINER_NAME) || true
@echo "Контейнер $(CONTAINER_NAME) остановлен и удален"
logs: ## Показать логи (Docker)
docker logs -f $(CONTAINER_NAME)
logs-podman: ## Показать логи (Podman)
podman logs -f $(CONTAINER_NAME)
clean: ## Удалить контейнер и образ
docker stop $(CONTAINER_NAME) || true
docker rm $(CONTAINER_NAME) || true
docker rmi $(IMAGE_NAME):$(IMAGE_TAG) || true
@echo "Контейнер и образ удалены"
compose-up: ## Запустить через docker-compose
docker-compose up -d
@echo "Сервисы запущены через docker-compose"
compose-down: ## Остановить docker-compose
docker-compose down
@echo "Сервисы остановлены"
podman-compose-up: ## Запустить через podman-compose
podman-compose -f podman-compose.yml up -d
@echo "Сервисы запущены через podman-compose"
podman-compose-down: ## Остановить podman-compose
podman-compose -f podman-compose.yml down
@echo "Сервисы остановлены"
shell: ## Подключиться к контейнеру (Docker)
docker exec -it $(CONTAINER_NAME) sh
shell-podman: ## Подключиться к контейнеру (Podman)
podman exec -it $(CONTAINER_NAME) sh
pull-model: ## Загрузить модель codegeex4 (Docker)
docker exec $(CONTAINER_NAME) ollama pull codegeex4
pull-model-podman: ## Загрузить модель codegeex4 (Podman)
podman exec $(CONTAINER_NAME) ollama pull codegeex4

View File

@@ -1,172 +0,0 @@
# 🚀 Быстрый старт - LCG с Ollama
## Подготовка
1. Убедитесь, что у вас установлен Docker или Podman
2. Клонируйте репозиторий (если еще не сделали)
3. Перейдите в папку с Dockerfile
```bash
cd Dockerfiles/OllamaServer
```
## Запуск с Docker
### Вариант 1: Docker Compose (рекомендуется)
```bash
docker-compose up -d
```
### Вариант 2: Ручная сборка и запуск
```bash
# Сборка образа
docker build -f Dockerfile -t lcg-ollama:latest ../..
# Запуск контейнера
docker run -d \
--name lcg-ollama \
-p 8080:8080 \
-p 11434:11434 \
-v ollama-data:/home/ollama/.ollama \
-v lcg-results:/app/data/results \
lcg-ollama:latest
```
## Запуск с Podman
### Вариант 1: Podman Compose
```bash
podman-compose -f podman-compose.yml up -d
```
### Вариант 2: Ручная сборка и запуск
```bash
# Сборка образа
podman build -f Dockerfile -t lcg-ollama:latest ../..
# Запуск контейнера
podman run -d \
--name lcg-ollama \
-p 8080:8080 \
-p 11434:11434 \
-v ollama-data:/home/ollama/.ollama \
-v lcg-results:/app/data/results \
lcg-ollama:latest
```
## Проверка запуска
### Проверка логов
```bash
# Docker
docker logs -f lcg-ollama
# Podman
podman logs -f lcg-ollama
```
Дождитесь сообщений:
- `Ollama сервер готов!`
- `LCG сервер запущен на http://0.0.0.0:8080`
### Проверка доступности
```bash
# Проверка Ollama
curl http://localhost:11434/api/tags
# Проверка LCG
curl http://localhost:8080/
```
## Загрузка модели
После запуска контейнера загрузите модель:
```bash
# Docker
docker exec lcg-ollama ollama pull codegeex4
# Podman
podman exec lcg-ollama ollama pull codegeex4
```
Или используйте модель по умолчанию, указанную в переменных окружения.
## Доступ к веб-интерфейсу
Откройте в браузере: http://localhost:8080
## Остановка
```bash
# Docker
docker-compose down
# Podman
podman-compose -f podman-compose.yml down
```
Или для ручного запуска:
```bash
# Docker
docker stop lcg-ollama
docker rm lcg-ollama
# Podman
podman stop lcg-ollama
podman rm lcg-ollama
```
## Решение проблем
### Порт занят
Измените порты в docker-compose.yml или команде run:
```bash
-p 9000:8080 # LCG на порту 9000
-p 11435:11434 # Ollama на порту 11435
```
### Контейнер не запускается
Проверьте логи:
```bash
docker logs lcg-ollama
# или
podman logs lcg-ollama
```
### Модель не загружена
Убедитесь, что модель существует:
```bash
docker exec lcg-ollama ollama list
# или
podman exec lcg-ollama ollama list
```
Если модели нет, загрузите её:
```bash
docker exec lcg-ollama ollama pull codegeex4
# или
podman exec lcg-ollama ollama pull codegeex4
```
## Следующие шаги
- Прочитайте полную документацию в [README.md](README.md)
- Настройте аутентификацию для продакшена
- Настройте reverse proxy для HTTPS
- Загрузите нужные модели Ollama

View File

@@ -1,397 +0,0 @@
# 🐳 LCG с Ollama Server - Docker/Podman контейнер
Этот образ содержит Linux Command GPT (LCG) и Ollama сервер, работающие вместе в одном контейнере.
Поддерживается запуск через Docker и Podman.
## 📋 Описание
Контейнер автоматически запускает:
1. **Ollama сервер** (v0.9.5) на порту 11434
2. **LCG веб-сервер** на порту 8080
Ollama используется как провайдер LLM для генерации Linux команд.
## 🚀 Быстрый старт
### Сборка образа
#### Docker
```bash
# Из корня проекта
docker build -f Dockerfiles/OllamaServer/Dockerfile -t lcg-ollama:latest .
```
#### Podman
```bash
# Из корня проекта
podman build -f Dockerfiles/OllamaServer/Dockerfile -t lcg-ollama:latest .
```
### Запуск контейнера
#### Docker
```bash
docker run -d \
--name lcg-ollama \
-p 8080:8080 \
-p 11434:11434 \
lcg-ollama:latest
```
#### Podman
```bash
podman run -d \
--name lcg-ollama \
-p 8080:8080 \
-p 11434:11434 \
lcg-ollama:latest
```
### Использование docker-compose / podman-compose
#### Docker Compose
```bash
cd Dockerfiles/OllamaServer
docker-compose up -d
```
#### Podman Compose
```bash
cd Dockerfiles/OllamaServer
podman-compose -f podman-compose.yml up -d
```
Или используйте встроенную поддержку Podman:
```bash
cd Dockerfiles/OllamaServer
podman play kube podman-compose.yml
```
## 🌐 Доступ к сервисам
После запуска контейнера доступны:
- **LCG веб-интерфейс**: http://localhost:8080
- **Ollama API**: http://localhost:11434
## ⚙️ Переменные окружения
### Настройки LCG
| Переменная | Значение по умолчанию | Описание |
|------------|----------------------|----------|
| `LCG_PROVIDER` | `ollama` | Тип провайдера |
| `LCG_HOST` | `http://127.0.0.1:11434/` | URL Ollama API |
| `LCG_MODEL` | `codegeex4` | Модель для использования |
| `LCG_SERVER_HOST` | `0.0.0.0` | Хост LCG сервера |
| `LCG_SERVER_PORT` | `8080` | Порт LCG сервера |
| `LCG_SERVER_ALLOW_HTTP` | `true` | Разрешить HTTP |
| `LCG_RESULT_FOLDER` | `/app/data/results` | Папка для результатов |
| `LCG_PROMPT_FOLDER` | `/app/data/prompts` | Папка для промптов |
| `LCG_CONFIG_FOLDER` | `/app/data/config` | Папка для конфигурации |
### Настройки Ollama
| Переменная | Значение по умолчанию | Описание |
|------------|----------------------|----------|
| `OLLAMA_HOST` | `127.0.0.1` | Хост Ollama сервера |
| `OLLAMA_PORT` | `11434` | Порт Ollama сервера |
### Безопасность
| Переменная | Значение по умолчанию | Описание |
|------------|----------------------|----------|
| `LCG_SERVER_REQUIRE_AUTH` | `false` | Требовать аутентификацию |
| `LCG_SERVER_PASSWORD` | `admin#123456` | Пароль для аутентификации |
## 📦 Volumes
Рекомендуется монтировать volumes для персистентного хранения данных:
```bash
docker run -d \
--name lcg-ollama \
-p 8080:8080 \
-p 11434:11434 \
-v ollama-data:/home/ollama/.ollama \
-v lcg-results:/app/data/results \
-v lcg-prompts:/app/data/prompts \
-v lcg-config:/app/data/config \
lcg-ollama:latest
```
### Volumes описание
- `ollama-data`: Модели и данные Ollama
- `lcg-results`: Результаты генерации команд
- `lcg-prompts`: Системные промпты
- `lcg-config`: Конфигурация LCG
## 🔧 Примеры использования
### Запуск с кастомной моделью
```bash
docker run -d \
--name lcg-ollama \
-p 8080:8080 \
-p 11434:11434 \
-e LCG_MODEL=llama3:8b \
lcg-ollama:latest
```
### Запуск с аутентификацией
```bash
docker run -d \
--name lcg-ollama \
-p 8080:8080 \
-p 11434:11434 \
-e LCG_SERVER_REQUIRE_AUTH=true \
-e LCG_SERVER_PASSWORD=my_secure_password \
lcg-ollama:latest
```
### Запуск с кастомным портом
```bash
docker run -d \
--name lcg-ollama \
-p 9000:9000 \
-p 11434:11434 \
-e LCG_SERVER_PORT=9000 \
lcg-ollama:latest
```
## 📥 Загрузка моделей Ollama
После запуска контейнера можно загрузить модели:
```bash
# Подключиться к контейнеру
docker exec -it lcg-ollama sh
# Загрузить модель
ollama pull codegeex4
ollama pull llama3:8b
ollama pull qwen2.5:7b
```
Или извне контейнера:
```bash
# Убедитесь, что Ollama доступен извне (OLLAMA_HOST=0.0.0.0)
docker exec lcg-ollama ollama pull codegeex4
```
## 🔍 Проверка работоспособности
### Проверка Ollama
```bash
# Проверка health
curl http://localhost:11434/api/tags
# Список моделей
curl http://localhost:11434/api/tags | jq '.models'
```
### Проверка LCG
```bash
# Проверка веб-интерфейса
curl http://localhost:8080/
# Проверка через API
curl -X POST http://localhost:8080/api/execute \
-H "Content-Type: application/json" \
-d '{"prompt": "создать директорию test"}'
```
## 🐧 Podman специфичные инструкции
### Запуск с Podman
Podman работает аналогично Docker, но есть несколько отличий:
#### Создание сетей (если нужно)
```bash
podman network create lcg-network
```
#### Запуск с сетью
```bash
podman run -d \
--name lcg-ollama \
--network lcg-network \
-p 8080:8080 \
-p 11434:11434 \
lcg-ollama:latest
```
#### Запуск в rootless режиме
Podman по умолчанию работает в rootless режиме, что повышает безопасность:
```bash
# Не требует sudo
podman run -d \
--name lcg-ollama \
-p 8080:8080 \
-p 11434:11434 \
lcg-ollama:latest
```
#### Использование systemd для автозапуска
Создайте systemd unit файл:
```bash
# Генерируем unit файл
podman generate systemd --name lcg-ollama --files
# Копируем в systemd
sudo cp container-lcg-ollama.service /etc/systemd/system/
# Включаем автозапуск
sudo systemctl enable container-lcg-ollama.service
sudo systemctl start container-lcg-ollama.service
```
#### Проверка статуса
```bash
# Статус контейнера
podman ps
# Логи
podman logs lcg-ollama
# Логи в реальном времени
podman logs -f lcg-ollama
```
## 🐛 Отладка
### Просмотр логов
#### Docker
```bash
# Логи контейнера
docker logs lcg-ollama
# Логи в реальном времени
docker logs -f lcg-ollama
```
#### Podman
```bash
# Логи контейнера
podman logs lcg-ollama
# Логи в реальном времени
podman logs -f lcg-ollama
```
### Подключение к контейнеру
#### Docker
```bash
docker exec -it lcg-ollama sh
```
#### Podman
```bash
podman exec -it lcg-ollama sh
```
### Проверка процессов
#### Docker
```bash
docker exec lcg-ollama ps aux
```
#### Podman
```bash
podman exec lcg-ollama ps aux
```
## 🔒 Безопасность
### Рекомендации для продакшена
1. **Используйте аутентификацию**:
```bash
-e LCG_SERVER_REQUIRE_AUTH=true
-e LCG_SERVER_PASSWORD=strong_password
```
2. **Ограничьте доступ к портам**:
- Используйте firewall правила
- Не экспортируйте порты на публичный интерфейс
3. **Используйте HTTPS**:
- Настройте reverse proxy (nginx, traefik)
- Используйте SSL сертификаты
4. **Ограничьте ресурсы**:
```bash
docker run -d \
--name lcg-ollama \
--memory="4g" \
--cpus="2" \
lcg-ollama:latest
```
## 📊 Мониторинг
### Healthcheck
Контейнер включает healthcheck, который проверяет доступность LCG сервера:
```bash
docker inspect lcg-ollama | jq '.[0].State.Health'
```
### Метрики
LCG предоставляет Prometheus метрики на `/metrics` endpoint (если включено).
## 🚀 Production Deployment
### С docker-compose
```bash
cd Dockerfiles/OllamaServer
docker-compose up -d
```
### С Kubernetes
Используйте манифесты из папки `deploy/` или `kustomize/`.
## 📝 Примечания
- Ollama версия: 0.9.5
- LCG версия: см. VERSION.txt
- Минимальные требования: 2GB RAM, 2 CPU cores
- Рекомендуется: 4GB+ RAM для больших моделей
## 🔗 Полезные ссылки
- [Ollama документация](https://github.com/ollama/ollama)
- [LCG документация](../../docs/README.md)
- [LCG API Guide](../../docs/API_GUIDE.md)
## ❓ Поддержка
При возникновении проблем:
1. Проверьте логи: `docker logs lcg-ollama`
2. Проверьте переменные окружения
3. Убедитесь, что порты не заняты
4. Проверьте, что модели загружены в Ollama

View File

@@ -1,111 +0,0 @@
# 📁 Структура проекта OllamaServer
## Файлы
```
Dockerfiles/OllamaServer/
├── Dockerfile # Multi-stage Dockerfile для сборки образа
├── entrypoint.sh # Скрипт запуска LCG и Ollama серверов
├── docker-compose.yml # Docker Compose конфигурация
├── podman-compose.yml # Podman Compose конфигурация
├── Makefile # Команды для сборки и запуска
├── README.md # Полная документация
├── QUICKSTART.md # Быстрый старт
├── STRUCTURE.md # Этот файл
├── .dockerignore # Исключения для Docker build
└── .gitignore # Исключения для Git
```
## Описание файлов
### Dockerfile
Multi-stage Dockerfile, который:
1. Собирает бинарник LCG из исходного кода
2. Устанавливает Ollama 0.9.5
3. Создает пользователя ollama
4. Настраивает рабочее окружение
### entrypoint.sh
Скрипт запуска, который:
1. Запускает Ollama сервер в фоне
2. Ожидает готовности Ollama API
3. Запускает LCG сервер в фоне
4. Мониторит состояние процессов
5. Корректно обрабатывает сигналы завершения
### docker-compose.yml / podman-compose.yml
Конфигурация для запуска через compose:
- Настройки портов
- Переменные окружения
- Volumes для персистентного хранения
- Healthcheck
### Makefile
Удобные команды для:
- Сборки образа
- Запуска/остановки контейнера
- Просмотра логов
- Работы с compose
### README.md
Полная документация с:
- Описанием функциональности
- Инструкциями по установке
- Настройками переменных окружения
- Примерами использования
- Решением проблем
### QUICKSTART.md
Краткое руководство для быстрого старта.
## Порты
- **8080**: LCG веб-сервер
- **11434**: Ollama API
## Volumes
- `ollama-data`: Данные Ollama (модели)
- `lcg-results`: Результаты генерации команд
- `lcg-prompts`: Системные промпты
- `lcg-config`: Конфигурация LCG
## Переменные окружения
Основные переменные (см. README.md для полного списка):
- `LCG_PROVIDER=ollama`
- `LCG_HOST=http://127.0.0.1:11434/`
- `LCG_MODEL=codegeex4`
- `OLLAMA_HOST=0.0.0.0`
- `OLLAMA_PORT=11434`
## Запуск
### Docker
```bash
cd Dockerfiles/OllamaServer
docker-compose up -d
```
### Podman
```bash
cd Dockerfiles/OllamaServer
podman-compose -f podman-compose.yml up -d
```
### Make
```bash
cd Dockerfiles/OllamaServer
make compose-up
# или
make podman-compose-up
```
## Архитектура
Контейнер запускает два сервиса:
1. **Ollama** (порт 11434) - LLM сервер
2. **LCG** (порт 8080) - Веб-интерфейс и API
Оба сервиса работают в одном контейнере и общаются через localhost.

View File

@@ -1,54 +0,0 @@
version: '3.8'
services:
lcg-ollama:
build:
context: ../..
dockerfile: Dockerfiles/OllamaServer/Dockerfile
container_name: lcg-ollama
ports:
- "8080:8080" # LCG веб-сервер
- "11434:11434" # Ollama API
environment:
# Настройки LCG
- LCG_PROVIDER=ollama
- LCG_HOST=http://127.0.0.1:11434/
- LCG_MODEL=codegeex4
- LCG_RESULT_FOLDER=/app/data/results
- LCG_PROMPT_FOLDER=/app/data/prompts
- LCG_CONFIG_FOLDER=/app/data/config
- LCG_SERVER_HOST=0.0.0.0
- LCG_SERVER_PORT=8080
- LCG_SERVER_ALLOW_HTTP=true
# Настройки Ollama
- OLLAMA_HOST=0.0.0.0
- OLLAMA_PORT=11434
- OLLAMA_ORIGINS=*
# Опционально: настройки безопасности
- LCG_SERVER_REQUIRE_AUTH=false
- LCG_SERVER_PASSWORD=admin#123456
volumes:
# Персистентное хранилище для данных Ollama
- ollama-data:/home/ollama/.ollama
# Персистентное хранилище для результатов LCG
- lcg-results:/app/data/results
- lcg-prompts:/app/data/prompts
- lcg-config:/app/data/config
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
volumes:
ollama-data:
driver: local
lcg-results:
driver: local
lcg-prompts:
driver: local
lcg-config:
driver: local

View File

@@ -1,171 +0,0 @@
#!/bin/bash
set -e
# Цвета для вывода
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Функция для логирования
log() {
echo -e "${GREEN}[$(date +'%Y-%m-%d %H:%M:%S')]${NC} $1"
}
error() {
echo -e "${RED}[ERROR]${NC} $1" >&2
}
warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
info() {
echo -e "${BLUE}[INFO]${NC} $1"
}
# Обработка сигналов для корректного завершения
cleanup() {
log "Получен сигнал завершения, останавливаем сервисы..."
if [ ! -z "$LCG_PID" ]; then
kill $LCG_PID 2>/dev/null || true
wait $LCG_PID 2>/dev/null || true
fi
if [ ! -z "$OLLAMA_PID" ]; then
kill $OLLAMA_PID 2>/dev/null || true
wait $OLLAMA_PID 2>/dev/null || true
fi
log "Сервисы остановлены"
exit 0
}
trap cleanup SIGTERM SIGINT
# Проверка наличия бинарника lcg
if [ ! -f /usr/local/bin/lcg ]; then
error "Бинарник lcg не найден в /usr/local/bin/lcg"
exit 1
fi
# Проверка наличия Ollama
if [ ! -f /usr/local/bin/ollama ]; then
error "Ollama не найден в /usr/local/bin/ollama"
exit 1
fi
# Создаем необходимые директории
mkdir -p "${LCG_RESULT_FOLDER:-/app/data/results}"
mkdir -p "${LCG_PROMPT_FOLDER:-/app/data/prompts}"
mkdir -p "${LCG_CONFIG_FOLDER:-/app/data/config}"
# Настройка переменных окружения для Ollama
export OLLAMA_HOST="${OLLAMA_HOST:-0.0.0.0}"
export OLLAMA_PORT="${OLLAMA_PORT:-11434}"
export OLLAMA_ORIGINS="*"
# Настройка переменных окружения для LCG
export LCG_PROVIDER="${LCG_PROVIDER:-ollama}"
export LCG_HOST="${LCG_HOST:-http://127.0.0.1:11434/}"
export LCG_MODEL="${LCG_MODEL:-codegeex4}"
export LCG_RESULT_FOLDER="${LCG_RESULT_FOLDER:-/app/data/results}"
export LCG_PROMPT_FOLDER="${LCG_PROMPT_FOLDER:-/app/data/prompts}"
export LCG_CONFIG_FOLDER="${LCG_CONFIG_FOLDER:-/app/data/config}"
export LCG_SERVER_HOST="${LCG_SERVER_HOST:-0.0.0.0}"
export LCG_SERVER_PORT="${LCG_SERVER_PORT:-8080}"
export LCG_SERVER_ALLOW_HTTP="${LCG_SERVER_ALLOW_HTTP:-true}"
log "=========================================="
log "Запуск LCG с Ollama сервером"
log "=========================================="
info "LCG Provider: $LCG_PROVIDER"
info "LCG Host: $LCG_HOST"
info "LCG Model: $LCG_MODEL"
info "LCG Server: http://${LCG_SERVER_HOST}:${LCG_SERVER_PORT}"
info "Ollama Host: $OLLAMA_HOST:$OLLAMA_PORT"
log "=========================================="
# Запускаем Ollama сервер в фоне
log "Запуск Ollama сервера..."
/usr/local/bin/ollama serve &
OLLAMA_PID=$!
# Ждем, пока Ollama запустится
log "Ожидание запуска Ollama сервера..."
sleep 5
# Проверяем, что Ollama запущен
if ! kill -0 $OLLAMA_PID 2>/dev/null; then
error "Ollama сервер не запустился"
exit 1
fi
# Проверяем доступность Ollama API
max_attempts=30
attempt=0
while [ $attempt -lt $max_attempts ]; do
# Проверяем через localhost, так как OLLAMA_HOST может быть 0.0.0.0
if curl -s -f "http://127.0.0.1:${OLLAMA_PORT}/api/tags" > /dev/null 2>&1; then
log "Ollama сервер готов!"
break
fi
attempt=$((attempt + 1))
if [ $attempt -eq $max_attempts ]; then
error "Ollama сервер не отвечает после $max_attempts попыток"
exit 1
fi
sleep 1
done
# Запускаем LCG сервер в фоне
log "Запуск LCG сервера..."
/usr/local/bin/lcg serve \
--host "${LCG_SERVER_HOST}" \
--port "${LCG_SERVER_PORT}" &
LCG_PID=$!
# Ждем, пока LCG запустится
sleep 3
# Проверяем, что LCG запущен
if ! kill -0 $LCG_PID 2>/dev/null; then
error "LCG сервер не запустился"
kill $OLLAMA_PID 2>/dev/null || true
exit 1
fi
log "LCG сервер запущен на http://${LCG_SERVER_HOST}:${LCG_SERVER_PORT}"
log "Ollama сервер доступен на http://${OLLAMA_HOST}:${OLLAMA_PORT}"
log "=========================================="
log "Сервисы запущены и готовы к работе!"
log "=========================================="
# Функция для проверки здоровья процессов
health_check() {
while true; do
# Проверяем Ollama
if ! kill -0 $OLLAMA_PID 2>/dev/null; then
error "Ollama процесс завершился неожиданно"
kill $LCG_PID 2>/dev/null || true
exit 1
fi
# Проверяем LCG
if ! kill -0 $LCG_PID 2>/dev/null; then
error "LCG процесс завершился неожиданно"
kill $OLLAMA_PID 2>/dev/null || true
exit 1
fi
sleep 10
done
}
# Запускаем проверку здоровья в фоне
health_check &
HEALTH_CHECK_PID=$!
# Ждем завершения процессов
wait $LCG_PID $OLLAMA_PID
kill $HEALTH_CHECK_PID 2>/dev/null || true

View File

@@ -1,54 +0,0 @@
version: '3.8'
services:
lcg-ollama:
build:
context: ../..
dockerfile: Dockerfiles/OllamaServer/Dockerfile
container_name: lcg-ollama
ports:
- "8080:8080" # LCG веб-сервер
- "11434:11434" # Ollama API
environment:
# Настройки LCG
- LCG_PROVIDER=ollama
- LCG_HOST=http://127.0.0.1:11434/
- LCG_MODEL=codegeex4
- LCG_RESULT_FOLDER=/app/data/results
- LCG_PROMPT_FOLDER=/app/data/prompts
- LCG_CONFIG_FOLDER=/app/data/config
- LCG_SERVER_HOST=0.0.0.0
- LCG_SERVER_PORT=8080
- LCG_SERVER_ALLOW_HTTP=true
# Настройки Ollama
- OLLAMA_HOST=0.0.0.0
- OLLAMA_PORT=11434
- OLLAMA_ORIGINS=*
# Опционально: настройки безопасности
- LCG_SERVER_REQUIRE_AUTH=false
- LCG_SERVER_PASSWORD=admin#123456
volumes:
# Персистентное хранилище для данных Ollama
- ollama-data:/home/ollama/.ollama
# Персистентное хранилище для результатов LCG
- lcg-results:/app/data/results
- lcg-prompts:/app/data/prompts
- lcg-config:/app/data/config
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
volumes:
ollama-data:
driver: local
lcg-results:
driver: local
lcg-prompts:
driver: local
lcg-config:
driver: local

View File

@@ -1 +1 @@
v2.0.15
v2.0.10

View File

@@ -6,8 +6,6 @@ builds:
binary: "lcg_{{ .Version }}"
goos:
- linux
- windows
- darwin
goarch:
- amd64
- arm64
@@ -23,10 +21,9 @@ builds:
archives:
- id: lcg
ids:
builds:
- lcg
formats:
- binary
format: binary
name_template: "{{ .Binary }}_{{ .Os }}_{{ .Arch }}"
files:
- "lcg_{{ .Version }}"

View File

@@ -198,7 +198,14 @@ log "🔍 Проверка образа:"
echo " docker run --rm $REPOSITORY:$VERSION /app/lcg --version"
echo ""
log "📝 Команды для использования:"
echo " kubectl apply -k kustomize"
echo " kubectl get pods"
echo " kubectl get services"
echo " kubectl get ingress"
echo " kubectl get hpa"
echo " kubectl get servicemonitor"
echo " kubectl get pods"
echo " kubectl get services"
echo " kubectl get ingress"
echo " kubectl get hpa"
echo " kubectl get servicemonitor"

View File

@@ -1 +1 @@
v2.0.15
v2.0.10

View File

@@ -1,170 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
# release-goreleaser.sh
# Копирует deploy/.goreleaser.yaml в корень, запускает релиз и удаляет файл.
#
# Использование:
# deploy/release-goreleaser.sh # обычный релиз на GitHub (нужен GITHUB_TOKEN)
# deploy/release-goreleaser.sh --snapshot # локальный снепшот без публикации
ROOT_DIR="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
SRC_CFG="$ROOT_DIR/deploy/.goreleaser.yaml"
DST_CFG="$ROOT_DIR/.goreleaser.yaml"
log() { echo -e "\033[36m[release]\033[0m $*"; }
err() { echo -e "\033[31m[error]\033[0m $*" >&2; }
if ! command -v goreleaser >/dev/null 2>&1; then
err "goreleaser не найден. Установите: https://goreleaser.com/install/"
exit 1
fi
if [[ ! -f "$SRC_CFG" ]]; then
err "Не найден файл конфигурации: $SRC_CFG"
exit 1
fi
MODE="release"
if [[ "${1:-}" == "--snapshot" ]]; then
MODE="snapshot"
shift || true
fi
if [[ -f "$DST_CFG" ]]; then
err "В корне уже существует .goreleaser.yaml. Удалите/переименуйте перед запуском."
exit 1
fi
cleanup() {
if [[ -f "$DST_CFG" ]]; then
rm -f "$DST_CFG" || true
log "Удалил временный $DST_CFG"
fi
}
trap cleanup EXIT
log "Копирую конфиг: $SRC_CFG -> $DST_CFG"
cp "$SRC_CFG" "$DST_CFG"
pushd "$ROOT_DIR" >/dev/null
EXTRA_FLAGS=()
PREV_HEAD="$(git rev-parse HEAD 2>/dev/null || echo "")"
git add .
git commit --amend --no-edit || true
## Версию берём из deploy/VERSION.txt или VERSION.txt в корне
VERSION_FILE="$ROOT_DIR/deploy/VERSION.txt"
[[ -f "$VERSION_FILE" ]] || VERSION_FILE="$ROOT_DIR/VERSION.txt"
if [[ -f "$VERSION_FILE" ]]; then
VERSION_RAW="$(head -n1 "$VERSION_FILE" | tr -d ' \t\r\n')"
if [[ -n "$VERSION_RAW" ]]; then
TAG="$VERSION_RAW"
[[ "$TAG" == v* ]] || TAG="v$TAG"
export GORELEASER_CURRENT_TAG="$TAG"
log "Версия релиза: $TAG (из $(realpath --relative-to="$ROOT_DIR" "$VERSION_FILE" 2>/dev/null || echo "$VERSION_FILE"))"
fi
fi
create_and_push_tag() {
local tag="$1"
if git rev-parse "$tag" >/dev/null 2>&1; then
log "Git tag уже существует: $tag"
else
log "Создаю git tag: $tag"
git tag -a "$tag" -m "Release $tag"
if [[ "${NO_GIT_PUSH:-false}" != "true" ]]; then
log "Пушу тег $tag на origin"
git push origin "$tag"
else
log "Пропущен пуш тега (NO_GIT_PUSH=true)"
fi
fi
}
move_tag_to_head() {
local tag="$1"
if [[ -z "$tag" ]]; then
return 0
fi
if git rev-parse "$tag" >/dev/null 2>&1; then
log "Переношу тег $tag на текущий коммит (HEAD)"
git tag -f "$tag" HEAD
if [[ "${NO_GIT_PUSH:-false}" != "true" ]]; then
log "Форс‑пуш тега $tag на origin"
git push -f origin "$tag"
else
log "Пропущен пуш тега (NO_GIT_PUSH=true)"
fi
else
log "Тега $tag нет — пропускаю перенос"
fi
}
fetch_token_from_k8s() {
export KUBECONFIG=/home/su/.kube/config_hlab
local ns="${K8S_NAMESPACE:-flux-system}"
local name="${K8S_SECRET_NAME:-git-secrets}"
# Предпочитаем jq (как в примере), при отсутствии используем jsonpath + base64 -d
if command -v jq >/dev/null 2>&1; then
kubectl get secret "$name" -n "$ns" -o json \
| jq -r '.data.password | @base64d'
else
kubectl get secret "$name" -n "$ns" -o jsonpath='{.data.password}' \
| base64 -d 2>/dev/null || true
fi
}
if [[ "$MODE" == "snapshot" ]]; then
log "Запуск goreleaser (snapshot, без публикации)"
goreleaser release --snapshot --clean --config "$DST_CFG" "${EXTRA_FLAGS[@]}"
else
# Если версия определена и тега нет — создадим (goreleaser ориентируется на теги)
if [[ -n "${GORELEASER_CURRENT_TAG:-}" ]]; then
create_and_push_tag "$GORELEASER_CURRENT_TAG"
# Перемещаем тег на текущий HEAD (если существовал ранее, закрепим на последнем коммите)
move_tag_to_head "$GORELEASER_CURRENT_TAG"
else
# Если версия не задана, попробуем взять последний существующий тег и перенести его на HEAD
LAST_TAG="$(git describe --tags --abbrev=0 2>/dev/null || true)"
if [[ -n "$LAST_TAG" ]]; then
move_tag_to_head "$LAST_TAG"
export GORELEASER_CURRENT_TAG="$LAST_TAG"
log "Использую последний тег: $LAST_TAG"
fi
fi
if [[ -z "${GITHUB_TOKEN:-}" ]]; then
log "GITHUB_TOKEN не задан — пробую получить из k8s секрета (${K8S_NAMESPACE:-flux-system}/${K8S_SECRET_NAME:-git-secrets}, ключ: password)"
if ! command -v kubectl >/dev/null 2>&1; then
err "kubectl не найден, а GITHUB_TOKEN не задан. Установите kubectl или экспортируйте GITHUB_TOKEN."
exit 1
fi
TOKEN_FROM_K8S="$(fetch_token_from_k8s || true)"
if [[ -n "$TOKEN_FROM_K8S" && "$TOKEN_FROM_K8S" != "null" ]]; then
export GITHUB_TOKEN="$TOKEN_FROM_K8S"
log "GITHUB_TOKEN получен из секрета Kubernetes."
else
err "Не удалось получить GITHUB_TOKEN из секрета Kubernetes. Экспортируйте GITHUB_TOKEN и повторите."
exit 1
fi
fi
log "Запуск goreleaser (публикация на GitHub)"
goreleaser release --clean --config "$DST_CFG" "${EXTRA_FLAGS[@]}"
fi
popd >/dev/null
# Откатываем временный коммит, если он был
if [[ "${TEMP_COMMIT_DONE:-false}" == "true" && -n "$PREV_HEAD" ]]; then
if git reset --soft "$PREV_HEAD" >/dev/null 2>&1; then
log "Откатил временный коммит"
else
log "Не удалось откатить временный коммит — проверьте историю вручную"
fi
fi
log "Готово."

View File

@@ -69,8 +69,8 @@ lcg co -f
"host": "localhost"
},
"validation": {
"max_system_prompt_length": 2000,
"max_user_message_length": 4000,
"max_system_prompt_length": 1000,
"max_user_message_length": 2000,
"max_prompt_name_length": 2000,
"max_prompt_desc_length": 5000,
"max_command_length": 8000,
@@ -116,12 +116,12 @@ lcg co -f
### Настройки валидации (validation)
- **max_system_prompt_length** - максимальная длина системного промпта (по умолчанию: 2000)
- **max_user_message_length** - максимальная длина пользовательского сообщения (по умолчанию: 4000)
- **max_prompt_name_length** - максимальная длина названия промпта (по умолчанию: 2000)
- **max_prompt_desc_length** - максимальная длина описания промпта (по умолчанию: 5000)
- **max_command_length** - максимальная длина команды/ответа (по умолчанию: 8000)
- **max_explanation_length** - максимальная длина объяснения (по умолчанию: 20000)
- **max_system_prompt_length** - максимальная длина системного промпта
- **max_user_message_length** - максимальная длина пользовательского сообщения
- **max_prompt_name_length** - максимальная длина названия промпта
- **max_prompt_desc_length** - максимальная длина описания промпта
- **max_command_length** - максимальная длина команды/ответа
- **max_explanation_length** - максимальная длина объяснения
## 🔒 Безопасность

View File

@@ -35,17 +35,10 @@ Explanations:
Clipboard support requires `xclip` or `xsel`.
## What's new in 2.0.14
## What's new in 2.0.1
- Authentication: JWT-based authentication with HTTP-only cookies
- CSRF protection: Full CSRF protection with tokens and middleware
- Security: Enhanced security with token validation and sessions
- Kubernetes deployment: Full set of manifests for Kubernetes deployment with Traefik
- Reverse Proxy: Support for working behind reverse proxy with cookie configuration
- Web interface: Improved web interface with modern design
- Monitoring: Prometheus metrics and ServiceMonitor
- Scaling: HPA for automatic scaling
- Testing: CSRF protection testing tools
- Mobile UI improvements: better responsiveness (buttons, fonts, spacing) and reduced motion support
- Public REST endpoint: `POST /execute` (curl-only) for programmatic access — see `API_GUIDE.md`
## Environment
@@ -140,15 +133,10 @@ The `serve` command provides both a web interface and REST API:
**Web Interface:**
- Browse results at `http://localhost:8080/` (or `http://localhost:8080<BASE_PATH>/` if `LCG_BASE_URL` set)
- Execute requests at `.../run`
- Manage prompts at `.../prompts`
- View history at `.../history`
Notes:
- Base path: set `LCG_BASE_URL` (e.g. `/lcg`) to prefix all routes and API.
- Custom 404: unknown paths under base path render a modern 404 page.
- Debug: enable via flag `--debug` or env `LCG_DEBUG=1|true`.
- Browse results at `http://localhost:8080/`
- Execute requests at `http://localhost:8080/run`
- Manage prompts at `http://localhost:8080/prompts`
- View history at `http://localhost:8080/history`
**REST API:**

View File

@@ -22,7 +22,7 @@ sudo apt-get install xsel
```bash
git clone --depth 1 https://github.com/Direct-Dev-Ru/linux-command-gpt.git ~/.linux-command-gpt
git clone --depth 1 https://github.com/Direct-Dev-Ru/go-lcg.git ~/.linux-command-gpt
cd ~/.linux-command-gpt
go build -o lcg
@@ -60,7 +60,7 @@ lcg --file /path/to/context.txt "хочу вывести список дирек
Действия: (c)копировать, (s)сохранить, (r)перегенерировать, (e)выполнить, (v|vv|vvv)подробно, (n)ничего:
```
### Что нового в 2.0.14
### Что нового в 3.0.0
- **Аутентификация**: Добавлена система аутентификации с JWT токенами и HTTP-only cookies
- **CSRF защита**: Полная защита от CSRF атак с токенами и middleware

View File

@@ -8,26 +8,26 @@
| Переменная | Описание | По умолчанию |
|------------|----------|--------------|
| `LCG_MAX_SYSTEM_PROMPT_LENGTH` | Максимальная длина системного промпта | 2000 |
| `LCG_MAX_USER_MESSAGE_LENGTH` | Максимальная длина пользовательского сообщения | 4000 |
| `LCG_MAX_PROMPT_NAME_LENGTH` | Максимальная длина названия промпта | 2000 |
| `LCG_MAX_PROMPT_DESC_LENGTH` | Максимальная длина описания промпта | 5000 |
| `LCG_MAX_COMMAND_LENGTH` | Максимальная длина команды/ответа | 8000 |
| `LCG_MAX_EXPLANATION_LENGTH` | Максимальная длина объяснения | 20000 |
| `LCG_MAX_SYSTEM_PROMPT_LENGTH` | Максимальная длина системного промпта | 1000 |
| `LCG_MAX_USER_MESSAGE_LENGTH` | Максимальная длина пользовательского сообщения | 2000 |
| `LCG_MAX_PROMPT_NAME_LENGTH` | Максимальная длина названия промпта | 200 |
| `LCG_MAX_PROMPT_DESC_LENGTH` | Максимальная длина описания промпта | 500 |
| `LCG_MAX_COMMAND_LENGTH` | Максимальная длина команды/ответа | 2000 |
| `LCG_MAX_EXPLANATION_LENGTH` | Максимальная длина объяснения | 2000 |
## 🚀 Примеры использования
### Установка через переменные окружения
```bash
# Увеличить лимит системного промпта до 3к символов
export LCG_MAX_SYSTEM_PROMPT_LENGTH=3000
# Увеличить лимит системного промпта до 2к символов
export LCG_MAX_SYSTEM_PROMPT_LENGTH=2000
# Уменьшить лимит пользовательского сообщения до 2к символов
export LCG_MAX_USER_MESSAGE_LENGTH=2000
# Уменьшить лимит пользовательского сообщения до 1к символов
export LCG_MAX_USER_MESSAGE_LENGTH=1000
# Увеличить лимит названия промпта до 3000 символов
export LCG_MAX_PROMPT_NAME_LENGTH=3000
# Увеличить лимит названия промпта до 500 символов
export LCG_MAX_PROMPT_NAME_LENGTH=500
```
### Установка в .env файле
@@ -35,11 +35,11 @@ export LCG_MAX_PROMPT_NAME_LENGTH=3000
```bash
# .env файл
LCG_MAX_SYSTEM_PROMPT_LENGTH=2000
LCG_MAX_USER_MESSAGE_LENGTH=4000
LCG_MAX_PROMPT_NAME_LENGTH=2000
LCG_MAX_PROMPT_DESC_LENGTH=5000
LCG_MAX_COMMAND_LENGTH=8000
LCG_MAX_EXPLANATION_LENGTH=20000
LCG_MAX_USER_MESSAGE_LENGTH=1500
LCG_MAX_PROMPT_NAME_LENGTH=300
LCG_MAX_PROMPT_DESC_LENGTH=1000
LCG_MAX_COMMAND_LENGTH=3000
LCG_MAX_EXPLANATION_LENGTH=5000
```
### Установка в systemd сервисе
@@ -55,8 +55,8 @@ User=lcg
WorkingDirectory=/opt/lcg
ExecStart=/opt/lcg/lcg serve
Environment=LCG_MAX_SYSTEM_PROMPT_LENGTH=2000
Environment=LCG_MAX_USER_MESSAGE_LENGTH=4000
Environment=LCG_MAX_PROMPT_NAME_LENGTH=2000
Environment=LCG_MAX_USER_MESSAGE_LENGTH=1500
Environment=LCG_MAX_PROMPT_NAME_LENGTH=300
Restart=always
[Install]
@@ -72,7 +72,7 @@ FROM golang:1.21-alpine AS builder
FROM alpine:latest
COPY --from=builder /app/lcg /usr/local/bin/
ENV LCG_MAX_SYSTEM_PROMPT_LENGTH=2000
ENV LCG_MAX_USER_MESSAGE_LENGTH=4000
ENV LCG_MAX_USER_MESSAGE_LENGTH=1500
CMD ["lcg", "serve"]
```
@@ -84,8 +84,8 @@ services:
image: lcg:latest
environment:
- LCG_MAX_SYSTEM_PROMPT_LENGTH=2000
- LCG_MAX_USER_MESSAGE_LENGTH=4000
- LCG_MAX_PROMPT_NAME_LENGTH=2000
- LCG_MAX_USER_MESSAGE_LENGTH=1500
- LCG_MAX_PROMPT_NAME_LENGTH=300
ports:
- "8080:8080"
```
@@ -153,9 +153,9 @@ validation.FormatLengthInfo(systemPrompt, userMessage)
## 📝 Примеры сообщений об ошибках
```
❌ Ошибка: system_prompt: системный промпт слишком длинный: 2500 символов (максимум 2000)
❌ Ошибка: user_message: пользовательское сообщение слишком длинное: 4500 символов (максимум 4000)
❌ Ошибка: prompt_name: название промпта слишком длинное: 2500 символов (максимум 2000)
❌ Ошибка: system_prompt: системный промпт слишком длинный: 1500 символов (максимум 1000)
❌ Ошибка: user_message: пользовательское сообщение слишком длинное: 2500 символов (максимум 2000)
❌ Ошибка: prompt_name: название промпта слишком длинное: 300 символов (максимум 200)
```
## 🔄 Миграция с жестко заданных значений
@@ -179,25 +179,25 @@ if err := validation.ValidateSystemPrompt(prompt); err != nil {
### Для разработки
```bash
export LCG_MAX_SYSTEM_PROMPT_LENGTH=2000
export LCG_MAX_USER_MESSAGE_LENGTH=4000
export LCG_MAX_PROMPT_NAME_LENGTH=2000
export LCG_MAX_PROMPT_DESC_LENGTH=5000
export LCG_MAX_USER_MESSAGE_LENGTH=2000
export LCG_MAX_PROMPT_NAME_LENGTH=200
export LCG_MAX_PROMPT_DESC_LENGTH=500
```
### Для продакшена
```bash
export LCG_MAX_SYSTEM_PROMPT_LENGTH=2000
export LCG_MAX_USER_MESSAGE_LENGTH=4000
export LCG_MAX_PROMPT_NAME_LENGTH=2000
export LCG_MAX_PROMPT_DESC_LENGTH=5000
export LCG_MAX_SYSTEM_PROMPT_LENGTH=1000
export LCG_MAX_USER_MESSAGE_LENGTH=1500
export LCG_MAX_PROMPT_NAME_LENGTH=100
export LCG_MAX_PROMPT_DESC_LENGTH=300
```
### Для высоконагруженных систем
```bash
export LCG_MAX_SYSTEM_PROMPT_LENGTH=1000
export LCG_MAX_USER_MESSAGE_LENGTH=2000
export LCG_MAX_PROMPT_NAME_LENGTH=1000
export LCG_MAX_PROMPT_DESC_LENGTH=2500
export LCG_MAX_SYSTEM_PROMPT_LENGTH=500
export LCG_MAX_USER_MESSAGE_LENGTH=1000
export LCG_MAX_PROMPT_NAME_LENGTH=50
export LCG_MAX_PROMPT_DESC_LENGTH=200
```
---

View File

@@ -5,7 +5,7 @@ metadata:
namespace: lcg
data:
# Основные настройки
LCG_VERSION: "v2.0.14"
LCG_VERSION: "v2.0.10"
LCG_BASE_PATH: "/lcg"
LCG_SERVER_HOST: "0.0.0.0"
LCG_SERVER_PORT: "8080"

View File

@@ -5,7 +5,7 @@ metadata:
namespace: lcg
labels:
app: lcg
version: v2.0.14
version: v2.0.10
spec:
replicas: 1
selector:
@@ -18,7 +18,7 @@ spec:
spec:
containers:
- name: lcg
image: kuznetcovay/lcg:v2.0.14
image: kuznetcovay/lcg:v2.0.10
imagePullPolicy: Always
ports:
- containerPort: 8080

View File

@@ -15,11 +15,11 @@ resources:
# Common labels
# commonLabels:
# app: lcg
# version: v2.0.14
# version: v2.0.10
# managed-by: kustomize
# Images
# images:
# - name: lcg
# newName: kuznetcovay/lcg
# newTag: v2.0.14
# newTag: v2.0.10

60
main.go
View File

@@ -60,7 +60,7 @@ func main() {
CompileConditions.NoServe = false
}
// fmt.Println("Build conditions:", CompileConditions)
fmt.Println("Build conditions:", CompileConditions)
_ = colorBlue
@@ -87,56 +87,12 @@ lcg [опции] <описание команды>
{{.AppName}} - инструмент для генерации Linux команд из описаний на естественном языке.
Поддерживает чтение частей промпта из файлов и позволяет сохранять, копировать или перегенерировать результаты.
может задавать системный промпт или выбирать из предустановленных промптов.
Переменные окружения:
Основные настройки:
LCG_HOST Endpoint для LLM API (по умолчанию: http://192.168.87.108:11434/)
LCG_MODEL Название модели (по умолчанию: hf.co/yandex/YandexGPT-5-Lite-8B-instruct-GGUF:Q4_K_M)
LCG_PROMPT Текст промпта по умолчанию
LCG_PROVIDER Тип провайдера: "ollama" или "proxy" (по умолчанию: ollama)
LCG_JWT_TOKEN JWT токен для proxy провайдера
LCG_PROMPT_ID ID промпта по умолчанию (по умолчанию: 1)
LCG_TIMEOUT Таймаут запроса в секундах (по умолчанию: 300)
LCG_COMPLETIONS_PATH Путь к API для завершений (по умолчанию: api/chat)
LCG_PROXY_URL URL прокси для proxy провайдера (по умолчанию: /api/v1/protected/sberchat/chat)
LCG_API_KEY_FILE Файл с API ключом (по умолчанию: .openai_api_key)
LCG_APP_NAME Название приложения (по умолчанию: Linux Command GPT)
Настройки истории и выполнения:
LCG_NO_HISTORY Отключить запись истории ("1" или "true" = отключено, пусто = включено)
LCG_ALLOW_EXECUTION Разрешить выполнение команд ("1" или "true" = разрешено, пусто = запрещено)
LCG_RESULT_FOLDER Папка для сохранения результатов (по умолчанию: ~/.config/lcg/gpt_results)
LCG_RESULT_HISTORY Файл истории результатов (по умолчанию: <result_folder>/lcg_history.json)
LCG_PROMPT_FOLDER Папка для системных промптов (по умолчанию: ~/.config/lcg/gpt_sys_prompts)
LCG_CONFIG_FOLDER Папка для конфигурации (по умолчанию: ~/.config/lcg/config)
Настройки сервера (команда serve):
LCG_SERVER_PORT Порт сервера (по умолчанию: 8080)
LCG_SERVER_HOST Хост сервера (по умолчанию: localhost)
LCG_SERVER_ALLOW_HTTP Разрешить HTTP соединения ("true" для localhost, "false" для других хостов)
LCG_SERVER_REQUIRE_AUTH Требовать аутентификацию ("1" или "true" = требуется, пусто = не требуется)
LCG_SERVER_PASSWORD Пароль администратора (по умолчанию: admin#123456)
LCG_SERVER_SSL_CERT_FILE Путь к SSL сертификату
LCG_SERVER_SSL_KEY_FILE Путь к приватному ключу SSL
LCG_DOMAIN Домен для сервера (по умолчанию: значение LCG_SERVER_HOST)
LCG_COOKIE_SECURE Безопасные cookie ("1" или "true" = включено, пусто = выключено)
LCG_COOKIE_PATH Путь для cookie (по умолчанию: /lcg)
LCG_COOKIE_TTL_HOURS Время жизни cookie в часах (по умолчанию: 168)
LCG_BASE_URL Базовый URL приложения (по умолчанию: /lcg)
LCG_HEALTH_URL URL для проверки здоровья API (по умолчанию: /api/v1/protected/sberchat/health)
Настройки валидации:
LCG_MAX_SYSTEM_PROMPT_LENGTH Максимальная длина системного промпта (по умолчанию: 2000)
LCG_MAX_USER_MESSAGE_LENGTH Максимальная длина пользовательского сообщения (по умолчанию: 4000)
LCG_MAX_PROMPT_NAME_LENGTH Максимальная длина названия промпта (по умолчанию: 2000)
LCG_MAX_PROMPT_DESC_LENGTH Максимальная длина описания промпта (по умолчанию: 5000)
LCG_MAX_COMMAND_LENGTH Максимальная длина команды (по умолчанию: 8000)
LCG_MAX_EXPLANATION_LENGTH Максимальная длина объяснения (по умолчанию: 20000)
Отладка и браузер:
LCG_DEBUG Включить режим отладки ("1" или "true" = включено, пусто = выключено)
LCG_BROWSER_PATH Путь к браузеру для автоматического открытия (команда serve --browser)
LCG_HOST Endpoint для LLM API (по умолчанию: http://192.168.87.108:11434/)
LCG_MODEL Название модели (по умолчанию: codegeex4)
LCG_PROMPT Текст промпта по умолчанию
LCG_PROVIDER Тип провайдера: "ollama" или "proxy" (по умолчанию: ollama)
LCG_JWT_TOKEN JWT токен для proxy провайдера
`,
Flags: []cli.Flag{
&cli.StringFlag{
@@ -203,8 +159,8 @@ lcg [опции] <описание команды>
config.AppConfig.MainFlags.Debug = config.AppConfig.MainFlags.Debug || config.GetEnvBool("LCG_DEBUG", false)
// fmt.Println("Debug:", config.AppConfig.MainFlags.Debug)
// fmt.Println("LCG_DEBUG:", config.GetEnvBool("LCG_DEBUG", false))
fmt.Println("Debug:", config.AppConfig.MainFlags.Debug)
fmt.Println("LCG_DEBUG:", config.GetEnvBool("LCG_DEBUG", false))
args := c.Args().Slice()

View File

@@ -39,12 +39,11 @@ func generateAbbreviation(appName string) string {
// FileInfo содержит информацию о файле
type FileInfo struct {
Name string
DisplayName string
Size string
ModTime string
Preview template.HTML
Content string // Полное содержимое для поиска
Name string
Size string
ModTime string
Preview template.HTML
Content string // Полное содержимое для поиска
}
// handleResultsPage обрабатывает главную страницу со списком файлов
@@ -134,12 +133,11 @@ func getResultFiles() ([]FileInfo, error) {
}
files = append(files, FileInfo{
Name: entry.Name(),
DisplayName: formatFileDisplayName(entry.Name()),
Size: formatFileSize(info.Size()),
ModTime: info.ModTime().Format("02.01.2006 15:04"),
Preview: template.HTML(preview),
Content: fullContent,
Name: entry.Name(),
Size: formatFileSize(info.Size()),
ModTime: info.ModTime().Format("02.01.2006 15:04"),
Preview: template.HTML(preview),
Content: fullContent,
})
}
@@ -169,65 +167,6 @@ func formatFileSize(size int64) string {
return fmt.Sprintf("%.1f %cB", float64(size)/float64(div), "KMGTPE"[exp])
}
// formatFileDisplayName преобразует имя файла вида
// gpt_request_GigaChat-2-Max_2025-10-22_13-50-13.md
// в "Gpt Request GigaChat 2 Max — 2025-10-22 13:50:13"
func formatFileDisplayName(filename string) string {
name := strings.TrimSuffix(filename, ".md")
// Разделим на части по '_'
parts := strings.Split(name, "_")
if len(parts) == 0 {
return filename
}
// Первая часть может быть префиксом gpt/request — заменим '_' на пробел и приведем регистр
var words []string
for _, p := range parts {
if p == "" {
continue
}
// Заменяем '-' на пробел в словах модели/текста
p = strings.ReplaceAll(p, "-", " ")
// Разбиваем по пробелам и капитализуем каждое слово
for _, w := range strings.Fields(p) {
if w == "" {
continue
}
r := []rune(w)
r[0] = unicode.ToUpper(r[0])
words = append(words, string(r))
}
}
// Попробуем распознать хвост как дату и время
// Ищем шаблон YYYY-MM-DD_HH-MM-SS в исходном имени
var pretty string
// ожидаем последние две части — дата и время
if len(parts) >= 3 {
datePart := parts[len(parts)-2]
timePart := parts[len(parts)-1]
// заменить '-' в времени на ':'
timePretty := strings.ReplaceAll(timePart, "-", ":")
if len(datePart) == 10 && len(timePart) == 8 { // примитивная проверка
// Собираем текст до датных частей
text := strings.Join(words[:len(words)-2], " ")
pretty = strings.TrimSpace(text)
if pretty != "" {
pretty += " — " + datePart + " " + timePretty
} else {
pretty = datePart + " " + timePretty
}
return pretty
}
}
if len(words) > 0 {
pretty = strings.Join(words, " ")
return pretty
}
return filename
}
// handleFileView обрабатывает просмотр конкретного файла
func handleFileView(w http.ResponseWriter, r *http.Request) {
// Учитываем BasePath при извлечении имени файла

View File

@@ -232,11 +232,11 @@ func registerRoutesExceptHome() {
http.HandleFunc(makePath("/api/add-to-history"), AuthMiddleware(CSRFMiddleware(handleAddToHistory)))
// Catch-all 404 для любых незарегистрированных путей (только когда BasePath задан)
// if getBasePath() != "" {
// http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
// renderNotFound(w, "Страница не найдена", getBasePath())
// })
// }
if getBasePath() != "" {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
renderNotFound(w, "Страница не найдена", getBasePath())
})
}
}
// registerRoutes регистрирует все маршруты сервера

View File

@@ -111,26 +111,19 @@ const HistoryPageTemplate = `
font-size: 0.9em;
color: #2d5016;
border-left: 3px solid #2d5016;
max-height: 72px; /* ~4 строки */
overflow: hidden;
display: -webkit-box;
-webkit-line-clamp: 4;
-webkit-box-orient: vertical;
}
.delete-btn {
background: transparent;
color: #ef9a9a; /* бледно-красный */
background: #e74c3c;
color: white;
border: none;
padding: 2px 6px;
padding: 6px 12px;
border-radius: 4px;
cursor: pointer;
font-size: 18px;
line-height: 1;
transition: color 0.2s ease, transform 0.2s ease;
font-size: 0.8em;
transition: background 0.3s ease;
}
.delete-btn:hover {
color: rgb(171, 27, 24); /* ярче при ховере */
transform: translateY(-1px);
background: #c0392b;
}
.empty-state {
text-align: center;
@@ -187,7 +180,7 @@ const HistoryPageTemplate = `
<span class="history-index">#{{.Index}}</span>
<span class="history-timestamp">{{.Timestamp}}</span>
</div>
<button class="delete-btn" onclick="event.stopPropagation(); deleteHistoryEntry({{.Index}})"></button>
<button class="delete-btn" onclick="event.stopPropagation(); deleteHistoryEntry({{.Index}})">🗑️ Удалить</button>
</div>
<div class="history-command">{{.Command}}</div>
<div class="history-response">{{.Response}}</div>

View File

@@ -53,16 +53,6 @@ const NotFoundTemplate = `
backdrop-filter: blur(10px);
text-align: center;
}
@keyframes pulse {
0%, 100% {
transform: scale(1);
text-shadow: 0 8px 40px var(--accentGlow);
}
50% {
transform: scale(1.15);
text-shadow: 0 12px 60px var(--accentGlow), 0 0 30px var(--accentGlow2);
}
}
.code {
font-size: clamp(48px, 12vw, 120px);
line-height: 0.9;
@@ -74,8 +64,6 @@ const NotFoundTemplate = `
color: transparent;
margin: 8px 0 12px 0;
text-shadow: 0 8px 40px var(--accentGlow);
animation: pulse 2.5s ease-in-out infinite;
transform-origin: center;
}
.title {
font-size: clamp(18px, 3.2vw, 28px);
@@ -145,7 +133,7 @@ const NotFoundTemplate = `
<div class="card">
<div class="code">404</div>
<div class="title">Страница не найдена</div>
<p class="desc">Такой страницы не существует. Вы можете вернуться на главную страницу или выполнить команду.</p>
<p class="desc">{{.Message}}</p>
<div class="btns">
<a class="btn" href="{{.BasePath}}/">🏠 На главную</a>
<a class="btn secondary" href="{{.BasePath}}/run">🚀 К выполнению</a>
@@ -155,3 +143,5 @@ const NotFoundTemplate = `
</body>
</html>
`

View File

@@ -73,10 +73,8 @@ const ResultsPageTemplate = `
}
.files-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 20px;
align-items: stretch;
grid-auto-rows: auto;
}
.file-card {
background: white;
@@ -93,36 +91,32 @@ const ResultsPageTemplate = `
}
.file-card-content {
cursor: pointer;
padding-left: 28px;
}
.file-actions {
position: absolute;
top: 10px;
left: 10px;
right: 10px;
display: flex;
gap: 8px;
}
.delete-btn {
background: transparent;
color: #ef9a9a; /* бледно-красный */
background: #e74c3c;
color: white;
border: none;
padding: 4px 8px;
padding: 6px 12px;
border-radius: 4px;
cursor: pointer;
font-size: 18px;
line-height: 1;
transition: color 0.2s ease, transform 0.2s ease;
font-size: 0.8em;
transition: background 0.3s ease;
}
.delete-btn:hover {
color:rgb(171, 27, 24); /* чуть ярче при ховере */
transform: translateY(-1px);
background: #c0392b;
}
.file-name {
font-weight: 600;
color: #333;
margin-bottom: 8px;
font-size: 1.1em;
padding-right: 10px;
}
.file-info {
color: #666;
@@ -171,25 +165,16 @@ const ResultsPageTemplate = `
body { padding: 10px; }
.container { margin: 0; border-radius: 8px; box-shadow: 0 10px 20px rgba(0,0,0,0.1); }
.header { padding: 20px; }
.header h1 { font-size: 1.9em; }
.header h1 { font-size: 2em; }
.content { padding: 20px; }
.files-grid { dummy-attr: none; }
/* Стили карточек как в истории */
.file-card { background: #f0f8f0; border: 1px solid #a8e6cf; padding: 15px; }
.file-card:hover { border-color: #2d5016; box-shadow: 0 8px 25px rgba(45,80,22,0.2); transform: translateY(-2px); }
.file-name { color: #333; margin-bottom: 8px; }
.file-info { color: #666; font-size: 0.9em; }
.file-preview { background: #f8f9fa; border-left: 3px solid #2d5016; font-size: 0.85em; }
.file-actions { top: 8px; left: 8px; }
.delete-btn { padding: 2px 6px; font-size: 16px; }
.files-grid { grid-template-columns: 1fr; }
.stats { grid-template-columns: 1fr 1fr; }
.nav-buttons { flex-direction: column; gap: 8px; }
.nav-btn, .nav-button { text-align: center; padding: 12px 16px; font-size: 14px; }
.search-container input { font-size: 16px; width: 96% !important; }
}
@media (max-width: 480px) {
.header h1 { font-size: 1.6em; }
.content { padding: 16px; }
.header h1 { font-size: 1.8em; }
.stats { grid-template-columns: 1fr; }
}
</style>
@@ -231,10 +216,10 @@ const ResultsPageTemplate = `
{{range .Files}}
<div class="file-card" data-content="{{.Content}}">
<div class="file-actions">
<button class="delete-btn" onclick="deleteFile('{{.Name}}')" title="Удалить файл"></button>
<button class="delete-btn" onclick="deleteFile('{{.Name}}')" title="Удалить файл">🗑️</button>
</div>
<div class="file-card-content" onclick="window.location.href='{{$.BasePath}}/file/{{.Name}}'">
<div class="file-name">{{.DisplayName}}</div>
<div class="file-name">{{.Name}}</div>
<div class="file-info">
📅 {{.ModTime}} | 📏 {{.Size}}
</div>