BOS_AI / figures.py
IT-BOS's picture
Upload 8 files
67d4b81 verified
Raw History Blame Contribute Delete
10.4 kB
"""
Inline SVG diagrams for the training modules. Built with small helpers so the
brand palette and Arial stay consistent. FIGURES maps (module_index, section_heading)
to an (svg, caption) pair; app.py renders the figure right after that section.
TEAM_FIGURE is shown on the Tools by team page.
"""
BLUE, BLUE_DEEP, TEAL, TEAL_DEEP = "#15516B", "#0E3A4D", "#13A89E", "#0E7F78"
INK, MUTED, RULE, WASH = "#1B2430", "#61707E", "#D5DFE6", "#F4F7F9"
RED, RED_BG, AMBER, AMBER_BG, GREEN_BG = "#B84A2F", "#FBEDE8", "#B7791F", "#FCF3E1", "#E7F6F4"
F = 'font-family="Arial, Helvetica, sans-serif"'
def _esc(s):
return s.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;")
def text(x, y, s, size=14, fill=INK, weight="normal", anchor="start"):
return f'<text x="{x}" y="{y}" {F} font-size="{size}" fill="{fill}" font-weight="{weight}" text-anchor="{anchor}">{_esc(s)}</text>'
def lines(x, y, items, size=13, fill=INK, lh=19, anchor="start"):
return "".join(text(x, y + i * lh, s, size, fill, anchor=anchor) for i, s in enumerate(items))
def box(x, y, w, h, fill="#fff", stroke=BLUE, sw=1.5, r=10):
return f'<rect x="{x}" y="{y}" width="{w}" height="{h}" rx="{r}" fill="{fill}" stroke="{stroke}" stroke-width="{sw}"/>'
def arrow(x1, y1, x2, y2, color=TEAL, sw=2.5):
return f'<line x1="{x1}" y1="{y1}" x2="{x2}" y2="{y2}" stroke="{color}" stroke-width="{sw}" marker-end="url(#ah)"/>'
def svg(w, h, body):
return (
f'<svg viewBox="0 0 {w} {h}" xmlns="http://www.w3.org/2000/svg" role="img" style="width:100%;height:auto;display:block">'
f'<defs><marker id="ah" markerWidth="10" markerHeight="10" refX="8" refY="5" orient="auto">'
f'<path d="M0,0 L10,5 L0,10 z" fill="{TEAL}"/></marker></defs>{body}</svg>'
)
# Module 1: approved vs not approved
def fig_approved():
b = ""
b += box(20, 20, 340, 250, GREEN_BG, TEAL, 2)
b += text(40, 55, "Approved for BOS and client work", 17, TEAL_DEEP, "bold")
b += box(40, 80, 300, 62, "#fff", TEAL, 1.5)
b += text(190, 106, "BOS Claude Enterprise", 18, BLUE, "bold", "middle")
b += text(190, 128, "company account, company terms", 13, MUTED, anchor="middle")
b += lines(40, 175, ["Data handled under the company agreement", "Supported and configured by BOS IT", "Defensible in an audit"], 13, INK, 24)
b += box(400, 20, 340, 250, RED_BG, RED, 2)
b += text(420, 55, "Not approved for any BOS information", 17, RED, "bold")
b += lines(420, 92, ["Personal Claude or ChatGPT accounts", "Gemini, Copilot on a personal login", "Free tiers of any AI product", "AI features in browser extensions", "Phone keyboards and note apps with AI", "Anything IT has not reviewed"], 14, INK, 27)
return svg(760, 290, b), "One approved destination for company and client information. Everything on the right has terms we have not reviewed."
# Module 2: prediction pipeline
def fig_prediction():
b = ""
b += box(20, 40, 210, 170, WASH, BLUE)
b += text(125, 68, "Context", 16, BLUE, "bold", "middle")
b += lines(38, 96, ["Your messages", "Earlier replies", "Attached files"], 14, INK, 24)
b += text(125, 190, "Everything the model can see", 12, MUTED, anchor="middle")
b += arrow(232, 125, 288, 125)
b += box(290, 40, 210, 170, "#fff", BLUE, 2)
b += text(395, 68, "Language model", 16, BLUE, "bold", "middle")
b += lines(308, 96, ["Predicts the most", "plausible next words,", "one piece at a time"], 14, INK, 24)
b += text(395, 190, "No fact check step by default", 12, RED, anchor="middle")
b += arrow(502, 125, 558, 125)
b += box(560, 40, 180, 170, GREEN_BG, TEAL)
b += text(650, 68, "Answer", 16, TEAL_DEEP, "bold", "middle")
b += lines(578, 96, ["Fluent and confident", "Plausible by design", "True only if the", "context supports it"], 14, INK, 22)
b += text(380, 250, "If the answer depends on something that is not in the context, the model guesses. Put the material in.", 13, MUTED, anchor="middle")
return svg(760, 270, b), "The model works from the conversation in front of it, not from a database of facts."
# Module 3: four parts of a request
def fig_request():
parts = [
("Context", ["Who it is for and", "what it is for"], ['"a property manager', 'who is not technical"']),
("Specifics", ["Length, tone, format,", "what to leave out"], ['"three sentences,', 'no bullet points"']),
("Material", ["The notes, the file,", "the email you answer"], ['"here is the', 'original message"']),
("Next step", ["What to change in", "the first draft"], ['"shorter, keep the', 'invoice line"']),
]
b = ""
for i, (t, d, ex) in enumerate(parts):
x = 20 + i * 185
b += box(x, 20, 165, 190, "#fff", BLUE)
b += f'<path d="M{x + 10},20 h145 a10,10 0 0 1 10,10 v34 h-165 v-34 a10,10 0 0 1 10,-10 z" fill="{BLUE}"/>'
b += text(x + 82, 49, t, 16, "#fff", "bold", "middle")
b += lines(x + 82, 92, d, 13, INK, 19, "middle")
b += lines(x + 82, 156, ex, 12.5, TEAL_DEEP, 17, "middle")
if i < 3:
b += f'<text x="{x + 175}" y="123" {F} font-size="22" fill="{TEAL}" font-weight="bold" text-anchor="middle">+</text>'
return svg(760, 230, b), "A request that would confuse a colleague will confuse the model. Four parts fix most of it."
# Module 4: outline then sections vs one shot
def fig_steps():
b = ""
b += text(20, 34, "One request for the whole thing", 15, RED, "bold")
b += box(20, 48, 300, 54, RED_BG, RED, 1.5)
b += text(170, 71, '"Write the full 20 page document"', 13, INK, anchor="middle")
b += text(170, 91, "one pass, problems found at the end", 12, MUTED, anchor="middle")
b += text(20, 150, "Step by step", 15, TEAL_DEEP, "bold")
steps = ["Ask for an outline", "Review and adjust it", "Write section 1", "Write section 2 ...", "Assemble and edit"]
for i, s in enumerate(steps):
x = 20 + i * 150
b += box(x, 164, 118, 60, GREEN_BG if i % 2 == 0 else "#fff", TEAL, 1.5)
b += text(x + 59, 199, s, 12.5, INK, anchor="middle")
if i < 4:
b += arrow(x + 121, 194, x + 147, 194)
b += text(380, 258, "You catch problems early, and each piece gets the model's full attention.", 13, MUTED, anchor="middle")
return svg(760, 275, b), "Break big deliverables into an outline and sections. It is slower per step and much faster overall."
# Module 5: three lanes for data
def fig_datalanes():
lanes = [
("Never, in any AI tool", RED, RED_BG, ["Controlled Unclassified Information", "Federal Contract Information", "Export controlled material", "Passwords, logins, IPs, network details", "HR, payroll, personnel, medical", "Raw incident narratives and dispatch"]),
("Ask BOS IT first", AMBER, AMBER_BG, ["Client names inside a working draft", "A file you have not read all the way", "Anything that might be controlled", "A new tool or feature you want to try", "Connecting Claude to a system", "When you are unsure at all"]),
("Good to go", TEAL_DEEP, GREEN_BG, ["Your own notes, client as Site A", "Public information", "Drafts you wrote and want tightened", "Procedures with codes removed", "Metric level summaries", "Questions about how the tool works"]),
]
b = ""
for i, (t, c, bg, items) in enumerate(lanes):
x = 20 + i * 245
b += box(x, 20, 230, 260, bg, c, 2)
b += text(x + 115, 52, t, 16, c, "bold", "middle")
b += lines(x + 16, 86, items, 12.5, INK, 30)
return svg(760, 300, b), "When a piece of information could sit in more than one lane, treat it as the lane to the left."
# Module 6: pre send checklist
def fig_checklist():
checks = ["Read every line, not skimmed", "Verified every number, name, date, source", "Removed or generalized client and site detail", "Made it sound like me", "Comfortable if the recipient knew how it was made"]
b = ""
for i, c in enumerate(checks):
y = 20 + i * 44
b += box(20, y, 520, 36, "#fff", RULE, 1.2, 8)
b += f'<rect x="32" y="{y + 8}" width="20" height="20" rx="4" fill="none" stroke="{TEAL}" stroke-width="2"/>'
b += f'<path d="M36 {y + 18} l5 5 l9 -10" stroke="{TEAL}" stroke-width="2.5" fill="none"/>'
b += text(64, y + 24, c, 14, INK)
b += arrow(546, 128, 596, 128)
b += box(600, 96, 140, 64, TEAL, TEAL)
b += text(670, 134, "Send", 18, "#fff", "bold", "middle")
b += text(280, 262, "If any box is not checked, it is not done.", 13, MUTED, anchor="middle")
return svg(760, 280, b), "The AI is a drafting partner. A person is always the last check before anything leaves the building."
# Team page: copy in, work, paste back loop
def fig_loop():
systems = ["Zoho", "Apollo", "Microsoft 365"]
b = ""
for i, s in enumerate(systems):
y = 30 + i * 70
b += box(20, y, 170, 50, WASH, BLUE)
b += text(105, y + 31, s, 16, BLUE, "bold", "middle")
b += box(20, 240, 170, 40, "#fff", RULE, 1.2)
b += text(105, 265, "where the record lives", 12, MUTED, anchor="middle")
b += arrow(200, 90, 300, 130)
b += text(275, 96, "copy in", 13, TEAL_DEEP, "bold", "middle")
b += arrow(300, 190, 200, 230)
b += text(240, 258, "paste back", 13, TEAL_DEEP, "bold", "middle")
b += box(305, 90, 250, 140, GREEN_BG, TEAL, 2)
b += text(430, 122, "Claude Enterprise", 17, BLUE, "bold", "middle")
b += lines(430, 150, ["draft, rewrite, summarize,", "explain, organize, think", "with placeholders for", "client and site specifics"], 13, INK, 20, "middle")
b += box(585, 90, 155, 140, "#fff", RULE, 1.2)
b += text(662, 118, "Connectors", 15, BLUE, "bold", "middle")
b += lines(662, 145, ["Only when BOS IT", "has set one up.", "Ask what is", "connected and", "what rules apply."], 12.5, INK, 18, "middle")
return svg(760, 300, b), "The default working pattern. Records stay in the system of record; Claude is the workbench beside it."
FIGURES = {
(0, "Why one tool instead of many"): fig_approved(),
(1, "It predicts, it does not look up"): fig_prediction(),
(2, "The four things every good request has"): fig_request(),
(3, "Break big tasks into steps"): fig_steps(),
(4, "Never enter this into any AI tool, including the company one"): fig_datalanes(),
(5, "A short checklist before anything leaves your hands"): fig_checklist(),
}
TEAM_FIGURE = fig_loop()