File size: 8,030 Bytes
458d3c2 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 | import json
import gradio as gr
AUTHOR = "Richard Amir Nasser"
DOI_STANDARD = "https://doi.org/10.5281/zenodo.20360964"
DOI_PACKAGE = "https://doi.org/10.5281/zenodo.20435828"
REPOSITORY = "https://github.com/RichNass87/inspector-roofing-protocols"
STANDARDS_SITE = "https://standards.inspector-roofing.com/"
STEPS = [
{
"step": 1,
"title": "Set inspection context",
"purpose": "Record the property context, access limits, weather context, and the question being reviewed.",
"checklist": [
"State what was inspected and what was inaccessible.",
"Record roof system, slopes, and visible conditions without guessing.",
"Separate observed facts from homeowner or third-party statements.",
],
},
{
"step": 2,
"title": "Map the roof",
"purpose": "Give every observation a stable roof area, slope, or component reference.",
"checklist": [
"Use consistent slope and component names.",
"Connect each photo to a roof area.",
"Record limitations such as height, access, lighting, or obstruction.",
],
},
{
"step": 3,
"title": "Capture evidence in sequence",
"purpose": "Use context, overview, detail, and scale photos so another reviewer can follow the record.",
"checklist": [
"Start with context and overview images.",
"Capture detail images for the specific condition.",
"Add scale or reference images when size or pattern matters.",
],
},
{
"step": 4,
"title": "Label observable conditions",
"purpose": "Describe what is visible and distinguish candidates from confirmed conclusions.",
"checklist": [
"Use condition labels supported by the image and notes.",
"Separate storm candidates from wear, installation, maintenance, and inconclusive findings.",
"Record uncertainty instead of forcing a conclusion.",
],
},
{
"step": 5,
"title": "Log documentation gaps",
"purpose": "Make missing context visible so the next reviewer knows what still needs work.",
"checklist": [
"Name the missing photo, measurement, access detail, or date context.",
"Explain why the gap matters.",
"Recommend the smallest responsible follow-up step.",
],
},
{
"step": 6,
"title": "Keep the insurance boundary",
"purpose": "Support review-ready documentation without deciding coverage or claim outcomes.",
"checklist": [
"Document observable roof conditions and scope context.",
"Do not interpret policy language or promise approval, payment, or coverage.",
"State that carriers decide coverage, payment, and claim outcomes.",
],
},
{
"step": 7,
"title": "Export a review-ready record",
"purpose": "Preserve a structured record that another person can inspect without relying on memory.",
"checklist": [
"Keep the observation, media references, gaps, and next steps together.",
"Use the published schemas and versioned release files.",
"Cite the exact DOI record used by the artifact.",
],
},
]
def step_markdown(step_number):
step = STEPS[step_number - 1]
checklist = "\n".join(f"- {item}" for item in step["checklist"])
return f"## Step {step['step']}: {step['title']}\n\n{step['purpose']}\n\n{checklist}"
def review_scenario(step_number, scenario, note):
step = STEPS[step_number - 1]
note = (note or "").strip()
result = {
"selected_step": step["title"],
"assessment": "Review the record against the checklist before making a roofing decision.",
"next_action": "Add the smallest missing context, photo, scale reference, or limitation note.",
"insurance_boundary": (
"Inspector Roofing documents observable conditions and does not act as a public adjuster. "
"Carriers decide coverage, payment, and claim outcomes."
),
"scenario_received": scenario or "No scenario supplied.",
"note_received": note or "No note supplied.",
"sources": [DOI_STANDARD, DOI_PACKAGE, REPOSITORY, STANDARDS_SITE],
}
if not scenario and not note:
result["assessment"] = "Start with a short description of the roof area and what the image or note shows."
elif step_number == 4 and any(word in (scenario + " " + note).lower() for word in ["maybe", "appears", "possible"]):
result["assessment"] = "The wording signals uncertainty. Keep the finding as a candidate or inconclusive condition and name the evidence gap."
elif step_number == 6:
result["assessment"] = "Keep the output factual: describe the roof condition and documentation, not coverage, payment, or claim approval."
return json.dumps(result, indent=2)
def source_markdown():
return f"""## Public source spine
- Canonical author: **{AUTHOR}**
- Public citable standard: [{DOI_STANDARD}]({DOI_STANDARD})
- Source package record: [{DOI_PACKAGE}]({DOI_PACKAGE})
- Versioned repository: [{REPOSITORY}]({REPOSITORY})
- Standards site: [{STANDARDS_SITE}]({STANDARDS_SITE})
- ORCID: [0009-0000-2980-7543](https://orcid.org/0009-0000-2980-7543)
This educational Space explains documentation workflow. It does not diagnose a roof, determine causation, interpret an insurance policy, or predict coverage, payment, or claim outcomes.
"""
with gr.Blocks(title="Inspector Roofing Protocols Learning Lab") as demo:
gr.Markdown(
f"""# Inspector Roofing Protocols: Evidence-First Learning Lab
Learn the seven-step workflow for recording observable roof conditions, organizing photo evidence, documenting gaps, and preparing a review-ready record.
**Canonical author:** {AUTHOR}
**Package version:** 1.1.1
**Insurance boundary:** Inspector Roofing documents observable conditions and does not act as a public adjuster.
"""
)
with gr.Tab("Learn the steps"):
step_choice = gr.Dropdown(
choices=[f"{item['step']}. {item['title']}" for item in STEPS],
value="1. Set inspection context",
label="Choose a step",
)
step_output = gr.Markdown(step_markdown(1))
def choose_step(value):
return step_markdown(int(value.split(".", 1)[0]))
step_choice.change(choose_step, inputs=step_choice, outputs=step_output)
with gr.Tab("Practice a record"):
practice_step = gr.Dropdown(
choices=[f"{item['step']}. {item['title']}" for item in STEPS],
value="4. Label observable conditions",
label="Practice step",
)
scenario = gr.Textbox(
label="Scenario or observation",
placeholder="Example: Close-up image shows a possible impact-like mark on the south slope.",
lines=3,
)
note = gr.Textbox(
label="Evidence note",
placeholder="Example: No scale reference; overview photo is available.",
lines=3,
)
review_button = gr.Button("Review against the protocol", variant="primary")
review_output = gr.Code(label="Structured teaching response", language="json")
review_button.click(
lambda value, scenario_text, note_text: review_scenario(
int(value.split(".", 1)[0]), scenario_text, note_text
),
inputs=[practice_step, scenario, note],
outputs=review_output,
)
with gr.Tab("Sources and limits"):
gr.Markdown(source_markdown())
gr.Markdown(
"**Training note:** This Space is educational and uses synthetic examples. Do not upload customer names, exact addresses, policy numbers, certificate numbers, signatures, faces, license plates, or GPS metadata."
)
if __name__ == "__main__":
demo.launch()
|