Metadata-Version: 2.4
Name: psygen-llm
Version: 0.2.0
Summary: LLM-chained psychological profile generator for fictional characters (Psygen revised).
Author: Stardew AI NPC contributors
License-Expression: MIT
License-File: LICENSE
Keywords: character,llm,npc,profile,psychology,stardew
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
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: Typing :: Typed
Requires-Python: >=3.10
Requires-Dist: jsonschema>=4.20.0
Provides-Extra: dev
Requires-Dist: pytest-asyncio>=0.24.0; extra == 'dev'
Requires-Dist: pytest>=8.0.0; extra == 'dev'
Provides-Extra: openai
Requires-Dist: openai>=1.40.0; extra == 'openai'
Description-Content-Type: text/markdown

# psygen-llm

Python package implementing **Psygen Revised**: a three-stage (optional fourth) LLM pipeline that produces a structured psychological profile for a character from a natural-language query.

- **Schema**: JSON Schema for each layer and the merged profile (`package data`).
- **Runner**: `ProfileGenerator` chains axiom → intermediate → emergent calls, validates JSON, merges evidence.
- **Prompt surface**: `to_prompt_string()` emits dialogue-ready text (20 emergent traits + coping style + role identity), capped at 600 characters per the design contract.

## Install

```bash
pip install psygen-llm
```

With OpenAI client helper:

```bash
pip install psygen-llm[openai]
```

## OpenAI config

Create a JSON file (e.g. `psygen.json`, keep it private — `chmod 600` — and do not commit it):

```json
{
  "openai": {
    "api_key": "sk-...",
    "model": "gpt-4o-mini",
    "base_url": null
  }
}
```

`openai.api_key` and `openai.model` are required. `openai.base_url` is optional; omit it or set it to `null` for the default OpenAI API URL.

## Quick use

```python
import asyncio
from psygen_llm import ProfileGenerator, OpenAiLlmClient

async def main():
    client = OpenAiLlmClient.from_config_file("psygen.json")
    gen = ProfileGenerator(client)
    profile = await gen.generate("Linus from Stardew Valley")
    print(profile.to_prompt_string())
    print(profile.to_json())

asyncio.run(main())
```

## Custom LLM backend

Implement `psygen_llm.protocols.LlmClient` (`complete(system, user) -> str`) and pass it to `ProfileGenerator`.

## CLI

By default the merged profile JSON is written to `output/<slug>.json` (slug derived from your query; the `output/` directory is created if needed). Use `-o` for another path, or `-o -` to print JSON to stdout.

```bash
psygen-generate --config psygen.json "Linus from Stardew Valley"
psygen-generate --config psygen.json "Linus from Stardew Valley" -o /tmp/linus.json
psygen-generate --config psygen.json "Linus from Stardew Valley" -o -
```

## Design

See [DESIGN.md](./DESIGN.md) and [PLAN.md](./PLAN.md) in this directory.

## Develop and publish

```bash
cd path/to/psygen-llm
pip install -e ".[dev]"
pytest
python -m build
```

Upload to PyPI (after configuring credentials):

```bash
python -m twine upload dist/*
```

## License

MIT
