diff --git a/Dockerfile_paddleocr b/Dockerfile_paddleocr index 89cc5a2..95b5001 100644 --- a/Dockerfile_paddleocr +++ b/Dockerfile_paddleocr @@ -32,7 +32,7 @@ RUN pip install --no-cache-dir \ pillow # Copy server files -COPY image_support_files/paddleocr-server.py /app/paddleocr-server.py +COPY image_support_files/paddleocr_server.py /app/paddleocr_server.py COPY image_support_files/paddleocr-entrypoint.sh /usr/local/bin/paddleocr-entrypoint.sh RUN chmod +x /usr/local/bin/paddleocr-entrypoint.sh diff --git a/Dockerfile_paddleocr_cpu b/Dockerfile_paddleocr_cpu index 2ea9cbc..8281ec1 100644 --- a/Dockerfile_paddleocr_cpu +++ b/Dockerfile_paddleocr_cpu @@ -35,7 +35,7 @@ RUN pip install --no-cache-dir \ pillow # Copy server files -COPY image_support_files/paddleocr-server.py /app/paddleocr-server.py +COPY image_support_files/paddleocr_server.py /app/paddleocr_server.py COPY image_support_files/paddleocr-entrypoint.sh /usr/local/bin/paddleocr-entrypoint.sh RUN chmod +x /usr/local/bin/paddleocr-entrypoint.sh diff --git a/build-images.sh b/build-images.sh index 2c11fb9..cfb3a7b 100755 --- a/build-images.sh +++ b/build-images.sh @@ -29,9 +29,30 @@ docker build \ -t ${REGISTRY}/${NAMESPACE}/${IMAGE_NAME}:minicpm45v-cpu \ . +# Build PaddleOCR GPU variant +echo -e "${GREEN}Building PaddleOCR GPU variant...${NC}" +docker build \ + -f Dockerfile_paddleocr \ + -t ${REGISTRY}/${NAMESPACE}/${IMAGE_NAME}:paddleocr \ + -t ${REGISTRY}/${NAMESPACE}/${IMAGE_NAME}:paddleocr-gpu \ + . + +# Build PaddleOCR CPU variant +echo -e "${GREEN}Building PaddleOCR CPU variant...${NC}" +docker build \ + -f Dockerfile_paddleocr_cpu \ + -t ${REGISTRY}/${NAMESPACE}/${IMAGE_NAME}:paddleocr-cpu \ + . + echo -e "${GREEN}All images built successfully!${NC}" echo "" echo "Available images:" +echo " MiniCPM-V 4.5:" echo " - ${REGISTRY}/${NAMESPACE}/${IMAGE_NAME}:minicpm45v (GPU)" echo " - ${REGISTRY}/${NAMESPACE}/${IMAGE_NAME}:minicpm45v-cpu (CPU)" echo " - ${REGISTRY}/${NAMESPACE}/${IMAGE_NAME}:latest (GPU)" +echo "" +echo " PaddleOCR:" +echo " - ${REGISTRY}/${NAMESPACE}/${IMAGE_NAME}:paddleocr (GPU)" +echo " - ${REGISTRY}/${NAMESPACE}/${IMAGE_NAME}:paddleocr-gpu (GPU)" +echo " - ${REGISTRY}/${NAMESPACE}/${IMAGE_NAME}:paddleocr-cpu (CPU)" diff --git a/changelog.md b/changelog.md index acd83bd..068cb84 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,13 @@ # Changelog +## 2026-01-16 - 1.2.0 - feat(paddleocr) +add PaddleOCR support: Docker images, FastAPI server, entrypoint and tests + +- Add PaddleOCR FastAPI server implementation at image_support_files/paddleocr_server.py +- Remove old image_support_files/paddleocr-server.py and update entrypoint to import paddleocr_server:app +- Extend build-images.sh to build paddleocr (GPU) and paddleocr-cpu images and list them +- Extend test-images.sh to add paddleocr health/OCR tests, new test_paddleocr_image function, port config, and cleanup; rename test_image -> test_minicpm_image + ## 2026-01-16 - 1.1.0 - feat(ocr) add PaddleOCR GPU Docker image and FastAPI OCR server with entrypoint; implement OCR endpoints and consensus extraction testing diff --git a/image_support_files/paddleocr-entrypoint.sh b/image_support_files/paddleocr-entrypoint.sh index aff8737..3ab8d5b 100644 --- a/image_support_files/paddleocr-entrypoint.sh +++ b/image_support_files/paddleocr-entrypoint.sh @@ -19,7 +19,7 @@ else fi # Start the FastAPI server with uvicorn -exec python -m uvicorn paddleocr-server:app \ +exec python -m uvicorn paddleocr_server:app \ --host "${SERVER_HOST}" \ --port "${SERVER_PORT}" \ --workers 1 diff --git a/image_support_files/paddleocr-server.py b/image_support_files/paddleocr_server.py similarity index 100% rename from image_support_files/paddleocr-server.py rename to image_support_files/paddleocr_server.py diff --git a/test-images.sh b/test-images.sh index 52bbcc4..142aced 100755 --- a/test-images.sh +++ b/test-images.sh @@ -5,7 +5,8 @@ set -e REGISTRY="code.foss.global" NAMESPACE="host.today" IMAGE_NAME="ht-docker-ai" -TEST_PORT=11434 +MINICPM_PORT=11434 +PADDLEOCR_PORT=5000 # Colors for output GREEN='\033[0;32m' @@ -17,11 +18,13 @@ cleanup() { echo -e "${BLUE}Cleaning up test containers...${NC}" docker rm -f test-minicpm-gpu 2>/dev/null || true docker rm -f test-minicpm-cpu 2>/dev/null || true + docker rm -f test-paddleocr-gpu 2>/dev/null || true + docker rm -f test-paddleocr-cpu 2>/dev/null || true } trap cleanup EXIT -test_image() { +test_minicpm_image() { local tag=$1 local container_name=$2 local extra_args=$3 @@ -31,7 +34,7 @@ test_image() { # Start container docker run -d \ --name ${container_name} \ - -p ${TEST_PORT}:11434 \ + -p ${MINICPM_PORT}:11434 \ ${extra_args} \ ${REGISTRY}/${NAMESPACE}/${IMAGE_NAME}:${tag} @@ -41,7 +44,7 @@ test_image() { # Test API endpoint echo "Testing API endpoint..." - if curl -s -f http://localhost:${TEST_PORT}/api/tags > /dev/null; then + if curl -s -f http://localhost:${MINICPM_PORT}/api/tags > /dev/null; then echo -e "${GREEN}API endpoint responding!${NC}" else echo -e "${RED}API endpoint not responding!${NC}" @@ -56,17 +59,85 @@ test_image() { echo "" } +test_paddleocr_image() { + local tag=$1 + local container_name=$2 + local extra_args=$3 + + echo -e "${BLUE}Testing ${tag}...${NC}" + + # Start container + docker run -d \ + --name ${container_name} \ + -p ${PADDLEOCR_PORT}:5000 \ + ${extra_args} \ + ${REGISTRY}/${NAMESPACE}/${IMAGE_NAME}:${tag} + + # Wait for startup (PaddleOCR takes longer to initialize) + echo "Waiting for container to start..." + sleep 30 + + # Test health endpoint + echo "Testing health endpoint..." + if curl -s -f http://localhost:${PADDLEOCR_PORT}/health > /dev/null; then + echo -e "${GREEN}Health endpoint responding!${NC}" + else + echo -e "${RED}Health endpoint not responding!${NC}" + docker logs ${container_name} + return 1 + fi + + # Test OCR endpoint with a minimal base64 image (1x1 white pixel PNG) + echo "Testing OCR endpoint..." + local test_image="iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg==" + local response=$(curl -s -X POST http://localhost:${PADDLEOCR_PORT}/ocr \ + -H "Content-Type: application/json" \ + -d "{\"image\": \"${test_image}\"}") + + if echo "$response" | grep -q '"success"'; then + echo -e "${GREEN}OCR endpoint responding!${NC}" + else + echo -e "${RED}OCR endpoint not responding correctly!${NC}" + echo "Response: $response" + docker logs ${container_name} + return 1 + fi + + # Cleanup this container + docker rm -f ${container_name} + + echo -e "${GREEN}${tag} test passed!${NC}" + echo "" +} + echo -e "${BLUE}=== Testing ht-docker-ai images ===${NC}" echo "" -# Test CPU variant (doesn't require GPU) -test_image "minicpm45v-cpu" "test-minicpm-cpu" "" +echo -e "${BLUE}--- MiniCPM-V Tests ---${NC}" +echo "" -# Test GPU variant only if NVIDIA runtime is available +# Test MiniCPM CPU variant (doesn't require GPU) +test_minicpm_image "minicpm45v-cpu" "test-minicpm-cpu" "" + +# Test MiniCPM GPU variant only if NVIDIA runtime is available if docker info 2>/dev/null | grep -q "nvidia"; then - test_image "minicpm45v" "test-minicpm-gpu" "--gpus all" + test_minicpm_image "minicpm45v" "test-minicpm-gpu" "--gpus all" else - echo -e "${BLUE}Skipping GPU test (NVIDIA runtime not available)${NC}" + echo -e "${BLUE}Skipping MiniCPM GPU test (NVIDIA runtime not available)${NC}" +fi + +echo "" +echo -e "${BLUE}--- PaddleOCR Tests ---${NC}" +echo "" + +# Test PaddleOCR CPU variant (doesn't require GPU) +test_paddleocr_image "paddleocr-cpu" "test-paddleocr-cpu" "" + +# Test PaddleOCR GPU variant only if NVIDIA runtime is available +if docker info 2>/dev/null | grep -q "nvidia"; then + test_paddleocr_image "paddleocr" "test-paddleocr-gpu" "--gpus all" +else + echo -e "${BLUE}Skipping PaddleOCR GPU test (NVIDIA runtime not available)${NC}" fi echo -e "${GREEN}=== All tests passed! ===${NC}"