docxpert / app.py
adil9858's picture
Create app.py
62cf059 verified
import gradio as gr
from openai import OpenAI
import base64
from PIL import Image
import io
import json
# Initialize OpenAI client
client = OpenAI(
base_url="https://integrate.api.nvidia.com/v1",
api_key="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"
)
# Custom CSS for styling
css = """
.test-card {
border-left: 4px solid #4a90e2;
padding: 1rem;
margin-bottom: 1rem;
background-color: #ffffff;
border-radius: 8px;
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
}
.test-card h4 {
color: #2c3e50;
margin-top: 0;
margin-bottom: 0.5rem;
}
.test-card p {
color: #333333;
margin-bottom: 0.25rem;
}
.critical {
background-color: #ffebee;
color: #c62828;
font-weight: bold;
padding: 0.1rem 0.3rem;
border-radius: 3px;
}
.abnormal {
background-color: #fff8e1;
color: #ff8f00;
padding: 0.1rem 0.3rem;
border-radius: 3px;
}
.normal {
background-color: #e8f5e9;
color: #2e7d32;
padding: 0.1rem 0.3rem;
border-radius: 3px;
}
.summary-card {
background-color: #e3f2fd;
padding: 1rem;
border-radius: 8px;
margin-bottom: 1rem;
border-left: 4px solid #1565c0;
}
.summary-card h4 {
color: #0d47a1;
}
"""
# Prompt templates
def get_prompt_template(mode, rtype):
base_prompt = {
"Standard Report": """Extract all key information from this test report in structured JSON format...""",
"Detailed Analysis": """Analyze this test report thoroughly and provide...""",
"Comparative Assessment": """Perform comparative analysis of this test report including..."""
}
type_specific = {
"Medical/Lab": " Focus on clinical significance and health implications.",
"Academic": " Analyze performance patterns and competency areas.",
"Technical": " Evaluate against technical specifications and tolerances.",
"Other": ""
}
return base_prompt[mode] + type_specific[rtype]
def analyze_report(file, analysis_mode, report_type):
# Process the uploaded file
if file is None:
return "Please upload a file first", None, None
# Convert image to base64 if it's an image
if file.name.lower().endswith(('.jpg', '.jpeg', '.png')):
image = Image.open(file)
buffered = io.BytesIO()
image.save(buffered, format="JPEG")
image_b64 = base64.b64encode(buffered.getvalue()).decode('utf-8')
media_content = { "type": "image_url", "image_url": { "url": f"data:image/png;base64,{image_b64}" } }
else:
media_content = { "type": "text", "text": "PDF content extraction placeholder" }
# Get appropriate prompt
user_prompt = get_prompt_template(analysis_mode, report_type)
# Call the API
completion = client.chat.completions.create(
model="nvidia/llama-3.1-nemotron-nano-vl-8b-v1",
messages=[
{
"role": "system",
"content": "You are an expert test report analyzer. Provide accurate, detailed analysis of reports in valid JSON format."
},
{
"role": "user",
"content": [
media_content,
{ "type": "text", "text": user_prompt }
]
}
],
temperature=0.2,
top_p=0.01,
max_tokens=2500
)
full_response = completion.choices[0].message.content
# Try to parse the JSON response
try:
json_start = full_response.find('{')
json_end = full_response.rfind('}') + 1
json_str = full_response[json_start:json_end]
parsed_data = json.loads(json_str)
# Generate HTML output for display
html_output = generate_html_output(parsed_data)
return full_response, html_output, parsed_data.get('summary', 'No summary available')
except Exception as e:
return f"Error parsing response: {str(e)}", None, None
def generate_html_output(parsed_data):
html = "<div style='font-family: Arial, sans-serif;'>"
# Metadata
metadata = parsed_data.get('metadata', {})
html += "<div style='display: flex; margin-bottom: 20px;'>"
html += f"<div style='flex: 1;'><b>Patient/Subject:</b> {metadata.get('patient_name', 'Not identified')}</div>"
html += f"<div style='flex: 1;'><b>Report Date:</b> {metadata.get('report_date', 'Unknown')}</div>"
# Status
findings = parsed_data.get('results', parsed_data.get('findings', []))
abnormal_count = sum(1 for f in findings if f.get('status', '') in ['abnormal', 'critical'])
status = "critical" if any(f.get('status', '') == 'critical' for f in findings) else "abnormal" if abnormal_count > 0 else "normal"
status_class = f"class='{status}'" if status in ['critical', 'abnormal', 'normal'] else ""
html += f"<div style='flex: 1;'><b>Status:</b> <span {status_class}>{status.upper()}</span></div>"
html += "</div>"
# Findings
html += "<h3>Test Results</h3>"
if findings:
for finding in findings:
status_class = finding.get('status', 'normal')
html += f"""
<div class='test-card'>
<h4>{finding.get('test_name', 'Unnamed Test')}</h4>
<p><b>Value:</b> <span class='{status_class}'>{finding.get('value', '')} {finding.get('unit', '')}</span></p>
<p><b>Normal range:</b> {finding.get('normal_range', '')}</p>
<p><b>Interpretation:</b> {finding.get('interpretation', '')}</p>
</div>
"""
else:
html += "<p>No test results were extracted from this report</p>"
# Summary and recommendations
if 'assessment' in parsed_data or 'summary' in parsed_data:
assessment = parsed_data.get('assessment', {})
summary = assessment.get('summary', parsed_data.get('summary', ''))
if summary:
html += f"""
<div class='summary-card'>
<h4>Summary</h4>
<p>{summary}</p>
</div>
"""
if 'recommendations' in assessment and assessment['recommendations']:
html += "<h4>Recommendations</h4><ul>"
for rec in assessment['recommendations']:
html += f"<li>{rec}</li>"
html += "</ul>"
html += "</div>"
return html
# Gradio interface
with gr.Blocks(css=css) as demo:
gr.Markdown("""
# Koshur AI Test Report Analyzer
Advanced analysis of medical, laboratory, and academic test reports.
Identify key findings, anomalies, and generate insights automatically.
""")
with gr.Row():
with gr.Column():
file_input = gr.File(label="Upload Test Report", file_types=[".jpg", ".jpeg", ".png", ".pdf"])
analysis_mode = gr.Dropdown(
label="Analysis Mode",
choices=["Standard Report", "Detailed Analysis", "Comparative Assessment"],
value="Standard Report"
)
report_type = gr.Dropdown(
label="Report Type",
choices=["Medical/Lab", "Academic", "Technical", "Other"],
value="Medical/Lab"
)
analyze_btn = gr.Button("Analyze Report", variant="primary")
with gr.Column():
json_output = gr.Textbox(label="Raw JSON Output", interactive=False)
html_output = gr.HTML(label="Analysis Results")
summary_output = gr.Textbox(label="Summary", interactive=False)
analyze_btn.click(
fn=analyze_report,
inputs=[file_input, analysis_mode, report_type],
outputs=[json_output, html_output, summary_output]
)
# Run the app
if __name__ == "__main__":
demo.launch()