diff --git a/aitools/Dockerfile b/aitools/Dockerfile new file mode 100644 index 0000000..c10cdec --- /dev/null +++ b/aitools/Dockerfile @@ -0,0 +1,29 @@ +# Stage 1: Build the application +FROM maven:3.9.11-eclipse-temurin-25 AS build +WORKDIR /app + +# Copy pom.xml and download dependencies +COPY pom.xml . +RUN mvn dependency:go-offline + +# Copy source code +COPY src ./src + +# Build the application +RUN mvn package -DskipTests + +# Stage 2: Create the runtime image +FROM eclipse-temurin:25-jdk +WORKDIR /app + +# Copy the built JAR file +COPY --from=build /app/target/*.jar app.jar + +# Set environment variables +ENV JAVA_OPTS="" + +# Expose the application port +EXPOSE 8080 + +# Run the application +ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar"] \ No newline at end of file diff --git a/aitools/pom.xml b/aitools/pom.xml index 2ae4f67..9e2031b 100644 --- a/aitools/pom.xml +++ b/aitools/pom.xml @@ -40,11 +40,18 @@ lombok true + org.springframework.boot spring-boot-starter-webflux-test test + + + org.springdoc + springdoc-openapi-starter-webflux-ui + 3.0.1 + diff --git a/aitools/src/main/java/ru/ldeloff/aitools/datetime/controller/TimeController.java b/aitools/src/main/java/ru/ldeloff/aitools/datetime/controller/TimeController.java index 4f56cd3..595a383 100644 --- a/aitools/src/main/java/ru/ldeloff/aitools/datetime/controller/TimeController.java +++ b/aitools/src/main/java/ru/ldeloff/aitools/datetime/controller/TimeController.java @@ -1,4 +1,40 @@ package ru.ldeloff.aitools.datetime.controller; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; +import reactor.core.publisher.Mono; +import java.time.ZoneId; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +@Slf4j +@RestController public class TimeController { + + @GetMapping("/time/moscow") + @Operation(summary = "Get current Moscow time", description = "Returns current date and time in Moscow timezone (Europe/Moscow) as ISO 8601 string. Used as a tool for LLMs to get accurate local time.") + @ApiResponses({ + @ApiResponse(responseCode = "200", description = "Current time in Moscow in format yyyy-MM-dd HH:mm:ss"), + @ApiResponse(responseCode = "500", description = "Internal server error") + }) + public Mono getMoscowTime() { + log.info("getMoscowTime"); + return Mono.fromSupplier(() -> { + LocalDateTime moscowTime = LocalDateTime.now(ZoneId.of("Europe/Moscow")); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + return new TimeResponse(moscowTime.format(formatter)); + }); + } + + public static class TimeResponse { + public final String time; + + public TimeResponse(String time) { + this.time = time; + } + } } diff --git a/aitools/src/main/resources/application.properties b/aitools/src/main/resources/application.properties index 061f835..fb3d424 100644 --- a/aitools/src/main/resources/application.properties +++ b/aitools/src/main/resources/application.properties @@ -1 +1,3 @@ spring.application.name=aitools + +springdoc.api-docs.path=/api-docs diff --git a/cmd/deploy-common.bat b/cmd/deploy-common.bat new file mode 100644 index 0000000..7f74ff4 --- /dev/null +++ b/cmd/deploy-common.bat @@ -0,0 +1,106 @@ +@echo off +setlocal enabledelayedexpansion + +set SSH_SERVER_IP=192.168.10.110 +set SSH_SERVER_USER=root +set SSH_CERT_PATH=%USERPROFILE%\.ssh\root_jarviceai +set IMAGE_NAME=aitools-amd64:latest +set ENV_FILE=.env +set COMPOSE_FILE=docker-compose.yaml +set PLATFORM=linux/amd64/v3 + + +REM === Общие настройки === +set DOCKERFILE=.\aitools\Dockerfile +set PATH=.\aitools +set IMAGE_TAR_NAME=image-aitools.tar +set IMAGE_TAR_GZ_NAME=image-aitools.tar.gz + +REM === Проверка запущен ли Docker Daemon === +echo Checking if Docker is running... +docker version >nul 2>&1 +if !errorlevel! neq 0 ( + echo ERROR: Docker is not running or not installed! + echo Please start Docker Desktop and try again. + echo. + echo If Docker is installed, ensure it's running in the system tray. + echo You may need to restart Docker Desktop. + pause + exit /b 1 +) + + +REM === Проверка наличия .env === +if not exist "%ENV_FILE%" ( + echo Error: %ENV_FILE% not found! + pause + exit /b 1 +) + + +REM === Собираем образы === +set TMP_ENV_ARGS=tmp_env_args.txt +> "%TMP_ENV_ARGS%" ( + for /f "usebackq tokens=*" %%a in ("%ENV_FILE%") do ( + echo --build-arg %%a + ) +) +set BUILD_ARGS= +for /f "usebackq tokens=*" %%a in ("%TMP_ENV_ARGS%") do ( + set BUILD_ARGS=!BUILD_ARGS! %%a +) +echo Building image locally with build args... +docker build --platform "%PLATFORM%" -f "%DOCKERFILE%" -t "%IMAGE_NAME%" --progress=plain !BUILD_ARGS! "%PATH%" + +REM === Экспорт образов в tar === +echo Creating tar archives of images... +docker save -o "%IMAGE_TAR_NAME%" "%IMAGE_NAME%" + +REM === Сжатие gzip (если доступно) === +where gzip >nul +if !errorlevel! equ 0 ( + echo Compressing images with gzip... + gzip "%IMAGE_TAR_NAME%" + set IMAGE=%IMAGE_TAR_GZ_NAME% +) else ( + echo Warning: gzip not found. Using uncompressed .tar files. + set IMAGE=%IMAGE_TAR_NAME% +) + +REM === Передача на сервер === +echo Transferring images and files to server... +scp -i "%SSH_CERT_PATH%" "%IMAGE%" "%SSH_SERVER_USER%@%SSH_SERVER_IP%:/tmp/" +if errorlevel 1 ( + echo Error: scp failed to upload %IMAGE% + pause + exit /b 1 +) + +scp -i "%SSH_CERT_PATH%" "%COMPOSE_FILE%" "%SSH_SERVER_USER%@%SSH_SERVER_IP%:/tmp/docker-compose.yaml" +if errorlevel 1 ( + echo Error: scp failed to upload %COMPOSE_FILE% + pause + exit /b 1 +) + +scp -i "%SSH_CERT_PATH%" "%ENV_FILE%" "%SSH_SERVER_USER%@%SSH_SERVER_IP%:/tmp/.env" +if errorlevel 1 ( + echo Error: scp failed to upload %ENV_FILE% + pause + exit /b 1 +) + +REM === Выполнение на сервере === +echo Creating directory on server and moving files... +ssh -i "%SSH_CERT_PATH%" "%SSH_SERVER_USER%@%SSH_SERVER_IP%" "mkdir -p /opt/aitools && mv -f /tmp/docker-compose.yaml /opt/aitools/docker-compose.yaml && mv -f /tmp/.env /opt/aitools/.env && echo 'Files moved'" + +echo Loading images on server and starting... +ssh -i "%SSH_CERT_PATH%" "%SSH_SERVER_USER%@%SSH_SERVER_IP%" "docker stop aitools 2>/dev/null || true && docker rm aitools 2>/dev/null || true && docker load < /tmp/%IMAGE% && rm /tmp/%IMAGE% && && cd /opt/aitools && docker compose up -d && echo 'Deployment completed!'" + +REM === Очистка локальных файлов === +echo Cleaning local archives... +del /q "%IMAGE_TAR_NAME%" "%TMP_ENV_ARGS%" 2>nul +del /q "%IMAGE_TAR_GZ_NAME%" 2>nul + +echo Deployment completed! +pause \ No newline at end of file diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 0000000..4dd8a26 --- /dev/null +++ b/docker-compose.yaml @@ -0,0 +1,15 @@ +version: '3.8' + +services: + backend: + container_name: aitools + image: aitools-amd64:latest + env_file: .env + restart: unless-stopped + networks: + llm_tools: + +networks: + llm_tools: + name: llm_tools + driver: bridge