Everything you need to integrate Synthya OCR into your application β with ready-to-use code examples in Python, JavaScript, Java, cURL, Go, and C#.
The Synthya OCR API provides a single, simple endpoint for all OCR operations. You send a base64-encoded image and receive structured JSON results. The server automatically batches concurrent requests for optimal throughput.
Content-Type: application/json
Max request size: 30 MB
Timeout: 5 minutes per request
| Field | Type | Required | Description |
|---|---|---|---|
image | string | β Yes | Base64-encoded image data (no data: prefix) |
imageType | string | No | Image format: png, jpg, jpeg, gif, tif. Default: png |
mode | string | No | OCR mode: receipt, full, targeted, template, survey, tree. Default: full |
prompt | string | No | Custom prompt (only for full mode) |
query | object | No | Structured query (only for targeted mode). See Modes section. |
data:image/...;base64, prefix. The server adds the correct MIME type based on imageType.
All responses are JSON with the following structure:
{
"id": "uuid-of-the-request",
"mode": "full",
"data": {
// Mode-specific result β see below
}
}
On error:
{
"id": "uuid-of-the-request",
"mode": "full",
"error": "description of the error"
}
Extracts all visible text from the image. Returns {"text": "...", "mode": "full"}. Optionally accepts a prompt for custom instructions.
Extracts structured receipt data: store name, items, prices, totals, discounts. Returns a verified receipt object with suspicious item detection.
Extracts specific data using a structured query object. The query field supports:
| Field | Description |
|---|---|
documentType | Type of document (e.g. "invoice", "report") |
columns | Array of column names to extract |
items | Array of specific items to look for |
freeText | Additional instructions in natural language |
Specialized for NH μ°©κ³Όμ μ‘°μ¬ν (fruit survey) forms. Returns structured JSON with validation.
Specialized for NH νμ§μ‘°μ¬μ (field survey) forms. Returns structured JSON with validation.
Specialized for NH λλ¬΄μ‘°μ¬ (tree investigation) forms. Returns structured JSON with validation.
import base64
import requests
API_URL = "http://localhost:6800/api/ocr"
# Read and encode the image
with open("document.png", "rb") as f:
image_b64 = base64.b64encode(f.read()).decode("utf-8")
# Send the request
response = requests.post(API_URL, json={
"image": image_b64,
"imageType": "png",
"mode": "full"
})
result = response.json()
print(result["data"]["text"])
import base64
import requests
API_URL = "http://localhost:6800/api/ocr"
with open("receipt.jpg", "rb") as f:
image_b64 = base64.b64encode(f.read()).decode("utf-8")
response = requests.post(API_URL, json={
"image": image_b64,
"imageType": "jpg",
"mode": "receipt"
})
receipt = response.json()["data"]
print(f"Store: {receipt['storeName']}")
print(f"Total: {receipt['totalAfterTax']}")
for item in receipt["items"]:
flag = " β οΈ" if item["isSuspicious"] else ""
print(f" {item['name']}: {item['totalPrice']}{flag}")
import base64
import requests
API_URL = "http://localhost:6800/api/ocr"
with open("invoice.png", "rb") as f:
image_b64 = base64.b64encode(f.read()).decode("utf-8")
response = requests.post(API_URL, json={
"image": image_b64,
"imageType": "png",
"mode": "targeted",
"query": {
"documentType": "invoice",
"columns": ["νλͺ
", "μλ", "λ¨κ°", "κΈμ‘"],
"items": ["μ¬κ³Ό", "λ°°", "κ°"],
"freeText": "ν©κ³λ μΆμΆν΄ μ£ΌμΈμ"
}
})
data = response.json()["data"]
for item in data["json"]["items"]:
print(f"{item['name']}: {item['values']}")
import base64
import requests
import json
API_URL = "http://localhost:6800/api/ocr"
def process_nh_form(image_path, mode):
"""Process an NH agricultural form.
Args:
image_path: Path to the scanned form image
mode: One of 'template' (μ°©κ³Όμ), 'survey' (νμ§μ‘°μ¬μ), 'tree' (λ무쑰μ¬)
"""
with open(image_path, "rb") as f:
image_b64 = base64.b64encode(f.read()).decode("utf-8")
ext = image_path.rsplit(".", 1)[-1].lower()
response = requests.post(API_URL, json={
"image": image_b64,
"imageType": ext,
"mode": mode
}, timeout=300)
result = response.json()
if "error" in result:
print(f"Error: {result['error']}")
return None
data = result["data"]
parsed = data.get("json")
validation = data.get("validation")
if validation:
trusted = validation.get("trusted", validation.get("valid", False))
issues = validation.get("issues") or []
print(f"Validation: {'β
Trusted' if trusted else 'β οΈ Issues found'}")
for issue in issues:
print(f" - {issue}")
return parsed
# Example: Process a μ°©κ³Όμ μ‘°μ¬ν (fruit survey)
fruit_data = process_nh_form("fruit_survey_scan.jpg", "template")
if fruit_data:
print(json.dumps(fruit_data, ensure_ascii=False, indent=2))
# Example: Process a νμ§μ‘°μ¬μ (field survey)
field_data = process_nh_form("field_survey_scan.png", "survey")
# Example: Process a λλ¬΄μ‘°μ¬ (tree investigation)
tree_data = process_nh_form("tree_investigation_scan.tif", "tree")
import asyncio
import base64
import aiohttp
from pathlib import Path
API_URL = "http://localhost:6800/api/ocr"
async def process_image(session, filepath):
"""Process a single image β the server auto-batches concurrent requests."""
data = Path(filepath).read_bytes()
ext = Path(filepath).suffix.lstrip(".").lower()
if ext == "jpg":
ext = "jpeg"
async with session.post(API_URL, json={
"image": base64.b64encode(data).decode(),
"imageType": ext,
"mode": "receipt"
}) as resp:
return await resp.json()
async def main():
images = list(Path("receipts/").glob("*.jpg"))
print(f"Processing {len(images)} images...")
async with aiohttp.ClientSession() as session:
tasks = [process_image(session, img) for img in images]
results = await asyncio.gather(*tasks)
for img, result in zip(images, results):
if "error" in result:
print(f"β {img.name}: {result['error']}")
else:
total = result["data"].get("totalAfterTax", "N/A")
print(f"β
{img.name}: total = {total}")
asyncio.run(main())
const fs = require('fs');
const path = require('path');
const API_URL = 'http://localhost:6800/api/ocr';
async function ocrImage(filePath, mode = 'full') {
const imageBuffer = fs.readFileSync(filePath);
const imageB64 = imageBuffer.toString('base64');
const ext = path.extname(filePath).slice(1).toLowerCase();
const response = await fetch(API_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
image: imageB64,
imageType: ext === 'jpg' ? 'jpeg' : ext,
mode: mode,
}),
});
return response.json();
}
// Usage
const result = await ocrImage('document.png', 'full');
console.log(result.data.text);
async function processFile(file) {
// Convert File to base64
const buffer = await file.arrayBuffer();
const base64 = btoa(
new Uint8Array(buffer).reduce((s, b) => s + String.fromCharCode(b), '')
);
// Determine image type from file name
const ext = file.name.split('.').pop().toLowerCase();
const response = await fetch('/api/ocr', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
image: base64,
imageType: ext === 'jpg' ? 'jpeg' : ext,
mode: 'receipt',
}),
});
return response.json();
}
// With a file input
document.getElementById('fileInput').addEventListener('change', async (e) => {
const file = e.target.files[0];
if (!file) return;
const result = await processFile(file);
console.log('OCR result:', result);
});
const fs = require('fs');
const path = require('path');
const API_URL = 'http://localhost:6800/api/ocr';
/**
* Process an NH agricultural form.
* @param {string} filePath - Path to the scanned form image
* @param {'template'|'survey'|'tree'} mode - NH form type
*/
async function processNHForm(filePath, mode) {
const buffer = fs.readFileSync(filePath);
const ext = path.extname(filePath).slice(1).toLowerCase();
const response = await fetch(API_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
image: buffer.toString('base64'),
imageType: ext === 'jpg' ? 'jpeg' : ext,
mode: mode,
}),
});
const result = await response.json();
if (result.error) {
console.error(`Error: ${result.error}`);
return null;
}
const { json: parsed, validation } = result.data;
if (validation) {
const trusted = validation.trusted ?? validation.valid ?? false;
console.log(`Validation: ${trusted ? 'β
Trusted' : 'β οΈ Issues'}`);
(validation.issues || []).forEach(i => console.log(` - ${i}`));
}
return parsed;
}
// Usage
const fruitData = await processNHForm('fruit_survey.jpg', 'template');
const fieldData = await processNHForm('field_survey.png', 'survey');
const treeData = await processNHForm('tree_form.tif', 'tree');
console.log(JSON.stringify(fruitData, null, 2));
const fs = require('fs');
const path = require('path');
const { glob } = require('fs/promises');
const API_URL = 'http://localhost:6800/api/ocr';
async function processImage(filePath) {
const buffer = fs.readFileSync(filePath);
const ext = path.extname(filePath).slice(1).toLowerCase();
const resp = await fetch(API_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
image: buffer.toString('base64'),
imageType: ext,
mode: 'receipt',
}),
});
return { file: path.basename(filePath), result: await resp.json() };
}
// Process all JPGs concurrently β server auto-batches them
const files = fs.readdirSync('receipts/')
.filter(f => /\.(jpg|jpeg|png)$/i.test(f))
.map(f => path.join('receipts/', f));
const results = await Promise.all(files.map(processImage));
for (const { file, result } of results) {
console.log(`${file}: ${result.data?.totalAfterTax ?? result.error}`);
}
import java.net.URI;
import java.net.http.*;
import java.nio.file.*;
import java.util.Base64;
public class SynthyaOCR {
private static final String API_URL = "http://localhost:6800/api/ocr";
public static String ocr(String imagePath, String mode) throws Exception {
// Read and encode the image
byte[] imageBytes = Files.readAllBytes(Path.of(imagePath));
String imageB64 = Base64.getEncoder().encodeToString(imageBytes);
// Determine image type from extension
String ext = imagePath.substring(imagePath.lastIndexOf('.') + 1).toLowerCase();
if (ext.equals("jpg")) ext = "jpeg";
// Build JSON payload
String json = String.format("""
{
"image": "%s",
"imageType": "%s",
"mode": "%s"
}
""", imageB64, ext, mode);
// Send the request
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(API_URL))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(json))
.build();
HttpResponse<String> response = client.send(
request, HttpResponse.BodyHandlers.ofString()
);
return response.body();
}
public static void main(String[] args) throws Exception {
String result = ocr("document.png", "full");
System.out.println(result);
}
}
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.node.*;
import java.net.URI;
import java.net.http.*;
import java.nio.file.*;
import java.util.Base64;
public class TargetedOCR {
private static final String API_URL = "http://localhost:6800/api/ocr";
private static final ObjectMapper mapper = new ObjectMapper();
public static JsonNode targetedOcr(String imagePath, String docType,
String[] columns, String[] items) throws Exception {
byte[] imageBytes = Files.readAllBytes(Path.of(imagePath));
ObjectNode payload = mapper.createObjectNode();
payload.put("image", Base64.getEncoder().encodeToString(imageBytes));
payload.put("imageType", "png");
payload.put("mode", "targeted");
ObjectNode query = mapper.createObjectNode();
query.put("documentType", docType);
ArrayNode cols = query.putArray("columns");
for (String c : columns) cols.add(c);
ArrayNode itms = query.putArray("items");
for (String i : items) itms.add(i);
payload.set("query", query);
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(API_URL))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(mapper.writeValueAsString(payload)))
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
return mapper.readTree(response.body());
}
public static void main(String[] args) throws Exception {
JsonNode result = targetedOcr("invoice.png", "invoice",
new String[]{"νλͺ
", "μλ", "λ¨κ°"},
new String[]{"μ¬κ³Ό", "λ°°"});
System.out.println(result.toPrettyString());
}
}
import com.fasterxml.jackson.databind.*;
import java.net.URI;
import java.net.http.*;
import java.nio.file.*;
import java.util.Base64;
public class NHFormOCR {
private static final String API_URL = "http://localhost:6800/api/ocr";
private static final ObjectMapper mapper = new ObjectMapper();
private static final HttpClient client = HttpClient.newHttpClient();
/**
* Process an NH agricultural form.
* @param imagePath path to the scanned image
* @param mode "template" (μ°©κ³Όμ), "survey" (νμ§μ‘°μ¬μ), or "tree" (λ무쑰μ¬)
*/
public static JsonNode processForm(String imagePath, String mode) throws Exception {
byte[] bytes = Files.readAllBytes(Path.of(imagePath));
String ext = imagePath.substring(imagePath.lastIndexOf('.') + 1).toLowerCase();
if (ext.equals("jpg")) ext = "jpeg";
String json = String.format("""
{
"image": "%s",
"imageType": "%s",
"mode": "%s"
}
""", Base64.getEncoder().encodeToString(bytes), ext, mode);
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(API_URL))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(json))
.build();
HttpResponse<String> response = client.send(
request, HttpResponse.BodyHandlers.ofString());
JsonNode root = mapper.readTree(response.body());
// Check validation results
JsonNode validation = root.at("/data/validation");
if (!validation.isMissingNode()) {
boolean trusted = validation.path("trusted").asBoolean(
validation.path("valid").asBoolean(false));
System.out.println("Validation: " + (trusted ? "β
Trusted" : "β οΈ Issues"));
validation.path("issues").forEach(
issue -> System.out.println(" - " + issue.asText()));
}
return root.at("/data/json");
}
public static void main(String[] args) throws Exception {
// μ°©κ³Όμ μ‘°μ¬ν
JsonNode fruit = processForm("fruit_survey.jpg", "template");
System.out.println(fruit.toPrettyString());
// νμ§μ‘°μ¬μ
JsonNode field = processForm("field_survey.png", "survey");
// λ무쑰μ¬
JsonNode tree = processForm("tree_form.tif", "tree");
}
}
import java.net.URI;
import java.net.http.*;
import java.nio.file.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.stream.*;
public class BatchOCR {
private static final String API_URL = "http://localhost:6800/api/ocr";
private static final HttpClient client = HttpClient.newHttpClient();
public static CompletableFuture<String> processAsync(Path imagePath) {
try {
byte[] bytes = Files.readAllBytes(imagePath);
String ext = imagePath.toString().substring(
imagePath.toString().lastIndexOf('.') + 1);
String json = String.format("""
{"image":"%s","imageType":"%s","mode":"receipt"}
""", Base64.getEncoder().encodeToString(bytes), ext);
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create(API_URL))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(json))
.build();
return client.sendAsync(req, HttpResponse.BodyHandlers.ofString())
.thenApply(HttpResponse::body);
} catch (Exception e) {
return CompletableFuture.failedFuture(e);
}
}
public static void main(String[] args) throws Exception {
List<Path> images = Files.list(Path.of("receipts/"))
.filter(p -> p.toString().matches(".*\\.(jpg|png|jpeg)$"))
.collect(Collectors.toList());
// All requests are sent concurrently β server auto-batches them
List<CompletableFuture<String>> futures = images.stream()
.map(BatchOCR::processAsync)
.collect(Collectors.toList());
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
for (int i = 0; i < images.size(); i++) {
System.out.printf("%s: %s%n",
images.get(i).getFileName(), futures.get(i).get());
}
}
}
# Encode the image to base64
IMAGE_B64=$(base64 -w 0 document.png)
# Send the request
curl -s -X POST http://localhost:6800/api/ocr \
-H "Content-Type: application/json" \
-d "{
\"image\": \"$IMAGE_B64\",
\"imageType\": \"png\",
\"mode\": \"full\"
}" | jq .
# One-liner: encode + send receipt for processing
curl -s -X POST http://localhost:6800/api/ocr \
-H "Content-Type: application/json" \
-d "$(jq -n --arg img "$(base64 -w 0 receipt.jpg)" '{
image: $img,
imageType: "jpg",
mode: "receipt"
}')" | jq '.data | {store: .storeName, total: .totalAfterTax}'
curl -s -X POST http://localhost:6800/api/ocr \
-H "Content-Type: application/json" \
-d "$(jq -n --arg img "$(base64 -w 0 invoice.png)" '{
image: $img,
imageType: "png",
mode: "targeted",
query: {
documentType: "invoice",
columns: ["νλͺ
", "μλ", "λ¨κ°", "κΈμ‘"],
items: ["μ¬κ³Ό", "λ°°"]
}
}')" | jq '.data.json.items'
# μ°©κ³Όμ μ‘°μ¬ν (fruit survey) β mode: template
curl -s -X POST http://localhost:6800/api/ocr \
-H "Content-Type: application/json" \
-d "$(jq -n --arg img "$(base64 -w 0 fruit_survey.jpg)" '{
image: $img,
imageType: "jpg",
mode: "template"
}')" | jq '.data | {json, validation}'
# νμ§μ‘°μ¬μ (field survey) β mode: survey
curl -s -X POST http://localhost:6800/api/ocr \
-H "Content-Type: application/json" \
-d "$(jq -n --arg img "$(base64 -w 0 field_survey.png)" '{
image: $img,
imageType: "png",
mode: "survey"
}')" | jq '.data.validation'
# λλ¬΄μ‘°μ¬ (tree investigation) β mode: tree
curl -s -X POST http://localhost:6800/api/ocr \
-H "Content-Type: application/json" \
-d "$(jq -n --arg img "$(base64 -w 0 tree_form.tif)" '{
image: $img,
imageType: "tif",
mode: "tree"
}')" | jq '.data.json'
# Process all images in parallel (4 at a time)
# Server auto-batches concurrent requests for optimal throughput
ls receipts/*.jpg | xargs -P 4 -I {} bash -c '
FILE="{}"
B64=$(base64 -w 0 "$FILE")
RESULT=$(curl -s -X POST http://localhost:6800/api/ocr \
-H "Content-Type: application/json" \
-d "{\"image\":\"$B64\",\"imageType\":\"jpg\",\"mode\":\"receipt\"}")
TOTAL=$(echo "$RESULT" | jq -r ".data.totalAfterTax // \"error\"")
echo "$FILE: $TOTAL"
'
package main
import (
"bytes"
"encoding/base64"
"encoding/json"
"fmt"
"net/http"
"os"
"path/filepath"
"strings"
)
const apiURL = "http://localhost:6800/api/ocr"
type OCRRequest struct {
Image string `json:"image"`
ImageType string `json:"imageType"`
Mode string `json:"mode"`
Prompt string `json:"prompt,omitempty"`
Query interface{} `json:"query,omitempty"`
}
type OCRResponse struct {
ID string `json:"id"`
Mode string `json:"mode"`
Error string `json:"error,omitempty"`
Data map[string]interface{} `json:"data,omitempty"`
}
func ocrImage(filePath, mode string) (*OCRResponse, error) {
data, err := os.ReadFile(filePath)
if err != nil {
return nil, err
}
ext := strings.TrimPrefix(filepath.Ext(filePath), ".")
if ext == "jpg" {
ext = "jpeg"
}
payload, _ := json.Marshal(OCRRequest{
Image: base64.StdEncoding.EncodeToString(data),
ImageType: ext,
Mode: mode,
})
resp, err := http.Post(apiURL, "application/json", bytes.NewReader(payload))
if err != nil {
return nil, err
}
defer resp.Body.Close()
var result OCRResponse
json.NewDecoder(resp.Body).Decode(&result)
return &result, nil
}
func main() {
result, err := ocrImage("document.png", "full")
if err != nil {
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
os.Exit(1)
}
if result.Error != "" {
fmt.Fprintf(os.Stderr, "OCR error: %s\n", result.Error)
os.Exit(1)
}
fmt.Println(result.Data["text"])
}
package main
import (
"bytes"
"encoding/base64"
"encoding/json"
"fmt"
"net/http"
"os"
"path/filepath"
"strings"
)
const apiURL = "http://localhost:6800/api/ocr"
// processNHForm sends a scanned NH form for OCR.
// mode: "template" (μ°©κ³Όμ), "survey" (νμ§μ‘°μ¬μ), "tree" (λ무쑰μ¬)
func processNHForm(filePath, mode string) (map[string]interface{}, error) {
data, err := os.ReadFile(filePath)
if err != nil {
return nil, err
}
ext := strings.TrimPrefix(filepath.Ext(filePath), ".")
if ext == "jpg" {
ext = "jpeg"
}
payload, _ := json.Marshal(map[string]string{
"image": base64.StdEncoding.EncodeToString(data),
"imageType": ext,
"mode": mode,
})
resp, err := http.Post(apiURL, "application/json", bytes.NewReader(payload))
if err != nil {
return nil, err
}
defer resp.Body.Close()
var result map[string]interface{}
json.NewDecoder(resp.Body).Decode(&result)
if errMsg, ok := result["error"].(string); ok {
return nil, fmt.Errorf("OCR error: %s", errMsg)
}
// Extract data and check validation
resultData, _ := result["data"].(map[string]interface{})
if validation, ok := resultData["validation"].(map[string]interface{}); ok {
trusted, _ := validation["trusted"].(bool)
if !trusted {
if valid, ok := validation["valid"].(bool); ok {
trusted = valid
}
}
if trusted {
fmt.Println("β
Validation passed")
} else {
fmt.Println("β οΈ Validation issues found")
if issues, ok := validation["issues"].([]interface{}); ok {
for _, issue := range issues {
fmt.Printf(" - %v\n", issue)
}
}
}
}
parsed, _ := resultData["json"].(map[string]interface{})
return parsed, nil
}
func main() {
// μ°©κ³Όμ μ‘°μ¬ν
fruit, err := processNHForm("fruit_survey.jpg", "template")
if err != nil {
fmt.Println(err)
} else {
out, _ := json.MarshalIndent(fruit, "", " ")
fmt.Println(string(out))
}
// νμ§μ‘°μ¬μ
processNHForm("field_survey.png", "survey")
// λ무쑰μ¬
processNHForm("tree_form.tif", "tree")
}
package main
import (
"bytes"
"encoding/base64"
"encoding/json"
"fmt"
"net/http"
"os"
"path/filepath"
"strings"
"sync"
)
func main() {
files, _ := filepath.Glob("receipts/*.jpg")
fmt.Printf("Processing %d images...\n", len(files))
var wg sync.WaitGroup
for _, f := range files {
wg.Add(1)
go func(path string) {
defer wg.Done()
data, _ := os.ReadFile(path)
ext := strings.TrimPrefix(filepath.Ext(path), ".")
payload, _ := json.Marshal(map[string]string{
"image": base64.StdEncoding.EncodeToString(data),
"imageType": ext,
"mode": "receipt",
})
resp, err := http.Post("http://localhost:6800/api/ocr",
"application/json", bytes.NewReader(payload))
if err != nil {
fmt.Printf("β %s: %v\n", filepath.Base(path), err)
return
}
defer resp.Body.Close()
var result map[string]interface{}
json.NewDecoder(resp.Body).Decode(&result)
fmt.Printf("β
%s: %v\n", filepath.Base(path), result["data"])
}(f)
}
wg.Wait()
}
using System.Net.Http.Json;
using System.Text.Json;
var apiUrl = "http://localhost:6800/api/ocr";
var client = new HttpClient();
async Task<JsonDocument> OcrImageAsync(string filePath, string mode = "full")
{
var imageBytes = await File.ReadAllBytesAsync(filePath);
var ext = Path.GetExtension(filePath).TrimStart('.').ToLower();
if (ext == "jpg") ext = "jpeg";
var payload = new {
image = Convert.ToBase64String(imageBytes),
imageType = ext,
mode = mode
};
var response = await client.PostAsJsonAsync(apiUrl, payload);
var json = await response.Content.ReadAsStringAsync();
return JsonDocument.Parse(json);
}
// Usage
var result = await OcrImageAsync("document.png", "full");
Console.WriteLine(result.RootElement
.GetProperty("data")
.GetProperty("text")
.GetString());
using System.Net.Http.Json;
using System.Text.Json;
var apiUrl = "http://localhost:6800/api/ocr";
var client = new HttpClient { Timeout = TimeSpan.FromMinutes(5) };
/// <summary>
/// Process an NH agricultural form.
/// mode: "template" (μ°©κ³Όμ), "survey" (νμ§μ‘°μ¬μ), "tree" (λ무쑰μ¬)
/// </summary>
async Task<JsonElement?> ProcessNHFormAsync(string filePath, string mode)
{
var bytes = await File.ReadAllBytesAsync(filePath);
var ext = Path.GetExtension(filePath).TrimStart('.').ToLower();
if (ext == "jpg") ext = "jpeg";
var payload = new {
image = Convert.ToBase64String(bytes),
imageType = ext,
mode = mode
};
var response = await client.PostAsJsonAsync(apiUrl, payload);
var json = await response.Content.ReadAsStringAsync();
var doc = JsonDocument.Parse(json);
var root = doc.RootElement;
// Check for errors
if (root.TryGetProperty("error", out var error))
{
Console.WriteLine($"Error: {error.GetString()}");
return null;
}
// Check validation
var data = root.GetProperty("data");
if (data.TryGetProperty("validation", out var validation))
{
var trusted = validation.TryGetProperty("trusted", out var t)
? t.GetBoolean()
: validation.TryGetProperty("valid", out var v) && v.GetBoolean();
Console.WriteLine(trusted ? "β
Validation passed" : "β οΈ Issues found");
if (validation.TryGetProperty("issues", out var issues))
{
foreach (var issue in issues.EnumerateArray())
Console.WriteLine($" - {issue.GetString()}");
}
}
return data.TryGetProperty("json", out var parsed) ? parsed : null;
}
// Usage
var fruitData = await ProcessNHFormAsync("fruit_survey.jpg", "template");
Console.WriteLine(fruitData?.ToString());
var fieldData = await ProcessNHFormAsync("field_survey.png", "survey");
var treeData = await ProcessNHFormAsync("tree_form.tif", "tree");
using System.Net.Http.Json;
using System.Text.Json;
var apiUrl = "http://localhost:6800/api/ocr";
var client = new HttpClient { Timeout = TimeSpan.FromMinutes(5) };
var images = Directory.GetFiles("receipts/", "*.jpg");
Console.WriteLine($"Processing {images.Length} images...");
// All requests are sent concurrently β server auto-batches
var tasks = images.Select(async file =>
{
var bytes = await File.ReadAllBytesAsync(file);
var payload = new {
image = Convert.ToBase64String(bytes),
imageType = "jpg",
mode = "receipt"
};
var resp = await client.PostAsJsonAsync(apiUrl, payload);
var json = await resp.Content.ReadAsStringAsync();
return (File: Path.GetFileName(file), Result: json);
}).ToList();
var results = await Task.WhenAll(tasks);
foreach (var (file, result) in results)
{
Console.WriteLine($"{file}: {result[..Math.Min(result.Length, 120)]}...");
}
The API returns standard HTTP status codes:
| Status | Meaning |
|---|---|
200 | Success β check the response data field |
400 | Bad request β invalid JSON, missing image, unsupported imageType or mode |
405 | Method not allowed β only POST is accepted |
413 | Request too large β max 30 MB |
500 | Internal error β VLM processing failure |
429 | Rate limited β too many requests (if rate limiter is enabled) |
"error" field in the JSON body. Always check for result.error in your response handling.
import requests
def safe_ocr(image_b64, image_type="png", mode="full"):
try:
resp = requests.post("http://localhost:6800/api/ocr", json={
"image": image_b64,
"imageType": image_type,
"mode": mode,
}, timeout=300)
# HTTP-level error
resp.raise_for_status()
result = resp.json()
# Application-level error
if "error" in result:
print(f"OCR error: {result['error']}")
return None
return result["data"]
except requests.Timeout:
print("Request timed out (5 min limit)")
return None
except requests.RequestException as e:
print(f"Request failed: {e}")
return None
The server transparently batches incoming requests for optimal GPU utilization:
/api/ocr/enhance endpoint first.receipt, template, survey, tree) when the document type matches β they use optimized prompts and return structured, validated data.targeted mode with a query object returns exactly what you ask for.error field in the response body).