BareGit
#!/usr/bin/env python3
"""Create a SillyTavern Character Card V2 JSON document."""

import argparse
import json
import sys
from dataclasses import asdict, dataclass, field
from pathlib import Path
from typing import Any, TextIO


@dataclass
class CharacterCard:
    """The data section of a SillyTavern Character Card V2 document."""

    name: str = ""
    description: str = ""
    personality: str = ""
    scenario: str = ""
    first_mes: str = ""
    mes_example: str = ""
    creator_notes: str = ""
    system_prompt: str = ""
    post_history_instructions: str = ""
    alternate_greetings: list[str] = field(default_factory=list)
    character_book: None = None
    tags: list[str] = field(default_factory=list)
    creator: str = ""
    character_version: str = ""
    extensions: dict[str, Any] = field(default_factory=dict)

    def document(self) -> dict[str, Any]:
        """Return this card in the Character Card V2 document structure."""
        return {
            "spec": "chara_card_v2",
            "spec_version": "2.0",
            "data": asdict(self),
        }


def parseArguments() -> argparse.Namespace:
    """Parse command-line arguments for the character card generator."""
    parser = argparse.ArgumentParser(
        description="Create a SillyTavern Character Card V2 JSON document.",
    )
    parser.add_argument(
        "description",
        help="Character description.",
    )
    parser.add_argument(
        "personality",
        help="Character personality summary.",
    )
    parser.add_argument(
        "mes_example",
        help="Example messages that demonstrate the character's voice.",
    )
    parser.add_argument(
        "--name",
        default="",
        help="Optional character name.",
    )
    parser.add_argument(
        "-o",
        "--output",
        type=Path,
        help="Write JSON to this file instead of standard output.",
    )
    return parser.parse_args()


def writeJson(document: dict[str, Any], output: TextIO) -> None:
    """Write a UTF-8, human-readable JSON document followed by a newline."""
    json.dump(document, output, ensure_ascii=False, indent=2)
    output.write("\n")


def main() -> int:
    """Create a card from command-line values and write its JSON document."""
    arguments = parseArguments()
    card = CharacterCard(
        name=arguments.name,
        description=arguments.description,
        personality=arguments.personality,
        mes_example=arguments.mes_example,
    )

    if arguments.output is None:
        writeJson(card.document(), sys.stdout)
        return 0

    try:
        with arguments.output.open("w", encoding="utf-8") as output:
            writeJson(card.document(), output)
    except OSError as error:
        print(
            f"Could not write {arguments.output}: {error}",
            file=sys.stderr,
        )
        return 1

    return 0


if __name__ == "__main__":
    raise SystemExit(main())