mirror of
https://github.com/serty2005/rmser.git
synced 2026-02-04 19:02:33 -06:00
85 lines
2.5 KiB
Go
85 lines
2.5 KiB
Go
package ocr_client
|
||
|
||
import (
|
||
"bytes"
|
||
"context"
|
||
"encoding/json"
|
||
"fmt"
|
||
"io"
|
||
"mime/multipart"
|
||
"net/http"
|
||
"net/textproto"
|
||
"time"
|
||
)
|
||
|
||
type Client struct {
|
||
pythonServiceURL string
|
||
httpClient *http.Client
|
||
}
|
||
|
||
func NewClient(pythonServiceURL string) *Client {
|
||
return &Client{
|
||
pythonServiceURL: pythonServiceURL,
|
||
httpClient: &http.Client{
|
||
// OCR может быть долгим, ставим таймаут побольше (например, 30 сек)
|
||
Timeout: 30 * time.Second,
|
||
},
|
||
}
|
||
}
|
||
|
||
// ProcessImage отправляет изображение в Python и возвращает сырые данные
|
||
func (c *Client) ProcessImage(ctx context.Context, imageData []byte, filename string) (*RecognitionResult, error) {
|
||
// 1. Создаем буфер для multipart формы
|
||
body := &bytes.Buffer{}
|
||
writer := multipart.NewWriter(body)
|
||
|
||
// Создаем заголовок части вручную, чтобы прописать Content-Type: image/jpeg
|
||
h := make(textproto.MIMEHeader)
|
||
h.Set("Content-Disposition", fmt.Sprintf(`form-data; name="image"; filename="%s"`, filename))
|
||
h.Set("Content-Type", "image/jpeg") // Явно указываем, что это картинка
|
||
|
||
part, err := writer.CreatePart(h)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("create part error: %w", err)
|
||
}
|
||
|
||
// Записываем байты картинки
|
||
if _, err := io.Copy(part, bytes.NewReader(imageData)); err != nil {
|
||
return nil, fmt.Errorf("copy file error: %w", err)
|
||
}
|
||
|
||
// Закрываем writer, чтобы записать boundary
|
||
if err := writer.Close(); err != nil {
|
||
return nil, fmt.Errorf("writer close error: %w", err)
|
||
}
|
||
|
||
// 2. Создаем запрос
|
||
req, err := http.NewRequestWithContext(ctx, "POST", c.pythonServiceURL+"/recognize", body)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("create request error: %w", err)
|
||
}
|
||
|
||
// Важно: Content-Type с boundary
|
||
req.Header.Set("Content-Type", writer.FormDataContentType())
|
||
|
||
// 3. Отправляем
|
||
resp, err := c.httpClient.Do(req)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("ocr service request failed: %w", err)
|
||
}
|
||
defer resp.Body.Close()
|
||
|
||
if resp.StatusCode != http.StatusOK {
|
||
bodyBytes, _ := io.ReadAll(resp.Body)
|
||
return nil, fmt.Errorf("ocr service error (code %d): %s", resp.StatusCode, string(bodyBytes))
|
||
}
|
||
|
||
// 4. Парсим ответ
|
||
var result RecognitionResult
|
||
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
|
||
return nil, fmt.Errorf("json decode error: %w", err)
|
||
}
|
||
|
||
return &result, nil
|
||
}
|