Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 18 additions & 10 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
# Настройки базы данных PostgreSQL
DB_HOST=db
DB_PORT=5432
DB_USER=ragdm_user
DB_PASSWORD=secret_postgres_password
=ragdm_db

# Настройки Go-бэкенда
APP_PORT=8080
GIN_MODE=debug # Для продакшена потом поменяем на release
DB_USER=your_user
DB_PASSWORD=your_password
DB_NAME=your_database_name
DB_HOST=your_host
DB_PORT=your_port

HTTP_PORT=8080
API_TIMEOUT=5s

LOG_LEVEL=debug
GIN_MODE=debug

DB_MAX_CONNS=20
DB_MIN_CONNS=5

TOKENIZER_PATH=/app/models/tokenizer.json
ONNX_MODEL_PATH=/app/models/model.onnx
ONNX_LIBRARY_PATH=/usr/local/lib/libonnxruntime.so
2 changes: 1 addition & 1 deletion .github/workflows/lint-go.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:

- uses: actions/setup-go@v6
with:
go-version: '1.24'
go-version-file: 'backend/go.mod'
check-latest: true

- name: Run golangci-lint
Expand Down
54 changes: 54 additions & 0 deletions Dockerfile.backend
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Stage 1: Builder (Build C-core и Go-code)
FROM golang:1.25-bookworm AS builder

# Install dependencies for building C code
RUN apt-get update && apt-get install -y cmake build-essential

# Set the working directory
WORKDIR /app

COPY backend/go.mod backend/go.sum ./backend/
RUN cd backend && go mod download

# Copy the entire source code
COPY backend/ ./backend/
COPY algorithm/ ./algorithm/

# 1. Compile the C library
RUN cmake -B /app/algorithm/build -S /app/algorithm && \
cmake --build /app/algorithm/build

#2. Build the Go binary (enable CGO)
WORKDIR /app/backend
RUN apt-get update && \
apt-get install -y ca-certificates wget tar && \
wget -qO- https://github.com/daulet/tokenizers/releases/download/v1.27.0/libtokenizers.linux-amd64.tar.gz | tar xvz -C /usr/lib/

RUN CGO_ENABLED=1 GOOS=linux go build -ldflags="-s -w" -o /app/bin/server ./cmd/server/main.go

# Stage 2: Runner
FROM debian:bookworm-slim

# Installing CA certificates
RUN apt-get update && apt-get install -y ca-certificates && rm -rf /var/lib/apt/lists/*

WORKDIR /root/

# 1. Download and copy the ONNX libraries to /usr/local/lib/
RUN apt-get update && \
apt-get install -y ca-certificates wget tar && \
wget -qO onnxruntime.tgz https://github.com/microsoft/onnxruntime/releases/download/v1.20.1/onnxruntime-linux-x64-1.20.1.tgz && \
tar -xzf onnxruntime.tgz && \
cp -Pr onnxruntime-linux-x64-1.20.1/lib/* /usr/local/lib/ && \
ldconfig && \
rm -rf onnxruntime.tgz onnxruntime-linux-x64-1.20.1

# 2. Add this right after the RUN block to guarantee the app finds the .so file
ENV LD_LIBRARY_PATH=/usr/local/lib:${LD_LIBRARY_PATH}

COPY --from=builder /app/bin/server .
COPY --from=builder /app/algorithm/build/libspaced_rep.a /usr/local/lib/

EXPOSE 8080

CMD ["./server"]
33 changes: 33 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Environment Variables
# Include variables from .env file if it exists
ifneq (,$(wildcard ./.env))
include .env
export
endif

# Default database connection string for Goose migrations
DB_DSN ?= "postgres://$(DB_USER):$(DB_PASSWORD)@localhost:$(DB_PORT)/$(DB_NAME)?sslmode=disable"

.PHONY: help db-up db-down migrate-up migrate-down

# Docker Commands
## db-up: Start only the database container
db-up:
docker compose up -d db
## db-down: Down the database container
db-down:
docker compose down db -v
## env-up: Start the entire application (DB + Backend)
env-up:
docker compose up --build -d
## env-down: Stop and remove all containers
env-down:
docker compose down

# Database Migrations (Goose)
## migrate-up: Apply all pending migrations
migrate-up:
goose -dir migrations postgres $(DB_DSN) up
## migrate-down: Rollback the last migration
migrate-down:
goose -dir migrations postgres $(DB_DSN) down
31 changes: 0 additions & 31 deletions backend/Dockerfile

This file was deleted.

7 changes: 0 additions & 7 deletions backend/cmd/main.go

This file was deleted.

111 changes: 111 additions & 0 deletions backend/cmd/server/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package main

import (
"context"
"errors"
"log"
nhttp "net/http"
"os"
"os/signal"
"syscall"
"time"

"github.com/ilindan-dev/RAGDM/backend/internal/algorithm"
"github.com/ilindan-dev/RAGDM/backend/internal/config"
"github.com/ilindan-dev/RAGDM/backend/internal/http"
"github.com/ilindan-dev/RAGDM/backend/internal/repository"
"github.com/ilindan-dev/RAGDM/backend/internal/repository/gen"
"github.com/ilindan-dev/RAGDM/backend/internal/service"
"github.com/ilindan-dev/RAGDM/backend/internal/tokenizer"
"github.com/rs/zerolog"
)

func main() {
cfg, err := config.NewConfig()
if err != nil {
log.Fatalf("error loading config: %v", err)
}

output := zerolog.ConsoleWriter{Out: os.Stdout, TimeFormat: time.RFC3339}
logger := zerolog.New(output).With().Timestamp().Logger()

if level, err := zerolog.ParseLevel(cfg.Log.Level); err == nil {
zerolog.SetGlobalLevel(level)
}

ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
defer stop()

pool, err := repository.NewPool(ctx, cfg.DB.URL, cfg.DB.MaxConns, cfg.DB.MinConns, &logger)
if err != nil {
logger.Fatal().Err(err).Msg("Database connection failed")
}
defer pool.Close()

logger.Info().Msg("Running database migrations...")
if err := repository.RunMigrations(ctx, pool); err != nil {
logger.Fatal().Err(err).Msg("Failed to run migrations")
}
logger.Info().Msg("Migrations completed successfully")

seedPath := "/app/seed_cards.sql"
if _, err := os.Stat(seedPath); err == nil {
var count int
err := pool.QueryRow(ctx, "SELECT COUNT(*) FROM card_contents").Scan(&count)
if err == nil && count == 0 {
logger.Info().Msg("Seeding database with initial cards...")
sqlBytes, err := os.ReadFile(seedPath)
if err != nil {
logger.Error().Err(err).Msg("Failed to read seed file")
} else {
_, err = pool.Exec(ctx, string(sqlBytes))
if err != nil {
logger.Error().Err(err).Msg("Failed to execute seed_cards.sql")
} else {
logger.Info().Msg("Database seeded successfully!")
}
}
} else if count > 0 {
logger.Debug().Int("count", count).Msg("Database already contains data, skipping seed.")
}
}

queries := gen.New(pool)

cardRepo := repository.NewPgCardRepository(queries, &logger)
algoEngine := algorithm.NewSM2Engine()
embeder, err := tokenizer.NewOnnxEmbedder(cfg.TokenizerPath, cfg.ONNXModelPath, cfg.ONNXLibraryPath, &logger)
if err != nil {
logger.Fatal().Err(err).Msg("Failed to create embedded tokenizer")
}

cardService := service.NewCardService(cardRepo, algoEngine, embeder, &logger)

cardHandler := http.NewHandler(cardService, &logger)

srv := &nhttp.Server{
Addr: ":" + cfg.HTTP.Port,
Handler: cardHandler.InitRoutes(cfg.GinMode),
ReadTimeout: cfg.HTTP.Timeout,
}

go func() {
logger.Info().Msgf("HTTP server listening on %s", cfg.HTTP.Port)
if err := srv.ListenAndServe(); err != nil && !errors.Is(err, nhttp.ErrServerClosed) {
logger.Fatal().Err(err).Msg("Server failed")
}
}()

<-ctx.Done()

logger.Info().Msg("Shutting down gracefully...")

shutdownCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

if err := srv.Shutdown(shutdownCtx); err != nil {
logger.Error().Err(err).Msg("Server forced to shutdown")
}

logger.Info().Msg("Server exited correctly")
}
58 changes: 57 additions & 1 deletion backend/go.mod
Original file line number Diff line number Diff line change
@@ -1,3 +1,59 @@
module github.com/ilindan-dev/RAGDM/backend

go 1.24
go 1.25.0

require (
github.com/daulet/tokenizers v1.27.0
github.com/gin-gonic/gin v1.12.0
github.com/google/uuid v1.6.0
github.com/ilyakaznacheev/cleanenv v1.5.0
github.com/jackc/pgx/v5 v5.9.1
github.com/pgvector/pgvector-go v0.3.0
github.com/pressly/goose/v3 v3.27.0
github.com/rs/zerolog v1.35.0
github.com/yalue/onnxruntime_go v1.11.0
)

require (
github.com/BurntSushi/toml v1.2.1 // indirect
github.com/bytedance/gopkg v0.1.3 // indirect
github.com/bytedance/sonic v1.15.0 // indirect
github.com/bytedance/sonic/loader v0.5.0 // indirect
github.com/cloudwego/base64x v0.1.6 // indirect
github.com/gabriel-vasile/mimetype v1.4.12 // indirect
github.com/gin-contrib/sse v1.1.0 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.30.1 // indirect
github.com/goccy/go-json v0.10.5 // indirect
github.com/goccy/go-yaml v1.19.2 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
github.com/jackc/puddle/v2 v2.2.2 // indirect
github.com/joho/godotenv v1.5.1 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mfridman/interpolate v0.0.2 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
github.com/quic-go/qpack v0.6.0 // indirect
github.com/quic-go/quic-go v0.59.0 // indirect
github.com/sethvargo/go-retry v0.3.0 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.3.1 // indirect
go.mongodb.org/mongo-driver/v2 v2.5.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/arch v0.22.0 // indirect
golang.org/x/crypto v0.48.0 // indirect
golang.org/x/net v0.51.0 // indirect
golang.org/x/sync v0.19.0 // indirect
golang.org/x/sys v0.41.0 // indirect
golang.org/x/text v0.34.0 // indirect
google.golang.org/protobuf v1.36.11 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
olympos.io/encoding/edn v0.0.0-20201019073823-d3554ca0b0a3 // indirect
)
Loading