""" Analysis View Component - Main analysis interface with input and results """ import gradio as gr import re from typing import Optional def parse_markdown(text: str) -> str: """Convert basic markdown to HTML""" text = re.sub(r'\*\*(.+?)\*\*', r'\1', text) text = re.sub(r'__(.+?)__', r'\1', text) text = re.sub(r'\*(.+?)\*', r'\1', text) # Bullet lists lines = text.split('\n') in_list = False result = [] for line in lines: stripped = line.strip() if re.match(r'^[\*\-] ', stripped): if not in_list: result.append('') in_list = False result.append(line) if in_list: result.append('') return '\n'.join(result) # Regex patterns for output parsing _STAGE_RE = re.compile(r'\[STAGE:(\w+)\](.*?)\[/STAGE\]') _THINKING_RE = re.compile(r'\[THINKING\](.*?)\[/THINKING\]') _OBSERVATION_RE = re.compile(r'\[OBSERVATION\](.*?)\[/OBSERVATION\]') _TOOL_OUTPUT_RE = re.compile(r'\[TOOL_OUTPUT:(.*?)\]\n(.*?)\[/TOOL_OUTPUT\]', re.DOTALL) _RESULT_RE = re.compile(r'\[RESULT\](.*?)\[/RESULT\]') _ERROR_RE = re.compile(r'\[ERROR\](.*?)\[/ERROR\]') _GRADCAM_RE = re.compile(r'\[GRADCAM_IMAGE:[^\]]+\]\n?') _RESPONSE_RE = re.compile(r'\[RESPONSE\]\n(.*?)\n\[/RESPONSE\]', re.DOTALL) _COMPLETE_RE = re.compile(r'\[COMPLETE\](.*?)\[/COMPLETE\]') _CONFIRM_RE = re.compile(r'\[CONFIRM:(\w+)\](.*?)\[/CONFIRM\]') _REFERENCES_RE = re.compile(r'\[REFERENCES\](.*?)\[/REFERENCES\]', re.DOTALL) _REF_RE = re.compile(r'\[REF:([^:]+):([^:]+):([^:]+):([^:]+):([^\]]+)\]') def format_output(raw_text: str, gradcam_base64: Optional[str] = None) -> str: """Convert tagged output to styled HTML""" html = raw_text # Stage headers html = _STAGE_RE.sub( r'
\2
', html ) # Thinking html = _THINKING_RE.sub(r'
\1
', html) # Observations html = _OBSERVATION_RE.sub(r'
\1
', html) # Tool outputs html = _TOOL_OUTPUT_RE.sub( r'
\1
\2
', html ) # Results html = _RESULT_RE.sub(r'
\1
', html) # Errors html = _ERROR_RE.sub(r'
\1
', html) # GradCAM image if gradcam_base64: img_html = f'
Attention Map
Grad-CAM
' html = _GRADCAM_RE.sub(img_html, html) else: html = _GRADCAM_RE.sub('', html) # Response section def format_response(match): content = match.group(1) parsed = parse_markdown(content) parsed = re.sub(r'\n\n+', '

', parsed) parsed = parsed.replace('\n', '
') return f'

{parsed}

' html = _RESPONSE_RE.sub(format_response, html) # Complete html = _COMPLETE_RE.sub(r'
\1
', html) # Confirmation html = _CONFIRM_RE.sub( r'
\2
', html ) # References def format_references(match): ref_content = match.group(1) refs_html = ['
References
') return '\n'.join(refs_html) html = _REFERENCES_RE.sub(format_references, html) # Convert newlines html = html.replace('\n', '
') return f'
{html}
' def create_analysis_view(): """ Create the analysis view component. Returns: Tuple of (container, components dict) """ with gr.Group(visible=False, elem_classes=["analysis-container"]) as container: with gr.Row(): # Main content area with gr.Column(elem_classes=["main-content"]): # Input greeting (shown when no analysis yet) with gr.Group(visible=True, elem_classes=["input-greeting"]) as input_greeting: gr.Markdown("What would you like to analyze?", elem_classes=["greeting-title"]) gr.Markdown("Upload an image and describe what you'd like to know", elem_classes=["greeting-subtitle"]) with gr.Column(elem_classes=["input-box-container"]): message_input = gr.Textbox( placeholder="Describe the lesion or ask a question...", show_label=False, lines=3, elem_classes=["message-input"] ) # Image upload (compact) image_input = gr.Image( label="", type="pil", height=180, elem_classes=["image-preview"], show_label=False ) with gr.Row(elem_classes=["input-actions"]): upload_hint = gr.Markdown("*Upload a skin lesion image above*", visible=True) send_btn = gr.Button("Analyze", elem_classes=["send-btn"], interactive=False) # Chat/results view (shown after analysis starts) with gr.Group(visible=False, elem_classes=["chat-view"]) as chat_view: results_output = gr.HTML( value='
Starting analysis...
', elem_classes=["results-area"] ) # Confirmation buttons with gr.Group(visible=False, elem_classes=["confirm-buttons"]) as confirm_group: gr.Markdown("**Do you agree with this diagnosis?**") with gr.Row(): confirm_yes_btn = gr.Button("Yes, continue", variant="primary", size="sm") confirm_no_btn = gr.Button("No, I disagree", variant="secondary", size="sm") feedback_input = gr.Textbox( label="Your assessment", placeholder="Enter your diagnosis...", visible=False ) submit_feedback_btn = gr.Button("Submit", visible=False, size="sm") # Follow-up input with gr.Row(elem_classes=["chat-input-area"]): followup_input = gr.Textbox( placeholder="Ask a follow-up question...", show_label=False, lines=1 ) followup_btn = gr.Button("Send", size="sm", elem_classes=["send-btn"]) components = { "input_greeting": input_greeting, "chat_view": chat_view, "message_input": message_input, "image_input": image_input, "send_btn": send_btn, "results_output": results_output, "confirm_group": confirm_group, "confirm_yes_btn": confirm_yes_btn, "confirm_no_btn": confirm_no_btn, "feedback_input": feedback_input, "submit_feedback_btn": submit_feedback_btn, "followup_input": followup_input, "followup_btn": followup_btn, "upload_hint": upload_hint } return container, components