Skip to content

AI Parser

ShowParser converts a natural language description directly into a Show object using a local language model via Ollama. No exec() is involved — the model returns structured JSON that flaight safely converts into drone actions.

Two modes

Mode What you provide What the model does
Direct (parse) Explicit choreography instructions Follows them literally — no added creativity
Thematic (parse_thematic) A theme, mood, or emotion Freely designs formations, movement, and a colour palette to express it

Setup

from flaight import ShowParser

parser = ShowParser(
    host="http://localhost:11434",  # Ollama server URL
    model="llama3.2",              # model name
)

Mode 1 — direct choreography

Describe exactly what the drones should do.

from flaight import DryRunRunner, ShowParser

parser = ShowParser(host="http://localhost:11434", model="llama3.2")

show = parser.parse(
    "Two drones take off, fly apart to opposite sides, alternate red and blue, then land.",
    uris=["radio://0/80/2M/E7E7E7E701", "radio://0/80/2M/E7E7E7E702"],
)
DryRunRunner(show).run()

The model follows instructions literally. If you don't mention flying, no Takeoff/Land actions are generated — only color actions.

Mode 2 — thematic / emotional

Provide a theme or feeling. The model acts as a creative choreographer and designs the entire show.

show = parser.parse_thematic(
    "Melancholy — a lone farewell slowly fading into darkness.",
    uris=["radio://0/80/2M/E7E7E7E701", "radio://0/80/2M/E7E7E7E702",
          "radio://0/80/2M/E7E7E7E703"],
)
DryRunRunner(show, realtime=True).run()

Thematic prompts in any language work:

  • "Euphoria — an explosion of energy and colour"
  • "Aufbruch — ein Neuanfang voller Hoffnung"
  • "A thunderstorm building and breaking"
  • "Sunrise over the mountains"
  • "Tense standoff, then sudden release"

Preview before generating

Ask the model for a plain-text summary first — useful to check that it understood the description before committing to a full generation:

# Mode 1 — summarizes the explicit instructions
summary = parser.summarize(description, uris=uris)

# Mode 2 — describes the creative concept the model would build
summary = parser.summarize_thematic(description, uris=uris)

print(summary)

Interactive REPL

run_interactive runs a loop: describe → confirm summary → generate → simulate or fly → repeat.

parser.run_interactive(
    uris=["radio://0/80/2M/E7E7E7E701", "radio://0/80/2M/E7E7E7E702"],
    fly=False,       # True → real hardware instead of dry-run
    realtime=True,
)

Tip

The same loop is available from the command line via flaight — no Python script needed. See CLI — flaight.

For a self-contained code example of both modes without the REPL, see examples/ai_show.py.

Saving generated shows

Any AI-generated show can be exported as a standalone Python script:

from flaight import save_script

path = save_script(show)
print(f"Saved: {path}")

See Exporting for details.

Error handling

from flaight import ParseError

try:
    show = parser.parse(description, uris=uris)
except ParseError as exc:
    print(f"Could not parse show: {exc}")

ParseError is raised when the model returns invalid JSON or a response that cannot be mapped to flaight actions (e.g. because the model timed out or returned an unexpected format).

Constructor reference

ShowParser(
    host="http://localhost:11434",  # Ollama server URL
    model="llama3.2",              # Ollama model name
    verbose=False,                 # log raw LLM response at DEBUG level
    timeout=300.0,                 # request timeout in seconds
)