Compare commits
336 Commits
0.31.0
...
prep-0.33.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
65a8cbf853 | ||
|
|
7dbff08056 | ||
|
|
159efc500d | ||
|
|
c0a11b8546 | ||
|
|
f90099999c | ||
|
|
3ca4299214 | ||
|
|
260f9fa374 | ||
|
|
bed6158003 | ||
|
|
bc5234a3a4 | ||
|
|
ca1f761ad7 | ||
|
|
1422fc4541 | ||
|
|
b71d9a580f | ||
|
|
248333139a | ||
|
|
fb4e73c6e8 | ||
|
|
ae36f8491c | ||
|
|
501668b2fe | ||
|
|
cbcef92ed7 | ||
|
|
8a95b02099 | ||
|
|
5c33723b7b | ||
|
|
1ab24396f1 | ||
|
|
b6729f3290 | ||
|
|
913db13590 | ||
|
|
ba1e64d359 | ||
|
|
519b600bc9 | ||
|
|
9901c36af6 | ||
|
|
6d4bfd59ac | ||
|
|
466bac8061 | ||
|
|
6328062c3d | ||
|
|
f9c1228b3e | ||
|
|
5d40b650dc | ||
|
|
aeef4c266f | ||
|
|
e7180b0dd5 | ||
|
|
154a02adf0 | ||
|
|
fe73970f67 | ||
|
|
007b944c4a | ||
|
|
8a79edc693 | ||
|
|
1e29c7eab4 | ||
|
|
07f1a72618 | ||
|
|
d51c7a2700 | ||
|
|
bb14f90669 | ||
|
|
4791918e34 | ||
|
|
5d6a4eef63 | ||
|
|
875deb2682 | ||
|
|
cc60ee1beb | ||
|
|
db8c021b68 | ||
|
|
7d7f210a2f | ||
|
|
27bc0a5b2f | ||
|
|
d25fdd9422 | ||
|
|
f5a2b9a67b | ||
|
|
8ebcd4ba5d | ||
|
|
ffc6d75f46 | ||
|
|
160b9c4e69 | ||
|
|
2e925c95b5 | ||
|
|
7edb830246 | ||
|
|
61bde467cd | ||
|
|
1274155e84 | ||
|
|
7569998cdb | ||
|
|
a9fed9a4dd | ||
|
|
7f0c8a339e | ||
|
|
2cc1c8c6ed | ||
|
|
ce03243ecf | ||
|
|
1923282727 | ||
|
|
0b41f76b07 | ||
|
|
5d9fdca5d8 | ||
|
|
0b1a2c5159 | ||
|
|
b9dbe9179c | ||
|
|
9ec55a0004 | ||
|
|
7529726df9 | ||
|
|
ebc2ae804b | ||
|
|
2b3cb8d101 | ||
|
|
6c3b53e37c | ||
|
|
3dee0ec0e9 | ||
|
|
504707796c | ||
|
|
0f59e1cd21 | ||
|
|
2f742b95d6 | ||
|
|
2627972d8b | ||
|
|
934e62dded | ||
|
|
238ff1dfe5 | ||
|
|
8b4e1962c4 | ||
|
|
d3a9c7f2c1 | ||
|
|
b8df7cfed8 | ||
|
|
4b27917173 | ||
|
|
8b94312f1f | ||
|
|
15aea906c5 | ||
|
|
fe36431a27 | ||
|
|
f6dabc18eb | ||
|
|
b5e30600fa | ||
|
|
765cd5799c | ||
|
|
9457620767 | ||
|
|
8b07422939 | ||
|
|
4eb185e895 | ||
|
|
78d434afd3 | ||
|
|
dc2b1c9149 | ||
|
|
511a33f69f | ||
|
|
0e3eb15fce | ||
|
|
f925758319 | ||
|
|
81e1da3c21 | ||
|
|
9dea2daef5 | ||
|
|
1c592a438f | ||
|
|
fadf4b8f2d | ||
|
|
22f97f60ea | ||
|
|
6782bfe93f | ||
|
|
2c2d2f160c | ||
|
|
3b85d007e2 | ||
|
|
ca1a1872ec | ||
|
|
1f5baf9958 | ||
|
|
b9dcfd54a5 | ||
|
|
ceb998088f | ||
|
|
a21117674b | ||
|
|
40bdf7b361 | ||
|
|
7161786b50 | ||
|
|
5c960784d9 | ||
|
|
0fd6d01184 | ||
|
|
4a9522d030 | ||
|
|
3a00e33dc1 | ||
|
|
751a2acfcb | ||
|
|
acb3b66328 | ||
|
|
8d56eb1ff8 | ||
|
|
435082935e | ||
|
|
d7fe0e36d9 | ||
|
|
0ae92c39de | ||
|
|
cfc84eb357 | ||
|
|
0336f19066 | ||
|
|
e2cca100f5 | ||
|
|
51d4ae57e9 | ||
|
|
8714fd1726 | ||
|
|
7e4d3b7268 | ||
|
|
117ea78f06 | ||
|
|
5f396b22d2 | ||
|
|
430c69a83d | ||
|
|
9d38432a8b | ||
|
|
bd378f4f44 | ||
|
|
e800179a0c | ||
|
|
a21c3d2ccf | ||
|
|
d41953a70d | ||
|
|
99efbade54 | ||
|
|
6db3cb72ff | ||
|
|
68ed364270 | ||
|
|
665cc6f4b1 | ||
|
|
7ef5b70ff2 | ||
|
|
a6d1065dcb | ||
|
|
33d093e5bb | ||
|
|
b2035ddebe | ||
|
|
3e06f8a64d | ||
|
|
152fb9b474 | ||
|
|
b7fdc3dc38 | ||
|
|
3cf5557780 | ||
|
|
e29496f650 | ||
|
|
2bb1e45eb5 | ||
|
|
4dc580f630 | ||
|
|
6a27c49594 | ||
|
|
131479e29b | ||
|
|
e6d528323b | ||
|
|
ccf6284442 | ||
|
|
99a9488564 | ||
|
|
42d08e5ac9 | ||
|
|
b137546697 | ||
|
|
f13d306470 | ||
|
|
7aa274a0e0 | ||
|
|
160818a26c | ||
|
|
6953ccec69 | ||
|
|
b746b8773b | ||
|
|
8652e88ea8 | ||
|
|
ad31e54e3a | ||
|
|
748a2cfccf | ||
|
|
20db574155 | ||
|
|
65e17f234f | ||
|
|
850679a0e8 | ||
|
|
ae0749d173 | ||
|
|
b13eb5be69 | ||
|
|
a4985c1888 | ||
|
|
67571ec9be | ||
|
|
29a5a5ac52 | ||
|
|
60f5f20715 | ||
|
|
00e3aa4a19 | ||
|
|
b59c3ab273 | ||
|
|
4dbc824c07 | ||
|
|
0463fd37e5 | ||
|
|
a18a43cbe6 | ||
|
|
b1cbaf650f | ||
|
|
73c544211a | ||
|
|
c65a7889d3 | ||
|
|
dc9e297587 | ||
|
|
5d361331d5 | ||
|
|
0b8810073f | ||
|
|
6ba65ff75e | ||
|
|
291921a9f2 | ||
|
|
1b8ba12e61 | ||
|
|
9adbb2c518 | ||
|
|
883dffdd73 | ||
|
|
0c5fd2e48d | ||
|
|
7a6ae0f135 | ||
|
|
6da7b29b94 | ||
|
|
b423bc3a18 | ||
|
|
bf8a580c33 | ||
|
|
734b2bab19 | ||
|
|
46afdeeb0b | ||
|
|
674dfc5978 | ||
|
|
71595a1fff | ||
|
|
219b5e2786 | ||
|
|
1243d03718 | ||
|
|
ac9c66915b | ||
|
|
00b3c05f3d | ||
|
|
308363c93c | ||
|
|
78cc9334d3 | ||
|
|
e74e9c679a | ||
|
|
6549d65ee8 | ||
|
|
babe77929c | ||
|
|
531c0b4e87 | ||
|
|
3dc2269678 | ||
|
|
26d7886c31 | ||
|
|
3dadf49a69 | ||
|
|
4cb612bc23 | ||
|
|
b85b983522 | ||
|
|
922f520ec3 | ||
|
|
555d90e53a | ||
|
|
e84c36a31b | ||
|
|
072cd7fd12 | ||
|
|
b9f5423f92 | ||
|
|
e9f0e4124a | ||
|
|
c361f4723b | ||
|
|
e0c92be628 | ||
|
|
52f07b26fa | ||
|
|
1c7d28f83c | ||
|
|
5fb22467f2 | ||
|
|
b9f4d0a88a | ||
|
|
fb43310049 | ||
|
|
e98cafa63d | ||
|
|
ae82e7ba2d | ||
|
|
bad9453ba1 | ||
|
|
f41506eeeb | ||
|
|
6f47edbb27 | ||
|
|
67facdf39e | ||
|
|
1fdc95e7cf | ||
|
|
ab956f25a7 | ||
|
|
cbbc843f86 | ||
|
|
028b0abf53 | ||
|
|
a7bbabbcad | ||
|
|
e61baa6a5a | ||
|
|
56b8e033ba | ||
|
|
1dd796aeb2 | ||
|
|
8d824acebc | ||
|
|
2a1bd5864f | ||
|
|
e666cfe81a | ||
|
|
d4182705e1 | ||
|
|
e57d5dbb73 | ||
|
|
4fb5bc54ba | ||
|
|
f68610f315 | ||
|
|
e0e81a3796 | ||
|
|
c53bbf2693 | ||
|
|
9c60d4c046 | ||
|
|
a427b940b5 | ||
|
|
63c992ab44 | ||
|
|
910764bde4 | ||
|
|
7bbe5ced7e | ||
|
|
119dee7418 | ||
|
|
ddbb74a7a3 | ||
|
|
64f7165fc8 | ||
|
|
5d008ae676 | ||
|
|
62db9b1221 | ||
|
|
a544367501 | ||
|
|
314f24d23a | ||
|
|
fbde0103bd | ||
|
|
1c84ad76ea | ||
|
|
9c5d5cc322 | ||
|
|
bf605604f0 | ||
|
|
62d3aa25ca | ||
|
|
eb4e1426ac | ||
|
|
11f5242008 | ||
|
|
4b0b252bfb | ||
|
|
85680a5285 | ||
|
|
c8969d0fb7 | ||
|
|
3e5697d072 | ||
|
|
e446b01ac8 | ||
|
|
1cc73f1899 | ||
|
|
238911630b | ||
|
|
89c9364db3 | ||
|
|
b291afefd0 | ||
|
|
08850a7cb3 | ||
|
|
9732e90a5b | ||
|
|
e689b18088 | ||
|
|
5123cbbef7 | ||
|
|
b19e8cc645 | ||
|
|
681102116d | ||
|
|
1b0f738e0b | ||
|
|
eb094cc4b5 | ||
|
|
c434fb5a78 | ||
|
|
6a37f673f6 | ||
|
|
9cd5434a58 | ||
|
|
4fdebcb803 | ||
|
|
145be1096e | ||
|
|
05b3065ed2 | ||
|
|
6d7b1cb063 | ||
|
|
dd9a8f8ad4 | ||
|
|
d4fcd724e3 | ||
|
|
c0d3d7f14f | ||
|
|
3ce834a432 | ||
|
|
dc84c416b3 | ||
|
|
e182a178c2 | ||
|
|
2b3251b46c | ||
|
|
09f136dfb9 | ||
|
|
3c7c5565f0 | ||
|
|
19af0e8156 | ||
|
|
6baadc544d | ||
|
|
bc072d9b68 | ||
|
|
67487b227e | ||
|
|
4d4ca5e2cb | ||
|
|
ed3f725b17 | ||
|
|
4646bad50e | ||
|
|
2fe1f4ff82 | ||
|
|
533a618658 | ||
|
|
d59807a68f | ||
|
|
a497775de6 | ||
|
|
599d7115e0 | ||
|
|
5f26134647 | ||
|
|
b971c3044d | ||
|
|
f3d02530d5 | ||
|
|
9bf08b1f00 | ||
|
|
b0f1b7307c | ||
|
|
9134c0cc26 | ||
|
|
3141e53eac | ||
|
|
307439b210 | ||
|
|
ab3f4f3b2e | ||
|
|
b862159aef | ||
|
|
8f4aa75e09 | ||
|
|
7320196ac6 | ||
|
|
e7b949c443 | ||
|
|
7ffbfe8d0d | ||
|
|
72867c930e | ||
|
|
eddddd5034 | ||
|
|
25e646c56a | ||
|
|
ce4c302d73 | ||
|
|
685ca994f9 | ||
|
|
285b0699ab | ||
|
|
7825489cfc | ||
|
|
fb2fa31f13 |
53
.github/workflows/ci.yml
vendored
@@ -1,30 +1,57 @@
|
||||
name: ci
|
||||
name: ci
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- main
|
||||
- prep-0.26.0
|
||||
- master
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
packages: write
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
container-build:
|
||||
if: github.event_name == 'release'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Configure Git Credentials
|
||||
run: |
|
||||
git config user.name github-actions[bot]
|
||||
git config user.email 41898282+github-actions[bot]@users.noreply.github.com
|
||||
- uses: actions/setup-python@v5
|
||||
|
||||
- name: Log in to GHCR
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
python-version: 3.x
|
||||
- run: echo "cache_id=$(date --utc '+%V')" >> $GITHUB_ENV
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Build & push
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
file: Dockerfile
|
||||
push: true
|
||||
tags: |
|
||||
ghcr.io/${{ github.repository }}:latest
|
||||
ghcr.io/${{ github.repository }}:${{ github.ref_name }}
|
||||
|
||||
deploy-docs:
|
||||
if: github.event_name == 'release'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Configure Git credentials
|
||||
run: |
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
||||
- uses: actions/setup-python@v5
|
||||
with: { python-version: '3.x' }
|
||||
- run: echo "cache_id=$(date --utc '+%V')" >> $GITHUB_ENV
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
key: mkdocs-material-${{ env.cache_id }}
|
||||
path: .cache
|
||||
restore-keys: |
|
||||
mkdocs-material-
|
||||
restore-keys: mkdocs-material-
|
||||
- run: pip install mkdocs-material mkdocs-awesome-pages-plugin mkdocs-glightbox
|
||||
- run: mkdocs gh-deploy --force
|
||||
32
.github/workflows/test-container-build.yml
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
name: test-container-build
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ 'prep-*' ]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
|
||||
jobs:
|
||||
container-build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Log in to GHCR
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Build & push
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
file: Dockerfile
|
||||
push: true
|
||||
# Tag with prep suffix to avoid conflicts with production
|
||||
tags: |
|
||||
ghcr.io/${{ github.repository }}:${{ github.ref_name }}
|
||||
5
.github/workflows/test.yml
vendored
@@ -42,6 +42,11 @@ jobs:
|
||||
source .venv/bin/activate
|
||||
uv pip install -e ".[dev]"
|
||||
|
||||
- name: Run linting
|
||||
run: |
|
||||
source .venv/bin/activate
|
||||
uv run pre-commit run --all-files
|
||||
|
||||
- name: Setup configuration file
|
||||
run: |
|
||||
cp config.example.yaml config.yaml
|
||||
|
||||
13
.gitignore
vendored
@@ -8,11 +8,20 @@
|
||||
talemate_env
|
||||
chroma
|
||||
config.yaml
|
||||
.cursor
|
||||
.claude
|
||||
|
||||
# uv
|
||||
.venv/
|
||||
templates/llm-prompt/user/*.jinja2
|
||||
templates/world-state/*.yaml
|
||||
tts/voice/piper/*.onnx
|
||||
tts/voice/piper/*.json
|
||||
tts/voice/kokoro/*.pt
|
||||
tts/voice/xtts2/*.wav
|
||||
tts/voice/chatterbox/*.wav
|
||||
tts/voice/f5tts/*.wav
|
||||
tts/voice/voice-library.json
|
||||
scenes/
|
||||
!scenes/infinity-quest-dynamic-scenario/
|
||||
!scenes/infinity-quest-dynamic-scenario/assets/
|
||||
@@ -21,4 +30,6 @@ scenes/
|
||||
!scenes/infinity-quest/assets/
|
||||
!scenes/infinity-quest/infinity-quest.json
|
||||
tts_voice_samples/*.wav
|
||||
third-party-docs/
|
||||
third-party-docs/
|
||||
legacy-state-reinforcements.yaml
|
||||
CLAUDE.md
|
||||
16
.pre-commit-config.yaml
Normal file
@@ -0,0 +1,16 @@
|
||||
fail_fast: false
|
||||
exclude: |
|
||||
(?x)^(
|
||||
tests/data/.*
|
||||
|install-utils/.*
|
||||
)$
|
||||
repos:
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
# Ruff version.
|
||||
rev: v0.12.1
|
||||
hooks:
|
||||
# Run the linter.
|
||||
- id: ruff
|
||||
args: [ --fix ]
|
||||
# Run the formatter.
|
||||
- id: ruff-format
|
||||
64
CONTRIBUTING.md
Normal file
@@ -0,0 +1,64 @@
|
||||
# Contributing to Talemate
|
||||
|
||||
## About This Project
|
||||
|
||||
Talemate is a **personal hobbyist project** that I maintain in my spare time. While I appreciate the community's interest and contributions, please understand that:
|
||||
|
||||
- This is primarily a passion project that I enjoy working on myself
|
||||
- I have limited time for code reviews and prefer to spend that time developing fixes or new features myself
|
||||
- Large contributions require significant review and testing time that takes away from my own development
|
||||
|
||||
For these reasons, I've established contribution guidelines that balance community involvement with my desire to actively develop the project myself.
|
||||
|
||||
## Contribution Policy
|
||||
|
||||
**I welcome small bugfix and small feature pull requests!** If you've found a bug and have a fix, or have a small feature improvement, I'd love to review it.
|
||||
|
||||
However, please note that **I am not accepting large refactors or major feature additions** at this time. This includes:
|
||||
- Major architectural changes
|
||||
- Large new features or significant functionality additions
|
||||
- Large-scale code reorganization
|
||||
- Breaking API changes
|
||||
- Features that would require significant maintenance
|
||||
|
||||
## What is accepted
|
||||
|
||||
✅ **Small bugfixes** - Fixes for specific, isolated bugs
|
||||
|
||||
✅ **Small features** - Minor improvements that don't break existing functionality
|
||||
|
||||
✅ **Documentation fixes** - Typo corrections, clarifications in existing docs
|
||||
|
||||
✅ **Minor dependency updates** - Security patches or minor version bumps
|
||||
|
||||
## What is not accepted
|
||||
|
||||
❌ **Major features** - Large new functionality or systems
|
||||
|
||||
❌ **Large refactors** - Code reorganization or architectural changes
|
||||
|
||||
❌ **Breaking changes** - Any changes that break existing functionality
|
||||
|
||||
❌ **Major dependency changes** - Framework upgrades or replacements
|
||||
|
||||
## Submitting a PR
|
||||
|
||||
If you'd like to submit a bugfix or small feature:
|
||||
|
||||
1. **Open an issue first** - Describe the bug you've found or feature you'd like to add
|
||||
2. **Keep it small** - Focus on one specific issue or small improvement
|
||||
3. **Follow existing code style** - Match the project's current patterns
|
||||
4. **Don't break existing functionality** - Ensure all existing tests pass
|
||||
5. **Include tests** - Add or update tests that verify your fix or feature
|
||||
6. **Update documentation** - If your changes affect behavior, update relevant docs
|
||||
|
||||
## Testing
|
||||
|
||||
Ensure all tests pass by running:
|
||||
```bash
|
||||
uv run pytest tests/ -p no:warnings
|
||||
```
|
||||
|
||||
## Questions?
|
||||
|
||||
If you're unsure whether your contribution would be welcome, please open an issue to discuss it first. This saves everyone time and ensures alignment with the project's direction.
|
||||
11
Dockerfile
@@ -35,18 +35,9 @@ COPY pyproject.toml uv.lock /app/
|
||||
# Copy the Python source code (needed for editable install)
|
||||
COPY ./src /app/src
|
||||
|
||||
# Create virtual environment and install dependencies
|
||||
# Create virtual environment and install dependencies (includes CUDA support via pyproject.toml)
|
||||
RUN uv sync
|
||||
|
||||
# Conditional PyTorch+CUDA install
|
||||
ARG CUDA_AVAILABLE=false
|
||||
RUN . /app/.venv/bin/activate && \
|
||||
if [ "$CUDA_AVAILABLE" = "true" ]; then \
|
||||
echo "Installing PyTorch with CUDA support..." && \
|
||||
uv pip uninstall torch torchaudio && \
|
||||
uv pip install torch~=2.7.0 torchaudio~=2.7.0 --index-url https://download.pytorch.org/whl/cu128; \
|
||||
fi
|
||||
|
||||
# Stage 3: Final image
|
||||
FROM python:3.11-slim
|
||||
|
||||
|
||||
20
docker-compose.manual.yml
Normal file
@@ -0,0 +1,20 @@
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
talemate:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
ports:
|
||||
- "${FRONTEND_PORT:-8080}:8080"
|
||||
- "${BACKEND_PORT:-5050}:5050"
|
||||
volumes:
|
||||
- ./config.yaml:/app/config.yaml
|
||||
- ./scenes:/app/scenes
|
||||
- ./templates:/app/templates
|
||||
- ./chroma:/app/chroma
|
||||
- ./tts:/app/tts
|
||||
environment:
|
||||
- PYTHONUNBUFFERED=1
|
||||
- PYTHONPATH=/app/src:$PYTHONPATH
|
||||
command: ["uv", "run", "src/talemate/server/run.py", "runserver", "--host", "0.0.0.0", "--port", "5050", "--frontend-host", "0.0.0.0", "--frontend-port", "8080"]
|
||||
@@ -2,11 +2,7 @@ version: '3.8'
|
||||
|
||||
services:
|
||||
talemate:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
args:
|
||||
- CUDA_AVAILABLE=${CUDA_AVAILABLE:-false}
|
||||
image: ghcr.io/vegu-ai/talemate:latest
|
||||
ports:
|
||||
- "${FRONTEND_PORT:-8080}:8080"
|
||||
- "${BACKEND_PORT:-5050}:5050"
|
||||
@@ -15,6 +11,7 @@ services:
|
||||
- ./scenes:/app/scenes
|
||||
- ./templates:/app/templates
|
||||
- ./chroma:/app/chroma
|
||||
- ./tts:/app/tts
|
||||
environment:
|
||||
- PYTHONUNBUFFERED=1
|
||||
- PYTHONPATH=/app/src:$PYTHONPATH
|
||||
|
||||
@@ -1,60 +1,63 @@
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
import argparse
|
||||
|
||||
|
||||
def find_image_references(md_file):
|
||||
"""Find all image references in a markdown file."""
|
||||
with open(md_file, 'r', encoding='utf-8') as f:
|
||||
with open(md_file, "r", encoding="utf-8") as f:
|
||||
content = f.read()
|
||||
|
||||
pattern = r'!\[.*?\]\((.*?)\)'
|
||||
|
||||
pattern = r"!\[.*?\]\((.*?)\)"
|
||||
matches = re.findall(pattern, content)
|
||||
|
||||
|
||||
cleaned_paths = []
|
||||
for match in matches:
|
||||
path = match.lstrip('/')
|
||||
if 'img/' in path:
|
||||
path = path[path.index('img/') + 4:]
|
||||
path = match.lstrip("/")
|
||||
if "img/" in path:
|
||||
path = path[path.index("img/") + 4 :]
|
||||
# Only keep references to versioned images
|
||||
parts = os.path.normpath(path).split(os.sep)
|
||||
if len(parts) >= 2 and parts[0].replace('.', '').isdigit():
|
||||
if len(parts) >= 2 and parts[0].replace(".", "").isdigit():
|
||||
cleaned_paths.append(path)
|
||||
|
||||
|
||||
return cleaned_paths
|
||||
|
||||
|
||||
def scan_markdown_files(docs_dir):
|
||||
"""Recursively scan all markdown files in the docs directory."""
|
||||
md_files = []
|
||||
for root, _, files in os.walk(docs_dir):
|
||||
for file in files:
|
||||
if file.endswith('.md'):
|
||||
if file.endswith(".md"):
|
||||
md_files.append(os.path.join(root, file))
|
||||
return md_files
|
||||
|
||||
|
||||
def find_all_images(img_dir):
|
||||
"""Find all image files in version subdirectories."""
|
||||
image_files = []
|
||||
for root, _, files in os.walk(img_dir):
|
||||
# Get the relative path from img_dir to current directory
|
||||
rel_dir = os.path.relpath(root, img_dir)
|
||||
|
||||
|
||||
# Skip if we're in the root img directory
|
||||
if rel_dir == '.':
|
||||
if rel_dir == ".":
|
||||
continue
|
||||
|
||||
|
||||
# Check if the immediate parent directory is a version number
|
||||
parent_dir = rel_dir.split(os.sep)[0]
|
||||
if not parent_dir.replace('.', '').isdigit():
|
||||
if not parent_dir.replace(".", "").isdigit():
|
||||
continue
|
||||
|
||||
|
||||
for file in files:
|
||||
if file.lower().endswith(('.png', '.jpg', '.jpeg', '.gif', '.svg')):
|
||||
if file.lower().endswith((".png", ".jpg", ".jpeg", ".gif", ".svg")):
|
||||
rel_path = os.path.relpath(os.path.join(root, file), img_dir)
|
||||
image_files.append(rel_path)
|
||||
return image_files
|
||||
|
||||
|
||||
def grep_check_image(docs_dir, image_path):
|
||||
"""
|
||||
Check if versioned image is referenced anywhere using grep.
|
||||
@@ -65,33 +68,46 @@ def grep_check_image(docs_dir, image_path):
|
||||
parts = os.path.normpath(image_path).split(os.sep)
|
||||
version = parts[0] # e.g., "0.29.0"
|
||||
filename = parts[-1] # e.g., "world-state-suggestions-2.png"
|
||||
|
||||
|
||||
# For versioned images, require both version and filename to match
|
||||
version_pattern = f"{version}.*{filename}"
|
||||
try:
|
||||
result = subprocess.run(
|
||||
['grep', '-r', '-l', version_pattern, docs_dir],
|
||||
["grep", "-r", "-l", version_pattern, docs_dir],
|
||||
capture_output=True,
|
||||
text=True
|
||||
text=True,
|
||||
)
|
||||
if result.stdout.strip():
|
||||
print(f"Found reference to {image_path} with version pattern: {version_pattern}")
|
||||
print(
|
||||
f"Found reference to {image_path} with version pattern: {version_pattern}"
|
||||
)
|
||||
return True
|
||||
except subprocess.CalledProcessError:
|
||||
pass
|
||||
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error during grep check for {image_path}: {e}")
|
||||
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description='Find and optionally delete unused versioned images in MkDocs project')
|
||||
parser.add_argument('--docs-dir', type=str, required=True, help='Path to the docs directory')
|
||||
parser.add_argument('--img-dir', type=str, required=True, help='Path to the images directory')
|
||||
parser.add_argument('--delete', action='store_true', help='Delete unused images')
|
||||
parser.add_argument('--verbose', action='store_true', help='Show all found references and files')
|
||||
parser.add_argument('--skip-grep', action='store_true', help='Skip the additional grep validation')
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Find and optionally delete unused versioned images in MkDocs project"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--docs-dir", type=str, required=True, help="Path to the docs directory"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--img-dir", type=str, required=True, help="Path to the images directory"
|
||||
)
|
||||
parser.add_argument("--delete", action="store_true", help="Delete unused images")
|
||||
parser.add_argument(
|
||||
"--verbose", action="store_true", help="Show all found references and files"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--skip-grep", action="store_true", help="Skip the additional grep validation"
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
# Convert paths to absolute paths
|
||||
@@ -118,7 +134,7 @@ def main():
|
||||
print("\nAll versioned image references found in markdown:")
|
||||
for img in sorted(used_images):
|
||||
print(f"- {img}")
|
||||
|
||||
|
||||
print("\nAll versioned images in directory:")
|
||||
for img in sorted(all_images):
|
||||
print(f"- {img}")
|
||||
@@ -133,9 +149,11 @@ def main():
|
||||
for img in unused_images:
|
||||
if not grep_check_image(docs_dir, img):
|
||||
actually_unused.add(img)
|
||||
|
||||
|
||||
if len(actually_unused) != len(unused_images):
|
||||
print(f"\nGrep validation found {len(unused_images) - len(actually_unused)} additional image references!")
|
||||
print(
|
||||
f"\nGrep validation found {len(unused_images) - len(actually_unused)} additional image references!"
|
||||
)
|
||||
unused_images = actually_unused
|
||||
|
||||
# Report findings
|
||||
@@ -148,7 +166,7 @@ def main():
|
||||
print("\nUnused versioned images:")
|
||||
for img in sorted(unused_images):
|
||||
print(f"- {img}")
|
||||
|
||||
|
||||
if args.delete:
|
||||
print("\nDeleting unused versioned images...")
|
||||
for img in unused_images:
|
||||
@@ -162,5 +180,6 @@ def main():
|
||||
else:
|
||||
print("\nNo unused versioned images found!")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
main()
|
||||
|
||||
@@ -4,12 +4,12 @@ from talemate.events import GameLoopEvent
|
||||
import talemate.emit.async_signals
|
||||
from talemate.emit import emit
|
||||
|
||||
|
||||
@register()
|
||||
class TestAgent(Agent):
|
||||
|
||||
agent_type = "test"
|
||||
verbose_name = "Test"
|
||||
|
||||
|
||||
def __init__(self, client):
|
||||
self.client = client
|
||||
self.is_enabled = True
|
||||
@@ -20,7 +20,7 @@ class TestAgent(Agent):
|
||||
description="Test",
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
@property
|
||||
def enabled(self):
|
||||
return self.is_enabled
|
||||
@@ -36,7 +36,7 @@ class TestAgent(Agent):
|
||||
def connect(self, scene):
|
||||
super().connect(scene)
|
||||
talemate.emit.async_signals.get("game_loop").connect(self.on_game_loop)
|
||||
|
||||
|
||||
async def on_game_loop(self, emission: GameLoopEvent):
|
||||
"""
|
||||
Called on the beginning of every game loop
|
||||
@@ -45,4 +45,8 @@ class TestAgent(Agent):
|
||||
if not self.enabled:
|
||||
return
|
||||
|
||||
emit("status", status="info", message="Annoying you with a test message every game loop.")
|
||||
emit(
|
||||
"status",
|
||||
status="info",
|
||||
message="Annoying you with a test message every game loop.",
|
||||
)
|
||||
|
||||
@@ -19,14 +19,17 @@ from talemate.config import Client as BaseClientConfig
|
||||
|
||||
log = structlog.get_logger("talemate.client.runpod_vllm")
|
||||
|
||||
|
||||
class Defaults(pydantic.BaseModel):
|
||||
max_token_length: int = 4096
|
||||
model: str = ""
|
||||
runpod_id: str = ""
|
||||
|
||||
|
||||
|
||||
class ClientConfig(BaseClientConfig):
|
||||
runpod_id: str = ""
|
||||
|
||||
|
||||
@register()
|
||||
class RunPodVLLMClient(ClientBase):
|
||||
client_type = "runpod_vllm"
|
||||
@@ -49,7 +52,6 @@ class RunPodVLLMClient(ClientBase):
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
def __init__(self, model=None, runpod_id=None, **kwargs):
|
||||
self.model_name = model
|
||||
self.runpod_id = runpod_id
|
||||
@@ -59,12 +61,10 @@ class RunPodVLLMClient(ClientBase):
|
||||
def experimental(self):
|
||||
return False
|
||||
|
||||
|
||||
def set_client(self, **kwargs):
|
||||
log.debug("set_client", kwargs=kwargs, runpod_id=self.runpod_id)
|
||||
self.runpod_id = kwargs.get("runpod_id", self.runpod_id)
|
||||
|
||||
|
||||
|
||||
def tune_prompt_parameters(self, parameters: dict, kind: str):
|
||||
super().tune_prompt_parameters(parameters, kind)
|
||||
|
||||
@@ -88,32 +88,37 @@ class RunPodVLLMClient(ClientBase):
|
||||
self.log.debug("generate", prompt=prompt[:128] + " ...", parameters=parameters)
|
||||
|
||||
try:
|
||||
|
||||
async with aiohttp.ClientSession() as session:
|
||||
endpoint = runpod.AsyncioEndpoint(self.runpod_id, session)
|
||||
|
||||
run_request = await endpoint.run({
|
||||
"input": {
|
||||
"prompt": prompt,
|
||||
|
||||
run_request = await endpoint.run(
|
||||
{
|
||||
"input": {
|
||||
"prompt": prompt,
|
||||
}
|
||||
# "parameters": parameters
|
||||
}
|
||||
#"parameters": parameters
|
||||
})
|
||||
|
||||
while (await run_request.status()) not in ["COMPLETED", "FAILED", "CANCELLED"]:
|
||||
)
|
||||
|
||||
while (await run_request.status()) not in [
|
||||
"COMPLETED",
|
||||
"FAILED",
|
||||
"CANCELLED",
|
||||
]:
|
||||
status = await run_request.status()
|
||||
log.debug("generate", status=status)
|
||||
await asyncio.sleep(0.1)
|
||||
|
||||
|
||||
status = await run_request.status()
|
||||
|
||||
|
||||
log.debug("generate", status=status)
|
||||
|
||||
|
||||
response = await run_request.output()
|
||||
|
||||
|
||||
log.debug("generate", response=response)
|
||||
|
||||
|
||||
return response["choices"][0]["tokens"][0]
|
||||
|
||||
|
||||
except Exception as e:
|
||||
self.log.error("generate error", e=e)
|
||||
emit(
|
||||
|
||||
@@ -9,6 +9,7 @@ class Defaults(pydantic.BaseModel):
|
||||
api_url: str = "http://localhost:1234"
|
||||
max_token_length: int = 4096
|
||||
|
||||
|
||||
@register()
|
||||
class TestClient(ClientBase):
|
||||
client_type = "test"
|
||||
@@ -22,14 +23,13 @@ class TestClient(ClientBase):
|
||||
self.client = AsyncOpenAI(base_url=self.api_url + "/v1", api_key="sk-1111")
|
||||
|
||||
def tune_prompt_parameters(self, parameters: dict, kind: str):
|
||||
|
||||
"""
|
||||
Talemate adds a bunch of parameters to the prompt, but not all of them are valid for all clients.
|
||||
|
||||
|
||||
This method is called before the prompt is sent to the client, and it allows the client to remove
|
||||
any parameters that it doesn't support.
|
||||
"""
|
||||
|
||||
|
||||
super().tune_prompt_parameters(parameters, kind)
|
||||
|
||||
keys = list(parameters.keys())
|
||||
@@ -41,11 +41,10 @@ class TestClient(ClientBase):
|
||||
del parameters[key]
|
||||
|
||||
async def get_model_name(self):
|
||||
|
||||
"""
|
||||
This should return the name of the model that is being used.
|
||||
"""
|
||||
|
||||
|
||||
return "Mock test model"
|
||||
|
||||
async def generate(self, prompt: str, parameters: dict, kind: str):
|
||||
|
||||
@@ -27,10 +27,10 @@ uv run src\talemate\server\run.py runserver --host 0.0.0.0 --port 1234
|
||||
|
||||
### Letting the frontend know about the new host and port
|
||||
|
||||
Copy `talemate_frontend/example.env.development.local` to `talemate_frontend/.env.production.local` and edit the `VUE_APP_TALEMATE_BACKEND_WEBSOCKET_URL`.
|
||||
Copy `talemate_frontend/example.env.development.local` to `talemate_frontend/.env.production.local` and edit the `VITE_TALEMATE_BACKEND_WEBSOCKET_URL`.
|
||||
|
||||
```env
|
||||
VUE_APP_TALEMATE_BACKEND_WEBSOCKET_URL=ws://localhost:1234
|
||||
VITE_TALEMATE_BACKEND_WEBSOCKET_URL=ws://localhost:1234
|
||||
```
|
||||
|
||||
Next rebuild the frontend.
|
||||
|
||||
@@ -1,22 +1,15 @@
|
||||
!!! example "Experimental"
|
||||
Talemate through docker has not received a lot of testing from me, so please let me know if you encounter any issues.
|
||||
|
||||
You can do so by creating an issue on the [:material-github: GitHub repository](https://github.com/vegu-ai/talemate)
|
||||
|
||||
## Quick install instructions
|
||||
|
||||
1. `git clone https://github.com/vegu-ai/talemate.git`
|
||||
1. `cd talemate`
|
||||
1. copy config file
|
||||
1. linux: `cp config.example.yaml config.yaml`
|
||||
1. windows: `copy config.example.yaml config.yaml`
|
||||
1. If your host has a CUDA compatible Nvidia GPU
|
||||
1. Windows (via PowerShell): `$env:CUDA_AVAILABLE="true"; docker compose up`
|
||||
1. Linux: `CUDA_AVAILABLE=true docker compose up`
|
||||
1. If your host does **NOT** have a CUDA compatible Nvidia GPU
|
||||
1. Windows: `docker compose up`
|
||||
1. Linux: `docker compose up`
|
||||
1. windows: `copy config.example.yaml config.yaml` (or just copy the file and rename it via the file explorer)
|
||||
1. `docker compose up`
|
||||
1. Navigate your browser to http://localhost:8080
|
||||
|
||||
!!! info "Pre-built Images"
|
||||
The default setup uses pre-built images from GitHub Container Registry that include CUDA support by default. To manually build the container instead, use `docker compose -f docker-compose.manual.yml up --build`.
|
||||
|
||||
!!! note
|
||||
When connecting local APIs running on the hostmachine (e.g. text-generation-webui), you need to use `host.docker.internal` as the hostname.
|
||||
|
||||
@@ -12,14 +12,6 @@
|
||||
!!! note "First start can take a while"
|
||||
The initial download and dependency installation may take several minutes, especially on slow internet connections. The console will keep you updated – just wait until the Talemate logo shows up.
|
||||
|
||||
### Optional: CUDA support
|
||||
|
||||
If you have an NVIDIA GPU and want CUDA acceleration for larger embedding models:
|
||||
|
||||
1. Close Talemate (if it is running).
|
||||
2. Double-click **`install-cuda.bat`**. This script swaps the CPU-only Torch build for the CUDA 12.8 build.
|
||||
3. Start Talemate again via **`start.bat`**.
|
||||
|
||||
## Maintenance & advanced usage
|
||||
|
||||
| Script | Purpose |
|
||||
|
||||
BIN
docs/img/0.32.0/add-chatterbox-voice.png
Normal file
|
After Width: | Height: | Size: 35 KiB |
BIN
docs/img/0.32.0/add-elevenlabs-voice.png
Normal file
|
After Width: | Height: | Size: 29 KiB |
BIN
docs/img/0.32.0/add-f5tts-voice.png
Normal file
|
After Width: | Height: | Size: 43 KiB |
BIN
docs/img/0.32.0/character-voice-assignment.png
Normal file
|
After Width: | Height: | Size: 65 KiB |
BIN
docs/img/0.32.0/chatterbox-api-settings.png
Normal file
|
After Width: | Height: | Size: 54 KiB |
BIN
docs/img/0.32.0/chatterbox-parameters.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
docs/img/0.32.0/client-reasoning-2.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
docs/img/0.32.0/client-reasoning.png
Normal file
|
After Width: | Height: | Size: 75 KiB |
BIN
docs/img/0.32.0/elevenlabs-api-settings.png
Normal file
|
After Width: | Height: | Size: 61 KiB |
BIN
docs/img/0.32.0/elevenlabs-copy-voice-id.png
Normal file
|
After Width: | Height: | Size: 9.6 KiB |
BIN
docs/img/0.32.0/f5tts-api-settings.png
Normal file
|
After Width: | Height: | Size: 72 KiB |
BIN
docs/img/0.32.0/f5tts-parameters.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
docs/img/0.32.0/google-tts-api-settings.png
Normal file
|
After Width: | Height: | Size: 63 KiB |
BIN
docs/img/0.32.0/kokoro-mixer.png
Normal file
|
After Width: | Height: | Size: 33 KiB |
BIN
docs/img/0.32.0/openai-tts-api-settings.png
Normal file
|
After Width: | Height: | Size: 61 KiB |
BIN
docs/img/0.32.0/voice-agent-settings.png
Normal file
|
After Width: | Height: | Size: 107 KiB |
BIN
docs/img/0.32.0/voice-agent-status-characters.png
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
docs/img/0.32.0/voice-library-access.png
Normal file
|
After Width: | Height: | Size: 9.3 KiB |
BIN
docs/img/0.32.0/voice-library-api-status.png
Normal file
|
After Width: | Height: | Size: 6.6 KiB |
BIN
docs/img/0.32.0/voice-library-interface.png
Normal file
|
After Width: | Height: | Size: 142 KiB |
BIN
docs/img/0.33.0/client-lock-template-0001.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
docs/img/0.33.0/client-lock-template-0002.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
docs/img/0.33.0/client-lock-template-0003.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
docs/img/0.33.0/director-agent-chat-settings.png
Normal file
|
After Width: | Height: | Size: 63 KiB |
BIN
docs/img/0.33.0/director-chat-0001.png
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
docs/img/0.33.0/director-chat-0002.png
Normal file
|
After Width: | Height: | Size: 64 KiB |
BIN
docs/img/0.33.0/director-chat-0003.png
Normal file
|
After Width: | Height: | Size: 61 KiB |
BIN
docs/img/0.33.0/director-chat-0004.png
Normal file
|
After Width: | Height: | Size: 42 KiB |
BIN
docs/img/0.33.0/director-chat-confirm-off.png
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
docs/img/0.33.0/director-chat-confirm-on.png
Normal file
|
After Width: | Height: | Size: 3.9 KiB |
BIN
docs/img/0.33.0/director-chat-expanded-function-call.png
Normal file
|
After Width: | Height: | Size: 72 KiB |
BIN
docs/img/0.33.0/director-chat-interaction.png
Normal file
|
After Width: | Height: | Size: 67 KiB |
BIN
docs/img/0.33.0/director-chat-mode.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
docs/img/0.33.0/director-chat-persona-0001.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
docs/img/0.33.0/director-chat-persona-0002.png
Normal file
|
After Width: | Height: | Size: 75 KiB |
BIN
docs/img/0.33.0/director-chat-reject-0001.png
Normal file
|
After Width: | Height: | Size: 60 KiB |
BIN
docs/img/0.33.0/director-chat-reject-0002.png
Normal file
|
After Width: | Height: | Size: 71 KiB |
BIN
docs/img/0.33.0/director-console-chat.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
docs/img/0.33.0/history-shared-context.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
docs/img/0.33.0/open-director-console.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
BIN
docs/img/0.33.0/restore-from-backup-dlg.png
Normal file
|
After Width: | Height: | Size: 46 KiB |
BIN
docs/img/0.33.0/restore-from-backup.png
Normal file
|
After Width: | Height: | Size: 107 KiB |
BIN
docs/img/0.33.0/share-with-world.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
docs/img/0.33.0/shared-context-1.png
Normal file
|
After Width: | Height: | Size: 39 KiB |
BIN
docs/img/0.33.0/shared-context-2.png
Normal file
|
After Width: | Height: | Size: 44 KiB |
BIN
docs/img/0.33.0/shared-context-3.png
Normal file
|
After Width: | Height: | Size: 6.9 KiB |
BIN
docs/img/0.33.0/shared-context-new-scene.png
Normal file
|
After Width: | Height: | Size: 32 KiB |
BIN
docs/img/0.33.0/unshare-from-world.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
BIN
docs/img/0.33.0/world-entry-shared-context.png
Normal file
|
After Width: | Height: | Size: 7.6 KiB |
125
docs/user-guide/agents/director/chat.md
Normal file
@@ -0,0 +1,125 @@
|
||||
# Director Chat
|
||||
|
||||
!!! example "Experimental"
|
||||
Currently experimental and may change substantially in the future.
|
||||
|
||||
Introduced in version 0.33.0 the director chat feature allows you interact with the director agent directly once a scene is loaded.
|
||||
|
||||
As part of the chat session the director can query for information as well as make changes to the scene.
|
||||
|
||||
!!! warning "Strong model recommended"
|
||||
In my personal testing I've found that while its possible to have a coherent chat session with weaker models, the experience is going to be
|
||||
significantly better with [reasoning enabled](/talemate/user-guide/clients/reasoning/) models past the 100B parameter mark.
|
||||
|
||||
This may change as smaller models get stronger and your mileage may vary.
|
||||
|
||||
!!! info "Chat settings"
|
||||
You can customize various aspects of the director chat behavior in the [Director Chat settings](/talemate/user-guide/agents/director/settings/#director-chat), including response length, token budgets, and custom instructions.
|
||||
|
||||
## Accessing the director chat
|
||||
|
||||
Once a scene is loaded click the **:material-bullhorn:** director console icon in the top right corner of the screen.
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
## Chat interface
|
||||
|
||||
The director chat provides a conversational interface where you can ask the director to perform various tasks, from querying information about your scene to making changes to characters, world entries, and progressing the story.
|
||||
|
||||

|
||||
|
||||
### What can you ask the director to do?
|
||||
|
||||
The director can help you with many tasks:
|
||||
|
||||
- Progress the story by generating new narration or dialogue
|
||||
- Answer questions about your characters, world, or story details
|
||||
- Create or modify characters, world entries, and story configuration
|
||||
- Advance time in your story
|
||||
- Manage game state variables (if your story uses them)
|
||||
|
||||
Simply describe what you want in natural language, and the director will figure out how to accomplish it.
|
||||
|
||||
### Viewing action details
|
||||
|
||||
When the director performs an action, you can expand it to see exactly what was done:
|
||||
|
||||

|
||||
|
||||
This gives you full transparency into the changes being made to your scene.
|
||||
|
||||
## Chat modes
|
||||
|
||||
The director chat supports three different modes that control how the director behaves:
|
||||
|
||||

|
||||
|
||||
!!! note
|
||||
Chat mode behavior is not guaranteed and depends heavily on the model's ability to follow instructions. Stronger models, especially those with reasoning capabilities, will respect these modes much more consistently than weaker models.
|
||||
|
||||
### Normal mode
|
||||
|
||||
The default mode where the director can freely discuss the story and reveal information. It will ask for clarification when needed and take a more conversational approach.
|
||||
|
||||
### Decisive mode
|
||||
|
||||
In this mode, the director acts more confidently on your instructions and avoids asking for clarifications unless strictly necessary. Use this when you trust the director to make the right decisions autonomously.
|
||||
|
||||
### No Spoilers mode
|
||||
|
||||
This mode prevents the director from revealing information that could spoil the story. The director will still make changes and answer questions, but will be careful not to discuss plot points or details that should remain hidden.
|
||||
|
||||
## Write action confirmation
|
||||
|
||||
By default, the director will ask for confirmation before performing actions that modify your scene (like progressing the story or making significant changes).
|
||||
|
||||

|
||||
|
||||
You can toggle this behavior to allow the director to act without confirmation:
|
||||
|
||||

|
||||
|
||||
!!! tip
|
||||
Keep confirmation enabled when experimenting or when you want more control over changes. Disable it when you trust the director to act autonomously.
|
||||
|
||||
### Confirmation workflow example
|
||||
|
||||
When confirmation is enabled, the director will describe what it plans to do and wait for your approval:
|
||||
|
||||

|
||||
|
||||
The confirmation dialog shows the instructions that will be sent and the expected result:
|
||||
|
||||

|
||||
|
||||
Once confirmed, the action executes and new content is added to your scene:
|
||||
|
||||

|
||||
|
||||
The director then analyzes the result and discusses what happened:
|
||||
|
||||

|
||||
|
||||
### Rejecting actions
|
||||
|
||||
You can also reject actions if you change your mind or want to revise your request:
|
||||
|
||||

|
||||
|
||||
When rejected, the director acknowledges and waits for your next instruction:
|
||||
|
||||

|
||||
|
||||
## Director personas
|
||||
|
||||
You can customize the director's personality and initial greeting by assigning a persona:
|
||||
|
||||

|
||||
|
||||
Personas can completely change how the director presents itself and communicates with you:
|
||||
|
||||

|
||||
|
||||
To create or manage personas, select "Manage Personas" from the persona dropdown. You can define a custom description and initial chat message for each persona.
|
||||
@@ -154,4 +154,56 @@ Allows the director to evaluate the current scene phase and switch to a differen
|
||||
The number of turns between evaluations. (0 = NEVER)
|
||||
|
||||
!!! note "Recommended to leave at 0 (never)"
|
||||
This isn't really working well at this point, so recommended to leave at 0 (never)
|
||||
This isn't really working well at this point, so recommended to leave at 0 (never)
|
||||
|
||||
## Director Chat
|
||||
|
||||
!!! example "Experimental"
|
||||
Currently experimental and may change substantially in the future.
|
||||
|
||||
The [Director Chat](/talemate/user-guide/agents/director/chat) feature allows you to interact with the director through a conversational interface where you can ask questions, make changes to your scene, and direct story progression.
|
||||
|
||||

|
||||
|
||||
##### Enable Analysis Step
|
||||
|
||||
When enabled, the director performs an internal analysis step before responding. This helps the director think through complex requests and plan actions more carefully.
|
||||
|
||||
!!! tip "Recommended for complex tasks"
|
||||
Enable this when working on complex scene modifications or when you want more thoughtful responses. Disable it for simple queries to get faster responses.
|
||||
|
||||
##### Response token budget
|
||||
|
||||
Controls the maximum number of tokens the director can use for generating responses. Higher values allow for more detailed responses but use more tokens. Default is 2048.
|
||||
|
||||
##### Auto-iteration limit
|
||||
|
||||
The maximum number of action-response cycles the director can perform in a single interaction. For example, if set to 10, the director can execute actions and generate follow-up responses up to 10 times before requiring your input again. Default is 10.
|
||||
|
||||
##### Retries
|
||||
|
||||
The number of times the director will retry if it encounters an error during response generation. Default is 1.
|
||||
|
||||
##### Scene context ratio
|
||||
|
||||
Controls the fraction of the remaining token budget (after fixed context and instructions) that is reserved for scene context. The rest is allocated to chat history.
|
||||
|
||||
- **Lower values** (e.g., 0.30): 30% for scene context, 70% for chat history
|
||||
- **Higher values** (e.g., 0.70): 70% for scene context, 30% for chat history
|
||||
|
||||
Default is 0.30.
|
||||
|
||||
##### Stale history share
|
||||
|
||||
When the chat history needs to be compacted (summarized), this controls what fraction of the chat history budget is treated as "stale" and should be summarized. The remaining portion is kept verbatim as recent messages.
|
||||
|
||||
- **Lower values** (e.g., 0.50): Summarize less (50%), keep more recent messages verbatim
|
||||
- **Higher values** (e.g., 0.90): Summarize more (90%), keep fewer recent messages verbatim
|
||||
|
||||
Default is 0.70 (70% will be summarized when compaction is triggered).
|
||||
|
||||
##### Custom instructions
|
||||
|
||||
Add custom instructions that will be included in all director chat prompts. Use this to customize the director's behavior for your specific scene or storytelling style.
|
||||
|
||||
For example, you might add instructions to maintain a particular tone, follow specific genre conventions, or handle certain types of requests in a particular way.
|
||||
58
docs/user-guide/agents/voice/chatterbox.md
Normal file
@@ -0,0 +1,58 @@
|
||||
# Chatterbox
|
||||
|
||||
Local zero shot voice cloning from .wav files.
|
||||
|
||||

|
||||
|
||||
##### Device
|
||||
|
||||
Auto-detects best available option
|
||||
|
||||
##### Model
|
||||
|
||||
Default Chatterbox model optimized for speed
|
||||
|
||||
##### Chunk size
|
||||
|
||||
Split text into chunks of this size. Smaller values will increase responsiveness at the cost of lost context between chunks. (Stuff like appropriate inflection, etc.). 0 = no chunking
|
||||
|
||||
## Adding Chatterbox Voices
|
||||
|
||||
### Voice Requirements
|
||||
|
||||
Chatterbox voices require:
|
||||
|
||||
- Reference audio file (.wav format, 5-15 seconds optimal)
|
||||
- Clear speech with minimal background noise
|
||||
- Single speaker throughout the sample
|
||||
|
||||
### Creating a Voice
|
||||
|
||||
1. Open the Voice Library
|
||||
2. Click **:material-plus: New**
|
||||
3. Select "Chatterbox" as the provider
|
||||
4. Configure the voice:
|
||||
|
||||

|
||||
|
||||
**Label:** Descriptive name (e.g., "Marcus - Deep Male")
|
||||
|
||||
**Voice ID / Upload File** Upload a .wav file containing the voice sample. The uploaded reference audio will also be the voice ID.
|
||||
|
||||
**Speed:** Adjust playback speed (0.5 to 2.0, default 1.0)
|
||||
|
||||
**Tags:** Add descriptive tags for organization
|
||||
|
||||
**Extra voice parameters**
|
||||
|
||||
There exist some optional parameters that can be set here on a per voice level.
|
||||
|
||||

|
||||
|
||||
##### Exaggeration Level
|
||||
|
||||
Exaggeration (Neutral = 0.5, extreme values can be unstable). Higher exaggeration tends to speed up speech; reducing cfg helps compensate with slower, more deliberate pacing.
|
||||
|
||||
##### CFG / Pace
|
||||
|
||||
If the reference speaker has a fast speaking style, lowering cfg to around 0.3 can improve pacing.
|
||||
@@ -1,7 +1,41 @@
|
||||
# ElevenLabs
|
||||
|
||||
If you have not configured the ElevenLabs TTS API, the voice agent will show that the API key is missing.
|
||||
Professional voice synthesis with voice cloning capabilities using ElevenLabs API.
|
||||
|
||||

|
||||

|
||||
|
||||
See the [ElevenLabs API setup](/talemate/user-guide/apis/elevenlabs/) for instructions on how to set up the API key.
|
||||
## API Setup
|
||||
|
||||
ElevenLabs requires an API key. See the [ElevenLabs API setup](/talemate/user-guide/apis/elevenlabs/) for instructions on obtaining and setting an API key.
|
||||
|
||||
## Configuration
|
||||
|
||||
**Model:** Select from available ElevenLabs models
|
||||
|
||||
!!! warning "Voice Limits"
|
||||
Your ElevenLabs subscription allows you to maintain a set number of voices (10 for the cheapest plan). Any voice that you generate audio for is automatically added to your voices at [https://elevenlabs.io/app/voice-lab](https://elevenlabs.io/app/voice-lab). This also happens when you use the "Test" button. It is recommended to test voices via their voice library instead.
|
||||
|
||||
## Adding ElevenLabs Voices
|
||||
|
||||
### Getting Voice IDs
|
||||
|
||||
1. Go to [https://elevenlabs.io/app/voice-lab](https://elevenlabs.io/app/voice-lab) to view your voices
|
||||
2. Find or create the voice you want to use
|
||||
3. Click "More Actions" -> "Copy Voice ID" for the desired voice
|
||||
|
||||

|
||||
|
||||
### Creating a Voice in Talemate
|
||||
|
||||

|
||||
|
||||
1. Open the Voice Library
|
||||
2. Click "Add Voice"
|
||||
3. Select "ElevenLabs" as the provider
|
||||
4. Configure the voice:
|
||||
|
||||
**Label:** Descriptive name for the voice
|
||||
|
||||
**Provider ID:** Paste the ElevenLabs voice ID you copied
|
||||
|
||||
**Tags:** Add descriptive tags for organization
|
||||
78
docs/user-guide/agents/voice/f5tts.md
Normal file
@@ -0,0 +1,78 @@
|
||||
# F5-TTS
|
||||
|
||||
Local zero shot voice cloning from .wav files.
|
||||
|
||||

|
||||
|
||||
##### Device
|
||||
Auto-detects best available option (GPU preferred)
|
||||
|
||||
##### Model
|
||||
|
||||
- F5TTS_v1_Base (default, most recent model)
|
||||
- F5TTS_Base
|
||||
- E2TTS_Base
|
||||
|
||||
##### NFE Step
|
||||
|
||||
Number of steps to generate the voice. Higher values result in more detailed voices.
|
||||
|
||||
##### Chunk size
|
||||
|
||||
Split text into chunks of this size. Smaller values will increase responsiveness at the cost of lost context between chunks. (Stuff like appropriate inflection, etc.). 0 = no chunking
|
||||
|
||||
##### Replace exclamation marks
|
||||
|
||||
If checked, exclamation marks will be replaced with periods. This is recommended for `F5TTS_v1_Base` since it seems to over exaggerate exclamation marks.
|
||||
|
||||
## Adding F5-TTS Voices
|
||||
|
||||
### Voice Requirements
|
||||
|
||||
F5-TTS voices require:
|
||||
|
||||
- Reference audio file (.wav format, 10-30 seconds)
|
||||
- Clear speech with minimal background noise
|
||||
- Single speaker throughout the sample
|
||||
- Reference text (optional but recommended)
|
||||
|
||||
### Creating a Voice
|
||||
|
||||
1. Open the Voice Library
|
||||
2. Click "Add Voice"
|
||||
3. Select "F5-TTS" as the provider
|
||||
4. Configure the voice:
|
||||
|
||||

|
||||
|
||||
**Label:** Descriptive name (e.g., "Emma - Calm Female")
|
||||
|
||||
**Voice ID / Upload File** Upload a .wav file containing the **reference audio** voice sample. The uploaded reference audio will also be the voice ID.
|
||||
|
||||
- Use 6-10 second samples (longer doesn't improve quality)
|
||||
- Ensure clear speech with minimal background noise
|
||||
- Record at natural speaking pace
|
||||
|
||||
**Reference Text:** Enter the exact text spoken in the reference audio for improved quality
|
||||
|
||||
- Enter exactly what is spoken in the reference audio
|
||||
- Include proper punctuation and capitalization
|
||||
- Improves voice cloning accuracy significantly
|
||||
|
||||
**Speed:** Adjust playback speed (0.5 to 2.0, default 1.0)
|
||||
|
||||
**Tags:** Add descriptive tags (gender, age, style) for organization
|
||||
|
||||
**Extra voice parameters**
|
||||
|
||||
There exist some optional parameters that can be set here on a per voice level.
|
||||
|
||||

|
||||
|
||||
##### Speed
|
||||
|
||||
Allows you to adjust the speed of the voice.
|
||||
|
||||
##### CFG Strength
|
||||
|
||||
A higher CFG strength generally leads to more faithful reproduction of the input text, while a lower CFG strength can result in more varied or creative speech output, potentially at the cost of text-to-speech accuracy.
|
||||
15
docs/user-guide/agents/voice/google.md
Normal file
@@ -0,0 +1,15 @@
|
||||
# Google Gemini-TTS
|
||||
|
||||
Google Gemini-TTS provides access to Google's text-to-speech service.
|
||||
|
||||
## API Setup
|
||||
|
||||
Google Gemini-TTS requires a Google Cloud API key.
|
||||
|
||||
See the [Google Cloud API setup](/talemate/user-guide/apis/google/) for instructions on obtaining an API key.
|
||||
|
||||
## Configuration
|
||||
|
||||

|
||||
|
||||
**Model:** Select from available Google TTS models
|
||||
@@ -1,6 +1,26 @@
|
||||
# Overview
|
||||
|
||||
Talemate supports Text-to-Speech (TTS) functionality, allowing users to convert text into spoken audio. This document outlines the steps required to configure TTS for Talemate using different providers, including ElevenLabs and a local TTS API.
|
||||
In 0.32.0 Talemate's TTS (Text-to-Speech) agent has been completely refactored to provide advanced voice capabilities including per-character voice assignment, speaker separation, and support for multiple local and remote APIs. The voice system now includes a comprehensive voice library for managing and organizing voices across all supported providers.
|
||||
|
||||
## Key Features
|
||||
|
||||
- **Per-character voice assignment** - Each character can have their own unique voice
|
||||
- **Speaker separation** - Automatic detection and separation of dialogue from narration
|
||||
- **Voice library management** - Centralized management of all voices across providers
|
||||
- **Multiple API support** - Support for both local and remote TTS providers
|
||||
- **Director integration** - Automatic voice assignment for new characters
|
||||
|
||||
## Supported APIs
|
||||
|
||||
### Local APIs
|
||||
- **Kokoro** - Fastest generation with predefined voice models and mixing
|
||||
- **F5-TTS** - Fast voice cloning with occasional mispronunciations
|
||||
- **Chatterbox** - High-quality voice cloning (slower generation)
|
||||
|
||||
### Remote APIs
|
||||
- **ElevenLabs** - Professional voice synthesis with voice cloning
|
||||
- **Google Gemini-TTS** - Google's text-to-speech service
|
||||
- **OpenAI** - OpenAI's TTS-1 and TTS-1-HD models
|
||||
|
||||
## Enable the Voice agent
|
||||
|
||||
@@ -12,28 +32,30 @@ If your voice agent is disabled - indicated by the grey dot next to the agent -
|
||||
|
||||
 
|
||||
|
||||
!!! note "Ctrl click to toggle agent"
|
||||
You can use Ctrl click to toggle the agent on and off.
|
||||
|
||||
!!! abstract "Next: Connect to a TTS api"
|
||||
Next you need to decide which service / api to use for audio generation and configure the voice agent accordingly.
|
||||
## Voice Library Management
|
||||
|
||||
- [OpenAI](openai.md)
|
||||
- [ElevenLabs](elevenlabs.md)
|
||||
- [Local TTS](local_tts.md)
|
||||
Voices are managed through the Voice Library, accessible from the main application bar. The Voice Library allows you to:
|
||||
|
||||
You can also find more information about the various settings [here](settings.md).
|
||||
- Add and organize voices from all supported providers
|
||||
- Assign voices to specific characters
|
||||
- Create mixed voices (Kokoro)
|
||||
- Manage both global and scene-specific voice libraries
|
||||
|
||||
## Select a voice
|
||||
See the [Voice Library Guide](voice-library.md) for detailed instructions.
|
||||
|
||||

|
||||
## Character Voice Assignment
|
||||
|
||||
Click on the agent to open the agent settings.
|
||||

|
||||
|
||||
Then click on the `Narrator Voice` dropdown and select a voice.
|
||||
Characters can have individual voices assigned through the Voice Library. When a character has a voice assigned:
|
||||
|
||||

|
||||
1. Their dialogue will use their specific voice
|
||||
2. The narrator voice is used for exposition in their messages (with speaker separation enabled)
|
||||
3. If their assigned voice's API is not available, it falls back to the narrator voice
|
||||
|
||||
The selection is saved automatically, click anywhere outside the agent window to close it.
|
||||
The Voice agent status will show all assigned character voices and their current status.
|
||||
|
||||
The Voice agent should now show that the voice is selected and be ready to use.
|
||||
|
||||

|
||||

|
||||
55
docs/user-guide/agents/voice/kokoro.md
Normal file
@@ -0,0 +1,55 @@
|
||||
# Kokoro
|
||||
|
||||
Kokoro provides predefined voice models and voice mixing capabilities for creating custom voices.
|
||||
|
||||
## Using Predefined Voices
|
||||
|
||||
Kokoro comes with built-in voice models that are ready to use immediately
|
||||
|
||||
Available predefined voices include various male and female voices with different characteristics.
|
||||
|
||||
## Creating Mixed Voices
|
||||
|
||||
Kokor allows you to mix voices together to create a new voice.
|
||||
|
||||
### Voice Mixing Interface
|
||||
|
||||
|
||||
To create a mixed voice:
|
||||
|
||||
1. Open the Voice Library
|
||||
2. Click ":material-plus: New"
|
||||
3. Select "Kokoro" as the provider
|
||||
4. Choose ":material-tune:Mixer" option
|
||||
5. Configure the mixed voice:
|
||||
|
||||

|
||||
|
||||
|
||||
**Label:** Descriptive name for the mixed voice
|
||||
|
||||
**Base Voices:** Select 2-4 existing Kokoro voices to combine
|
||||
|
||||
**Weights:** Set the influence of each voice (0.1 to 1.0)
|
||||
|
||||
**Tags:** Descriptive tags for organization
|
||||
|
||||
### Weight Configuration
|
||||
|
||||
Each selected voice can have its weight adjusted:
|
||||
|
||||
- Higher weights make that voice more prominent in the mix
|
||||
- Lower weights make that voice more subtle
|
||||
- Total weights need to sum to 1.0
|
||||
- Experiment with different combinations to achieve desired results
|
||||
|
||||
### Saving Mixed Voices
|
||||
|
||||
Once configured click "Add Voice", mixed voices are saved to your voice library and can be:
|
||||
|
||||
- Assigned to characters
|
||||
- Used as narrator voices
|
||||
|
||||
just like any other voice.
|
||||
|
||||
Saving a mixed cvoice may take a moment to complete.
|
||||
@@ -1,53 +0,0 @@
|
||||
# Local TTS
|
||||
|
||||
!!! warning
|
||||
This has not been tested in a while and may not work as expected. It will likely be replaced with something different in the future. If this approach is currently broken its likely to remain so until it is replaced.
|
||||
|
||||
For running a local TTS API, Talemate requires specific dependencies to be installed.
|
||||
|
||||
### Windows Installation
|
||||
|
||||
Run `install-local-tts.bat` to install the necessary requirements.
|
||||
|
||||
### Linux Installation
|
||||
|
||||
Execute the following command:
|
||||
|
||||
```bash
|
||||
pip install TTS
|
||||
```
|
||||
|
||||
### Model and Device Configuration
|
||||
|
||||
1. Choose a TTS model from the [Coqui TTS model list](https://github.com/coqui-ai/TTS).
|
||||
2. Decide whether to use `cuda` or `cpu` for the device setting.
|
||||
3. The first time you run TTS through the local API, it will download the specified model. Please note that this may take some time, and the download progress will be visible in the Talemate backend output.
|
||||
|
||||
Example configuration snippet:
|
||||
|
||||
```yaml
|
||||
tts:
|
||||
device: cuda # or 'cpu'
|
||||
model: tts_models/multilingual/multi-dataset/xtts_v2
|
||||
```
|
||||
|
||||
### Voice Samples Configuration
|
||||
|
||||
Configure voice samples by setting the `value` field to the path of a .wav file voice sample. Official samples can be downloaded from [Coqui XTTS-v2 samples](https://huggingface.co/coqui/XTTS-v2/tree/main/samples).
|
||||
|
||||
Example configuration snippet:
|
||||
|
||||
```yaml
|
||||
tts:
|
||||
voices:
|
||||
- label: English Male
|
||||
value: path/to/english_male.wav
|
||||
- label: English Female
|
||||
value: path/to/english_female.wav
|
||||
```
|
||||
|
||||
## Saving the Configuration
|
||||
|
||||
After configuring the `config.yaml` file, save your changes. Talemate will use the updated settings the next time it starts.
|
||||
|
||||
For more detailed information on configuring Talemate, refer to the `config.py` file in the Talemate source code and the `config.example.yaml` file for a barebone configuration example.
|
||||
@@ -8,16 +8,12 @@ See the [OpenAI API setup](/apis/openai.md) for instructions on how to set up th
|
||||
|
||||
## Settings
|
||||
|
||||

|
||||

|
||||
|
||||
##### Model
|
||||
|
||||
Which model to use for generation.
|
||||
|
||||
- GPT-4o Mini TTS
|
||||
- TTS-1
|
||||
- TTS-1 HD
|
||||
|
||||
!!! quote "OpenAI API documentation on quality"
|
||||
For real-time applications, the standard tts-1 model provides the lowest latency but at a lower quality than the tts-1-hd model. Due to the way the audio is generated, tts-1 is likely to generate content that has more static in certain situations than tts-1-hd. In some cases, the audio may not have noticeable differences depending on your listening device and the individual person.
|
||||
|
||||
Generally i have found that HD is fast enough for talemate, so this is the default.
|
||||
- TTS-1 HD
|
||||
@@ -1,36 +1,65 @@
|
||||
# Settings
|
||||
|
||||

|
||||

|
||||
|
||||
##### API
|
||||
##### Enabled APIs
|
||||
|
||||
The TTS API to use for voice generation.
|
||||
Select which TTS APIs to enable. You can enable multiple APIs simultaneously:
|
||||
|
||||
- OpenAI
|
||||
- ElevenLabs
|
||||
- Local TTS
|
||||
- **Kokoro** - Fastest generation with predefined voice models and mixing
|
||||
- **F5-TTS** - Fast voice cloning with occasional mispronunciations
|
||||
- **Chatterbox** - High-quality voice cloning (slower generation)
|
||||
- **ElevenLabs** - Professional voice synthesis with voice cloning
|
||||
- **Google Gemini-TTS** - Google's text-to-speech service
|
||||
- **OpenAI** - OpenAI's TTS-1 and TTS-1-HD models
|
||||
|
||||
!!! note "Multi-API Support"
|
||||
You can enable multiple APIs and assign different voices from different providers to different characters. The system will automatically route voice generation to the appropriate API based on the voice assignment.
|
||||
|
||||
##### Narrator Voice
|
||||
|
||||
The voice to use for narration. Each API will come with its own set of voices.
|
||||
The default voice used for narration and as a fallback for characters without assigned voices.
|
||||
|
||||

|
||||
The dropdown shows all available voices from all enabled APIs, with the format: "Voice Name (Provider)"
|
||||
|
||||
!!! note "Local TTS"
|
||||
For local TTS, you will have to provide voice samples yourself. See [Local TTS Instructions](local_tts.md) for more information.
|
||||
!!! info "Voice Management"
|
||||
Voices are managed through the Voice Library, accessible from the main application bar. Adding, removing, or modifying voices should be done through the Voice Library interface.
|
||||
|
||||
##### Generate for player
|
||||
##### Speaker Separation
|
||||
|
||||
Whether to generate voice for the player. If enabled, whenever the player speaks, the voice agent will generate audio for them.
|
||||
Controls how dialogue is separated from exposition in messages:
|
||||
|
||||
##### Generate for NPCs
|
||||
- **No separation** - Character messages use character voice entirely, narrator messages use narrator voice
|
||||
- **Simple** - Basic separation of dialogue from exposition using punctuation analysis, with exposition being read by the narrator voice
|
||||
- **Mixed** - Enables AI assisted separation for narrator messages and simple separation for character messages
|
||||
- **AI assisted** - AI assisted separation for both narrator and character messages
|
||||
|
||||
Whether to generate voice for NPCs. If enabled, whenever a non player character speaks, the voice agent will generate audio for them.
|
||||
!!! warning "AI Assisted Performance"
|
||||
AI-assisted speaker separation sends additional prompts to your LLM, which may impact response time and API costs.
|
||||
|
||||
##### Generate for narration
|
||||
##### Auto-generate for player
|
||||
|
||||
Whether to generate voice for narration. If enabled, whenever the narrator speaks, the voice agent will generate audio for them.
|
||||
Generate voice automatically for player messages
|
||||
|
||||
##### Split generation
|
||||
##### Auto-generate for AI characters
|
||||
|
||||
If enabled, the voice agent will generate audio in chunks, allowing for faster generation. This does however cause it lose context between chunks, and inflection may not be as good.
|
||||
Generate voice automatically for NPC/AI character messages
|
||||
|
||||
##### Auto-generate for narration
|
||||
|
||||
Generate voice automatically for narrator messages
|
||||
|
||||
##### Auto-generate for context investigation
|
||||
|
||||
Generate voice automatically for context investigation messages
|
||||
|
||||
## Advanced Settings
|
||||
|
||||
Advanced settings are configured per-API and can be found in the respective API configuration sections:
|
||||
|
||||
- **Chunk size** - Maximum text length per generation request
|
||||
- **Model selection** - Choose specific models for each API
|
||||
- **Voice parameters** - Provider-specific voice settings
|
||||
|
||||
!!! tip "Performance Optimization"
|
||||
Each API has different optimal chunk sizes and parameters. The system automatically handles chunking and queuing for optimal performance across all enabled APIs.
|
||||
156
docs/user-guide/agents/voice/voice-library.md
Normal file
@@ -0,0 +1,156 @@
|
||||
# Voice Library
|
||||
|
||||
The Voice Library is the central hub for managing all voices across all TTS providers in Talemate. It provides a unified interface for organizing, creating, and assigning voices to characters.
|
||||
|
||||
## Accessing the Voice Library
|
||||
|
||||
The Voice Library can be accessed from the main application bar at the top of the Talemate interface.
|
||||
|
||||

|
||||
|
||||
Click the voice icon to open the Voice Library dialog.
|
||||
|
||||
!!! note "Voice agent needs to be enabled"
|
||||
The Voice agent needs to be enabled for the voice library to be available.
|
||||
|
||||
## Voice Library Interface
|
||||
|
||||

|
||||
|
||||
The Voice Library interface consists of:
|
||||
|
||||
### Scope Tabs
|
||||
|
||||
- **Global** - Voices available across all scenes
|
||||
- **Scene** - Voices specific to the current scene (only visible when a scene is loaded)
|
||||
- **Characters** - Character voice assignments for the current scene (only visible when a scene is loaded)
|
||||
|
||||
### API Status
|
||||
|
||||
The toolbar shows the status of all TTS APIs:
|
||||
|
||||
- **Green** - API is enabled and ready
|
||||
- **Orange** - API is enabled but not configured
|
||||
- **Red** - API has configuration issues
|
||||
- **Gray** - API is disabled
|
||||
|
||||

|
||||
|
||||
## Managing Voices
|
||||
|
||||
### Global Voice Library
|
||||
|
||||
The global voice library contains voices that are available across all scenes. These include:
|
||||
|
||||
- Default voices provided by each TTS provider
|
||||
- Custom voices you've added
|
||||
|
||||
#### Adding New Voices
|
||||
|
||||
To add a new voice:
|
||||
|
||||
1. Click the "+ New" button
|
||||
2. Select the TTS provider
|
||||
3. Configure the voice parameters:
|
||||
- **Label** - Display name for the voice
|
||||
- **Provider ID** - Provider-specific identifier
|
||||
- **Tags** - Free-form descriptive tags you define (gender, age, style, etc.)
|
||||
- **Parameters** - Provider-specific settings
|
||||
|
||||
Check the provider specific documentation for more information on how to configure the voice.
|
||||
|
||||
#### Voice Types by Provider
|
||||
|
||||
**F5-TTS & Chatterbox:**
|
||||
|
||||
- Upload .wav reference files for voice cloning
|
||||
- Specify reference text for better quality
|
||||
- Adjust speed and other parameters
|
||||
|
||||
**Kokoro:**
|
||||
|
||||
- Select from predefined voice models
|
||||
- Create mixed voices by combining multiple models
|
||||
- Adjust voice mixing weights
|
||||
|
||||
**ElevenLabs:**
|
||||
|
||||
- Select from available ElevenLabs voices
|
||||
- Configure voice settings and stability
|
||||
- Use custom cloned voices from your ElevenLabs account
|
||||
|
||||
**OpenAI:**
|
||||
|
||||
- Choose from available OpenAI voice models
|
||||
- Configure model (GPT-4o Mini TTS, TTS-1, TTS-1-HD)
|
||||
|
||||
**Google Gemini-TTS:**
|
||||
|
||||
- Select from Google's voice models
|
||||
- Configure language and gender settings
|
||||
|
||||
### Scene Voice Library
|
||||
|
||||
Scene-specific voices are only available within the current scene. This is useful for:
|
||||
|
||||
- Scene-specific characters
|
||||
- Temporary voice experiments
|
||||
- Custom voices for specific scenarios
|
||||
|
||||
Scene voices are saved with the scene and will be available when the scene is loaded.
|
||||
|
||||
## Character Voice Assignment
|
||||
|
||||
### Automatic Assignment
|
||||
|
||||
The Director agent can automatically assign voices to new characters based on:
|
||||
|
||||
- Character tags and attributes
|
||||
- Voice tags matching character personality
|
||||
- Available voices in the voice library
|
||||
|
||||
This feature can be enabled in the Director agent settings.
|
||||
|
||||
### Manual Assignment
|
||||
|
||||

|
||||
|
||||
To manually assign a voice to a character:
|
||||
|
||||
1. Go to the "Characters" tab in the Voice Library
|
||||
2. Find the character in the list
|
||||
3. Click the voice dropdown for that character
|
||||
4. Select a voice from the available options
|
||||
5. The assignment is saved automatically
|
||||
|
||||
### Character Voice Status
|
||||
|
||||
The character list shows:
|
||||
|
||||
- **Character name**
|
||||
- **Currently assigned voice** (if any)
|
||||
- **Voice status** - whether the voice's API is available
|
||||
- **Quick assignment controls**
|
||||
|
||||
## Voice Tags and Organization
|
||||
|
||||
### Tagging System
|
||||
|
||||
Voices can be tagged with any descriptive attributes you choose. Tags are completely free-form and user-defined. Common examples include:
|
||||
|
||||
- **Gender**: male, female, neutral
|
||||
- **Age**: young, mature, elderly
|
||||
- **Style**: calm, energetic, dramatic, mysterious
|
||||
- **Quality**: deep, high, raspy, smooth
|
||||
- **Character types**: narrator, villain, hero, comic relief
|
||||
- **Custom tags**: You can create any tags that help you organize your voices
|
||||
|
||||
### Filtering and Search
|
||||
|
||||
Use the search bar to filter voices by:
|
||||
- Voice label/name
|
||||
- Provider
|
||||
- Tags
|
||||
- Character assignments
|
||||
|
||||
This makes it easy to find the right voice for specific characters or situations.
|
||||
82
docs/user-guide/clients/reasoning.md
Normal file
@@ -0,0 +1,82 @@
|
||||
# Reasoning Model Support
|
||||
|
||||
Talemate supports reasoning models that can perform step-by-step thinking before generating their final response. This feature allows models to work through complex problems internally before providing an answer.
|
||||
|
||||
## Enabling Reasoning Support
|
||||
|
||||
To enable reasoning support for a client:
|
||||
|
||||
1. Open the **Clients** dialog from the main toolbar
|
||||
2. Select the client you want to configure
|
||||
3. Navigate to the **Reasoning** tab in the client configuration
|
||||
|
||||

|
||||
|
||||
4. Check the **Enable Reasoning** checkbox
|
||||
|
||||
## Configuring Reasoning Tokens
|
||||
|
||||
Once reasoning is enabled, you can configure the **Reasoning Tokens** setting using the slider:
|
||||
|
||||

|
||||
|
||||
### Recommended Token Amounts
|
||||
|
||||
**For local reasoning models:** Use a high token allocation (recommended: 4096 tokens) to give the model sufficient space for complex reasoning.
|
||||
|
||||
**For remote APIs:** Start with lower amounts (512-1024 tokens) and adjust based on your needs and token costs.
|
||||
|
||||
### Token Allocation Behavior
|
||||
|
||||
The behavior of the reasoning tokens setting depends on your API provider:
|
||||
|
||||
**For APIs that support direct reasoning token specification:**
|
||||
|
||||
- The specified tokens will be allocated specifically for reasoning
|
||||
- The model will use these tokens for internal thinking before generating the response
|
||||
|
||||
**For APIs that do NOT support reasoning token specification:**
|
||||
|
||||
- The tokens are added as extra allowance to the response token limit for ALL requests
|
||||
- This may lead to more verbose responses than usual since Talemate normally uses response token limits to control verbosity
|
||||
|
||||
!!! warning "Increased Verbosity"
|
||||
For providers without direct reasoning token support, enabling reasoning may result in more verbose responses since the extra tokens are added to all requests.
|
||||
|
||||
## Response Pattern Configuration
|
||||
|
||||
When reasoning is enabled, you may need to configure a **Pattern to strip from the response** to remove the thinking process from the final output.
|
||||
|
||||
### Default Patterns
|
||||
|
||||
Talemate provides quick-access buttons for common reasoning patterns:
|
||||
|
||||
- **Default** - Uses the built-in pattern: `.*?</think>`
|
||||
- **`.*?◁/think▷`** - For models using arrow-style thinking delimiters
|
||||
- **`.*?</think>`** - For models using XML-style think tags
|
||||
|
||||
### Custom Patterns
|
||||
|
||||
You can also specify a custom regular expression pattern that matches your model's reasoning format. This pattern will be used to strip the thinking tokens from the response before displaying it to the user.
|
||||
|
||||
## Model Compatibility
|
||||
|
||||
Not all models support reasoning. This feature works best with:
|
||||
|
||||
- Models specifically trained for chain-of-thought reasoning
|
||||
- Models that support structured thinking patterns
|
||||
- APIs that provide reasoning token specification
|
||||
|
||||
## Important Notes
|
||||
|
||||
- **Coercion Disabled**: When reasoning is enabled, LLM coercion (pre-filling responses) is automatically disabled since reasoning models need to generate their complete thought process
|
||||
- **Response Time**: Reasoning models may take longer to respond as they work through their thinking process
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Pattern Not Working
|
||||
If the reasoning pattern isn't properly stripping the thinking process:
|
||||
|
||||
1. Check your model's actual reasoning output format
|
||||
2. Adjust the regular expression pattern to match your model's specific format
|
||||
3. Test with the default pattern first to see if it works
|
||||
70
docs/user-guide/clients/template-locking.md
Normal file
@@ -0,0 +1,70 @@
|
||||
# Template Locking
|
||||
|
||||
Template locking allows you to prevent a client's prompt template from automatically updating when the model changes. This is useful when you want to maintain a consistent prompt format across different models or when you've customized a template for a specific use case.
|
||||
|
||||
## What is Template Locking?
|
||||
|
||||
By default, Talemate automatically determines the appropriate prompt template for each model you load. When you switch models, the prompt template updates to match the new model's requirements. Template locking disables this automatic behavior, keeping your selected template fixed regardless of model changes.
|
||||
|
||||
## When to Use Template Locking
|
||||
|
||||
Some models have reasoning and non-reasoning variants of their templates. This allows you to lock one client to the reasoning template and another to the non-reasoning template.
|
||||
|
||||
## How to Lock a Template
|
||||
|
||||
### Step 1: Open Client Settings
|
||||
|
||||
Start with your client that has a template already assigned (either automatically detected or manually selected):
|
||||
|
||||

|
||||
|
||||
1. Open the client settings by clicking the cogwheels icon next to the client
|
||||
2. Review the currently assigned template in the preview area
|
||||
|
||||
### Step 2: Enable Template Lock
|
||||
|
||||
When you check the **Lock Template** checkbox, the current template selection is cleared and you must select which template to lock:
|
||||
|
||||

|
||||
|
||||
1. Check the **Lock Template** checkbox
|
||||
2. You'll see the message: "Please select a prompt template to lock for this client"
|
||||
3. Select your desired template from the dropdown menu
|
||||
|
||||
This gives you the opportunity to choose which specific template you want to lock, rather than automatically locking whatever template happened to be active.
|
||||
|
||||
### Step 3: Template Locked
|
||||
|
||||
Once you've selected a template and clicked **Save**:
|
||||
|
||||

|
||||
|
||||
- The template display shows your locked template with its name (e.g., `TextGenWebUI__LOCK.jinja2`)
|
||||
- The template will no longer automatically update when you change models
|
||||
- The lock icon indicates the template is fixed
|
||||
|
||||
## Understanding the Lock Template Setting
|
||||
|
||||
When the **Lock Template** checkbox is enabled:
|
||||
|
||||
- The prompt template will not automatically update when you change models
|
||||
|
||||
When disabled:
|
||||
|
||||
- Talemate automatically determines the best template for your loaded model
|
||||
- Templates update when you switch models
|
||||
- The system attempts to match templates via HuggingFace metadata
|
||||
|
||||
## Unlocking a Template
|
||||
|
||||
To return to automatic template detection:
|
||||
|
||||
1. Open the client settings
|
||||
2. Uncheck the **Lock Template** checkbox
|
||||
3. Click **Save**
|
||||
4. Re-open the client settings and confirm that the template is no longer locked and the correct template is selected.
|
||||
|
||||
## Related Topics
|
||||
|
||||
- [Prompt Templates](/talemate/user-guide/clients/prompt-templates/) - Learn more about how prompt templates work
|
||||
- [Client Configuration](/talemate/user-guide/clients/) - General client setup and configuration
|
||||
@@ -35,4 +35,19 @@ A unique name for the client that makes sense to you.
|
||||
Which model to use. Currently defaults to `gpt-4o`.
|
||||
|
||||
!!! note "Talemate lags behind OpenAI"
|
||||
When OpenAI adds a new model, it currently requires a Talemate update to add it to the list of available models. We are working on making this more dynamic.
|
||||
When OpenAI adds a new model, it currently requires a Talemate update to add it to the list of available models. We are working on making this more dynamic.
|
||||
|
||||
##### Reasoning models (o1, o3, gpt-5)
|
||||
|
||||
!!! important "Enable reasoning and allocate tokens"
|
||||
The `o1`, `o3`, and `gpt-5` families are reasoning models. They always perform internal thinking before producing the final answer. To use them effectively in Talemate:
|
||||
|
||||
- Enable the **Reasoning** option in the client configuration.
|
||||
- Set **Reasoning Tokens** to a sufficiently high value to make room for the model's thinking process.
|
||||
|
||||
A good starting range is 512–1024 tokens. Increase if your tasks are complex. Without enabling reasoning and allocating tokens, these models may return minimal or empty visible content because the token budget is consumed by internal reasoning.
|
||||
|
||||
See the detailed guide: [Reasoning Model Support](/talemate/user-guide/clients/reasoning/).
|
||||
|
||||
!!! tip "Getting empty responses?"
|
||||
If these models return empty or very short answers, it usually means the reasoning budget was exhausted. Increase **Reasoning Tokens** and try again.
|
||||
@@ -14,7 +14,7 @@ We **do not** care about changing any of the actual loop logic.
|
||||
|
||||
With this in mind we can extend a new scene loop from the default talemate loop. This will give us a copy of the default loop that we can add to while keeping the rest of the loop logic up to date with any future improvements.
|
||||
|
||||
The `scene-loop` module should already be selected in the **:material-group: Modules** library.
|
||||
The `scene-loop` module should already be selected in the **:material-tree-view: Modules** library.
|
||||
|
||||

|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 51 KiB |
|
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 3.9 KiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 2.1 KiB |
333
docs/user-guide/node-editor/core-concepts/collector_nodes.md
Normal file
@@ -0,0 +1,333 @@
|
||||
# Collector Nodes
|
||||
|
||||
!!! info "New in version 0.33"
|
||||
Collector nodes with dynamic sockets were introduced in Talemate version 0.33.0.
|
||||
|
||||
Collector nodes are specialized nodes that aggregate multiple inputs into a single data structure. They feature **dynamic sockets** that can be added or removed as needed, making them flexible for various data aggregation scenarios.
|
||||
|
||||
## Types of Collector Nodes
|
||||
|
||||
### Dict Collector
|
||||
|
||||

|
||||
|
||||
**Expected output from the example above:**
|
||||
|
||||
```json
|
||||
{
|
||||
"some_variable": "hello",
|
||||
"auto_save": true
|
||||
}
|
||||
```
|
||||
|
||||
The **Dict Collector** node collects key-value pairs into a dictionary.
|
||||
|
||||
**Inputs:**
|
||||
|
||||
- `dict` (optional): An existing dictionary to add items to
|
||||
- `item{i}` (dynamic): Multiple dynamic input slots for key-value pairs
|
||||
|
||||
**Outputs:**
|
||||
|
||||
- `dict`: The resulting dictionary containing all collected key-value pairs
|
||||
|
||||
**How it works:**
|
||||
|
||||
1. Each dynamic input can accept either:
|
||||
- A **tuple** in the format `(key, value)` from nodes like [Make Key-Value Pair](../img/dict-collector.png)
|
||||
- Any **value**, in which case the key is inferred from the connected node's properties
|
||||
|
||||
2. When a tuple `(key, value)` is provided, the key and value are directly added to the dictionary
|
||||
|
||||
3. When a non-tuple value is provided, the collector attempts to infer the key name by checking the source node for:
|
||||
- A `name` property/input
|
||||
- A `key` property/input
|
||||
- An `attribute` property/input
|
||||
- Falls back to the socket name if none are found
|
||||
|
||||
4. The final dictionary contains all collected key-value pairs
|
||||
|
||||
**Common use cases:**
|
||||
|
||||
- Collecting multiple values into a structured dictionary
|
||||
- Building configuration objects from separate nodes
|
||||
- Aggregating character properties or attributes
|
||||
- Creating data structures from unpacked objects
|
||||
|
||||
### List Collector
|
||||
|
||||

|
||||
|
||||
**Expected output from the example above:**
|
||||
|
||||
```json
|
||||
["hello", "world"]
|
||||
```
|
||||
|
||||
The **List Collector** node collects items into a list.
|
||||
|
||||
**Inputs:**
|
||||
|
||||
- `list` (optional): An existing list to append items to
|
||||
- `item{i}` (dynamic): Multiple dynamic input slots for list items
|
||||
|
||||
**Outputs:**
|
||||
|
||||
- `list`: The resulting list containing all collected items
|
||||
|
||||
**How it works:**
|
||||
|
||||
1. Each dynamic input accepts any value type
|
||||
2. Values are appended to the list in the order of the dynamic inputs (item0, item1, item2, etc.)
|
||||
3. If an existing list is provided, new items are appended to it
|
||||
4. If no list is provided, a new empty list is created
|
||||
|
||||
**Common use cases:**
|
||||
|
||||
- Collecting multiple values into an ordered list
|
||||
- Aggregating results from multiple nodes
|
||||
- Building lists for iteration or processing
|
||||
- Combining outputs from multiple sources
|
||||
|
||||
## Managing Dynamic Sockets
|
||||
|
||||
Collector nodes support **dynamic input sockets** that can be added or removed as needed.
|
||||
|
||||
### Adding Input Sockets
|
||||
|
||||
There are two ways to add input sockets:
|
||||
|
||||
1. **Using the on-node buttons**: Click the green **+** button at the bottom of the node
|
||||
2. **Using the context menu**: Right-click the node and select `Add Input Slot`
|
||||
|
||||
### Removing Input Sockets
|
||||
|
||||
There are two ways to remove input sockets:
|
||||
|
||||
1. **Using the on-node buttons**: Click the red **-** button at the bottom of the node (removes the last dynamic input)
|
||||
2. **Using the context menu**: Right-click the node and select `Remove Last Input`
|
||||
|
||||
!!! note "Only the last dynamic input can be removed"
|
||||
You can only remove the most recently added dynamic input. To remove an input from the middle, you must first remove all inputs after it.
|
||||
|
||||
## Working with Key-Value Pairs
|
||||
|
||||
When working with **Dict Collector**, you'll often use the **Make Key-Value Pair** node to create properly formatted tuple outputs.
|
||||
|
||||
**Make Key-Value Pair Node:**
|
||||
|
||||
- **Inputs**: `key` (string), `value` (any type)
|
||||
- **Outputs**: `kv` (tuple), `key` (string), `value` (any)
|
||||
|
||||
The `kv` output produces a tuple in the format `(key, value)` which can be directly connected to Dict Collector's dynamic inputs.
|
||||
|
||||
**Example:**
|
||||
|
||||
```
|
||||
[Make Key-Value Pair] [Make Key-Value Pair] [Get State]
|
||||
key: "name" key: "age" scope: local
|
||||
value: "Alice" value: 30 name: "works"
|
||||
↓ kv ↓ kv ↓ value
|
||||
└────────┐ ┌─────┘ │
|
||||
↓ ↓ ↓
|
||||
[Dict Collector] [Dict Collector]
|
||||
item0 item1 item2
|
||||
↓
|
||||
{"name": "Alice", "age": 30, "works": true}
|
||||
```
|
||||
|
||||
## Nested Collection
|
||||
|
||||
Collector nodes can be chained together to create nested data structures:
|
||||
|
||||
- **Dict into Dict**: A Dict Collector's output can feed into another Dict Collector's `dict` input to add more key-value pairs
|
||||
- **List into List**: A List Collector's output can feed into another List Collector's `list` input to combine lists
|
||||
- **Mixed nesting**: Lists can contain dictionaries and vice versa
|
||||
|
||||
**Example of nested collection:**
|
||||
|
||||
```
|
||||
[Dict Collector A] → [Dict Collector B]
|
||||
item0: ("x", 10) dict: (from A)
|
||||
item1: ("y", 20) item0: ("z", 30)
|
||||
|
||||
Result: {"x": 10, "y": 20, "z": 30}
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Dict Collector Example
|
||||
|
||||
In the Dict Collector screenshot above, two nodes are connected:
|
||||
|
||||
- **item0**: `value` output from "GET local.some_variable"
|
||||
- **item1**: `auto_save` output from "Get Scene State"
|
||||
|
||||
Since no explicit key-value tuples are provided, the Dict Collector uses key inference:
|
||||
|
||||
- **item0**: Infers key from the source node's `name` property → `"some_variable"`
|
||||
- **item1**: Uses the socket name → `"auto_save"`
|
||||
|
||||
**Expected output:**
|
||||
|
||||
```python
|
||||
{
|
||||
"some_variable": <value from local.some_variable>,
|
||||
"auto_save": <value from scene state's auto_save property>
|
||||
}
|
||||
```
|
||||
|
||||
For example, if `local.some_variable` contains `"hello"` and `auto_save` is `True`:
|
||||
|
||||
```python
|
||||
{
|
||||
"some_variable": "hello",
|
||||
"auto_save": True
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### List Collector Example
|
||||
|
||||
In the List Collector screenshot above, two Get State nodes are connected:
|
||||
|
||||
- **item0**: `value` from "GET local.some_variable"
|
||||
- **item1**: `value` from "GET local.other_variable"
|
||||
|
||||
The List Collector simply appends values in order.
|
||||
|
||||
**Expected output:**
|
||||
|
||||
```python
|
||||
[
|
||||
<value from local.some_variable>,
|
||||
<value from local.other_variable>
|
||||
]
|
||||
```
|
||||
|
||||
For example, if `local.some_variable` contains `"hello"` and `local.other_variable` contains `"world"`:
|
||||
|
||||
```python
|
||||
["hello", "world"]
|
||||
```
|
||||
|
||||
## String Formatting with Collected Data
|
||||
|
||||
Collector nodes work seamlessly with formatting nodes to convert collected data into formatted strings. Two powerful formatting nodes that support dynamic inputs are **Advanced Format** and **Jinja2 Format**.
|
||||
|
||||
### Advanced Format
|
||||
|
||||

|
||||
|
||||
**Expected output from the example above:**
|
||||
|
||||
```json
|
||||
"hello world"
|
||||
```
|
||||
|
||||
The **Advanced Format** node uses Python-style string formatting with dynamic inputs similar to Dict Collector.
|
||||
|
||||
!!! warning "Use single curly braces `{}`"
|
||||
Advanced Format uses Python's `.format()` syntax. Variables are referenced with **single curly braces**: `{variable_name}`
|
||||
|
||||
**Inputs:**
|
||||
|
||||
- `template` (required): A format string with placeholders (e.g., `"hello {hello}"`)
|
||||
- `variables` (optional): Base dictionary to merge with dynamic inputs
|
||||
- `item{i}` (dynamic): Multiple dynamic input slots for format variables
|
||||
|
||||
**Outputs:**
|
||||
|
||||
- `result`: The formatted string
|
||||
|
||||
**How it works:**
|
||||
|
||||
1. Each dynamic input can accept either:
|
||||
- A **tuple** in the format `(key, value)`
|
||||
- Any **value**, in which case the key is inferred from the connected node's properties (same logic as Dict Collector)
|
||||
|
||||
2. Variables from dynamic inputs are merged with the optional `variables` dictionary
|
||||
|
||||
3. The template is formatted using Python's `.format()` method with all collected variables
|
||||
|
||||
4. Placeholders in the template like `{hello}` are replaced with their corresponding values
|
||||
|
||||
**Example from screenshot:**
|
||||
|
||||
- Template: `"hello {hello}"`
|
||||
- Dynamic input `item0`: Connected to "GET local.hello" which has value `"world"`
|
||||
- Key inferred as `"hello"` from the source node's `name` property
|
||||
- Result: `"hello world"`
|
||||
|
||||
### Jinja2 Format
|
||||
|
||||

|
||||
|
||||
**Expected output from the example above:**
|
||||
|
||||
```json
|
||||
"hello world"
|
||||
```
|
||||
|
||||
The **Jinja2 Format** node extends Advanced Format but uses Jinja2 templating instead of Python's `.format()`.
|
||||
|
||||
!!! warning "Use double curly braces `{{}}`"
|
||||
Jinja2 Format uses Jinja2 template syntax. Variables are referenced with **double curly braces**: `{{ variable_name }}`
|
||||
|
||||
**Inputs:**
|
||||
|
||||
- `template` (required): A Jinja2 template string (e.g., `"hello {{ hello }}"`)
|
||||
- `variables` (optional): Base dictionary to merge with dynamic inputs
|
||||
- `item{i}` (dynamic): Multiple dynamic input slots for template variables
|
||||
|
||||
**Outputs:**
|
||||
|
||||
- `result`: The rendered template string
|
||||
|
||||
**How it works:**
|
||||
|
||||
1. Inherits all the dynamic input behavior from Advanced Format
|
||||
2. Uses Jinja2 template syntax: `{{ variable }}` for variables, `{% %}` for logic
|
||||
3. Supports all Jinja2 features: filters, conditionals, loops, etc.
|
||||
4. Perfect for complex formatting needs beyond simple placeholder replacement
|
||||
|
||||
**Example from screenshot:**
|
||||
|
||||
- Template: `"hello {{ hello }}"`
|
||||
- Dynamic input `item0`: Connected to "GET local.hello" with value `"world"`
|
||||
- Key inferred as `"hello"` from the source node's `name` property
|
||||
- Result: `"hello world"`
|
||||
|
||||
### Combining Collectors with Formatters
|
||||
|
||||
A common pattern is to use collectors to gather data, then format it into strings:
|
||||
|
||||
```
|
||||
[Get State] ──→ [Dict Collector] ──→ [Advanced Format]
|
||||
[Get State] ──→ item0 variables
|
||||
item1 ↓
|
||||
↓ template: "Name: {name}, Age: {age}"
|
||||
{"name": "Alice",
|
||||
"age": 30}
|
||||
```
|
||||
|
||||
Or use dynamic inputs directly on the formatter:
|
||||
|
||||
```
|
||||
[Get State] ──→ [Advanced Format]
|
||||
[Get State] ──→ item0
|
||||
item1
|
||||
template: "{name} is {age} years old"
|
||||
```
|
||||
|
||||
### Format vs Advanced Format vs Jinja2 Format
|
||||
|
||||
| Feature | Format | Advanced Format | Jinja2 Format |
|
||||
|---------|--------|-----------------|---------------|
|
||||
| **Dynamic Inputs** | No | Yes | Yes |
|
||||
| **Syntax** | Python `.format()` | Python `.format()` | Jinja2 `{{ }}` |
|
||||
| **Key Inference** | No | Yes | Yes |
|
||||
| **Conditionals** | No | No | Yes |
|
||||
| **Loops** | No | No | Yes |
|
||||
| **Filters** | No | No | Yes |
|
||||
| **Best For** | Simple static formatting | Dynamic formatting with multiple inputs | Complex templates with logic |
|
||||
@@ -1,5 +1,8 @@
|
||||
# Prompt Templates
|
||||
|
||||
!!! tip "Want a more streamlined approach?"
|
||||
If you need quick prompts with automatic context management, check out [Prompt Building](prompt_building.md) for a simplified alternative to manual template construction.
|
||||
|
||||
Prompt templates in the node editor allow you to create dynamic, reusable prompts that can be customized with variables and sent to agents for processing.
|
||||
|
||||
## Overview
|
||||
|
||||
191
docs/user-guide/node-editor/core-concepts/prompt_building.md
Normal file
@@ -0,0 +1,191 @@
|
||||
# Prompt Building
|
||||
|
||||
!!! info "New in version 0.33"
|
||||
The Build Prompt node was introduced in Talemate version 0.33.0.
|
||||
|
||||
The **Build Prompt** node is a high-level alternative to manually constructing prompts with templates. It automatically assembles prompts with contextual information based on configurable needs, making it much faster to create agent prompts without managing template files.
|
||||
|
||||
## Build Prompt vs Prompt Templates
|
||||
|
||||
While [Prompt Templates](prompt-templates.md) give you complete control over every aspect of your prompt construction, **Build Prompt** provides a streamlined approach:
|
||||
|
||||
| Feature | Build Prompt | Prompt Templates |
|
||||
|---------|--------------|------------------|
|
||||
| **Complexity** | Simple configuration | Full template control |
|
||||
| **Context Management** | Automatic | Manual |
|
||||
| **Token Budgeting** | Built-in | Manual calculation |
|
||||
| **Setup Time** | Fast | Requires template creation |
|
||||
| **Flexibility** | Predefined options | Complete customization |
|
||||
| **Best For** | Quick prompts, standard patterns | Complex custom prompts |
|
||||
|
||||
**Use Build Prompt when:**
|
||||
|
||||
- You need standard contextual prompts quickly
|
||||
- You want automatic context and memory management
|
||||
- You're using common prompt patterns (analysis, direction, creation, etc.)
|
||||
|
||||
**Use Prompt Templates when:**
|
||||
|
||||
- You need precise control over prompt structure
|
||||
- You have complex custom requirements
|
||||
- You want to reuse specific prompt patterns across scenes
|
||||
|
||||
## The Build Prompt Node
|
||||
|
||||

|
||||
|
||||
**Expected output from the example above:**
|
||||
|
||||
A fully assembled prompt with:
|
||||
|
||||
- Base template structure from `common.base`
|
||||
- Director agent context
|
||||
- Dynamic instructions: "Don't over-analyze"
|
||||
- Scene context with memory, intent, and extra context
|
||||
- Question: "Answer this question: Is there a tiger in the room?"
|
||||
|
||||
### Inputs
|
||||
|
||||
- **`state`**: The graph state (required)
|
||||
- **`agent`**: The agent that will receive the prompt (required)
|
||||
- **`instructions`** (optional): Text instructions to include in the prompt
|
||||
- **`dynamic_context`** (optional): List of `DynamicInstruction` objects for context
|
||||
- **`dynamic_instructions`** (optional): List of `DynamicInstruction` objects for instructions
|
||||
- **`memory_prompt`** (optional): Semantic query for memory retrieval
|
||||
|
||||
### Outputs
|
||||
|
||||
- **`state`**: Passthrough of the input state
|
||||
- **`agent`**: Passthrough of the input agent
|
||||
- **`prompt`**: The constructed `Prompt` object
|
||||
- **`rendered`**: The rendered prompt as a string
|
||||
- **`response_length`**: The calculated response length for token budgeting
|
||||
|
||||
### Properties
|
||||
|
||||
#### Template Configuration
|
||||
|
||||
- **`template_file`** (default: `"base"`): The template file to use
|
||||
- **`scope`** (default: `"common"`): The template scope (common, agent-specific, etc.)
|
||||
|
||||
!!! warning "Template Compatibility"
|
||||
The Build Prompt node requires templates specifically designed to work with its configuration options. The default `common/base.jinja2` template is pre-configured to respect all the `include_*` boolean properties and dynamic instruction inputs.
|
||||
|
||||
If you change the `template_file` or `scope`, ensure the template is compatible with Build Prompt's variable structure, or the context control properties may not work as expected.
|
||||
|
||||
#### Context Control
|
||||
|
||||
- **`include_scene_intent`** (default: `true`): Include the scene's current intent/direction
|
||||
- **`include_extra_context`** (default: `true`): Include pins, reinforcements, and content classification
|
||||
- **`include_memory_context`** (default: `true`): Include relevant memories from the scene via RAG (Retrieval-Augmented Generation). Works best when `memory_prompt` is provided to guide semantic search
|
||||
- **`include_scene_context`** (default: `true`): Include scene history and state
|
||||
- **`include_character_context`** (default: `false`): Include active character details
|
||||
- **`include_gamestate_context`** (default: `false`): Include game state variables
|
||||
|
||||
#### Advanced Settings
|
||||
|
||||
- **`reserved_tokens`** (default: `312`): Tokens reserved from the context budget before calculating how much scene history to include. This provides a buffer for the response and any template overhead (range: 16-1024)
|
||||
- **`limit_max_tokens`** (default: `0`): Maximum token limit (0 = use client context limit)
|
||||
- **`response_length`** (default: `0`): Expected length of the response
|
||||
- **`technical`** (default: `false`): Include technical context (IDs, typing information)
|
||||
- **`dedupe_enabled`** (default: `true`): Enable deduplication in the prompt
|
||||
- **`memory_prompt`** (default: `""`): Semantic query string for memory retrieval. Provide this to guide what memories are retrieved when `include_memory_context` is enabled
|
||||
- **`prefill_prompt`** (default: `""`): Text to prefill the response
|
||||
- **`return_prefill_prompt`** (default: `false`): Return the prefill with response
|
||||
|
||||
## Dynamic Instructions
|
||||
|
||||
Dynamic instructions allow you to inject contextual information into prompts at runtime. They come in two types:
|
||||
|
||||
### Dynamic Context
|
||||
|
||||
Provides background information and context to the agent. Use the **Dynamic Instruction** node connected to the `dynamic_context` input (typically via a List Collector).
|
||||
|
||||
### Dynamic Instructions
|
||||
|
||||
Provides specific instructions or directives to the agent. Use the **Dynamic Instruction** node connected to the `dynamic_instructions` input (typically via a List Collector).
|
||||
|
||||
**Dynamic Instruction Node Properties:**
|
||||
|
||||
- **`header`**: The instruction header/title
|
||||
- **`content`**: The instruction content/body
|
||||
|
||||
## Example Workflow
|
||||
|
||||
The example screenshot shows a typical workflow:
|
||||
|
||||
1. **Agent Selection**: Get the `director` agent
|
||||
2. **Dynamic Instructions**: Create a "Don't over-analyze" instruction using the Dynamic Instruction node
|
||||
3. **Collect Instructions**: Use a List Collector to gather dynamic instructions
|
||||
4. **Instructions**: Provide the main instruction via Make Text node: "Answer this question: Is there a tiger in the room?"
|
||||
5. **Build Prompt**: Configure context needs (scene intent, extra context, memory, scene context enabled)
|
||||
6. **Generate Response**: Send the built prompt to the agent with appropriate settings
|
||||
|
||||
## Common Patterns
|
||||
|
||||
### Simple Question Prompt
|
||||
|
||||
```
|
||||
[Get Agent] → [Build Prompt] → [Generate Response]
|
||||
↑
|
||||
[Make Text: "Your question here"]
|
||||
```
|
||||
|
||||
### Prompt with Dynamic Instructions
|
||||
|
||||
```
|
||||
[Dynamic Instruction] → [List Collector] → [Build Prompt] → [Generate Response]
|
||||
[Get Agent] ────────────────────────────────────↑
|
||||
[Make Text: "Main instruction"] ────────────────↑
|
||||
```
|
||||
|
||||
### Analysis with Full Context
|
||||
|
||||
Enable all context options:
|
||||
- `include_scene_intent`: true
|
||||
- `include_extra_context`: true
|
||||
- `include_memory_context`: true
|
||||
- `include_scene_context`: true
|
||||
- `include_character_context`: true
|
||||
- `include_gamestate_context`: true
|
||||
|
||||
### Quick Direction with Minimal Context
|
||||
|
||||
Disable unnecessary context:
|
||||
- `include_character_context`: false
|
||||
- `include_gamestate_context`: false
|
||||
- `include_memory_context`: false (if not needed)
|
||||
|
||||
## Token Budget Management
|
||||
|
||||
Build Prompt automatically manages token budgets for scene history inclusion:
|
||||
|
||||
1. **Start with max context**: Uses `max_tokens` from the agent's client
|
||||
2. **Subtract reserved tokens**: Removes `reserved_tokens` to create a buffer for the response
|
||||
3. **Count rendered context**: Calculates tokens used by all enabled contexts (intent, memory, instructions, etc.)
|
||||
4. **Calculate scene history budget**: `budget = max_tokens - reserved_tokens - count_tokens(rendered_contexts)`
|
||||
5. **Fill with scene history**: Includes as much scene history as fits in the remaining budget
|
||||
|
||||
The `reserved_tokens` setting (default: 312) ensures there's always space reserved for the agent's response and prevents the context from being completely filled. Increase it if responses are getting cut off; decrease it if you want more scene history included.
|
||||
|
||||
## How Build Prompt Works with Templates
|
||||
|
||||
The Build Prompt node works by passing all its configuration options as variables to the template. The default `common/base.jinja2` template is specifically structured to:
|
||||
|
||||
1. **Check boolean flags**: Uses `{% if include_scene_intent %}` to conditionally include context sections
|
||||
2. **Include sub-templates**: Dynamically includes templates like `scene-intent.jinja2`, `memory-context.jinja2`, etc.
|
||||
3. **Process dynamic instructions**: Renders both `dynamic_context` and `dynamic_instructions` lists
|
||||
4. **Calculate token budgets**: Uses `count_tokens()` to budget space for scene history
|
||||
5. **Apply prefill prompts**: Handles the `prefill_prompt` and `return_prefill_prompt` options
|
||||
|
||||
This is why changing the template requires ensuring compatibility - a different template must expect and use these same variables.
|
||||
|
||||
## Template Scopes
|
||||
|
||||
The `scope` property determines where templates are loaded from:
|
||||
|
||||
- **`common`**: Shared templates in `templates/prompts/common/`
|
||||
- **Agent types**: Agent-specific templates in `templates/prompts/{agent_type}/`
|
||||
- `narrator`, `director`, `creator`, `editor`, `summarizer`, `world_state`
|
||||
|
||||
The `template_file` property references the template name without the `.jinja2` extension.
|
||||
@@ -4,25 +4,31 @@
|
||||
|
||||
The node editor is available in the main scene window once the scene is switched to creative mode.
|
||||
|
||||
Switch to creative mode through the creative mode toggle in the scene toolbar.
|
||||
Open the node editor by clicking the :material-chart-timeline-variant-shimmer: icon in the main toolbar (upper left).
|
||||
|
||||

|
||||

|
||||
|
||||
Exit the node editor the same way by clicking the :material-exit-to-app: icon in the main toolbar (upper left).
|
||||
|
||||

|
||||
|
||||
## Module Library
|
||||
|
||||

|
||||
|
||||
The **:material-group: Modules** Library can be found at the bottom of the editor.
|
||||
The **:material-file-tree: Modules** Library can be found at the left sidebar of the editor. If the sidebar is closed, click the :material-file-tree: icon in the main toolbar (upper left) to open it.
|
||||
|
||||
It holds all the node modules that talemate has currently installed and is the main way to add new modules to the editor or open existing modules for inspection or editing.
|
||||
|
||||
### Module listing
|
||||
|
||||
Node modules come in three categories:
|
||||
Node modules are organized into hierarchical groups:
|
||||
|
||||
- Scene level modules: Purple, these modules live with scene project
|
||||
- Installed modules: Brown, these are the modules installed through the `templates/modules` directory
|
||||
- Core modules: Grey, these are the modules that are part of the core talemate installation
|
||||
- **scene**: Scene-level modules that live with your project
|
||||
- **agents/{agent}**: Agent-specific modules organized by agent name
|
||||
- **core**: Core talemate system modules
|
||||
- **installed/{project}**: Installed modules grouped by project (from `templates/modules/{project}`)
|
||||
- **templates**: General template modules
|
||||
|
||||
All modules can be opened and inspected, but **only scene level modules can be edited**.
|
||||
|
||||
@@ -62,6 +68,9 @@ Select the appropriate module type.
|
||||
| :material-function: Function | Creates a new [function](functions.md) module |
|
||||
| :material-file: Module | Creates a new module |
|
||||
| :material-source-branch-sync: Scene Loop | Creates a new scene loop module |
|
||||
| :material-package-variant: Package | Creates a new package module |
|
||||
| :material-chat: Director Chat Action | Creates a new director chat action module |
|
||||
| :material-robot-happy: Agent Websocket Handler | Creates a new agent websocket handler module |
|
||||
|
||||
In the upcoming dialog you can name the new module and set the registry path.
|
||||
|
||||
@@ -226,6 +235,20 @@ To paste a node, select the location where you want to paste it and hit `Ctrl+V`
|
||||
|
||||
You can also hold the `Alt` key and drag the selected node(s) to duplicate them and drag the duplicate to the desired location.
|
||||
|
||||
##### Alt+Shift drag to create counterpart
|
||||
|
||||
Certain nodes support creating a "counterpart" node. Hold `Alt+Shift` and drag the node to create its paired counterpart node.
|
||||
|
||||
For example:
|
||||
|
||||
- **Set State → Get State**: Creates a Get State node with matching scope and variable name
|
||||
- **Input → Output**: Creates the corresponding socket node with matching configuration
|
||||
|
||||
The counterpart node is positioned near the original and can be immediately dragged to the desired location.
|
||||
|
||||
!!! note "Limited node support"
|
||||
This feature is currently only available for specific node types like Get/Set State and Input/Output socket nodes.
|
||||
|
||||
#### Node Properties
|
||||
|
||||
Most nodes come with properties that can be edited. To edit a node property, click on the corresponding input widget in the node.
|
||||
|
||||
BIN
docs/user-guide/node-editor/img/advanced-format.png
Normal file
|
After Width: | Height: | Size: 60 KiB |
BIN
docs/user-guide/node-editor/img/build_prompt.png
Normal file
|
After Width: | Height: | Size: 362 KiB |
BIN
docs/user-guide/node-editor/img/close-node-editor.png
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
docs/user-guide/node-editor/img/dict-collector.png
Normal file
|
After Width: | Height: | Size: 97 KiB |
BIN
docs/user-guide/node-editor/img/jinja2-format.png
Normal file
|
After Width: | Height: | Size: 56 KiB |