import os import re import json import gradio as gr from huggingface_hub import InferenceClient # --------------------------------------------------------------------------- # Model configuration # --------------------------------------------------------------------------- MODEL = "mistralai/Mistral-7B-Instruct-v0.3" HF_TOKEN = os.environ.get("HF_TOKEN", None) SYSTEM_PROMPT = """You are an aviation training scenario analyst. Your role is to help flight instructors, students, and aviation enthusiasts structure hypothetical scenarios for training discussion and expert review. You do NOT make real flight safety decisions. You do NOT have access to live weather, NOTAMs, or real aviation data. You are NOT a certified dispatcher or aviation authority. Given a hypothetical aviation scenario, you extract structured training information and generate discussion questions for expert review. Return ONLY a valid JSON object with this exact schema. No markdown, no backticks, no extra text. { "scenario_summary": "2 sentences max. Plain English. Always starts with 'This hypothetical scenario...'", "extracted_parameters": { "departure": "string or 'Not specified'", "destination": "string or 'Not specified'", "aircraft_type": "string or 'Not specified'", "crew_experience": "string or 'Not specified'", "planned_altitude": "string or 'Not specified'", "weather_state": "string or 'Not specified'", "fuel_endurance": "string or 'Not specified'", "special_conditions": "string or 'None mentioned'" }, "weather_terrain_airspace": [ "string — each item is a consideration for training discussion, not a verdict. Use language like 'The described weather suggests...', 'Terrain profile implies...', 'Airspace in this context typically involves...'" ], "risk_flags": [ { "severity": "HIGH | MEDIUM | LOW", "factor": "short label", "discussion_point": "one sentence — what a training instructor would flag for discussion" } ], "assumptions_missing": [ "string — each item is something the model had to assume or that was not specified" ], "expert_questions": [ "string — each item is a question a flight instructor or safety examiner would raise in a debrief or training session. 5-7 questions." ], "training_verdict": "Low Concern | Caution | High Risk | Expert Review Recommended", "training_verdict_context": "One sentence. Avoid operational safety claims. Use: 'This hypothetical scenario presents factors that would typically warrant [level] of discussion in a training context.'", "expert_review_message": "Pre-filled message for user to send to a domain expert. Starts with: 'Hi — I used an AI training brief simulator to structure this hypothetical aviation scenario. I would appreciate your expert review of the risk flags and discussion questions below. Specifically: are these the right factors to flag for this scenario, and what important consideration did the model miss?'" }""" # --------------------------------------------------------------------------- # Demo scenario text # --------------------------------------------------------------------------- EX1 = """Hypothetical scenario: a student pilot with 75 hours total time plans a VFR day flight from Grenoble to Turin, crossing the French Alps at 6500ft in October. Aircraft is a Cessna 172. Weather: broken clouds at 5000ft, visibility 10km, light turbulence forecast above 5000ft. Fuel: 3 hours endurance. No IFR rating. Pilot has never flown above 4000ft before.""" EX2 = """Hypothetical scenario: a single-pilot helicopter ferry from Marseille to a fictional offshore platform 60 nautical miles south. Night VFR. Aircraft: fictional medium twin-engine helicopter. Crew: 1800 hours total, 200 hours night. Weather: wind 220/20G30KT, visibility 6km in haze, overcast 1200ft. Fuel: 2.2 hours endurance. No instrument approach at destination.""" EX3 = """Hypothetical scenario: a fictional regional turboprop completes its first post-maintenance test flight after a major avionics upgrade. Two experienced test pilots, 4000 hours each on type. Departure from a busy international airport. Weather: CAVOK, light wind. Duration: 2 hours. Test card includes full avionics checkout, one engine-out simulation at altitude, and return ILS approach.""" # --------------------------------------------------------------------------- # Fallback briefs (hardcoded, match exact model schema) # --------------------------------------------------------------------------- FALLBACK_EX1 = { "scenario_summary": "This hypothetical scenario involves a student pilot with limited high-altitude experience planning a VFR crossing of the French Alps in October, with cloud bases below the planned cruising altitude. The scenario presents multiple compounding risk factors that would be central to a structured training debrief.", "extracted_parameters": { "departure": "Grenoble", "destination": "Turin", "aircraft_type": "Cessna 172", "crew_experience": "Student pilot, 75 hours total time, no IFR rating, no prior flight above 4000ft", "planned_altitude": "6500ft", "weather_state": "Broken clouds at 5000ft, visibility 10km, light turbulence forecast above 5000ft", "fuel_endurance": "3 hours", "special_conditions": "Mountain crossing, October weather patterns, VFR-only pilot" }, "weather_terrain_airspace": [ "The described weather suggests that broken cloud coverage at 5000ft would place the planned cruise altitude of 6500ft in or above cloud layers, which raises IMC exposure concerns for a VFR-only flight.", "Terrain profile implies that the French-Italian Alpine corridor includes passes and peaks well above 6500ft, requiring precise route selection to maintain terrain clearance.", "Turbulence forecast above 5000ft is a consideration for the airframe and pilot workload during the most demanding phase of the crossing.", "Airspace in this context typically involves restricted zones, mandatory crossing altitudes, and limited diversion options once committed to the pass." ], "risk_flags": [ { "severity": "HIGH", "factor": "VFR into IMC exposure", "discussion_point": "Broken clouds at 5000ft combined with a planned altitude of 6500ft creates a high likelihood of cloud encounter for a pilot with no IFR rating — a serious training concern in general aviation, especially in mountainous terrain." }, { "severity": "HIGH", "factor": "Student experience vs. terrain complexity", "discussion_point": "75 hours total time with no prior high-altitude experience is a training-relevant mismatch for an Alpine crossing, where mountain wave, orographic lift, and rapid weather change are common." }, { "severity": "MEDIUM", "factor": "Turbulence forecast above MEA", "discussion_point": "Light turbulence forecast at and above the planned altitude introduces handling and fatigue factors that compound the other risk elements in this training discussion." }, { "severity": "MEDIUM", "factor": "Limited diversion options", "discussion_point": "Once committed to a high Alpine pass at low altitude with marginal weather, viable diversion airports are sparse — a scenario worth discussing in terms of decision-making under pressure." }, { "severity": "LOW", "factor": "Fuel endurance", "discussion_point": "Three hours endurance appears adequate for the planned route, but a diversion or weather hold could significantly reduce margins — worth noting in the training context." } ], "assumptions_missing": [ "No information provided on whether the pilot has completed mountain flying training or received a mountain checkout", "Specific route through the Alps not stated — critical for terrain clearance analysis", "No mention of alternate airports or diversion planning", "MEF (Maximum Elevation Figure) for the crossing corridor not included in the scenario", "No information on forecast evolution — whether weather is improving or deteriorating" ], "expert_questions": [ "At what point in flight preparation should a VFR student pilot recognize that this scenario warrants deferral, and what weather minimums would you set for this route in training?", "How would you structure a mountain weather briefing for a student unfamiliar with orographic effects and Alpine meteorology?", "What personal minimums framework would you recommend this pilot develop before attempting high-terrain VFR, and at what total time?", "If the pilot encountered clouds at 5500ft mid-crossing, what options should be discussed in a training debrief and how does limited terrain diversion factor into the analysis?", "How does October weather in the western Alps differ from summer conditions, and what training materials cover seasonal mountain weather patterns?", "What does a standard VFR flight following or AFIS service offer on this route, and what are the limitations in the Alpine corridor?" ], "training_verdict": "High Risk", "training_verdict_context": "This hypothetical scenario presents factors that would typically warrant High Risk discussion in a training context, given the combination of student experience level, planned altitude relative to cloud bases, and the complexity of Alpine terrain.", "expert_review_message": "Hi — I used an AI training brief simulator to structure this hypothetical aviation scenario. I would appreciate your expert review of the risk flags and discussion questions below. Specifically: are these the right factors to flag for this scenario, and what important consideration did the model miss?\n\nScenario: Student pilot, 75 hours TT, VFR Alps crossing Grenoble to Turin at 6500ft, October. Broken clouds at 5000ft, turbulence above 5000ft. Cessna 172, 3h fuel.\n\nTop risk flags identified: VFR into IMC exposure (HIGH), student experience vs. terrain complexity (HIGH), limited diversion options (MEDIUM).\n\nKey training questions: personal minimums for mountain VFR, in-flight decision triggers for weather deterioration, October Alpine meteorology." } FALLBACK_EX2 = { "scenario_summary": "This hypothetical scenario describes a single-pilot night VFR helicopter ferry over open water to a fictional offshore platform, with gusty crosswind conditions, reduced visibility, a low overcast, and no instrument approach available at the destination. The combination of environmental and operational factors makes this a high-complexity training discussion case.", "extracted_parameters": { "departure": "Marseille", "destination": "Fictional offshore platform, 60nm south", "aircraft_type": "Fictional medium twin-engine helicopter", "crew_experience": "Single pilot, 1800 hours total, 200 hours night", "planned_altitude": "Not specified", "weather_state": "Wind 220/20G30KT, visibility 6km in haze, overcast 1200ft", "fuel_endurance": "2.2 hours", "special_conditions": "Night VFR, offshore over-water, no instrument approach at destination, gusting crosswind" }, "weather_terrain_airspace": [ "The described weather suggests that an overcast at 1200ft with 6km visibility in haze creates marginal VFR conditions that could deteriorate rapidly over open water where visual horizon references are reduced at night.", "Terrain profile implies minimal obstruction concerns en route, but the offshore platform environment presents limited approach path options and no standard instrument procedure as a backup.", "Wind 20 gusting 30 knots introduces significant hover and landing considerations at the platform, particularly for a night arrival with limited visual cues.", "Airspace in this context typically involves offshore transition airspace and possibly restricted military or platform exclusion zones that require specific coordination." ], "risk_flags": [ { "severity": "HIGH", "factor": "Night over-water with no instrument approach", "discussion_point": "Night VFR over open water with an overcast at 1200ft and no instrument approach at the destination creates a scenario where spatial disorientation and weather deterioration have no procedural escape route — a critical training discussion point." }, { "severity": "HIGH", "factor": "Marginal VFR at night", "discussion_point": "Visibility 6km in haze at night is significantly more operationally limiting than the same condition in daylight, as horizon reference is lost and lighting on the water surface is absent." }, { "severity": "MEDIUM", "factor": "Fuel endurance vs. diversion options", "discussion_point": "2.2 hours endurance for a 60nm single-leg offshore flight leaves limited margin for weather hold, platform unavailability, or diversion back to Marseille with headwind component." }, { "severity": "MEDIUM", "factor": "Single-pilot workload at night", "discussion_point": "Night offshore single-pilot operations compress situational awareness, communication, and navigation tasks without a second crew member to cross-check — relevant for crew resource management training." }, { "severity": "LOW", "factor": "Night experience ratio", "discussion_point": "200 night hours from a total of 1800 is approximately 11% night exposure — worth flagging as context for the pilot's currency and recency on night offshore operations." } ], "assumptions_missing": [ "Planned cruise altitude not stated — relevant for obstacle clearance and VFR cloud clearance minimums", "Platform lighting and visual approach aids not described", "No mention of life raft, survival equipment, or offshore survival training currency", "Forecast trend not provided — whether conditions are improving or deteriorating during the flight", "No information on whether the platform has a dedicated landing officer or AFIS service" ], "expert_questions": [ "At what point does this scenario transition from night VFR to a flight that operationally requires IFR certification and an instrument approach at destination — and where is that regulatory boundary in French/EASA airspace?", "What spatial disorientation risk mitigation techniques would you brief for a night over-water segment with overcast conditions and no visible horizon?", "How would you calculate a minimum weather diversion fuel reserve for this scenario, and what airport would serve as the designated alternate?", "What offshore survival equipment requirements apply to this scenario, and how would you verify currency and training for the pilot?", "How does gusting crosswind at 20G30KT affect helicopter platform approach and hover technique, and what wind limits are typical for medium twin platforms?", "What are the crew resource management considerations for single-pilot night offshore operations, and what workload management techniques reduce risk in this profile?" ], "training_verdict": "Expert Review Recommended", "training_verdict_context": "This hypothetical scenario presents factors that would typically warrant Expert Review Recommended discussion in a training context, as the combination of night VFR, offshore over-water, marginal weather, and no instrument approach at destination exceeds the complexity of standard training scenario analysis.", "expert_review_message": "Hi — I used an AI training brief simulator to structure this hypothetical aviation scenario. I would appreciate your expert review of the risk flags and discussion questions below. Specifically: are these the right factors to flag for this scenario, and what important consideration did the model miss?\n\nScenario: Single-pilot night VFR helicopter ferry, Marseille to fictional offshore platform 60nm south. Medium twin helicopter. Wind 20G30KT, 6km in haze, overcast 1200ft. 2.2h fuel. No instrument approach at destination.\n\nTop risk flags: night over-water with no instrument approach (HIGH), marginal VFR at night (HIGH), fuel margin (MEDIUM).\n\nKey training questions: regulatory IFR threshold for this profile, spatial disorientation mitigation, offshore survival requirements." } FALLBACK_EX3 = { "scenario_summary": "This hypothetical scenario involves a post-maintenance test flight on a fictional regional turboprop following a major avionics upgrade, conducted by two experienced type-rated pilots with a structured test card including an engine-out simulation. The scenario is representative of a low meteorological risk but operationally high-complexity flight profile.", "extracted_parameters": { "departure": "Busy international airport (fictional)", "destination": "Return to departure", "aircraft_type": "Fictional regional turboprop", "crew_experience": "Two test pilots, 4000 hours each on type", "planned_altitude": "Not specified", "weather_state": "CAVOK, light wind", "fuel_endurance": "2 hours planned duration", "special_conditions": "Post-maintenance test flight, major avionics upgrade, engine-out simulation, ILS return approach" }, "weather_terrain_airspace": [ "The described weather (CAVOK, light wind) represents optimal conditions for a test flight, reducing environmental risk to its lowest practical level for this scenario.", "Airspace in this context typically involves coordination with ATC for the test area, engine-out simulation altitude, and return ILS — a busy international airport departure requires careful integration.", "Terrain profile is not a primary concern given CAVOK conditions and no mention of mountainous terrain — departure airspace complexity is the relevant factor." ], "risk_flags": [ { "severity": "HIGH", "factor": "Post-maintenance avionics uncertainty", "discussion_point": "The first flight following a major avionics upgrade introduces system uncertainty — displays, autopilot coupling, navigation databases, and failure modes may behave differently until the test card items are validated." }, { "severity": "HIGH", "factor": "Engine-out simulation in busy airspace", "discussion_point": "Conducting an engine-out simulation at altitude near a busy international airport requires precise ATC coordination and a defined recovery area — the risk is procedural and airspace-conflict related, not meteorological." }, { "severity": "MEDIUM", "factor": "ILS approach with unvalidated avionics", "discussion_point": "The return ILS approach serves as a functional check on the upgraded avionics, but an ILS coupled to a system under test introduces the possibility of unexpected behavior during the approach phase — a training-relevant discussion point." }, { "severity": "MEDIUM", "factor": "Test card sequence and abort criteria", "discussion_point": "A structured test card means the crew must decide in real time when a test item anomaly is significant enough to abandon the card — this decision framework is worth discussing in the context of test flight discipline." }, { "severity": "LOW", "factor": "Crew fatigue and briefing load", "discussion_point": "A comprehensive test card covering avionics checkout, engine-out, and ILS in a 2-hour flight is a high cognitive load for the crew — preflight briefing depth and crew coordination are worth examining." } ], "assumptions_missing": [ "Specific avionics system upgraded not stated — relevant to understanding which flight systems are under test", "Test altitude for engine-out simulation not provided", "No mention of whether a flight test engineer or observer is on board", "Abort criteria for the test card not described", "No information on maintenance release documentation or airworthiness sign-off process" ], "expert_questions": [ "What are the standard go/no-go criteria for a first post-maintenance test flight, and how would you structure the pre-test briefing for a major avionics upgrade?", "How do you define and communicate the test area and engine-out simulation parameters with ATC at a busy international airport — what coordination is required?", "What anomaly reporting and abort criteria would you include on the test card for an avionics upgrade validation flight?", "How would you validate autopilot and FMS coupling on the ILS approach, and what are the crew abort triggers if the approach behaves unexpectedly?", "What role does the airworthiness release process play before this test flight, and who has authority to approve the flight following the maintenance event?", "How would you structure the debrief after this test flight, and what documentation is required for the avionics system to be returned to line service?" ], "training_verdict": "Caution", "training_verdict_context": "This hypothetical scenario presents factors that would typically warrant Caution discussion in a training context, as weather and crew experience are favorable but the post-maintenance system uncertainty and test card complexity introduce operational risks worth structured review.", "expert_review_message": "Hi — I used an AI training brief simulator to structure this hypothetical aviation scenario. I would appreciate your expert review of the risk flags and discussion questions below. Specifically: are these the right factors to flag for this scenario, and what important consideration did the model miss?\n\nScenario: Fictional regional turboprop, first post-maintenance test flight after major avionics upgrade. Two test pilots, 4000h each on type. CAVOK conditions. Test card: full avionics checkout, engine-out sim at altitude, return ILS.\n\nTop risk flags: post-maintenance avionics uncertainty (HIGH), engine-out in busy airspace (HIGH), ILS with unvalidated systems (MEDIUM).\n\nKey training questions: go/no-go criteria for test flights, ATC coordination for engine-out, test card abort criteria." } FALLBACKS = [FALLBACK_EX1, FALLBACK_EX2, FALLBACK_EX3] # --------------------------------------------------------------------------- # HTML rendering # --------------------------------------------------------------------------- VERDICT_STYLES = { "Low Concern": ("background:#EAF3DE;border:1px solid #BBDFA0;border-left:4px solid #3B6D11;", "#2D5A0D", "🟢"), "Caution": ("background:#FAEEDA;border:1px solid #F0C68A;border-left:4px solid #854F0B;", "#6B3D08", "🟡"), "High Risk": ("background:#FCEBEB;border:1px solid #F5AAAA;border-left:4px solid #A32D2D;", "#8B1A1A", "🔴"), "Expert Review Recommended": ("background:#F0EAFF;border:1px solid #C4B5FD;border-left:4px solid #5B21B6;", "#4C1D95", "🔵"), } SEVERITY_STYLES = { "HIGH": ("background:#FCEBEB;border-left:4px solid #A32D2D;", "#A32D2D", "🔴"), "MEDIUM": ("background:#FAEEDA;border-left:4px solid #854F0B;", "#854F0B", "🟡"), "LOW": ("background:#EAF3DE;border-left:4px solid #3B6D11;", "#3B6D11", "🟢"), } def _card(content: str, style: str = "") -> str: return f'
{summary}
', style="background:#F8FAFC;border:1px solid #E2E8F0;" )) # ── 3. EXTRACTED PARAMETERS params = data.get("extracted_parameters", {}) param_labels = { "departure": "Departure", "destination": "Destination", "aircraft_type": "Aircraft Type", "crew_experience": "Crew Experience", "planned_altitude": "Planned Altitude", "weather_state": "Weather State", "fuel_endurance": "Fuel Endurance", "special_conditions": "Special Conditions", } rows = "" for i, (key, label) in enumerate(param_labels.items()): val = params.get(key, "Not specified") muted = val in ("Not specified", "None mentioned") val_color = "#9CA3AF" if muted else "#1F2937" prefix = '⚠' if muted else "" row_bg = "background:#F8FAFC;" if i % 2 == 0 else "background:#FFFFFF;" rows += ( f'What the model had to infer or could not determine
' f'For a flight instructor or safety examiner
' f'Send this to an aviation professional for review
' f'' f'', style="background:#FFFFFF;border:1px solid #E2E8F0;" )) # ── 9. SAFETY DISCLAIMER (always visible) parts.append( 'Enter a hypothetical scenario above and click Generate.
' data = call_model(scenario) if not data: return 'No output — please try again.
' return render_brief(data) # --------------------------------------------------------------------------- # Gradio UI # --------------------------------------------------------------------------- css = """ footer { display: none !important; } #flightbrief-hero { background: linear-gradient(135deg, #0F2142 0%, #1A3561 100%); border-radius: 12px; padding: 28px 32px; margin-bottom: 20px; } #fb-title { font-size: 24px; font-weight: 700; color: #FFFFFF; letter-spacing: -0.3px; margin-bottom: 6px; } #fb-subtitle { font-size: 14px; color: #94A3B8; margin-bottom: 14px; line-height: 1.5; } .fb-badge { display: inline-block; font-size: 11px; font-weight: 600; padding: 3px 11px; border-radius: 20px; margin-right: 6px; margin-bottom: 4px; } #fb-safety-note { border-left: 3px solid #D97706; background: #FFFBEB; padding: 9px 13px; border-radius: 0 6px 6px 0; margin-bottom: 14px; font-size: 12px; color: #92400E; line-height: 1.5; } """ _GR_MAJOR = int(gr.__version__.split(".")[0]) # theme/css moved to launch() in Gradio 6; in Gradio 4 they belong in Blocks() _theme = gr.themes.Soft(primary_hue="sky", font=["Inter", "sans-serif"]) _blocks_kw = {} if _GR_MAJOR >= 6 else {"theme": _theme, "css": css} _launch_kw = {"theme": _theme, "css": css} if _GR_MAJOR >= 6 else {} with gr.Blocks(**_blocks_kw) as demo: gr.HTML("""