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 }