Spaces:
Sleeping
Sleeping
YanBoChen
commited on
Commit
Β·
87da2f6
1
Parent(s):
6577369
Add high-resolution ASCII diagram converter for academic presentations
Browse files- tests/ascii_png.py +194 -0
- tests/ascii_png_5steps_general_pipeline.py +144 -0
- tests/ascii_png_chunk.py +130 -0
- tests/ascii_png_template.py +130 -0
tests/ascii_png.py
ADDED
|
@@ -0,0 +1,194 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""
|
| 3 |
+
Improved ASCII to High-Resolution Image Converter
|
| 4 |
+
Optimized for academic conferences (NeurIPS) with fallback font support
|
| 5 |
+
"""
|
| 6 |
+
|
| 7 |
+
from PIL import Image, ImageDraw, ImageFont
|
| 8 |
+
import os
|
| 9 |
+
from pathlib import Path
|
| 10 |
+
|
| 11 |
+
def create_ascii_diagram(ascii_text: str, output_path: str = "oncall_ai_flowchart.png") -> bool:
|
| 12 |
+
"""
|
| 13 |
+
Convert ASCII diagram to high-resolution image with academic quality
|
| 14 |
+
|
| 15 |
+
Args:
|
| 16 |
+
ascii_text: ASCII art text content
|
| 17 |
+
output_path: Output PNG file path
|
| 18 |
+
|
| 19 |
+
Returns:
|
| 20 |
+
Boolean indicating success
|
| 21 |
+
"""
|
| 22 |
+
|
| 23 |
+
# Font selection with fallback options
|
| 24 |
+
font_paths = [
|
| 25 |
+
"/System/Library/Fonts/SFNSMono.ttf", # macOS Big Sur+
|
| 26 |
+
"/System/Library/Fonts/Monaco.ttf", # macOS fallback
|
| 27 |
+
"/System/Library/Fonts/Menlo.ttf", # macOS alternative
|
| 28 |
+
"/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf", # Linux
|
| 29 |
+
"C:/Windows/Fonts/consola.ttf", # Windows
|
| 30 |
+
None # PIL default font fallback
|
| 31 |
+
]
|
| 32 |
+
|
| 33 |
+
font = None
|
| 34 |
+
font_size = 14 # Slightly smaller for better readability
|
| 35 |
+
|
| 36 |
+
# Try fonts in order of preference
|
| 37 |
+
for font_path in font_paths:
|
| 38 |
+
try:
|
| 39 |
+
if font_path is None:
|
| 40 |
+
font = ImageFont.load_default()
|
| 41 |
+
print("π€ Using PIL default font")
|
| 42 |
+
break
|
| 43 |
+
elif os.path.exists(font_path):
|
| 44 |
+
font = ImageFont.truetype(font_path, font_size)
|
| 45 |
+
print(f"β
Using font: {font_path}")
|
| 46 |
+
break
|
| 47 |
+
except Exception as e:
|
| 48 |
+
print(f"β οΈ Font loading failed: {font_path} - {e}")
|
| 49 |
+
continue
|
| 50 |
+
|
| 51 |
+
if font is None:
|
| 52 |
+
print("β No suitable font found")
|
| 53 |
+
return False
|
| 54 |
+
|
| 55 |
+
# Process text lines
|
| 56 |
+
lines = ascii_text.strip().split("\n")
|
| 57 |
+
lines = [line.rstrip() for line in lines] # Remove trailing whitespace
|
| 58 |
+
|
| 59 |
+
# Calculate dimensions using modern PIL methods
|
| 60 |
+
try:
|
| 61 |
+
# Modern Pillow 10.0+ method
|
| 62 |
+
line_metrics = [font.getbbox(line) for line in lines]
|
| 63 |
+
max_width = max([metrics[2] - metrics[0] for metrics in line_metrics])
|
| 64 |
+
line_height = max([metrics[3] - metrics[1] for metrics in line_metrics])
|
| 65 |
+
except AttributeError:
|
| 66 |
+
# Fallback for older Pillow versions
|
| 67 |
+
try:
|
| 68 |
+
line_sizes = [font.getsize(line) for line in lines]
|
| 69 |
+
max_width = max([size[0] for size in line_sizes])
|
| 70 |
+
line_height = max([size[1] for size in line_sizes])
|
| 71 |
+
except AttributeError:
|
| 72 |
+
# Ultimate fallback
|
| 73 |
+
max_width = len(max(lines, key=len)) * font_size * 0.6
|
| 74 |
+
line_height = font_size * 1.2
|
| 75 |
+
|
| 76 |
+
# Image dimensions with padding
|
| 77 |
+
padding = 40
|
| 78 |
+
img_width = int(max_width + padding * 2)
|
| 79 |
+
img_height = int(line_height * len(lines) + padding * 2)
|
| 80 |
+
|
| 81 |
+
print(f"π Image dimensions: {img_width} x {img_height}")
|
| 82 |
+
print(f"π Max line width: {max_width}, Line height: {line_height}")
|
| 83 |
+
|
| 84 |
+
# Create high-resolution image
|
| 85 |
+
img = Image.new("RGB", (img_width, img_height), "white")
|
| 86 |
+
draw = ImageDraw.Draw(img)
|
| 87 |
+
|
| 88 |
+
# Draw text lines
|
| 89 |
+
for i, line in enumerate(lines):
|
| 90 |
+
y_pos = padding + i * line_height
|
| 91 |
+
draw.text((padding, y_pos), line, font=font, fill="black")
|
| 92 |
+
|
| 93 |
+
# Save with high DPI for academic use
|
| 94 |
+
try:
|
| 95 |
+
img.save(output_path, dpi=(300, 300), optimize=True)
|
| 96 |
+
print(f"β
High-resolution diagram saved: {output_path}")
|
| 97 |
+
print(f"π Image size: {img_width}x{img_height} at 300 DPI")
|
| 98 |
+
return True
|
| 99 |
+
except Exception as e:
|
| 100 |
+
print(f"β Failed to save image: {e}")
|
| 101 |
+
return False
|
| 102 |
+
|
| 103 |
+
# Example usage with your OnCall.ai flowchart
|
| 104 |
+
if __name__ == "__main__":
|
| 105 |
+
|
| 106 |
+
# Your OnCall.ai ASCII flowchart
|
| 107 |
+
oncall_ascii = """
|
| 108 |
+
+-------------------------------------------------------+-------------------------------------------------------------+
|
| 109 |
+
| User Query | Pipeline Architecture Overview |
|
| 110 |
+
| (Medical emergency question) | 5-Level Fallback System Design |
|
| 111 |
+
+-------------------------------------------------------+-------------------------------------------------------------+
|
| 112 |
+
|
|
| 113 |
+
v
|
| 114 |
+
+-------------------------------------------------------+-------------------------------------------------------------+
|
| 115 |
+
| π― Level 1: Predefined Mapping | [High Precision, Low Coverage] |
|
| 116 |
+
| +---------------------------------------------------+ | β Handles common, well-defined conditions |
|
| 117 |
+
| | β’ Direct condition mapping (medical_conditions.py)| | |
|
| 118 |
+
| | β’ Regex pattern matching | | Examples: |
|
| 119 |
+
| | β’ Instant response for known conditions | | β’ "chest pain" β acute coronary syndrome |
|
| 120 |
+
| | β’ Processing time: ~0.001s | | β’ "stroke symptoms" β acute stroke |
|
| 121 |
+
| +---------------------------------------------------+ | β’ "heart attack" β myocardial infarction |
|
| 122 |
+
+-------------------------------------------------------+-------------------------------------------------------------+
|
| 123 |
+
|
|
| 124 |
+
[if fails]
|
| 125 |
+
v
|
| 126 |
+
+-------------------------------------------------------+-------------------------------------------------------------+
|
| 127 |
+
| π€ Level 2+4: LLM Analysis (Combined) | [Medium Precision, Medium Coverage] |
|
| 128 |
+
| +---------------------------------------------------+ | β Handles complex queries understandable by AI |
|
| 129 |
+
| | β’ Single Med42-70B call for dual tasks | | |
|
| 130 |
+
| | β’ Extract condition + Validate medical query | | Examples: |
|
| 131 |
+
| | β’ 40% time optimization (25s β 15s) | | β’ "elderly patient with multiple symptoms" |
|
| 132 |
+
| | β’ Processing time: 12-15s | | β’ "complex cardiovascular presentation" |
|
| 133 |
+
| +---------------------------------------------------+ | β’ "differential diagnosis for confusion" |
|
| 134 |
+
+-------------------------------------------------------+-------------------------------------------------------------+
|
| 135 |
+
| |
|
| 136 |
+
[condition found] [medical but no condition]
|
| 137 |
+
| |
|
| 138 |
+
| v
|
| 139 |
+
| +-------------------------------------------------------+-------------------------------------------------------------+
|
| 140 |
+
| | π Level 3: Semantic Search | [Medium Precision, High Coverage] |
|
| 141 |
+
| | +---------------------------------------------------+ | β Handles semantically similar, vague queries |
|
| 142 |
+
| | | β’ PubMedBERT embeddings (768 dimensions) | | |
|
| 143 |
+
| | | β’ Angular distance calculation | | Examples: |
|
| 144 |
+
| | | β’ Sliding window chunk search | | β’ "feeling unwell with breathing issues" |
|
| 145 |
+
| | | β’ Processing time: 1-2s | | β’ "patient experiencing discomfort" |
|
| 146 |
+
| | +---------------------------------------------------+ | β’ "concerning symptoms in elderly" |
|
| 147 |
+
| +-------------------------------------------------------+-------------------------------------------------------------+
|
| 148 |
+
| |
|
| 149 |
+
| [if fails]
|
| 150 |
+
| v
|
| 151 |
+
| +-------------------------------------------------------+-------------------------------------------------------------+
|
| 152 |
+
| | β
Level 4: Medical Validation | [Low Precision, Filtering] |
|
| 153 |
+
| | +---------------------------------------------------+ | β Ensures queries are medically relevant |
|
| 154 |
+
| | | β’ Medical keyword validation | | |
|
| 155 |
+
| | | β’ LLM-based medical query confirmation | | Examples: |
|
| 156 |
+
| | | β’ Non-medical query rejection | | β’ Rejects: "how to cook pasta" |
|
| 157 |
+
| | | β’ Processing time: <1s | | β’ Accepts: "persistent headache" |
|
| 158 |
+
| | +---------------------------------------------------+ | β’ Filters: "car repair" vs "chest pain" |
|
| 159 |
+
| +-------------------------------------------------------+-------------------------------------------------------------+
|
| 160 |
+
| |
|
| 161 |
+
| [if passes]
|
| 162 |
+
| v
|
| 163 |
+
| +-------------------------------------------------------+-------------------------------------------------------------+
|
| 164 |
+
| | π₯ Level 5: Generic Medical Search | [Low Precision, Full Coverage] |
|
| 165 |
+
| | +---------------------------------------------------+ | β Final fallback; always provides an answer |
|
| 166 |
+
| | | β’ Broad medical content search | | |
|
| 167 |
+
| | | β’ Generic medical terminology matching | | Examples: |
|
| 168 |
+
| | | β’ Always provides medical guidance | | β’ "I don't feel well" β general advice |
|
| 169 |
+
| | | β’ Processing time: ~1s | | β’ "something wrong" β seek medical care |
|
| 170 |
+
| | +---------------------------------------------------+ | β’ "health concern" β basic guidance |
|
| 171 |
+
| +-------------------------------------------------------+-------------------------------------------------------------+
|
| 172 |
+
| |
|
| 173 |
+
+βββββββββββββββββββββββββββββββββ+
|
| 174 |
+
|
|
| 175 |
+
v
|
| 176 |
+
+-------------------------------------------------------+-------------------------------------------------------------+
|
| 177 |
+
| π Medical Response | System Performance Metrics |
|
| 178 |
+
| +---------------------------------------------------+ | |
|
| 179 |
+
| | β’ Evidence-based clinical advice | | β’ Average pipeline time: 15.5s |
|
| 180 |
+
| | β’ Retrieved medical guidelines (8-9 per query) | | β’ Condition extraction: 2.6s average |
|
| 181 |
+
| | β’ Confidence scoring and citations | | β’ Retrieval relevance: 0.245-0.326 |
|
| 182 |
+
| | β’ 100% coverage guarantee | | β’ Overall success rate: 69.2% |
|
| 183 |
+
| +---------------------------------------------------+ | β’ Clinical actionability: 9.0/10 (RAG) |
|
| 184 |
+
+-------------------------------------------------------+-------------------------------------------------------------+
|
| 185 |
+
"""
|
| 186 |
+
|
| 187 |
+
# Execute conversion
|
| 188 |
+
success = create_ascii_diagram(oncall_ascii, "5_layer_fallback.png")
|
| 189 |
+
|
| 190 |
+
if success:
|
| 191 |
+
print("\nπ Ready for NeurIPS presentation!")
|
| 192 |
+
print("π‘ You can now insert this high-quality diagram into your paper or poster")
|
| 193 |
+
else:
|
| 194 |
+
print("\nβ Conversion failed - check font availability")
|
tests/ascii_png_5steps_general_pipeline.py
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""
|
| 3 |
+
Improved ASCII to High-Resolution Image Converter
|
| 4 |
+
Optimized for academic conferences (NeurIPS) with fallback font support
|
| 5 |
+
"""
|
| 6 |
+
|
| 7 |
+
from PIL import Image, ImageDraw, ImageFont
|
| 8 |
+
import os
|
| 9 |
+
from pathlib import Path
|
| 10 |
+
|
| 11 |
+
def create_ascii_diagram(ascii_text: str, output_path: str = "oncall_ai_flowchart.png") -> bool:
|
| 12 |
+
"""
|
| 13 |
+
Convert ASCII diagram to high-resolution image with academic quality
|
| 14 |
+
|
| 15 |
+
Args:
|
| 16 |
+
ascii_text: ASCII art text content
|
| 17 |
+
output_path: Output PNG file path
|
| 18 |
+
|
| 19 |
+
Returns:
|
| 20 |
+
Boolean indicating success
|
| 21 |
+
"""
|
| 22 |
+
|
| 23 |
+
# Font selection with fallback options
|
| 24 |
+
font_paths = [
|
| 25 |
+
"/System/Library/Fonts/SFNSMono.ttf", # macOS Big Sur+
|
| 26 |
+
"/System/Library/Fonts/Monaco.ttf", # macOS fallback
|
| 27 |
+
"/System/Library/Fonts/Menlo.ttf", # macOS alternative
|
| 28 |
+
"/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf", # Linux
|
| 29 |
+
"C:/Windows/Fonts/consola.ttf", # Windows
|
| 30 |
+
None # PIL default font fallback
|
| 31 |
+
]
|
| 32 |
+
|
| 33 |
+
font = None
|
| 34 |
+
font_size = 14 # Slightly smaller for better readability
|
| 35 |
+
|
| 36 |
+
# Try fonts in order of preference
|
| 37 |
+
for font_path in font_paths:
|
| 38 |
+
try:
|
| 39 |
+
if font_path is None:
|
| 40 |
+
font = ImageFont.load_default()
|
| 41 |
+
print("π€ Using PIL default font")
|
| 42 |
+
break
|
| 43 |
+
elif os.path.exists(font_path):
|
| 44 |
+
font = ImageFont.truetype(font_path, font_size)
|
| 45 |
+
print(f"β
Using font: {font_path}")
|
| 46 |
+
break
|
| 47 |
+
except Exception as e:
|
| 48 |
+
print(f"β οΈ Font loading failed: {font_path} - {e}")
|
| 49 |
+
continue
|
| 50 |
+
|
| 51 |
+
if font is None:
|
| 52 |
+
print("β No suitable font found")
|
| 53 |
+
return False
|
| 54 |
+
|
| 55 |
+
# Process text lines
|
| 56 |
+
lines = ascii_text.strip().split("\n")
|
| 57 |
+
lines = [line.rstrip() for line in lines] # Remove trailing whitespace
|
| 58 |
+
|
| 59 |
+
# Calculate dimensions using modern PIL methods
|
| 60 |
+
try:
|
| 61 |
+
# Modern Pillow 10.0+ method
|
| 62 |
+
line_metrics = [font.getbbox(line) for line in lines]
|
| 63 |
+
max_width = max([metrics[2] - metrics[0] for metrics in line_metrics])
|
| 64 |
+
line_height = max([metrics[3] - metrics[1] for metrics in line_metrics])
|
| 65 |
+
except AttributeError:
|
| 66 |
+
# Fallback for older Pillow versions
|
| 67 |
+
try:
|
| 68 |
+
line_sizes = [font.getsize(line) for line in lines]
|
| 69 |
+
max_width = max([size[0] for size in line_sizes])
|
| 70 |
+
line_height = max([size[1] for size in line_sizes])
|
| 71 |
+
except AttributeError:
|
| 72 |
+
# Ultimate fallback
|
| 73 |
+
max_width = len(max(lines, key=len)) * font_size * 0.6
|
| 74 |
+
line_height = font_size * 1.2
|
| 75 |
+
|
| 76 |
+
# Image dimensions with padding
|
| 77 |
+
padding = 40
|
| 78 |
+
img_width = int(max_width + padding * 2)
|
| 79 |
+
img_height = int(line_height * len(lines) + padding * 2)
|
| 80 |
+
|
| 81 |
+
print(f"π Image dimensions: {img_width} x {img_height}")
|
| 82 |
+
print(f"π Max line width: {max_width}, Line height: {line_height}")
|
| 83 |
+
|
| 84 |
+
# Create high-resolution image
|
| 85 |
+
img = Image.new("RGB", (img_width, img_height), "white")
|
| 86 |
+
draw = ImageDraw.Draw(img)
|
| 87 |
+
|
| 88 |
+
# Draw text lines
|
| 89 |
+
for i, line in enumerate(lines):
|
| 90 |
+
y_pos = padding + i * line_height
|
| 91 |
+
draw.text((padding, y_pos), line, font=font, fill="black")
|
| 92 |
+
|
| 93 |
+
# Save with high DPI for academic use
|
| 94 |
+
try:
|
| 95 |
+
img.save(output_path, dpi=(300, 300), optimize=True)
|
| 96 |
+
print(f"β
High-resolution diagram saved: {output_path}")
|
| 97 |
+
print(f"π Image size: {img_width}x{img_height} at 300 DPI")
|
| 98 |
+
return True
|
| 99 |
+
except Exception as e:
|
| 100 |
+
print(f"β Failed to save image: {e}")
|
| 101 |
+
return False
|
| 102 |
+
|
| 103 |
+
# Example usage with your OnCall.ai flowchart
|
| 104 |
+
if __name__ == "__main__":
|
| 105 |
+
|
| 106 |
+
# Your OnCall.ai ASCII flowchart
|
| 107 |
+
oncall_ascii = """
|
| 108 |
+
+---------------------------------------------------+-------------------------------------------------------------+
|
| 109 |
+
| User Input | 1. STEP 1: Condition Extraction |
|
| 110 |
+
| β | - Processes user input through 5-level fallback |
|
| 111 |
+
| STEP 1: Condition Extraction (5-level fallback) | - Extracts medical conditions and keywords |
|
| 112 |
+
| β | - Handles complex symptom descriptions & terminology |
|
| 113 |
+
| STEP 2: System Understanding Display (Transparent)|-------------------------------------------------------------|
|
| 114 |
+
| β | 2. STEP 2: System Understanding Display |
|
| 115 |
+
| STEP 3: Medical Guidelines Retrieval | - Shows transparent interpretation of user query |
|
| 116 |
+
| β | - No user interaction required |
|
| 117 |
+
| STEP 4: Evidence-based Advice Generation | - Builds confidence in system understanding |
|
| 118 |
+
| β |-------------------------------------------------------------|
|
| 119 |
+
| STEP 5: Performance Summary & Technical Details | 3. STEP 3: Medical Guidelines Retrieval |
|
| 120 |
+
| β | - Searches dual-index system (emergency + treatment) |
|
| 121 |
+
| Multi-format Output | - Returns 8-9 relevant guidelines per query |
|
| 122 |
+
| (Advice + Guidelines + Metrics) | - Maintains emergency/treatment balance |
|
| 123 |
+
| |-------------------------------------------------------------|
|
| 124 |
+
| | 4. STEP 4: Evidence-based Advice Generation |
|
| 125 |
+
| | - Uses RAG-based prompt construction |
|
| 126 |
+
| | - Integrates specialized medical LLM (Med42-70B) |
|
| 127 |
+
| | - Generates clinically appropriate guidance |
|
| 128 |
+
| |-------------------------------------------------------------|
|
| 129 |
+
| | 5. STEP 5: Performance Summary |
|
| 130 |
+
| | - Aggregates timing and confidence metrics |
|
| 131 |
+
| | - Provides technical metadata for transparency |
|
| 132 |
+
| | - Enables system performance monitoring |
|
| 133 |
+
+---------------------------------------------------+-------------------------------------------------------------+
|
| 134 |
+
| General Pipeline 5 steps Mechanism Overview |
|
| 135 |
+
"""
|
| 136 |
+
|
| 137 |
+
# Execute conversion
|
| 138 |
+
success = create_ascii_diagram(oncall_ascii, "5level_general_pipeline.png")
|
| 139 |
+
|
| 140 |
+
if success:
|
| 141 |
+
print("\nπ Ready for NeurIPS presentation!")
|
| 142 |
+
print("π‘ You can now insert this high-quality diagram into your paper or poster")
|
| 143 |
+
else:
|
| 144 |
+
print("\nβ Conversion failed - check font availability")
|
tests/ascii_png_chunk.py
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""
|
| 3 |
+
Improved ASCII to High-Resolution Image Converter
|
| 4 |
+
Optimized for academic conferences (NeurIPS) with fallback font support
|
| 5 |
+
"""
|
| 6 |
+
|
| 7 |
+
from PIL import Image, ImageDraw, ImageFont
|
| 8 |
+
import os
|
| 9 |
+
from pathlib import Path
|
| 10 |
+
|
| 11 |
+
def create_ascii_diagram(ascii_text: str, output_path: str = "oncall_ai_flowchart.png") -> bool:
|
| 12 |
+
"""
|
| 13 |
+
Convert ASCII diagram to high-resolution image with academic quality
|
| 14 |
+
|
| 15 |
+
Args:
|
| 16 |
+
ascii_text: ASCII art text content
|
| 17 |
+
output_path: Output PNG file path
|
| 18 |
+
|
| 19 |
+
Returns:
|
| 20 |
+
Boolean indicating success
|
| 21 |
+
"""
|
| 22 |
+
|
| 23 |
+
# Font selection with fallback options
|
| 24 |
+
font_paths = [
|
| 25 |
+
"/System/Library/Fonts/SFNSMono.ttf", # macOS Big Sur+
|
| 26 |
+
"/System/Library/Fonts/Monaco.ttf", # macOS fallback
|
| 27 |
+
"/System/Library/Fonts/Menlo.ttf", # macOS alternative
|
| 28 |
+
"/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf", # Linux
|
| 29 |
+
"C:/Windows/Fonts/consola.ttf", # Windows
|
| 30 |
+
None # PIL default font fallback
|
| 31 |
+
]
|
| 32 |
+
|
| 33 |
+
font = None
|
| 34 |
+
font_size = 14 # Slightly smaller for better readability
|
| 35 |
+
|
| 36 |
+
# Try fonts in order of preference
|
| 37 |
+
for font_path in font_paths:
|
| 38 |
+
try:
|
| 39 |
+
if font_path is None:
|
| 40 |
+
font = ImageFont.load_default()
|
| 41 |
+
print("π€ Using PIL default font")
|
| 42 |
+
break
|
| 43 |
+
elif os.path.exists(font_path):
|
| 44 |
+
font = ImageFont.truetype(font_path, font_size)
|
| 45 |
+
print(f"β
Using font: {font_path}")
|
| 46 |
+
break
|
| 47 |
+
except Exception as e:
|
| 48 |
+
print(f"β οΈ Font loading failed: {font_path} - {e}")
|
| 49 |
+
continue
|
| 50 |
+
|
| 51 |
+
if font is None:
|
| 52 |
+
print("β No suitable font found")
|
| 53 |
+
return False
|
| 54 |
+
|
| 55 |
+
# Process text lines
|
| 56 |
+
lines = ascii_text.strip().split("\n")
|
| 57 |
+
lines = [line.rstrip() for line in lines] # Remove trailing whitespace
|
| 58 |
+
|
| 59 |
+
# Calculate dimensions using modern PIL methods
|
| 60 |
+
try:
|
| 61 |
+
# Modern Pillow 10.0+ method
|
| 62 |
+
line_metrics = [font.getbbox(line) for line in lines]
|
| 63 |
+
max_width = max([metrics[2] - metrics[0] for metrics in line_metrics])
|
| 64 |
+
line_height = max([metrics[3] - metrics[1] for metrics in line_metrics])
|
| 65 |
+
except AttributeError:
|
| 66 |
+
# Fallback for older Pillow versions
|
| 67 |
+
try:
|
| 68 |
+
line_sizes = [font.getsize(line) for line in lines]
|
| 69 |
+
max_width = max([size[0] for size in line_sizes])
|
| 70 |
+
line_height = max([size[1] for size in line_sizes])
|
| 71 |
+
except AttributeError:
|
| 72 |
+
# Ultimate fallback
|
| 73 |
+
max_width = len(max(lines, key=len)) * font_size * 0.6
|
| 74 |
+
line_height = font_size * 1.2
|
| 75 |
+
|
| 76 |
+
# Image dimensions with padding
|
| 77 |
+
padding = 40
|
| 78 |
+
img_width = int(max_width + padding * 2)
|
| 79 |
+
img_height = int(line_height * len(lines) + padding * 2)
|
| 80 |
+
|
| 81 |
+
print(f"π Image dimensions: {img_width} x {img_height}")
|
| 82 |
+
print(f"π Max line width: {max_width}, Line height: {line_height}")
|
| 83 |
+
|
| 84 |
+
# Create high-resolution image
|
| 85 |
+
img = Image.new("RGB", (img_width, img_height), "white")
|
| 86 |
+
draw = ImageDraw.Draw(img)
|
| 87 |
+
|
| 88 |
+
# Draw text lines
|
| 89 |
+
for i, line in enumerate(lines):
|
| 90 |
+
y_pos = padding + i * line_height
|
| 91 |
+
draw.text((padding, y_pos), line, font=font, fill="black")
|
| 92 |
+
|
| 93 |
+
# Save with high DPI for academic use
|
| 94 |
+
try:
|
| 95 |
+
img.save(output_path, dpi=(300, 300), optimize=True)
|
| 96 |
+
print(f"β
High-resolution diagram saved: {output_path}")
|
| 97 |
+
print(f"π Image size: {img_width}x{img_height} at 300 DPI")
|
| 98 |
+
return True
|
| 99 |
+
except Exception as e:
|
| 100 |
+
print(f"β Failed to save image: {e}")
|
| 101 |
+
return False
|
| 102 |
+
|
| 103 |
+
# Example usage with your OnCall.ai flowchart
|
| 104 |
+
if __name__ == "__main__":
|
| 105 |
+
|
| 106 |
+
# Your OnCall.ai ASCII flowchart
|
| 107 |
+
oncall_ascii = """
|
| 108 |
+
ββββββββββββββββββββββββββββββββββββββββ ββββββββββββββββββββββββββββββββββββββββ
|
| 109 |
+
β OFFLINE STAGE β β ONLINE STAGE β
|
| 110 |
+
ββββββββββββββββββββββββββββββββββββββββ€ ββββββββββββββββββββββββββββββββββββββββ€
|
| 111 |
+
β data_processing.py β β retrieval.py β
|
| 112 |
+
β β’ Text cleaning β β β’ Query keyword extraction β
|
| 113 |
+
β β’ Keyword-centered chunking β β β’ Vector search β
|
| 114 |
+
β (overlap) β β (emergency / treatment) β
|
| 115 |
+
β β’ Metadata annotation β β β’ Dynamic grouping via metadata β
|
| 116 |
+
β β’ Embedding generation β β β’ Ranking & Top-K selection β
|
| 117 |
+
β β’ Annoy index construction β β β’ Return final results β
|
| 118 |
+
ββββββββββββββββββββββββββββββββββββββββ ββββββββββββββββββββββββββββββββββββββββ
|
| 119 |
+
|
| 120 |
+
| Offline vs. Online responsibility separation |
|
| 121 |
+
"""
|
| 122 |
+
|
| 123 |
+
# Execute conversion
|
| 124 |
+
success = create_ascii_diagram(oncall_ascii, "offline_online_responsibility_separation.png")
|
| 125 |
+
|
| 126 |
+
if success:
|
| 127 |
+
print("\nπ Ready for NeurIPS presentation!")
|
| 128 |
+
print("π‘ You can now insert this high-quality diagram into your paper or poster")
|
| 129 |
+
else:
|
| 130 |
+
print("\nβ Conversion failed - check font availability")
|
tests/ascii_png_template.py
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""
|
| 3 |
+
Improved ASCII to High-Resolution Image Converter
|
| 4 |
+
Optimized for academic conferences (NeurIPS) with fallback font support
|
| 5 |
+
"""
|
| 6 |
+
|
| 7 |
+
from PIL import Image, ImageDraw, ImageFont
|
| 8 |
+
import os
|
| 9 |
+
from pathlib import Path
|
| 10 |
+
|
| 11 |
+
def create_ascii_diagram(ascii_text: str, output_path: str = "oncall_ai_flowchart.png") -> bool:
|
| 12 |
+
"""
|
| 13 |
+
Convert ASCII diagram to high-resolution image with academic quality
|
| 14 |
+
|
| 15 |
+
Args:
|
| 16 |
+
ascii_text: ASCII art text content
|
| 17 |
+
output_path: Output PNG file path
|
| 18 |
+
|
| 19 |
+
Returns:
|
| 20 |
+
Boolean indicating success
|
| 21 |
+
"""
|
| 22 |
+
|
| 23 |
+
# Font selection with fallback options
|
| 24 |
+
font_paths = [
|
| 25 |
+
"/System/Library/Fonts/SFNSMono.ttf", # macOS Big Sur+
|
| 26 |
+
"/System/Library/Fonts/Monaco.ttf", # macOS fallback
|
| 27 |
+
"/System/Library/Fonts/Menlo.ttf", # macOS alternative
|
| 28 |
+
"/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf", # Linux
|
| 29 |
+
"C:/Windows/Fonts/consola.ttf", # Windows
|
| 30 |
+
None # PIL default font fallback
|
| 31 |
+
]
|
| 32 |
+
|
| 33 |
+
font = None
|
| 34 |
+
font_size = 14 # Slightly smaller for better readability
|
| 35 |
+
|
| 36 |
+
# Try fonts in order of preference
|
| 37 |
+
for font_path in font_paths:
|
| 38 |
+
try:
|
| 39 |
+
if font_path is None:
|
| 40 |
+
font = ImageFont.load_default()
|
| 41 |
+
print("π€ Using PIL default font")
|
| 42 |
+
break
|
| 43 |
+
elif os.path.exists(font_path):
|
| 44 |
+
font = ImageFont.truetype(font_path, font_size)
|
| 45 |
+
print(f"β
Using font: {font_path}")
|
| 46 |
+
break
|
| 47 |
+
except Exception as e:
|
| 48 |
+
print(f"β οΈ Font loading failed: {font_path} - {e}")
|
| 49 |
+
continue
|
| 50 |
+
|
| 51 |
+
if font is None:
|
| 52 |
+
print("β No suitable font found")
|
| 53 |
+
return False
|
| 54 |
+
|
| 55 |
+
# Process text lines
|
| 56 |
+
lines = ascii_text.strip().split("\n")
|
| 57 |
+
lines = [line.rstrip() for line in lines] # Remove trailing whitespace
|
| 58 |
+
|
| 59 |
+
# Calculate dimensions using modern PIL methods
|
| 60 |
+
try:
|
| 61 |
+
# Modern Pillow 10.0+ method
|
| 62 |
+
line_metrics = [font.getbbox(line) for line in lines]
|
| 63 |
+
max_width = max([metrics[2] - metrics[0] for metrics in line_metrics])
|
| 64 |
+
line_height = max([metrics[3] - metrics[1] for metrics in line_metrics])
|
| 65 |
+
except AttributeError:
|
| 66 |
+
# Fallback for older Pillow versions
|
| 67 |
+
try:
|
| 68 |
+
line_sizes = [font.getsize(line) for line in lines]
|
| 69 |
+
max_width = max([size[0] for size in line_sizes])
|
| 70 |
+
line_height = max([size[1] for size in line_sizes])
|
| 71 |
+
except AttributeError:
|
| 72 |
+
# Ultimate fallback
|
| 73 |
+
max_width = len(max(lines, key=len)) * font_size * 0.6
|
| 74 |
+
line_height = font_size * 1.2
|
| 75 |
+
|
| 76 |
+
# Image dimensions with padding
|
| 77 |
+
padding = 40
|
| 78 |
+
img_width = int(max_width + padding * 2)
|
| 79 |
+
img_height = int(line_height * len(lines) + padding * 2)
|
| 80 |
+
|
| 81 |
+
print(f"π Image dimensions: {img_width} x {img_height}")
|
| 82 |
+
print(f"π Max line width: {max_width}, Line height: {line_height}")
|
| 83 |
+
|
| 84 |
+
# Create high-resolution image
|
| 85 |
+
img = Image.new("RGB", (img_width, img_height), "white")
|
| 86 |
+
draw = ImageDraw.Draw(img)
|
| 87 |
+
|
| 88 |
+
# Draw text lines
|
| 89 |
+
for i, line in enumerate(lines):
|
| 90 |
+
y_pos = padding + i * line_height
|
| 91 |
+
draw.text((padding, y_pos), line, font=font, fill="black")
|
| 92 |
+
|
| 93 |
+
# Save with high DPI for academic use
|
| 94 |
+
try:
|
| 95 |
+
img.save(output_path, dpi=(300, 300), optimize=True)
|
| 96 |
+
print(f"β
High-resolution diagram saved: {output_path}")
|
| 97 |
+
print(f"π Image size: {img_width}x{img_height} at 300 DPI")
|
| 98 |
+
return True
|
| 99 |
+
except Exception as e:
|
| 100 |
+
print(f"β Failed to save image: {e}")
|
| 101 |
+
return False
|
| 102 |
+
|
| 103 |
+
# Example usage with your OnCall.ai flowchart
|
| 104 |
+
if __name__ == "__main__":
|
| 105 |
+
|
| 106 |
+
# Your OnCall.ai ASCII flowchart
|
| 107 |
+
oncall_ascii = """
|
| 108 |
+
Metric 5: Clinical Actionability (1-10 scale)
|
| 109 |
+
1-2 points: Almost no actionable advice; extremely abstract or empty responses.
|
| 110 |
+
3-4 points: Provides some directional suggestions but too vague, lacks clear steps.
|
| 111 |
+
5-6 points: Offers basic executable steps but lacks details or insufficient explanation for key aspects.
|
| 112 |
+
7-8 points: Clear and complete steps that clinicians can follow, with occasional gaps needing supplementation.
|
| 113 |
+
9-10 points: Extremely actionable with precise, step-by-step executable guidance; can be used "as-is" immediately.
|
| 114 |
+
|
| 115 |
+
Metric 6: Clinical Evidence Quality (1-10 scale)
|
| 116 |
+
1-2 points: Almost no evidence support; cites completely irrelevant or unreliable sources.
|
| 117 |
+
3-4 points: References lower quality literature or guidelines, or sources lack authority.
|
| 118 |
+
5-6 points: Uses general quality literature/guidelines but lacks depth or currency.
|
| 119 |
+
7-8 points: References reliable, authoritative sources (renowned journals or authoritative guidelines) with accurate explanations.
|
| 120 |
+
9-10 points: Rich and high-quality evidence sources (systematic reviews, RCTs, etc.) combined with latest research; enhances recommendation credibility.
|
| 121 |
+
"""
|
| 122 |
+
|
| 123 |
+
# Execute conversion
|
| 124 |
+
success = create_ascii_diagram(oncall_ascii, "Metric5_6.png")
|
| 125 |
+
|
| 126 |
+
if success:
|
| 127 |
+
print("\nπ Ready for NeurIPS presentation!")
|
| 128 |
+
print("π‘ You can now insert this high-quality diagram into your paper or poster")
|
| 129 |
+
else:
|
| 130 |
+
print("\nβ Conversion failed - check font availability")
|