falaw 0.0.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- falaw-0.0.2/.claude/skills/falaw/SKILL.md +116 -0
- falaw-0.0.2/.gitattributes +1 -0
- falaw-0.0.2/.github/workflows/ci.yml +207 -0
- falaw-0.0.2/.gitignore +117 -0
- falaw-0.0.2/LICENSE +21 -0
- falaw-0.0.2/PKG-INFO +126 -0
- falaw-0.0.2/README.md +105 -0
- falaw-0.0.2/falaw/__init__.py +57 -0
- falaw-0.0.2/falaw/__main__.py +54 -0
- falaw-0.0.2/falaw/base.py +43 -0
- falaw-0.0.2/falaw/bridges/__init__.py +8 -0
- falaw-0.0.2/falaw/bridges/mcp.py +16 -0
- falaw-0.0.2/falaw/bridges/service.py +16 -0
- falaw-0.0.2/falaw/bridges/skill.py +121 -0
- falaw-0.0.2/falaw/core.py +72 -0
- falaw-0.0.2/falaw/data/models.json +173 -0
- falaw-0.0.2/falaw/data/skills/falaw/SKILL.md +116 -0
- falaw-0.0.2/falaw/journal.py +132 -0
- falaw-0.0.2/falaw/operations/__init__.py +8 -0
- falaw-0.0.2/falaw/operations/audio.py +59 -0
- falaw-0.0.2/falaw/operations/images.py +69 -0
- falaw-0.0.2/falaw/refresh.py +382 -0
- falaw-0.0.2/falaw/registry.py +120 -0
- falaw-0.0.2/falaw/results.py +136 -0
- falaw-0.0.2/falaw/session.py +43 -0
- falaw-0.0.2/misc/docs/fal_ai_docs_full.md +92363 -0
- falaw-0.0.2/misc/docs/fal_ai_docs_full.pdf +0 -0
- falaw-0.0.2/misc/docs/fal_ai_docs_index.md +384 -0
- falaw-0.0.2/misc/docs/llms-full.txt +643 -0
- falaw-0.0.2/misc/docs/llms.txt +82 -0
- falaw-0.0.2/misc/falaw_state/.gitkeep +0 -0
- falaw-0.0.2/misc/regenerate_skill.py +30 -0
- falaw-0.0.2/misc/scheduled_refresh.py +48 -0
- falaw-0.0.2/pyproject.toml +162 -0
- falaw-0.0.2/tests/__init__.py +0 -0
- falaw-0.0.2/tests/test_journal.py +20 -0
- falaw-0.0.2/tests/test_operations.py +63 -0
- falaw-0.0.2/tests/test_refresh.py +132 -0
- falaw-0.0.2/tests/test_registry.py +34 -0
- falaw-0.0.2/tests/test_results.py +36 -0
- falaw-0.0.2/tests/test_skill_bridge.py +11 -0
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: falaw
|
|
3
|
+
description: >-
|
|
4
|
+
Generate and manage AI media (images, video, audio) via fal.ai. Use this
|
|
5
|
+
skill whenever the user wants to generate, edit, upscale, or compose media,
|
|
6
|
+
or asks about fal.ai or fal-client. The skill exposes Python tools that
|
|
7
|
+
wrap fal-client with smart model selection, result handling, and a journal
|
|
8
|
+
for self-improvement across sessions.
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# falaw
|
|
12
|
+
|
|
13
|
+
Use the `falaw` Python package as your primary interface to fal.ai.
|
|
14
|
+
|
|
15
|
+
## Read the journal first
|
|
16
|
+
|
|
17
|
+
Before doing anything novel, glance at recent journal entries --- past
|
|
18
|
+
sessions may have left notes, gotchas, or suggestions that save you time:
|
|
19
|
+
|
|
20
|
+
```python
|
|
21
|
+
from falaw import journal
|
|
22
|
+
for e in journal.recent(20):
|
|
23
|
+
print(e.kind, '-', e.text[:120])
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Leave a journal entry when something surprises you
|
|
27
|
+
|
|
28
|
+
Whenever a model behaved oddly, an error was confusing, or you had to work
|
|
29
|
+
around something, leave a note. This is how the next session learns:
|
|
30
|
+
|
|
31
|
+
```python
|
|
32
|
+
from falaw import journal
|
|
33
|
+
journal.issue("FLUX dev returned NSFW=True for a benign prompt",
|
|
34
|
+
suggestion="Document an example that triggers it",
|
|
35
|
+
tags=("flux", "safety"))
|
|
36
|
+
journal.improvement("Add an `upscale_image` tool that wraps clarity-upscaler",
|
|
37
|
+
tags=("backlog",))
|
|
38
|
+
journal.note("schnell quality=fast returns 1024x1024 by default")
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Pick a model without memorizing IDs
|
|
42
|
+
|
|
43
|
+
```python
|
|
44
|
+
from falaw import list_models, pick_model
|
|
45
|
+
[m.id for m in list_models(category='video')]
|
|
46
|
+
pick_model(category='image', quality_tier='ultra').id
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Tools
|
|
50
|
+
|
|
51
|
+
The functions below are also registered tools; bridges (MCP server, HTTP
|
|
52
|
+
service, UI) derive their surfaces from the same registry.
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
### `falaw.generate_image`
|
|
56
|
+
|
|
57
|
+
Generate an image from a text prompt. Picks a sensible FLUX model based on the requested quality tier ('fast', 'balanced', 'high', 'ultra'). Returns a falaw.Result whose .first asset has a URL you can .download(to=...).
|
|
58
|
+
|
|
59
|
+
Examples:
|
|
60
|
+
- `falaw.generate_image(**{'prompt': 'A red panda eating bamboo', 'quality': 'fast'})`
|
|
61
|
+
- `falaw.generate_image(**{'prompt': 'Cinematic portrait, 35mm film', 'quality': 'ultra'})`
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
### `falaw.text_to_speech`
|
|
65
|
+
|
|
66
|
+
Synthesize speech from text. Picks a TTS model by quality tier; pass `voice` and `extra` for model-specific knobs. Returns a falaw.Result whose .first asset is the audio URL.
|
|
67
|
+
|
|
68
|
+
Examples:
|
|
69
|
+
- `falaw.text_to_speech(**{'text': 'Hello world', 'quality': 'balanced'})`
|
|
70
|
+
- `falaw.text_to_speech(**{'text': 'Bonjour le monde', 'quality': 'high', 'voice': 'fr-FR-female-1'})`
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
### `falaw.refresh_llms`
|
|
74
|
+
|
|
75
|
+
Refresh `llms.txt` and `llms-full.txt` from fal.ai using conditional GETs (ETag-based). Cheap: returns immediately if nothing changed. On change, snapshots the previous version and journals the diff. Returns a summary dict like {'llms': {'changed': False}, ...}.
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
### `falaw.refresh_full_docs`
|
|
79
|
+
|
|
80
|
+
Re-crawl every per-page .md endpoint listed in `fal_ai_docs_index.md` with conditional GETs, then reassemble `fal_ai_docs_full.md`. Heavy. Gated on `is_stale(llms-full)` by default --- pass `force=True` to skip the gate. Pages that 304 are skipped; only changed pages re-download. Logs a single journal entry summarizing the run.
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
## Models known to falaw
|
|
84
|
+
|
|
85
|
+
The model registry lives at `falaw/data/models.json`. Refresh it from
|
|
86
|
+
`misc/docs/fal_ai_docs_full.md` when fal ships new models. Quick view:
|
|
87
|
+
|
|
88
|
+
```
|
|
89
|
+
avatar balanced fal-ai/ai-avatar
|
|
90
|
+
background_removal high fal-ai/birefnet/v2
|
|
91
|
+
image balanced fal-ai/flux/dev
|
|
92
|
+
image fast fal-ai/flux/schnell
|
|
93
|
+
image high fal-ai/flux-pro/v1.1
|
|
94
|
+
image ultra fal-ai/flux-pro/v1.1-ultra
|
|
95
|
+
image_edit ultra fal-ai/flux-pro/kontext/max
|
|
96
|
+
lipsync high fal-ai/sync-lipsync/v2
|
|
97
|
+
llm balanced fal-ai/any-llm
|
|
98
|
+
music balanced fal-ai/diffrhythm
|
|
99
|
+
music high fal-ai/lyria2
|
|
100
|
+
tts balanced fal-ai/playai/tts/v3
|
|
101
|
+
tts high fal-ai/minimax/speech-02-hd
|
|
102
|
+
tts high fal-ai/elevenlabs/tts/multilingual-v2
|
|
103
|
+
upscale high fal-ai/clarity-upscaler
|
|
104
|
+
video balanced fal-ai/minimax/hailuo-02/pro/image-to-video
|
|
105
|
+
video high fal-ai/kling-video/v2.1/master/image-to-video
|
|
106
|
+
video ultra fal-ai/veo3
|
|
107
|
+
voice_clone high fal-ai/minimax/voice-clone
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## When you can't find what you need
|
|
111
|
+
|
|
112
|
+
* Check `falaw/misc/docs/llms-full.txt` for a structured fal.ai overview.
|
|
113
|
+
* Check `falaw/misc/docs/fal_ai_docs_full.md` for the full corpus (~3MB).
|
|
114
|
+
* Drop into `falaw.call_fal(application, arguments)` for any model not
|
|
115
|
+
yet wrapped --- this is the escape hatch. Then leave a `journal.improvement`
|
|
116
|
+
asking for a proper tool wrapper.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
*.ipynb linguist-documentation
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
name: Continuous Integration (uv)
|
|
2
|
+
on: [push, pull_request]
|
|
3
|
+
|
|
4
|
+
# Note: Environment variables (PROJECT_NAME and vars from [tool.wads.ci.env])
|
|
5
|
+
# are set by the read-ci-config action in the setup job and made available
|
|
6
|
+
# to all subsequent jobs via GITHUB_ENV
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
# First job: Read configuration from pyproject.toml
|
|
10
|
+
setup:
|
|
11
|
+
name: Read Configuration
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
outputs:
|
|
14
|
+
project-name: ${{ steps.config.outputs.project-name }}
|
|
15
|
+
python-versions: ${{ steps.config.outputs.python-versions }}
|
|
16
|
+
pytest-args: ${{ steps.config.outputs.pytest-args }}
|
|
17
|
+
coverage-enabled: ${{ steps.config.outputs.coverage-enabled }}
|
|
18
|
+
exclude-paths: ${{ steps.config.outputs.exclude-paths }}
|
|
19
|
+
test-on-windows: ${{ steps.config.outputs.test-on-windows }}
|
|
20
|
+
build-sdist: ${{ steps.config.outputs.build-sdist }}
|
|
21
|
+
build-wheel: ${{ steps.config.outputs.build-wheel }}
|
|
22
|
+
metrics-enabled: ${{ steps.config.outputs.metrics-enabled }}
|
|
23
|
+
metrics-config-path: ${{ steps.config.outputs.metrics-config-path }}
|
|
24
|
+
metrics-storage-branch: ${{ steps.config.outputs.metrics-storage-branch }}
|
|
25
|
+
metrics-python-version: ${{ steps.config.outputs.metrics-python-version }}
|
|
26
|
+
metrics-force-run: ${{ steps.config.outputs.metrics-force-run }}
|
|
27
|
+
|
|
28
|
+
steps:
|
|
29
|
+
- uses: actions/checkout@v4
|
|
30
|
+
|
|
31
|
+
- name: Set up uv
|
|
32
|
+
uses: astral-sh/setup-uv@v5
|
|
33
|
+
|
|
34
|
+
- name: Set up Python
|
|
35
|
+
run: uv python install 3.11
|
|
36
|
+
|
|
37
|
+
- name: Read CI Config
|
|
38
|
+
id: config
|
|
39
|
+
uses: i2mint/wads/actions/read-ci-config@master
|
|
40
|
+
with:
|
|
41
|
+
pyproject-path: .
|
|
42
|
+
|
|
43
|
+
# Second job: Validation using the config
|
|
44
|
+
validation:
|
|
45
|
+
name: Validation
|
|
46
|
+
if: "!contains(github.event.head_commit.message, '[skip ci]')"
|
|
47
|
+
needs: setup
|
|
48
|
+
runs-on: ubuntu-latest
|
|
49
|
+
strategy:
|
|
50
|
+
matrix:
|
|
51
|
+
python-version: ${{ fromJson(needs.setup.outputs.python-versions) }}
|
|
52
|
+
|
|
53
|
+
steps:
|
|
54
|
+
- uses: actions/checkout@v4
|
|
55
|
+
|
|
56
|
+
- name: Set up uv
|
|
57
|
+
uses: astral-sh/setup-uv@v5
|
|
58
|
+
with:
|
|
59
|
+
enable-cache: true
|
|
60
|
+
|
|
61
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
62
|
+
uses: i2mint/wads/actions/setup-python-uv@master
|
|
63
|
+
with:
|
|
64
|
+
python-version: ${{ matrix.python-version }}
|
|
65
|
+
|
|
66
|
+
- name: Install System Dependencies
|
|
67
|
+
uses: i2mint/wads/actions/install-system-deps@master
|
|
68
|
+
with:
|
|
69
|
+
pyproject-path: .
|
|
70
|
+
|
|
71
|
+
- name: Install Dependencies
|
|
72
|
+
uses: i2mint/wads/actions/install-deps-uv@master
|
|
73
|
+
|
|
74
|
+
- name: Format Source Code
|
|
75
|
+
run: uvx ruff format .
|
|
76
|
+
|
|
77
|
+
- name: Lint Validation
|
|
78
|
+
run: uvx ruff check --output-format=github ${{ needs.setup.outputs.project-name }}
|
|
79
|
+
|
|
80
|
+
- name: Run Tests
|
|
81
|
+
uses: i2mint/wads/actions/run-tests-uv@master
|
|
82
|
+
with:
|
|
83
|
+
root-dir: ${{ needs.setup.outputs.project-name }}
|
|
84
|
+
pytest-args: ${{ needs.setup.outputs.pytest-args }}
|
|
85
|
+
exclude-paths: ${{ needs.setup.outputs.exclude-paths }}
|
|
86
|
+
coverage: ${{ needs.setup.outputs.coverage-enabled }}
|
|
87
|
+
|
|
88
|
+
- name: Track Code Metrics
|
|
89
|
+
if: needs.setup.outputs.metrics-enabled == 'true'
|
|
90
|
+
uses: i2mint/umpyre/actions/track-metrics@master
|
|
91
|
+
continue-on-error: true
|
|
92
|
+
with:
|
|
93
|
+
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
94
|
+
config-path: ${{ needs.setup.outputs.metrics-config-path }}
|
|
95
|
+
storage-branch: ${{ needs.setup.outputs.metrics-storage-branch }}
|
|
96
|
+
python-version: ${{ needs.setup.outputs.metrics-python-version }}
|
|
97
|
+
force-run: ${{ needs.setup.outputs.metrics-force-run }}
|
|
98
|
+
|
|
99
|
+
# Optional Windows testing (if enabled in config)
|
|
100
|
+
windows-validation:
|
|
101
|
+
name: Windows Tests
|
|
102
|
+
if: "!contains(github.event.head_commit.message, '[skip ci]') && needs.setup.outputs.test-on-windows == 'true'"
|
|
103
|
+
needs: setup
|
|
104
|
+
runs-on: windows-latest
|
|
105
|
+
continue-on-error: true
|
|
106
|
+
|
|
107
|
+
steps:
|
|
108
|
+
- uses: actions/checkout@v4
|
|
109
|
+
|
|
110
|
+
- name: Set up uv
|
|
111
|
+
uses: astral-sh/setup-uv@v5
|
|
112
|
+
with:
|
|
113
|
+
enable-cache: true
|
|
114
|
+
|
|
115
|
+
- name: Set up Python
|
|
116
|
+
uses: i2mint/wads/actions/setup-python-uv@master
|
|
117
|
+
with:
|
|
118
|
+
python-version: ${{ fromJson(needs.setup.outputs.python-versions)[0] }}
|
|
119
|
+
|
|
120
|
+
- name: Install System Dependencies
|
|
121
|
+
uses: i2mint/wads/actions/install-system-deps@master
|
|
122
|
+
with:
|
|
123
|
+
pyproject-path: .
|
|
124
|
+
|
|
125
|
+
- name: Install Dependencies
|
|
126
|
+
uses: i2mint/wads/actions/install-deps-uv@master
|
|
127
|
+
|
|
128
|
+
- name: Run Tests
|
|
129
|
+
uses: i2mint/wads/actions/run-tests-uv@master
|
|
130
|
+
with:
|
|
131
|
+
root-dir: ${{ needs.setup.outputs.project-name }}
|
|
132
|
+
|
|
133
|
+
# Publishing job
|
|
134
|
+
publish:
|
|
135
|
+
name: Publish
|
|
136
|
+
permissions:
|
|
137
|
+
contents: write
|
|
138
|
+
if: "!contains(github.event.head_commit.message, '[skip ci]') && (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/main')"
|
|
139
|
+
needs: [setup, validation]
|
|
140
|
+
runs-on: ubuntu-latest
|
|
141
|
+
|
|
142
|
+
steps:
|
|
143
|
+
- uses: actions/checkout@v4
|
|
144
|
+
with:
|
|
145
|
+
fetch-depth: 0
|
|
146
|
+
token: ${{ secrets.GITHUB_TOKEN }}
|
|
147
|
+
|
|
148
|
+
- name: Set up uv
|
|
149
|
+
uses: astral-sh/setup-uv@v5
|
|
150
|
+
|
|
151
|
+
- name: Set up Python
|
|
152
|
+
uses: i2mint/wads/actions/setup-python-uv@master
|
|
153
|
+
with:
|
|
154
|
+
python-version: ${{ fromJson(needs.setup.outputs.python-versions)[0] }}
|
|
155
|
+
create-venv: "false"
|
|
156
|
+
|
|
157
|
+
- name: Format Source Code
|
|
158
|
+
run: uvx ruff format .
|
|
159
|
+
|
|
160
|
+
- name: Update Version Number
|
|
161
|
+
id: version
|
|
162
|
+
uses: i2mint/isee/actions/bump-version-number@master
|
|
163
|
+
|
|
164
|
+
- name: Build Distribution
|
|
165
|
+
uses: i2mint/wads/actions/build-dist-uv@master
|
|
166
|
+
with:
|
|
167
|
+
sdist: ${{ needs.setup.outputs.build-sdist }}
|
|
168
|
+
wheel: ${{ needs.setup.outputs.build-wheel }}
|
|
169
|
+
|
|
170
|
+
- name: Publish to PyPI
|
|
171
|
+
uses: i2mint/wads/actions/pypi-publish-uv@master
|
|
172
|
+
with:
|
|
173
|
+
pypi-token: ${{ secrets.PYPI_PASSWORD }}
|
|
174
|
+
|
|
175
|
+
- name: Force SSH for git remote
|
|
176
|
+
run: git remote set-url origin git@github.com:${{ github.repository }}.git
|
|
177
|
+
|
|
178
|
+
- name: Commit Changes
|
|
179
|
+
uses: i2mint/wads/actions/git-commit@master
|
|
180
|
+
with:
|
|
181
|
+
commit-message: "**CI** Formatted code + Updated version to ${{ env.VERSION }} [skip ci]"
|
|
182
|
+
ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
|
|
183
|
+
push: true
|
|
184
|
+
|
|
185
|
+
- name: Tag Repository
|
|
186
|
+
uses: i2mint/wads/actions/git-tag@master
|
|
187
|
+
with:
|
|
188
|
+
tag: ${{ env.VERSION }}
|
|
189
|
+
message: "Release version ${{ env.VERSION }}"
|
|
190
|
+
push: true
|
|
191
|
+
|
|
192
|
+
# Optional GitHub Pages
|
|
193
|
+
github-pages:
|
|
194
|
+
name: Publish GitHub Pages
|
|
195
|
+
permissions:
|
|
196
|
+
contents: write
|
|
197
|
+
pages: write
|
|
198
|
+
id-token: write
|
|
199
|
+
if: "!contains(github.event.head_commit.message, '[skip ci]') && github.ref == format('refs/heads/{0}', github.event.repository.default_branch)"
|
|
200
|
+
needs: publish
|
|
201
|
+
runs-on: ubuntu-latest
|
|
202
|
+
|
|
203
|
+
steps:
|
|
204
|
+
- uses: i2mint/epythet/actions/publish-github-pages@master
|
|
205
|
+
with:
|
|
206
|
+
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
207
|
+
ignore: "tests/,scrap/,examples/"
|
falaw-0.0.2/.gitignore
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
.DS_Store
|
|
8
|
+
# C extensions
|
|
9
|
+
*.so
|
|
10
|
+
|
|
11
|
+
# TLS certificates
|
|
12
|
+
## Ignore all PEM files anywhere
|
|
13
|
+
*.pem
|
|
14
|
+
## Also ignore any certs directory
|
|
15
|
+
certs/
|
|
16
|
+
|
|
17
|
+
# Distribution / packaging
|
|
18
|
+
.Python
|
|
19
|
+
build/
|
|
20
|
+
develop-eggs/
|
|
21
|
+
dist/
|
|
22
|
+
downloads/
|
|
23
|
+
eggs/
|
|
24
|
+
.eggs/
|
|
25
|
+
lib/
|
|
26
|
+
lib64/
|
|
27
|
+
parts/
|
|
28
|
+
sdist/
|
|
29
|
+
var/
|
|
30
|
+
wheels/
|
|
31
|
+
*.egg-info/
|
|
32
|
+
.installed.cfg
|
|
33
|
+
*.egg
|
|
34
|
+
MANIFEST
|
|
35
|
+
_build
|
|
36
|
+
|
|
37
|
+
# PyInstaller
|
|
38
|
+
# Usually these files are written by a python script from a template
|
|
39
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
40
|
+
*.manifest
|
|
41
|
+
*.spec
|
|
42
|
+
|
|
43
|
+
# Installer logs
|
|
44
|
+
pip-log.txt
|
|
45
|
+
pip-delete-this-directory.txt
|
|
46
|
+
|
|
47
|
+
# Unit test / coverage reports
|
|
48
|
+
htmlcov/
|
|
49
|
+
.tox/
|
|
50
|
+
.coverage
|
|
51
|
+
.coverage.*
|
|
52
|
+
.cache
|
|
53
|
+
nosetests.xml
|
|
54
|
+
coverage.xml
|
|
55
|
+
*.cover
|
|
56
|
+
.hypothesis/
|
|
57
|
+
.pytest_cache/
|
|
58
|
+
|
|
59
|
+
# Translations
|
|
60
|
+
*.mo
|
|
61
|
+
*.pot
|
|
62
|
+
|
|
63
|
+
# Django stuff:
|
|
64
|
+
*.log
|
|
65
|
+
local_settings.py
|
|
66
|
+
db.sqlite3
|
|
67
|
+
|
|
68
|
+
# Flask stuff:
|
|
69
|
+
instance/
|
|
70
|
+
.webassets-cache
|
|
71
|
+
|
|
72
|
+
# Scrapy stuff:
|
|
73
|
+
.scrapy
|
|
74
|
+
|
|
75
|
+
# Sphinx documentation
|
|
76
|
+
docs/_build/
|
|
77
|
+
docs/*
|
|
78
|
+
|
|
79
|
+
# PyBuilder
|
|
80
|
+
target/
|
|
81
|
+
|
|
82
|
+
# Jupyter Notebook
|
|
83
|
+
.ipynb_checkpoints
|
|
84
|
+
|
|
85
|
+
# pyenv
|
|
86
|
+
.python-version
|
|
87
|
+
|
|
88
|
+
# celery beat schedule file
|
|
89
|
+
celerybeat-schedule
|
|
90
|
+
|
|
91
|
+
# SageMath parsed files
|
|
92
|
+
*.sage.py
|
|
93
|
+
|
|
94
|
+
# Environments
|
|
95
|
+
.env
|
|
96
|
+
.venv
|
|
97
|
+
env/
|
|
98
|
+
venv/
|
|
99
|
+
ENV/
|
|
100
|
+
env.bak/
|
|
101
|
+
venv.bak/
|
|
102
|
+
|
|
103
|
+
# Spyder project settings
|
|
104
|
+
.spyderproject
|
|
105
|
+
.spyproject
|
|
106
|
+
|
|
107
|
+
# Rope project settings
|
|
108
|
+
.ropeproject
|
|
109
|
+
|
|
110
|
+
# mkdocs documentation
|
|
111
|
+
/site
|
|
112
|
+
|
|
113
|
+
# mypy
|
|
114
|
+
.mypy_cache/
|
|
115
|
+
|
|
116
|
+
# PyCharm
|
|
117
|
+
.idea
|
falaw-0.0.2/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Thor Whalen
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
falaw-0.0.2/PKG-INFO
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: falaw
|
|
3
|
+
Version: 0.0.2
|
|
4
|
+
Summary: Agent-friendly Python facade over fal.ai for generating and managing AI media (images, video, audio).
|
|
5
|
+
Project-URL: Homepage, https://github.com/thorwhalen/falaw
|
|
6
|
+
Project-URL: Repository, https://github.com/thorwhalen/falaw
|
|
7
|
+
Project-URL: Documentation, https://thorwhalen.github.io/falaw
|
|
8
|
+
Author: Thor Whalen
|
|
9
|
+
License: mit
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Requires-Python: >=3.10
|
|
12
|
+
Requires-Dist: fal-client>=0.5
|
|
13
|
+
Provides-Extra: dev
|
|
14
|
+
Requires-Dist: pytest-cov>=4.0; extra == 'dev'
|
|
15
|
+
Requires-Dist: pytest>=7.0; extra == 'dev'
|
|
16
|
+
Requires-Dist: ruff>=0.1.0; extra == 'dev'
|
|
17
|
+
Provides-Extra: docs
|
|
18
|
+
Requires-Dist: sphinx-rtd-theme>=1.0; extra == 'docs'
|
|
19
|
+
Requires-Dist: sphinx>=6.0; extra == 'docs'
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
|
|
22
|
+
# falaw
|
|
23
|
+
|
|
24
|
+
Agent-friendly Python facade over fal.ai for generating and managing AI media (images, video, audio).
|
|
25
|
+
|
|
26
|
+
```python
|
|
27
|
+
from falaw import generate_image, list_models, journal
|
|
28
|
+
|
|
29
|
+
r = generate_image("a tiger eye, macro, 35mm", quality="fast")
|
|
30
|
+
r.first.download(to="./tiger.png")
|
|
31
|
+
|
|
32
|
+
[m.id for m in list_models(category="video")]
|
|
33
|
+
journal.note("schnell at quality='fast' defaults to 1024x1024")
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Why
|
|
37
|
+
|
|
38
|
+
`fal-client` already gives you 100+ models behind a uniform call. What
|
|
39
|
+
agents (and humans) still struggle with is *which* model to use, *what*
|
|
40
|
+
parameters it takes, and *what to do with* the URL it returns. `falaw`
|
|
41
|
+
adds:
|
|
42
|
+
|
|
43
|
+
- Task-level verbs (`generate_image`, `text_to_speech`, ...) with smart model selection by quality tier.
|
|
44
|
+
- A queryable model registry --- no more grepping docs for IDs.
|
|
45
|
+
- `Result` / `Asset` objects that download, name, and organize outputs.
|
|
46
|
+
- A journal so each session leaves notes for the next one.
|
|
47
|
+
- A Claude skill, plus stub bridges for MCP and HTTP services --- all derived from the same tool registry.
|
|
48
|
+
|
|
49
|
+
## Install
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
pip install -e .
|
|
53
|
+
export FAL_KEY="your-fal-api-key"
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Core surface
|
|
57
|
+
|
|
58
|
+
| Function | Purpose |
|
|
59
|
+
| --- | --- |
|
|
60
|
+
| `generate_image(prompt, *, quality, image_size, model_id, extra)` | Text-to-image, picks FLUX by quality tier. |
|
|
61
|
+
| `text_to_speech(text, *, quality, voice, model_id, extra)` | TTS, picks a voice model by tier. |
|
|
62
|
+
| `list_models(*, category, quality_tier)` | Browse the catalog. |
|
|
63
|
+
| `pick_model(*, category, quality_tier)` | Pick a sensible default. |
|
|
64
|
+
| `call_fal(application, arguments)` | Escape hatch to any fal model. Auto-journals on error. |
|
|
65
|
+
| `journal.note / issue / improvement(...)` | Leave a trace for future sessions. |
|
|
66
|
+
| `Session(output_dir=...)` | Optional stateful controller. |
|
|
67
|
+
|
|
68
|
+
## Architecture
|
|
69
|
+
|
|
70
|
+
Single source of truth: a `ToolSpec` dataclass per tool. From it we derive every external surface:
|
|
71
|
+
|
|
72
|
+
```
|
|
73
|
+
falaw.registry ──► bridges/skill.py ──► .claude/skills/falaw/SKILL.md
|
|
74
|
+
──► bridges/mcp.py ──► MCP server (planned)
|
|
75
|
+
──► bridges/service.py ──► qh HTTP service (planned)
|
|
76
|
+
──► (UI) (planned)
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Adding a new surface is a new bridge module, never a re-implementation of the operations.
|
|
80
|
+
|
|
81
|
+
## Self-improvement loop
|
|
82
|
+
|
|
83
|
+
Every session can read and write the agent journal at `~/.config/falaw/journal/`. The Claude skill instructs Claude to:
|
|
84
|
+
|
|
85
|
+
1. Read recent entries before novel work.
|
|
86
|
+
2. Write a note / issue / improvement when something surprises it.
|
|
87
|
+
|
|
88
|
+
`call_fal` auto-journals failures with the application id and arguments, so the next session recognizes the trap.
|
|
89
|
+
|
|
90
|
+
## Layout
|
|
91
|
+
|
|
92
|
+
```
|
|
93
|
+
falaw/
|
|
94
|
+
base.py ToolSpec, ModelRecord
|
|
95
|
+
core.py call_fal: subscribe + auto-journal
|
|
96
|
+
registry.py register_tool, list/get/pick model
|
|
97
|
+
results.py Asset, Result, parse_response
|
|
98
|
+
session.py Session
|
|
99
|
+
journal.py file-backed journal
|
|
100
|
+
operations/
|
|
101
|
+
images.py generate_image
|
|
102
|
+
audio.py text_to_speech
|
|
103
|
+
bridges/
|
|
104
|
+
skill.py render Claude SKILL.md from registry
|
|
105
|
+
mcp.py (stub)
|
|
106
|
+
service.py (stub)
|
|
107
|
+
data/
|
|
108
|
+
models.json seed catalog
|
|
109
|
+
skills/falaw/ generated skill files (shipped with package)
|
|
110
|
+
misc/
|
|
111
|
+
docs/ aggregated fal.ai docs (3MB md, llms.txt, llms-full.txt)
|
|
112
|
+
regenerate_skill.py
|
|
113
|
+
tests/
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Regenerate the skill after adding a tool
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
python misc/regenerate_skill.py
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Writes `falaw/data/skills/falaw/SKILL.md` and `.claude/skills/falaw/SKILL.md`.
|
|
123
|
+
|
|
124
|
+
## Status
|
|
125
|
+
|
|
126
|
+
v0 --- functional core, real Claude skill, stubs for MCP and HTTP service. The bridges share the same registry, so filling in the stubs is additive.
|
falaw-0.0.2/README.md
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# falaw
|
|
2
|
+
|
|
3
|
+
Agent-friendly Python facade over fal.ai for generating and managing AI media (images, video, audio).
|
|
4
|
+
|
|
5
|
+
```python
|
|
6
|
+
from falaw import generate_image, list_models, journal
|
|
7
|
+
|
|
8
|
+
r = generate_image("a tiger eye, macro, 35mm", quality="fast")
|
|
9
|
+
r.first.download(to="./tiger.png")
|
|
10
|
+
|
|
11
|
+
[m.id for m in list_models(category="video")]
|
|
12
|
+
journal.note("schnell at quality='fast' defaults to 1024x1024")
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Why
|
|
16
|
+
|
|
17
|
+
`fal-client` already gives you 100+ models behind a uniform call. What
|
|
18
|
+
agents (and humans) still struggle with is *which* model to use, *what*
|
|
19
|
+
parameters it takes, and *what to do with* the URL it returns. `falaw`
|
|
20
|
+
adds:
|
|
21
|
+
|
|
22
|
+
- Task-level verbs (`generate_image`, `text_to_speech`, ...) with smart model selection by quality tier.
|
|
23
|
+
- A queryable model registry --- no more grepping docs for IDs.
|
|
24
|
+
- `Result` / `Asset` objects that download, name, and organize outputs.
|
|
25
|
+
- A journal so each session leaves notes for the next one.
|
|
26
|
+
- A Claude skill, plus stub bridges for MCP and HTTP services --- all derived from the same tool registry.
|
|
27
|
+
|
|
28
|
+
## Install
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
pip install -e .
|
|
32
|
+
export FAL_KEY="your-fal-api-key"
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Core surface
|
|
36
|
+
|
|
37
|
+
| Function | Purpose |
|
|
38
|
+
| --- | --- |
|
|
39
|
+
| `generate_image(prompt, *, quality, image_size, model_id, extra)` | Text-to-image, picks FLUX by quality tier. |
|
|
40
|
+
| `text_to_speech(text, *, quality, voice, model_id, extra)` | TTS, picks a voice model by tier. |
|
|
41
|
+
| `list_models(*, category, quality_tier)` | Browse the catalog. |
|
|
42
|
+
| `pick_model(*, category, quality_tier)` | Pick a sensible default. |
|
|
43
|
+
| `call_fal(application, arguments)` | Escape hatch to any fal model. Auto-journals on error. |
|
|
44
|
+
| `journal.note / issue / improvement(...)` | Leave a trace for future sessions. |
|
|
45
|
+
| `Session(output_dir=...)` | Optional stateful controller. |
|
|
46
|
+
|
|
47
|
+
## Architecture
|
|
48
|
+
|
|
49
|
+
Single source of truth: a `ToolSpec` dataclass per tool. From it we derive every external surface:
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
falaw.registry ──► bridges/skill.py ──► .claude/skills/falaw/SKILL.md
|
|
53
|
+
──► bridges/mcp.py ──► MCP server (planned)
|
|
54
|
+
──► bridges/service.py ──► qh HTTP service (planned)
|
|
55
|
+
──► (UI) (planned)
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Adding a new surface is a new bridge module, never a re-implementation of the operations.
|
|
59
|
+
|
|
60
|
+
## Self-improvement loop
|
|
61
|
+
|
|
62
|
+
Every session can read and write the agent journal at `~/.config/falaw/journal/`. The Claude skill instructs Claude to:
|
|
63
|
+
|
|
64
|
+
1. Read recent entries before novel work.
|
|
65
|
+
2. Write a note / issue / improvement when something surprises it.
|
|
66
|
+
|
|
67
|
+
`call_fal` auto-journals failures with the application id and arguments, so the next session recognizes the trap.
|
|
68
|
+
|
|
69
|
+
## Layout
|
|
70
|
+
|
|
71
|
+
```
|
|
72
|
+
falaw/
|
|
73
|
+
base.py ToolSpec, ModelRecord
|
|
74
|
+
core.py call_fal: subscribe + auto-journal
|
|
75
|
+
registry.py register_tool, list/get/pick model
|
|
76
|
+
results.py Asset, Result, parse_response
|
|
77
|
+
session.py Session
|
|
78
|
+
journal.py file-backed journal
|
|
79
|
+
operations/
|
|
80
|
+
images.py generate_image
|
|
81
|
+
audio.py text_to_speech
|
|
82
|
+
bridges/
|
|
83
|
+
skill.py render Claude SKILL.md from registry
|
|
84
|
+
mcp.py (stub)
|
|
85
|
+
service.py (stub)
|
|
86
|
+
data/
|
|
87
|
+
models.json seed catalog
|
|
88
|
+
skills/falaw/ generated skill files (shipped with package)
|
|
89
|
+
misc/
|
|
90
|
+
docs/ aggregated fal.ai docs (3MB md, llms.txt, llms-full.txt)
|
|
91
|
+
regenerate_skill.py
|
|
92
|
+
tests/
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Regenerate the skill after adding a tool
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
python misc/regenerate_skill.py
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Writes `falaw/data/skills/falaw/SKILL.md` and `.claude/skills/falaw/SKILL.md`.
|
|
102
|
+
|
|
103
|
+
## Status
|
|
104
|
+
|
|
105
|
+
v0 --- functional core, real Claude skill, stubs for MCP and HTTP service. The bridges share the same registry, so filling in the stubs is additive.
|