This commit is contained in:
m
2026-07-12 10:51:09 +02:00
parent 874d8679ac
commit f303ac8b5c
5 changed files with 188 additions and 0 deletions
+25
View File
@@ -0,0 +1,25 @@
FROM golang:1.24-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o /bin/server ./cmd/server
FROM alpine:3.21
RUN apk add --no-cache ca-certificates curl
WORKDIR /app
COPY --from=builder /bin/server .
COPY internal/db/migrations ./internal/db/migrations
RUN mkdir -p /app/uploads /data
EXPOSE 8080
CMD ["./server"]
+12
View File
@@ -13,6 +13,7 @@ import (
"github.com/gin-gonic/gin"
"github.com/vaultdrop/backend/internal/db"
"github.com/vaultdrop/backend/internal/ocr"
"github.com/vaultdrop/backend/internal/service"
)
@@ -191,6 +192,8 @@ func (h *Handlers) UploadFiles(c *gin.Context) {
Id string `json:"id"`
}
client := ocr.NewClient("http://localhost:9090")
filesStats := []FileStats{}
for _, file := range files {
@@ -260,6 +263,15 @@ func (h *Handlers) UploadFiles(c *gin.Context) {
Id: dbFile.ID,
})
text, err := client.Recognize(fileByte)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(text)
}
c.JSON(http.StatusOK, gin.H{
+91
View File
@@ -0,0 +1,91 @@
package ocr
import (
"bytes"
"encoding/base64"
"encoding/json"
"fmt"
"io"
"net/http"
"time"
)
type Client struct {
endpoint string
httpClient *http.Client
}
func NewClient(endpoint string) *Client {
return &Client{
endpoint: endpoint,
httpClient: &http.Client{
Timeout: 120 * time.Second,
},
}
}
func (c *Client) Recognize(imageData []byte) ([]TextBlock, error) {
b64 := base64.StdEncoding.EncodeToString(imageData)
reqBody, err := json.Marshal(OCRRequest{Image: b64})
if err != nil {
return nil, fmt.Errorf("marshal request: %w", err)
}
resp, err := c.httpClient.Post(
c.endpoint+"/ocr",
"application/json",
bytes.NewReader(reqBody),
)
if err != nil {
return nil, fmt.Errorf("call paddleocr: %w", err)
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("read response: %w", err)
}
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("paddleocr returned %d: %s", resp.StatusCode, string(body))
}
var ocrResp OCRResponse
if err := json.Unmarshal(body, &ocrResp); err != nil {
return nil, fmt.Errorf("decode response: %w", err)
}
if ocrResp.ErrorCode != 0 {
return nil, fmt.Errorf("paddleocr error %d: %s", ocrResp.ErrorCode, ocrResp.Message)
}
return flattenResults(ocrResp.Result), nil
}
func (c *Client) HealthCheck() error {
resp, err := c.httpClient.Get(c.endpoint + "/health")
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("health check failed: status %d", resp.StatusCode)
}
return nil
}
func flattenResults(result OCRResult) []TextBlock {
var blocks []TextBlock
for _, page := range result.OCRResults {
for i, text := range page.RecTexts {
score := 0.0
if i < len(page.RecScores) {
score = page.RecScores[i]
}
blocks = append(blocks, TextBlock{Text: text, Score: score})
}
}
return blocks
}
+27
View File
@@ -0,0 +1,27 @@
package ocr
type OCRRequest struct {
Image string `json:"image"`
}
type OCRResponse struct {
ErrorCode int `json:"errorCode"`
Result OCRResult `json:"result"`
Message string `json:"message,omitempty"`
}
type OCRResult struct {
OCRResults []OCRPageResult `json:"ocrResults"`
}
type OCRPageResult struct {
RecTexts []string `json:"rec_texts"`
RecScores []float64 `json:"rec_scores"`
RecBoxes [][]int `json:"rec_boxes"`
RecPolys [][][]int `json:"rec_polys"`
}
type TextBlock struct {
Text string `json:"text"`
Score float64 `json:"score"`
}
+33
View File
@@ -0,0 +1,33 @@
services:
paddleocr:
image: paddlecloud/paddleocr:2.6-cpu-latest
ports:
- "9090:8080"
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-sf", "http://localhost:8080/health"]
interval: 30s
timeout: 10s
retries: 5
start_period: 60s
# backend:
# build:
# context: ./backend
# dockerfile: Dockerfile
# ports:
# - "8080:8080"
# environment:
# - PORT=8080
# - DB_PATH=/data/vaultdrop.db
# - OCR_ENDPOINT=http://paddleocr:8080
# volumes:
# - backend-data:/data
# - ./backend/uploads:/app/uploads
# depends_on:
# paddleocr:
# condition: service_healthy
# restart: unless-stopped
volumes:
backend-data: