Creating a Medical Report Analysis Tool with Python and Dedicated Inference
Introduction Medical reports are typically crafted for healthcare professionals, not patients. Values like or are significant only if you understand what these metrics represent...
Introduction
Medical reports are typically crafted for healthcare professionals, not patients. Values like WBC: 14,500 /uL or Hemoglobin: 9.1 g/dL are significant only if you understand what these metrics represent and their normal ranges. Most people receive these reports as PDFs, glance at the numbers, and struggle to interpret them without a follow-up appointment. However, large language models have advanced to the point where they can bridge this gap. They can analyze blood test reports, identify abnormal values, explain them in simple terms, and highlight findings that require medical attention. The challenge lies in using these models responsibly and privately, avoiding speculation and ensuring data privacy.
This guide will walk you through building a medical report analyzer using Python. The application will accept blood test reports in PDF or image format, extract the text locally, and send it to a model for analysis. The model will return a structured summary, including explanations of abnormal findings, guidance on when to consult a doctor, and health practices based on the results. By the end, you'll have built a complete application and gained insights into its components, such as document extraction, prompt design, API integration, and user interface development.
Disclaimer: This tool is designed for informational purposes only. It explains blood test values but does not diagnose medical conditions. Always consult a qualified healthcare provider with your results.
Key Takeaways
- Dedicated GPU resources are ideal for deploying AI models with consistent performance.
- The application uses pdfplumber and Tesseract OCR to extract text from medical reports in PDFs and images.
- Running the application and inference endpoint within the same private network can enhance privacy.
- The architecture can support additional healthcare workflows and document types.
- By combining OCR, large language models, and dedicated GPU infrastructure, developers can build AI applications that provide clear insights from complex medical reports.
Understanding Dedicated Inference
When building a language model-powered application, developers often use shared APIs. This approach is suitable for prototypes and low-volume use cases. However, as the application begins to handle sensitive data, like medical reports, the limitations of shared infrastructure become apparent.
Dedicated Inference is a managed service that allows AI models to run on dedicated GPUs, providing control over hardware, model settings, and performance. It is ideal for applications with consistent usage patterns and privacy requirements. Unlike shared services, Dedicated Inference ensures that sensitive information, such as lab report data, remains within a private network and does not traverse the public internet.
Prerequisites
Before you begin, ensure you have the following:
- An account with access to the AI Platform.
- Python 3.10 or higher installed on your machine.
- Familiarity with Python and virtual environments.
- Basic command-line knowledge.
Step 1 — Deploy the Model on Dedicated Inference
Create a Dedicated Inference Endpoint
Log into your account, navigate to the Dedicated Inference section, and start deploying a new endpoint.
Select a Datacenter Region
Choose a region close to your application to minimize latency.
Choose a Model
You can select from pre-trained models or import your own from a repository or storage bucket. For this project, import the Qwen3-8B model.
About Qwen3-8B
Qwen3-8B is an open-source language model with 8 billion parameters, designed for high-quality reasoning and text generation. It supports multiple languages and is optimized for efficient deployment on dedicated GPU infrastructure.
Step 2 — Set Up the Project
Create a directory and set up a Python virtual environment:
mkdir blood-test-analyzer
cd blood-test-analyzer
python3 -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
The project will include four files:
blood-test-analyzer/
├── app.py # Gradio UI and analysis pipeline
├── extract.py # Text extraction utilities
├── requirements.txt # Python dependencies
└── .env # Credentials
Create requirements.txt with the following content:
gradio>=4.20.0
pdfplumber>=0.10.0
pytesseract>=0.3.10
Pillow>=10.0.0
requests>=2.31.0
python-dotenv>=1.0.0
Install the dependencies:
pip install -r requirements.txt
Create a .env file with your credentials:
## .env
DO_INFERENCE_TOKEN=your_token_here
DO_INFERENCE_URL=https://YOUR-ENDPOINT-URL/v1/chat/completions
MODEL_NAME=Qwen/Qwen3-8B
Add .env to your .gitignore:
echo ".env" >> .gitignore
Step 3 — Extract Text from PDFs and Images
Create extract.py to handle text extraction from PDFs and images. Use pdfplumber for PDFs and pytesseract for OCR on images.
import pdfplumber
import pytesseract
from PIL import Image
def extract_text_from_pdf(file_path: str) -> str:
try:
pages_text = []
with pdfplumber.open(file_path) as pdf:
for page in pdf.pages:
text = page.extract_text()
if text:
pages_text.append(text)
if not pages_text:
return "Could not extract any text from this PDF."
return "\n".join(pages_text)
except Exception as e:
return f"PDF extraction error: {str(e)}"
def extract_text_from_image(file_path: str) -> str:
try:
image = Image.open(file_path)
custom_config = r"--oem 3 --psm 6"
text = pytesseract.image_to_string(image, config=custom_config)
if not text.strip():
return "OCR could not extract text from this image."
return text
except Exception as e:
return f"Image OCR error: {str(e)}"
def extract_text(file_path: str) -> str:
if file_path is None:
return ""
lower = file_path.lower()
if lower.endswith(".pdf"):
return extract_text_from_pdf(file_path)
elif lower.endswith((".png", ".jpg", ".jpeg", ".tiff", ".tif", ".bmp", ".webp")):
return extract_text_from_image(file_path)
else:
return "Unsupported file type. Please upload a PDF or an image file."
Step 4 — Design the System Prompt
The system prompt is critical for an LLM application. It ensures the output is structured, safe, and useful. For the medical report analyzer, the prompt must yield predictable, responsible, and actionable responses.
SYSTEM_PROMPT = """
You are a clinical blood test analysis assistant. Your job is to read extracted text
from a blood test report and explain what the results mean in plain language.
Strict rules:
- You do NOT diagnose diseases or medical conditions.
- You DO explain what each abnormal value means and its possible general causes.
- You DO flag values that are outside normal reference ranges.
- You DO recommend consulting a physician when findings are significant.
- You are factual, calm, and easy to understand.
Always respond using the following exact markdown structure. Do not skip any section.
---
## 🔬 Blood Test Summary
List every biomarker you detected in the report as a markdown table with these columns:
| Biomarker | Patient Value | Normal Range | Status |
Use ✅ for normal, ⚠️ for mildly abnormal, and 🔴 for significantly abnormal in the
Status column. If you cannot detect a specific normal range from the report, use widely
accepted adult reference ranges.
---
## ⚠️ Concerning Findings
For each flagged value (⚠️ or 🔴), write a short paragraph explaining:
- What this biomarker measures
- What a high or low value generally indicates
- Why it matters for overall health
Do not diagnose. Use phrases like "may suggest", "can be associated with", or
"warrants further evaluation."
If all values are normal, write: "All detected values are within normal ranges.
No concerning findings identified."
---
## 🏥 When to See a Doctor
Based on the flagged findings, clearly state:
- Whether this report requires urgent medical attention (yes / no / monitor)
- Which specific findings are most important to discuss with a physician and why
- Any combination of abnormal values that together may indicate something noteworthy
Keep this section direct and practical.
---
## 💚 Routine Health Practices
Suggest 4–6 evidence-based lifestyle practices relevant to the flagged findings. These
should be actionable and specific, paired with a one-line explanation of why they help,
and clearly framed as general wellness advice, not treatment.
Format as a numbered list.
---
End your response after the health practices section.
"""
Step 5 — Build the Analysis Pipeline and Gradio App
Create app.py to integrate the components and build the web application.
import os
import requests
import gradio as gr
from dotenv import load_dotenv
from extract import extract_text
load_dotenv()
INFERENCE_URL = os.getenv("DO_INFERENCE_URL", "")
API_TOKEN = os.getenv("DO_INFERENCE_TOKEN", "")
MODEL_NAME = os.getenv("MODEL_NAME", "Qwen/Qwen3-8B")
def analyze_report(extracted_text: str) -> str:
if not API_TOKEN:
return "❌ Configuration error: `DO_INFERENCE_TOKEN` is not set in your `.env` file."
if not extracted_text or not extracted_text.strip():
return "❌ No text could be extracted from the uploaded file."
headers = {
"Authorization": f"Bearer {API_TOKEN}",
"Content-Type": "application/json",
}
payload = {
"model": MODEL_NAME,
"messages": [
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": f"Here is the blood test report text:\n\n{extracted_text}"}
],
"temperature": 0.1,
"max_tokens": 2000,
}
try:
response = requests.post(INFERENCE_URL, headers=headers, json=payload, timeout=60)
response.raise_for_status()
return response.json()["choices"][0]["message"]["content"]
except requests.exceptions.Timeout:
return "❌ Request timed out. The inference endpoint took too long to respond. Please try again."
except requests.exceptions.HTTPError as e:
status = e.response.status_code
if status == 401:
return "❌ Authentication failed. Check that your `DO_INFERENCE_TOKEN` is correct."
elif status == 429:
return "❌ Rate limit hit. Wait a moment and try again."
else:
return f"❌ HTTP error {status}: {e.response.text}"
except Exception as e:
return f"❌ Unexpected error: {str(e)}"
def process_report(file_path: str) -> tuple[str, str]:
if file_path is None:
return "", "Please upload a blood test report to get started."
extracted = extract_text(file_path)
error_prefixes = (
"Could not extract", "OCR could not", "PDF extraction error",
"Image OCR error", "Unsupported"
)
if any(extracted.startswith(p) for p in error_prefixes):
return extracted, f"❌ Extraction failed: {extracted}"
analysis = analyze_report(extracted)
return extracted, analysis
def build_ui() -> gr.Blocks:
with gr.Blocks(title="Blood Test Analyzer", theme=gr.themes.Soft()) as app:
gr.Markdown("""
# 🩸 Blood Test Analyzer
Upload your blood test report as a **PDF** or **photo** (JPG/PNG).
The analyzer extracts your results and explains what they mean — flagging anything
outside normal ranges and suggesting when to see a doctor.
> ⚠️ **Disclaimer:** This tool is for informational purposes only. It does not
> provide medical diagnoses or replace professional medical advice.
""")
with gr.Row():
with gr.Column(scale=1):
file_input = gr.File(
label="Upload Blood Test Report",
file_types=[".pdf", ".jpg", ".jpeg", ".png", ".tiff", ".bmp", ".webp"],
type="filepath",
)
analyze_btn = gr.Button("🔍 Analyze Report", variant="primary", size="lg")
with gr.Accordion("📄 Extracted Text (debug)", open=False):
extracted_output = gr.Textbox(
label="Raw extracted text",
lines=12,
interactive=False,
)
with gr.Column(scale=2):
analysis_output = gr.Markdown(
value="Your analysis will appear here after you upload a report and click **Analyze Report**."
)
analyze_btn.click(
fn=process_report,
inputs=[file_input],
outputs=[extracted_output, analysis_output],
show_progress="full",
)
gr.Markdown("""
---
Built with Gradio · Powered by Qwen3-8B on Dedicated Inference
""")
return app
if __name__ == "__main__":
ui = build_ui()
ui.launch(
server_name="0.0.0.0",
server_port=7860,
share=False,
)
Step 6 — Run and Test the Application
Start the application:
python app.py
Open your browser to http://localhost:7860 to view the interface. Test the full pipeline by uploading a sample blood test report in PDF or image format. The tool should identify and explain any abnormalities, offer recommendations, and suggest health practices.
Step 7 — Deploy the Application
To deploy the application in a production environment:
- Push your code to a repository.
- Create a new application and connect your repository.
- Configure environment variables, including your inference endpoint and API credentials.
- Deploy and test the application.
- Optionally, set up a custom domain and enable HTTPS.
By deploying on dedicated infrastructure, sensitive data is processed securely and privately, providing a robust foundation for healthcare applications.
FAQs
What is Dedicated Inference?
Dedicated Inference is a managed service for deploying AI models on dedicated GPU infrastructure, providing predictable performance and enhanced privacy.
Why use Dedicated Inference?
It is ideal for applications with consistent traffic, requiring predictable latency, dedicated resources, or meeting privacy standards.
Why choose Qwen3-8B?
Qwen3-8B balances model quality with deployment cost, effectively analyzing medical report text while being efficient for production on dedicated GPUs.
Can the application analyze both PDFs and images?
Yes, it supports both formats, extracting text using pdfplumber for PDFs and Tesseract OCR for images.
Is patient data sent over the public internet?
If deployed within the same private network, data remains secure without exposure to the public internet.
Can I use a different language model?
Yes, you can import different models from repositories or storage to replace Qwen3-8B.
Is this application intended to replace medical professionals?
No, it aims to help users understand their reports better, not serve as a substitute for professional medical advice.
How can this project be extended?
Enhancements could include support for more medical documents, integration with patient history, trend analysis, authentication, and creating a conversational assistant for follow-up questions.
Conclusion
Congratulations on building a medical report analyzer. This application processes blood test PDFs and images, extracting text with pdfplumber and Tesseract OCR, and sends the content to a model for analysis. You now have a solid foundation for further developing advanced healthcare AI applications.