{% extends 'sbas/base.html' %}

{% block content %}
<h2>LLM Prompts</h2>
<p>
    Below are the prompts used for interacting with large language models (LLMs) within the SBA system.
</p>

<h3>Question Generation Prompt</h3>
    <div class="d-flex align-items-center mb-2">
        <div class="btn-group me-2" role="group" aria-label="Prompt actions">
            <button type="button" class="btn btn-outline-secondary btn-sm" id="copy-llm-prompt">Copy prompt</button>
            <button type="button" class="btn btn-outline-secondary btn-sm" id="download-llm-prompt">Download prompt</button>
            <button class="btn btn-outline-primary btn-sm" type="button" data-bs-toggle="collapse" data-bs-target="#collapse-llm-question-prompt" aria-expanded="false" aria-controls="collapse-llm-question-prompt">Show</button>
        </div>
        <small class="text-muted" id="llm-prompt-feedback" style="display:none;">Copied ✓</small>
    </div>
    <div class="collapse" id="collapse-llm-question-prompt">
    <pre id="llm-question-prompt">
You are an expert radiologist tasked with generating high-quality multiple-choice questions for medical imaging education. Each question should consist of a clinical vignette, an image description, and five answer choices (A through E), with one correct answer and four plausible distractors.

Please adhere to the following guidelines when creating each question:
1. Clinical Vignette: Provide a brief clinical scenario that sets the context for the question including relevant patient history and clinical findings.
2. Make sure the question focuses on key radiological concepts, findings, or diagnoses.
3. Answer Choices: Create five answer options. Ensure that one is the correct answer and the others are plausible distractors.
4. Explanation: Provide a concise explanation for why the correct answer is right and why the distractors are incorrect.
5. Difficulty Level: Aim for a moderate difficulty level suitable for training radiologists.
6. Clarity and Precision: Use clear and precise language, avoiding ambiguity.
7. Relevance: Ensure that the question is relevant to current radiological practices and guidelines.
8. Questions should feature metadata tags for finding, structure, condition, presentation, and subspecialty.
9. Each question output should be a json object with the following schema:
10. For article sources pleese reference the article doi within the explanation field in the format [doi:10.xxxx/xxxxx], if you do not know the doi please use the article name.
11. For statdx sources please reference the article name in the format [statdx:article_id] (article_id may be docid).
12. References should be included inline within the feedback fields.
13. Sources can also be included in the sources field as a list.
14. Questions need to have a radiology focus, please avoid questions that are purely clinical or biochemical without imaging relevance.
15. Category names should match one of the following options exactly: 'Central Nervous and Head & Neck', 'Paediatric', 'Genito-urinary, Adrenal, Obstetrics & Gynaecology and Breast', 'Gastro-intestinal', 'Musculoskeletal and Trauma', 'Cardiothoracic and Vascular'

JSON Schema (draft-07 compatible)
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "SBA Question",
"description": "Schema for importing LLM-generated questions into the sbas.Question model.",
"type": "object",
"additionalProperties": false,
"required": [
"title",
"stem",
"a_answer",
"b_answer",
"c_answer",
"d_answer",
"e_answer",
"best_answer",
"category"
],
"properties": {
"title": {
"type": "string",
"description": "Short title for the question."
},
"stem": {
"type": "string",
"description": "HTML or plain text question stem. Trim leading/trailing whitespace before saving."
},
"a_answer": { "type": "string" },
"a_feedback": { "type": "string", "default": "" },
"b_answer": { "type": "string" },
"b_feedback": { "type": "string", "default": "" },
"c_answer": { "type": "string" },
"c_feedback": { "type": "string", "default": "" },
"d_answer": { "type": "string" },
"d_feedback": { "type": "string", "default": "" },
"e_answer": { "type": "string" },
"e_feedback": { "type": "string", "default": "" },
"feedback": {
"type": "string",
"description": "General question feedback (may include HTML)."
},
"best_answer": {
"type": "string",
"enum": ["a", "b", "c", "d", "e"],
"description": "One of 'a','b','c','d','e'."
},
"category": {
"oneOf": [
{ "type": "string", "description": "Category name ('Central Nervous and Head & Neck', 'Paediatric', 'Genito-urinary, Adrenal, Obstetrics & Gynaecology and Breast', 'Gastro-intestinal', 'Musculoskeletal and Trauma', 'Cardiothoracic and Vascular')" }
]
},
"sources": {
"type": "array",
"description": "List of source references for the question (e.g. article DOIs or docid or StatDx IDs or Source file names).",
"items": { "type": "string" },
"uniqueItems": true
},
"finding": {
"type": "array",
"description": "References to Finding objects. Prefer numeric IDs; names allowed if importer resolves them.",
"items": {
"oneOf": [
{ "type": "integer" },
{ "type": "string" }
]
},
"uniqueItems": true
},
"structure": {
"type": "array",
"items": {
"oneOf": [
{ "type": "integer" },
{ "type": "string" }
]
},
"uniqueItems": true
},
"condition": {
"type": "array",
"items": {
"oneOf": [
{ "type": "integer" },
{ "type": "string" }
]
},
"uniqueItems": true
},
"presentation": {
"type": "array",
"items": {
"oneOf": [
{ "type": "integer" },
{ "type": "string" }
]
},
"uniqueItems": true
},
"subspecialty": {
"type": "array",
"items": {
"oneOf": [
{ "type": "integer" },
{ "type": "string", "description": "Subspecialty name (e.g. 'Haematology & Oncology', 'Vascular', 'Uroradiology', 'Thoracic', 'Paediatric', 'Obstetric and Gynaecological', 'Neuroradiology', 'Musculoskeletal', 'Head and Neck', 'Gastrointestinal and hepatobiliary', 'Cardiac', 'Breast')" }
]
},
"uniqueItems": true
},
}
}

</pre>
</div>

<h3>Question generation text</h3>

    <div class="d-flex align-items-center mb-2">
        <div class="btn-group me-2" role="group" aria-label="Prompt actions">
            <button type="button" class="btn btn-outline-secondary btn-sm" id="copy-llm-prompt-text">Copy prompt</button>
            <button type="button" class="btn btn-outline-secondary btn-sm" id="download-llm-prompt-text">Download prompt</button>
            <button class="btn btn-outline-primary btn-sm" type="button" data-bs-toggle="collapse" data-bs-target="#collapse-llm-question-prompt-text" aria-expanded="false" aria-controls="collapse-llm-question-prompt-text">Show</button>
        </div>
        <small class="text-muted" id="llm-prompt-text-feedback" style="display:none;">Copied ✓</small>
    </div>

    <div class="collapse" id="collapse-llm-question-prompt-text">
    <pre id="llm-question-prompt-text">
Paying particular attention to the content in the source "prompt" please generate 10 questions
</pre>
</div>

<script>
document.addEventListener('DOMContentLoaded', function() {
    const copyBtn = document.getElementById('copy-llm-prompt');
    const downloadBtn = document.getElementById('download-llm-prompt');
    const pre = document.getElementById('llm-question-prompt');
    const feedback = document.getElementById('llm-prompt-feedback');

    function showFeedback(msg) {
        if (!feedback) return;
        feedback.textContent = msg;
        feedback.style.display = 'inline';
        setTimeout(() => feedback.style.display = 'none', 2000);
    }

    if (copyBtn && pre) {
        copyBtn.addEventListener('click', function() {
            const text = pre.textContent;
            if (navigator.clipboard && navigator.clipboard.writeText) {
                navigator.clipboard.writeText(text).then(function() {
                    showFeedback('Copied ✓');
                }).catch(function() {
                    // Fallback to older execCommand
                    const ta = document.createElement('textarea');
                    ta.value = text;
                    document.body.appendChild(ta);
                    ta.select();
                    try { document.execCommand('copy'); showFeedback('Copied ✓'); } catch (e) { showFeedback('Copy failed'); }
                    ta.remove();
                });
            } else {
                const ta = document.createElement('textarea');
                ta.value = text;
                document.body.appendChild(ta);
                ta.select();
                try { document.execCommand('copy'); showFeedback('Copied ✓'); } catch (e) { showFeedback('Copy failed'); }
                ta.remove();
            }
        });
    }

    if (downloadBtn && pre) {
        downloadBtn.addEventListener('click', function() {
            const text = pre.textContent;
            const blob = new Blob([text], { type: 'text/plain;charset=utf-8' });
            const url = URL.createObjectURL(blob);
            const a = document.createElement('a');
            a.href = url;
            a.download = 'llm_prompt.txt';
            document.body.appendChild(a);
            a.click();
            a.remove();
            URL.revokeObjectURL(url);
            showFeedback('Downloaded');

            });
        }

    // Handlers for the second prompt (llm-question-prompt-text)
    const copyBtnText = document.getElementById('copy-llm-prompt-text');
    const downloadBtnText = document.getElementById('download-llm-prompt-text');
    const preText = document.getElementById('llm-question-prompt-text');
    const feedbackText = document.getElementById('llm-prompt-text-feedback');

    function showTextFeedback(msg) {
        if (!feedbackText) return;
        feedbackText.textContent = msg;
        feedbackText.style.display = 'inline';
        setTimeout(() => feedbackText.style.display = 'none', 2000);
    }

    if (copyBtnText && preText) {
        copyBtnText.addEventListener('click', function() {
            const text = preText.textContent;
            if (navigator.clipboard && navigator.clipboard.writeText) {
                navigator.clipboard.writeText(text).then(function() {
                    showTextFeedback('Copied ✓');
                }).catch(function() {
                    const ta = document.createElement('textarea');
                    ta.value = text;
                    document.body.appendChild(ta);
                    ta.select();
                    try { document.execCommand('copy'); showTextFeedback('Copied ✓'); } catch (e) { showTextFeedback('Copy failed'); }
                    ta.remove();
                });
            } else {
                const ta = document.createElement('textarea');
                ta.value = text;
                document.body.appendChild(ta);
                ta.select();
                try { document.execCommand('copy'); showTextFeedback('Copied ✓'); } catch (e) { showTextFeedback('Copy failed'); }
                ta.remove();
            }
        });
    }

    if (downloadBtnText && preText) {
        downloadBtnText.addEventListener('click', function() {
            const text = preText.textContent;
            const blob = new Blob([text], { type: 'text/plain;charset=utf-8' });
            const url = URL.createObjectURL(blob);
            const a = document.createElement('a');
            a.href = url;
            a.download = 'llm_prompt_text.txt';
            document.body.appendChild(a);
            a.click();
            a.remove();
            URL.revokeObjectURL(url);
            showTextFeedback('Downloaded');
        });
    }
});
</script>

{% endblock %}