Metadata-Version: 2.4
Name: play-parser
Version: 1.1.1
Summary: Parse dramatic play text into ordered dramatic events.
Author-email: Stergios Poularakis <stpoular@gmail.com>
License-Expression: MIT
Project-URL: Homepage, https://github.com/stpoular/play-parser
Project-URL: Documentation, https://github.com/stpoular/play-parser/tree/main/docs
Project-URL: Repository, https://github.com/stpoular/play-parser
Project-URL: Issues, https://github.com/stpoular/play-parser/issues
Project-URL: Changelog, https://github.com/stpoular/play-parser/blob/main/CHANGELOG.md
Keywords: theatre,drama,plays,parser,json
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Operating System :: OS Independent
Classifier: Topic :: Text Processing
Classifier: Typing :: Typed
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: dev
Requires-Dist: build>=1; extra == "dev"
Requires-Dist: pytest>=8; extra == "dev"
Requires-Dist: jsonschema>=4; extra == "dev"
Requires-Dist: ruff>=0.8; extra == "dev"
Requires-Dist: twine>=5; extra == "dev"
Dynamic: license-file

# play-parser

`play-parser` parses theatrical play text into a canonical JSON document and assembles canonical documents back into normalised play text.

Canonical text uses a stable output format. For example, speech labels are emitted in colon form such as `Hamlet: ...`, even when the source text used another supported layout.

## Features

- Parse raw `.txt` play files into structured JSON.
- Assemble canonical JSON documents into normalised `.txt` output.
- Read and validate existing canonical `.json` documents.
- Keep ingestion, parsing, and domain access separate.
- Choose between the production simple parser and the weighted FSM/Viterbi parser.
- Preserve speeches, stage directions, acts, scenes, metadata, characters, and document statistics.
- Use the package from Python or through the `play-parser` command line interface.

## Supported inputs

- Raw `.txt` play files.
- Canonical `.json` documents produced by this package.

The package does not parse PDFs, DOCX files, HTML pages, scans, images, or audio directly. Convert those sources to text first.

## Installation

```bash
pip install play-parser
```

## Python quick start

Recommended explicit pipeline:

```python
from play_parser import PlayIngestor, PlayParser

ingestor = PlayIngestor("Hamlet.txt")
parser = PlayParser.create("simple")
play = parser.parse(ingestor.data, profile="colon_inline", source_name=ingestor.source_name)

print(play.title)
print(play.author)
print(len(play.acts))
print(len(play.scenes))
print(len(play.characters))
print(len(play.speeches))

play.save_json("Hamlet.json")
play.save_text("Hamlet.canonical.txt")
```

Equivalent direct parser usage:

```python
from play_parser import SimplePlayParser

text = "ACT I\n\nSCENE I.\n\nHAMLET: Who's there?"
play = SimplePlayParser().parse(text, profile="colon_inline", source_name="Hamlet.txt")
```

Convenience domain usage:

```python
from play_parser import Play

text = "ACT I\n\nSCENE I.\n\nHAMLET: Who's there?"
play = Play(text, method="simple", profile="colon_inline", source_name="Hamlet.txt")
```

Weighted FSM parser:

```python
from play_parser import FSMPlayParser

play = FSMPlayParser().parse(text, profile="colon_inline", source_name="Hamlet.txt")

# The default beam is greedy; use a wider beam for delayed decisions.
play = FSMPlayParser(beam_width=2).parse(text, profile="colon_inline")
```

The FSM parser is a real separate parser entry point, not a wrapper around the simple parser. It uses a play-specific weighted finite-state model backed by a standalone Viterbi/beam decoder. The included simple and FSM corpus tests currently match a bundled 250-play regression corpus covering multiple stage-text formats. The scoring model remains explicit and tunable as more real-world plays are added.

Assemble a canonical document:

```python
from play_parser import assemble_play_text

canonical_text = assemble_play_text(play.as_dict())
```

## Command line usage

Show help and version information:

```bash
play-parser --help
play-parser --version
```

Parse one file with the production parser:

```bash
play-parser parse Hamlet.txt \
  --method simple \
  --profile colon_inline \
  --json-output Hamlet.json \
  --text-output Hamlet.canonical.txt
```

Run the weighted FSM parser:

```bash
play-parser parse Hamlet.txt --method fsm --beam-width 2 --json-output Hamlet.fsm.json
```

Parse a folder recursively:

```bash
play-parser parse \
  --input-root data/<play name> \
  --recursive \
  --profile colon_inline \
  --json-output-root data/<play name>/optimal.json/generated
```

Assemble canonical JSON files into text:

```bash
play-parser assemble \
  --input-root data/<play name>/optimal.json/generated \
  --recursive \
  --output-root data/<play name>/canonical
```

## Regression corpus

The repository includes 250 sample plays with checked `optimal.json` snapshots. The corpus covers colon-inline dialogue, dot-inline dialogue, dot-block dialogue, bare speaker blocks, screenplay sluglines, radio/SFX cues, cast-list preambles, act/scene numbering with digits, words and Roman numerals, multilingual speaker names, lowercase speaker labels, false-positive `ACT`/`SCENE` dialogue, page-header artefacts, no-dialogue physical scenes, mixed parenthetical cues, fixed-width and tabular dialogue, dash-separated dialogue, screenplay character blocks, foreign act/scene headings, line-numbered dialogue, verse continuations, PDF-style wrapping artefacts, OCR noise, cast-list ambiguity, subtitle/WebVTT/SRT fragments, markdown/web extraction artefacts, classical/verse conventions, and multilingual act/scene labels. Both the simple parser and FSM parser are tested against the same corpus.

## Public API

Stable top-level imports:

```python
from play_parser import (
    Play,
    PlayIngestor,
    PlayParser,
    SimplePlayParser,
    FSMPlayParser,
    assemble_play_text,
    get_format_profile,
    list_format_profiles,
    load_format_profile_config,
    load_format_profile_file,
    validate_play_document,
)
```

Domain classes such as `Act`, `Scene`, `Speech`, `Character`, `Monologue`, and `Dialogue` are also available from the top-level package.

## Format profiles

Built-in profiles are available through `list_format_profiles()` and can be passed to a parser or the CLI by name.

```python
from play_parser import list_format_profiles

print(list_format_profiles())
```

See [`docs/FORMAT_PROFILES.md`](docs/FORMAT_PROFILES.md) for the profile schema and examples.

## Documentation

- [`docs/API.md`](docs/API.md): Python API and CLI profile usage.
- [`docs/JSON_SCHEMA.md`](docs/JSON_SCHEMA.md): canonical JSON document format.
- [`docs/FORMAT_PROFILES.md`](docs/FORMAT_PROFILES.md): built-in and custom format profiles.

## Development

Install development dependencies:

```bash
python -m pip install -e .[dev]
```

Run local checks:

```bash
python -m ruff check .
python -m ruff format --check .
python -m pytest
python -m build
python -m twine check dist/*
```

Release steps are documented in [`RELEASE.md`](RELEASE.md).

## Licence

MIT
