cudag 0.3.10__py3-none-any.whl
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.
- cudag/__init__.py +334 -0
- cudag/annotation/__init__.py +77 -0
- cudag/annotation/codegen.py +648 -0
- cudag/annotation/config.py +545 -0
- cudag/annotation/loader.py +342 -0
- cudag/annotation/scaffold.py +121 -0
- cudag/annotation/transcription.py +296 -0
- cudag/cli/__init__.py +5 -0
- cudag/cli/main.py +315 -0
- cudag/cli/new.py +873 -0
- cudag/core/__init__.py +364 -0
- cudag/core/button.py +137 -0
- cudag/core/canvas.py +222 -0
- cudag/core/config.py +70 -0
- cudag/core/coords.py +233 -0
- cudag/core/data_grid.py +804 -0
- cudag/core/dataset.py +678 -0
- cudag/core/distribution.py +136 -0
- cudag/core/drawing.py +75 -0
- cudag/core/fonts.py +156 -0
- cudag/core/generator.py +163 -0
- cudag/core/grid.py +367 -0
- cudag/core/grounding_task.py +247 -0
- cudag/core/icon.py +207 -0
- cudag/core/iconlist_task.py +301 -0
- cudag/core/models.py +1251 -0
- cudag/core/random.py +130 -0
- cudag/core/renderer.py +190 -0
- cudag/core/screen.py +402 -0
- cudag/core/scroll_task.py +254 -0
- cudag/core/scrollable_grid.py +447 -0
- cudag/core/state.py +110 -0
- cudag/core/task.py +293 -0
- cudag/core/taskbar.py +350 -0
- cudag/core/text.py +212 -0
- cudag/core/utils.py +82 -0
- cudag/data/surnames.txt +5000 -0
- cudag/modal_apps/__init__.py +4 -0
- cudag/modal_apps/archive.py +103 -0
- cudag/modal_apps/extract.py +138 -0
- cudag/modal_apps/preprocess.py +529 -0
- cudag/modal_apps/upload.py +317 -0
- cudag/prompts/SYSTEM_PROMPT.txt +104 -0
- cudag/prompts/__init__.py +33 -0
- cudag/prompts/system.py +43 -0
- cudag/prompts/tools.py +382 -0
- cudag/py.typed +0 -0
- cudag/schemas/filesystem.json +90 -0
- cudag/schemas/test_record.schema.json +113 -0
- cudag/schemas/train_record.schema.json +90 -0
- cudag/server/__init__.py +21 -0
- cudag/server/app.py +232 -0
- cudag/server/services/__init__.py +9 -0
- cudag/server/services/generator.py +128 -0
- cudag/templates/scripts/archive.sh +35 -0
- cudag/templates/scripts/build.sh +13 -0
- cudag/templates/scripts/extract.sh +54 -0
- cudag/templates/scripts/generate.sh +116 -0
- cudag/templates/scripts/pre-commit.sh +44 -0
- cudag/templates/scripts/preprocess.sh +46 -0
- cudag/templates/scripts/upload.sh +63 -0
- cudag/templates/scripts/verify.py +428 -0
- cudag/validation/__init__.py +35 -0
- cudag/validation/validate.py +508 -0
- cudag-0.3.10.dist-info/METADATA +570 -0
- cudag-0.3.10.dist-info/RECORD +69 -0
- cudag-0.3.10.dist-info/WHEEL +4 -0
- cudag-0.3.10.dist-info/entry_points.txt +2 -0
- cudag-0.3.10.dist-info/licenses/LICENSE +66 -0
|
@@ -0,0 +1,570 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: cudag
|
|
3
|
+
Version: 0.3.10
|
|
4
|
+
Summary: CUDAG - ComputerUseDataAugmentedGeneration framework for building VLM training data generators
|
|
5
|
+
Project-URL: Homepage, https://github.com/claimhawk/pypi-cudag
|
|
6
|
+
Project-URL: Documentation, https://github.com/claimhawk/pypi-cudag#readme
|
|
7
|
+
Project-URL: Repository, https://github.com/claimhawk/pypi-cudag
|
|
8
|
+
Project-URL: Issues, https://github.com/claimhawk/pypi-cudag/issues
|
|
9
|
+
Author: ClaimHawk Michael
|
|
10
|
+
License-Expression: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: computer-use,dataset-generation,training-data,vision-language-model,vlm
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Intended Audience :: Science/Research
|
|
16
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
17
|
+
Classifier: Operating System :: OS Independent
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
23
|
+
Classifier: Typing :: Typed
|
|
24
|
+
Requires-Python: >=3.12
|
|
25
|
+
Requires-Dist: click>=8.0
|
|
26
|
+
Requires-Dist: fastapi>=0.109.0
|
|
27
|
+
Requires-Dist: modal>=0.60.0
|
|
28
|
+
Requires-Dist: pillow>=10.0.0
|
|
29
|
+
Requires-Dist: pyyaml>=6.0
|
|
30
|
+
Requires-Dist: uvicorn>=0.27.0
|
|
31
|
+
Provides-Extra: dev
|
|
32
|
+
Requires-Dist: mypy>=1.0.0; extra == 'dev'
|
|
33
|
+
Requires-Dist: pytest>=7.0.0; extra == 'dev'
|
|
34
|
+
Requires-Dist: ruff>=0.1.0; extra == 'dev'
|
|
35
|
+
Requires-Dist: types-pyyaml; extra == 'dev'
|
|
36
|
+
Description-Content-Type: text/markdown
|
|
37
|
+
|
|
38
|
+
# CUDAG - ComputerUseDataAugmentedGeneration
|
|
39
|
+
|
|
40
|
+
A Rails-like framework for building VLM (Vision-Language Model) training data generators.
|
|
41
|
+
|
|
42
|
+
## Overview
|
|
43
|
+
|
|
44
|
+
CUDAG provides a convention-over-configuration approach to generating training data for computer use models. It uses a domain-specific MVC-like pattern:
|
|
45
|
+
|
|
46
|
+
- **Screen** - Declarative UI definition (like Model in Rails)
|
|
47
|
+
- **State** - Dynamic data for rendering
|
|
48
|
+
- **Renderer** - Image generation (like View in Rails)
|
|
49
|
+
- **Task** - Interaction logic (like Controller in Rails)
|
|
50
|
+
- **Model** - Domain data types with generators (Patient, Provider, etc.)
|
|
51
|
+
|
|
52
|
+
## Installation
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
# Create virtual environment
|
|
56
|
+
python3 -m venv .venv
|
|
57
|
+
source .venv/bin/activate
|
|
58
|
+
|
|
59
|
+
# Install CUDAG and dev dependencies
|
|
60
|
+
make install
|
|
61
|
+
make dev
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Quality Checks
|
|
65
|
+
|
|
66
|
+
Always run quality checks during development:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
make check # Run all checks (lint, typecheck, complexity)
|
|
70
|
+
make lint # Ruff linting and format checking
|
|
71
|
+
make typecheck # Mypy strict type checking
|
|
72
|
+
make complexity # Radon cyclomatic complexity analysis
|
|
73
|
+
make format # Auto-format code
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Development Workflow
|
|
77
|
+
|
|
78
|
+
Building a CUDAG generator follows this process:
|
|
79
|
+
|
|
80
|
+
### Step 1: Generate New App
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
# Install CUDAG globally
|
|
84
|
+
uvx pip install cudag
|
|
85
|
+
|
|
86
|
+
# Create a new generator project
|
|
87
|
+
cudag new claim-window-generator
|
|
88
|
+
|
|
89
|
+
# Navigate into the project
|
|
90
|
+
cd claim-window-generator
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
This creates:
|
|
94
|
+
```
|
|
95
|
+
claim-window-generator/
|
|
96
|
+
├── assets/ # Base images, fonts
|
|
97
|
+
├── config/
|
|
98
|
+
│ └── dataset.yaml
|
|
99
|
+
├── models/ # Domain model definitions
|
|
100
|
+
├── tasks/ # Task implementations
|
|
101
|
+
├── screen.py # Screen definition
|
|
102
|
+
├── state.py # State dataclass
|
|
103
|
+
├── renderer.py # Image renderer
|
|
104
|
+
└── datasets/ # Output (gitignored)
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Step 2: Add Base Images
|
|
108
|
+
|
|
109
|
+
Copy your blank screen images and fonts:
|
|
110
|
+
- **Full screen blank**: `assets/base.png` - The base UI template
|
|
111
|
+
- **Region blanks**: `assets/grid_blank.png` - Headers, overlays, etc.
|
|
112
|
+
- **Fonts**: `assets/fonts/font.ttf` - Font for rendering text
|
|
113
|
+
|
|
114
|
+
### Step 3: Generate Data Models
|
|
115
|
+
|
|
116
|
+
Use Claude to generate domain models for your data:
|
|
117
|
+
|
|
118
|
+
```python
|
|
119
|
+
from cudag import Model, FirstName, LastName, DOB, NPI, Phone, Email
|
|
120
|
+
from cudag import string, date_field, money, choice, computed
|
|
121
|
+
|
|
122
|
+
class Patient(Model):
|
|
123
|
+
first_name = FirstName()
|
|
124
|
+
last_name = LastName()
|
|
125
|
+
dob = DOB()
|
|
126
|
+
member_id = string(pattern=r"[A-Z]{3}[0-9]{6}")
|
|
127
|
+
phone = Phone()
|
|
128
|
+
email = Email()
|
|
129
|
+
|
|
130
|
+
# Computed fields
|
|
131
|
+
full_name = computed("first_name", "last_name")
|
|
132
|
+
age = years_since("dob")
|
|
133
|
+
|
|
134
|
+
class Procedure(Model):
|
|
135
|
+
code = string(pattern=r"D[0-9]{4}")
|
|
136
|
+
description = choice("Exam", "Cleaning", "X-Ray", "Crown")
|
|
137
|
+
fee = money(min_value=50.0, max_value=2500.0)
|
|
138
|
+
|
|
139
|
+
class Provider(Model):
|
|
140
|
+
first_name = string(faker="first_name")
|
|
141
|
+
last_name = string(faker="last_name")
|
|
142
|
+
npi = string(faker="npi")
|
|
143
|
+
specialty = choice("General", "Orthodontics", "Oral Surgery")
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
**Field Types:**
|
|
147
|
+
- `string(faker=..., pattern=..., choices=...)` - Text
|
|
148
|
+
- `integer(min_value, max_value)` - Numbers
|
|
149
|
+
- `decimal(min_value, max_value, precision)` - Floats
|
|
150
|
+
- `money(min_value, max_value)` - Currency ($X.XX)
|
|
151
|
+
- `date_field(min_year, max_year, format)` - Dates
|
|
152
|
+
- `time_field(min_hour, max_hour, format)` - Times
|
|
153
|
+
- `boolean(probability)` - True/False
|
|
154
|
+
- `choice(*options, weights)` - Pick from list
|
|
155
|
+
- `computed(*sources)` - Derived from other fields
|
|
156
|
+
- `years_since(field)` - Age calculation
|
|
157
|
+
|
|
158
|
+
### Step 4: Define Screen Layout
|
|
159
|
+
|
|
160
|
+
Declare your screen structure with regions:
|
|
161
|
+
|
|
162
|
+
```python
|
|
163
|
+
from cudag import Screen, grid, button, scrollable, dropdown
|
|
164
|
+
|
|
165
|
+
class ClaimWindowScreen(Screen):
|
|
166
|
+
name = "claim-window"
|
|
167
|
+
base_image = "images/screen_blank.png"
|
|
168
|
+
size = (1155, 853)
|
|
169
|
+
|
|
170
|
+
# Grid region - bounds are (x, y, width, height)
|
|
171
|
+
procedure_grid = grid(
|
|
172
|
+
(0, 217, 1155, 167),
|
|
173
|
+
rows=8,
|
|
174
|
+
cols=17,
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
# Scrollable area
|
|
178
|
+
scroll_area = scrollable(
|
|
179
|
+
(0, 217, 1155, 167),
|
|
180
|
+
step=300,
|
|
181
|
+
direction="vertical",
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
# Buttons
|
|
185
|
+
billing_provider = button((85, 95, 200, 20), label="Billing Provider")
|
|
186
|
+
save_button = button((100, 800, 80, 30), label="Save")
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
**Region Types:**
|
|
190
|
+
- `region(bounds)` - Simple clickable area
|
|
191
|
+
- `button(bounds, label, description)` - Clickable button
|
|
192
|
+
- `grid(bounds, rows, cols)` - Grid of cells
|
|
193
|
+
- `scrollable(bounds, step, direction)` - Scrollable area
|
|
194
|
+
- `dropdown(bounds, items)` - Dropdown menu
|
|
195
|
+
|
|
196
|
+
### Step 5: Build Screen Renderer
|
|
197
|
+
|
|
198
|
+
Render your screen with PIL, drawing data onto the base image:
|
|
199
|
+
|
|
200
|
+
```python
|
|
201
|
+
from PIL import Image, ImageDraw, ImageFont
|
|
202
|
+
from cudag import BaseRenderer
|
|
203
|
+
from .screens import ClaimWindowScreen
|
|
204
|
+
from .state import GridState
|
|
205
|
+
|
|
206
|
+
class ClaimWindowRenderer(BaseRenderer[GridState]):
|
|
207
|
+
screen_class = ClaimWindowScreen
|
|
208
|
+
|
|
209
|
+
def load_assets(self) -> None:
|
|
210
|
+
self.font = ImageFont.truetype(
|
|
211
|
+
str(self.asset_path("fonts", "font.ttf")), 9
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
def render(self, state: GridState) -> tuple[Image.Image, dict]:
|
|
215
|
+
image = self.load_base_image()
|
|
216
|
+
draw = ImageDraw.Draw(image)
|
|
217
|
+
|
|
218
|
+
# Render grid rows
|
|
219
|
+
self._render_grid(image, draw, state)
|
|
220
|
+
|
|
221
|
+
# Render scrollbar
|
|
222
|
+
self._render_scrollbar(image, state)
|
|
223
|
+
|
|
224
|
+
metadata = self.build_metadata(state)
|
|
225
|
+
return image, metadata
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
### Step 6: Build Region Renderers
|
|
229
|
+
|
|
230
|
+
For complex regions (grids, tables), create dedicated rendering methods:
|
|
231
|
+
|
|
232
|
+
```python
|
|
233
|
+
def _render_grid(self, image, draw, state):
|
|
234
|
+
for idx, row in enumerate(state.visible_rows):
|
|
235
|
+
y = GRID_Y_START + idx * ROW_HEIGHT
|
|
236
|
+
for col in COLUMNS:
|
|
237
|
+
value = getattr(row, col["id"], "")
|
|
238
|
+
x = col["x"]
|
|
239
|
+
draw.text((x, y), str(value), font=self.font, fill=(0, 0, 0))
|
|
240
|
+
|
|
241
|
+
def _render_scrollbar(self, image, state):
|
|
242
|
+
# Calculate thumb position based on scroll state
|
|
243
|
+
thumb_y = calculate_thumb_position(state)
|
|
244
|
+
draw.rectangle([track_x, thumb_y, track_x + width, thumb_y + height],
|
|
245
|
+
fill=(100, 100, 100))
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
### Step 7: Test and Align Data
|
|
249
|
+
|
|
250
|
+
This is critical - manually verify that:
|
|
251
|
+
- Grid columns align with data
|
|
252
|
+
- Text fits within column widths
|
|
253
|
+
- Row wrapping works correctly
|
|
254
|
+
- Scroll positions show correct content
|
|
255
|
+
- All UI elements render properly
|
|
256
|
+
|
|
257
|
+
```bash
|
|
258
|
+
# Generate a small test batch
|
|
259
|
+
python -m my_generator.generator --config config/dataset.yaml
|
|
260
|
+
|
|
261
|
+
# View generated images
|
|
262
|
+
open datasets/my-dataset/images/
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
### Step 8: Create Tasks
|
|
266
|
+
|
|
267
|
+
Define tasks that generate training samples:
|
|
268
|
+
|
|
269
|
+
```python
|
|
270
|
+
from cudag import BaseTask, TaskSample, TaskContext, ToolCall
|
|
271
|
+
|
|
272
|
+
class ScrollGridTask(BaseTask):
|
|
273
|
+
task_type = "scroll-grid"
|
|
274
|
+
|
|
275
|
+
def generate_sample(self, ctx: TaskContext) -> TaskSample:
|
|
276
|
+
# Generate state
|
|
277
|
+
state = GridState.generate(ctx.rng, min_rows=15, max_rows=28)
|
|
278
|
+
|
|
279
|
+
# Render image
|
|
280
|
+
image, metadata = self.renderer.render(state)
|
|
281
|
+
image_path = self.save_image(image, ctx)
|
|
282
|
+
|
|
283
|
+
# Get scroll coordinates
|
|
284
|
+
grid_center = self.renderer.get_grid_center()
|
|
285
|
+
|
|
286
|
+
return TaskSample(
|
|
287
|
+
id=self.build_id(ctx),
|
|
288
|
+
image_path=image_path,
|
|
289
|
+
human_prompt="Scroll down in the grid.",
|
|
290
|
+
tool_call=ToolCall.scroll(grid_center, pixels=300),
|
|
291
|
+
pixel_coords=grid_center,
|
|
292
|
+
image_size=self.renderer.screen_class.meta().size,
|
|
293
|
+
metadata={"task_type": self.task_type, **metadata},
|
|
294
|
+
)
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
### Step 9: Create Dataset Generator
|
|
298
|
+
|
|
299
|
+
Use `run_generator()` to handle boilerplate (argument parsing, config loading, dataset naming):
|
|
300
|
+
|
|
301
|
+
```python
|
|
302
|
+
from pathlib import Path
|
|
303
|
+
from cudag import run_generator
|
|
304
|
+
from .renderer import ClaimWindowRenderer
|
|
305
|
+
from .tasks import ScrollGridTask
|
|
306
|
+
|
|
307
|
+
def main():
|
|
308
|
+
renderer = ClaimWindowRenderer(assets_dir=Path("assets"))
|
|
309
|
+
tasks = [ScrollGridTask(config={}, renderer=renderer)]
|
|
310
|
+
run_generator(renderer, tasks)
|
|
311
|
+
|
|
312
|
+
if __name__ == "__main__":
|
|
313
|
+
main()
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
The `run_generator()` helper handles:
|
|
317
|
+
- Script invocation check
|
|
318
|
+
- Argument parsing (`--config`, `--seed`)
|
|
319
|
+
- Config loading from YAML
|
|
320
|
+
- Dataset naming (`{prefix}-{researcher}-{timestamp}`)
|
|
321
|
+
- Building dataset and tests
|
|
322
|
+
|
|
323
|
+
For custom behavior, use optional parameters:
|
|
324
|
+
|
|
325
|
+
```python
|
|
326
|
+
run_generator(
|
|
327
|
+
renderer,
|
|
328
|
+
tasks,
|
|
329
|
+
extra_args=[("--debug", {"action": "store_true"})],
|
|
330
|
+
config_modifier=lambda config, args: setattr(config, 'seed', 999) if args.debug else None,
|
|
331
|
+
post_build=lambda output_dir, renderer: generate_debug_images(output_dir),
|
|
332
|
+
)
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
### Step 10: Generate Production Dataset
|
|
336
|
+
|
|
337
|
+
```bash
|
|
338
|
+
# Generate full dataset
|
|
339
|
+
PYTHONPATH=src python -m my_generator.generator
|
|
340
|
+
|
|
341
|
+
# Verify output
|
|
342
|
+
ls datasets/my-dataset/
|
|
343
|
+
# images/ data.jsonl train.jsonl test.jsonl config.json
|
|
344
|
+
|
|
345
|
+
# Check JSONL format
|
|
346
|
+
head -1 datasets/my-dataset/data.jsonl | python -m json.tool
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
## Output Format
|
|
350
|
+
|
|
351
|
+
Generated JSONL structure:
|
|
352
|
+
|
|
353
|
+
```json
|
|
354
|
+
{
|
|
355
|
+
"id": "my-dataset_00000",
|
|
356
|
+
"image": "images/my-dataset_00000.jpg",
|
|
357
|
+
"conversations": [
|
|
358
|
+
{"from": "system", "value": "...tool definitions..."},
|
|
359
|
+
{"from": "human", "value": "<image>\nScroll down in the grid."},
|
|
360
|
+
{"from": "gpt", "value": "<tool_call>{\"name\": \"computer_use\", \"arguments\": {\"action\": \"scroll\", \"coordinate\": [500, 352], \"pixels\": 300}}</tool_call>"}
|
|
361
|
+
],
|
|
362
|
+
"metadata": {
|
|
363
|
+
"task_type": "scroll-grid",
|
|
364
|
+
"real_coords": [577, 300]
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
## Utility Functions
|
|
370
|
+
|
|
371
|
+
### Researcher Name
|
|
372
|
+
|
|
373
|
+
Use `get_researcher_name()` to automatically include researcher identity in dataset names:
|
|
374
|
+
|
|
375
|
+
```python
|
|
376
|
+
from cudag import get_researcher_name
|
|
377
|
+
|
|
378
|
+
# Reads from .researcher file (supports "Name: mike" or plain "mike")
|
|
379
|
+
# Falls back to USER environment variable
|
|
380
|
+
researcher = get_researcher_name() # Returns "mike" or None
|
|
381
|
+
|
|
382
|
+
# Disable environment fallback
|
|
383
|
+
researcher = get_researcher_name(fallback_to_env=False)
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
### Font Loading
|
|
387
|
+
|
|
388
|
+
Use `load_font()` for platform-aware font loading with automatic fallbacks:
|
|
389
|
+
|
|
390
|
+
```python
|
|
391
|
+
from cudag import load_font, load_font_family
|
|
392
|
+
|
|
393
|
+
# Load with automatic system font fallback
|
|
394
|
+
font = load_font("assets/fonts/Inter.ttf", size=14)
|
|
395
|
+
|
|
396
|
+
# Load with explicit fallbacks
|
|
397
|
+
font = load_font(
|
|
398
|
+
"assets/fonts/Inter.ttf",
|
|
399
|
+
size=14,
|
|
400
|
+
fallbacks=["/System/Library/Fonts/Helvetica.ttc"]
|
|
401
|
+
)
|
|
402
|
+
|
|
403
|
+
# Load font family with variants
|
|
404
|
+
fonts = load_font_family(
|
|
405
|
+
"fonts/Inter-Regular.ttf",
|
|
406
|
+
size=14,
|
|
407
|
+
bold="fonts/Inter-Bold.ttf",
|
|
408
|
+
)
|
|
409
|
+
# fonts["regular"], fonts["bold"], fonts["italic"], fonts["bold_italic"]
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
### Random Data Generation
|
|
413
|
+
|
|
414
|
+
Use `choose()`, `date_in_range()`, and `amount()` for consistent random data:
|
|
415
|
+
|
|
416
|
+
```python
|
|
417
|
+
from random import Random
|
|
418
|
+
from cudag import choose, date_in_range, amount, weighted_choice
|
|
419
|
+
|
|
420
|
+
rng = Random(42)
|
|
421
|
+
|
|
422
|
+
# Choose random item from sequence
|
|
423
|
+
provider = choose(rng, ["Dr. Smith", "Dr. Jones", "Dr. Brown"])
|
|
424
|
+
|
|
425
|
+
# Generate random date in range
|
|
426
|
+
visit_date = date_in_range(rng, "2024-01-01", "2024-12-31", fmt="%m/%d/%Y")
|
|
427
|
+
|
|
428
|
+
# Generate random monetary amount
|
|
429
|
+
fee = amount(rng, 50.0, 500.0)
|
|
430
|
+
# With optional zero values (20% chance)
|
|
431
|
+
payment = amount(rng, 0.0, 100.0, allow_zero=True)
|
|
432
|
+
|
|
433
|
+
# Weighted random choice
|
|
434
|
+
status = weighted_choice(rng, {"pending": 0.7, "approved": 0.2, "denied": 0.1})
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
### Text Utilities
|
|
438
|
+
|
|
439
|
+
Use text utilities for measurement and rendering:
|
|
440
|
+
|
|
441
|
+
```python
|
|
442
|
+
from cudag import measure_text, center_text_position, draw_centered_text, wrap_text
|
|
443
|
+
from PIL import Image, ImageDraw, ImageFont
|
|
444
|
+
|
|
445
|
+
font = ImageFont.load_default()
|
|
446
|
+
|
|
447
|
+
# Measure text dimensions
|
|
448
|
+
width, height = measure_text("Hello World", font)
|
|
449
|
+
|
|
450
|
+
# Calculate centered position
|
|
451
|
+
tx, ty = center_text_position("Label", font, x=0, y=0, width=200, height=50)
|
|
452
|
+
|
|
453
|
+
# Draw centered text directly
|
|
454
|
+
img = Image.new("RGB", (200, 100), "white")
|
|
455
|
+
draw = ImageDraw.Draw(img)
|
|
456
|
+
draw_centered_text(draw, "Centered", font, x=0, y=0, width=200, height=100)
|
|
457
|
+
|
|
458
|
+
# Wrap text to fit width
|
|
459
|
+
lines = wrap_text("This is a long sentence that needs wrapping", max_width=100, font=font)
|
|
460
|
+
|
|
461
|
+
# Truncate text with ellipsis
|
|
462
|
+
short = truncate_text("This is a very long label", max_width=80, font=font)
|
|
463
|
+
# Returns "This is..." or similar
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
### Config Utilities
|
|
467
|
+
|
|
468
|
+
Load YAML configuration files:
|
|
469
|
+
|
|
470
|
+
```python
|
|
471
|
+
from cudag import load_yaml_config, get_config_path
|
|
472
|
+
|
|
473
|
+
# Get config path relative to your module
|
|
474
|
+
config_path = get_config_path(__file__, "canvas.yaml")
|
|
475
|
+
|
|
476
|
+
# Load YAML config
|
|
477
|
+
config = load_yaml_config(config_path)
|
|
478
|
+
# Returns dict with parsed YAML content
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
### Drawing Utilities
|
|
482
|
+
|
|
483
|
+
Use `render_scrollbar()` for scrollbar rendering:
|
|
484
|
+
|
|
485
|
+
```python
|
|
486
|
+
from cudag import render_scrollbar
|
|
487
|
+
|
|
488
|
+
scrollbar = render_scrollbar(
|
|
489
|
+
content_height=1000, # Total content height
|
|
490
|
+
visible_height=400, # Visible viewport
|
|
491
|
+
scroll_offset=200, # Current scroll position
|
|
492
|
+
width=12, # Scrollbar width
|
|
493
|
+
min_thumb=30, # Minimum thumb height
|
|
494
|
+
)
|
|
495
|
+
# Returns PIL Image of scrollbar
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
## Coordinate System
|
|
499
|
+
|
|
500
|
+
All coordinates use RU (Resolution Units) normalized to [0, 1000]:
|
|
501
|
+
- Conversion: `normalized = (pixel / image_dimension) * 1000`
|
|
502
|
+
- Real pixel coords stored in `metadata.real_coords`
|
|
503
|
+
|
|
504
|
+
## Tool Call Actions
|
|
505
|
+
|
|
506
|
+
- `left_click` - Click at coordinate
|
|
507
|
+
- `scroll` - Scroll at coordinate with pixels
|
|
508
|
+
- `type` - Type text
|
|
509
|
+
- `key` - Press key combination
|
|
510
|
+
- `wait` - Wait for duration
|
|
511
|
+
- `terminate` - End interaction
|
|
512
|
+
|
|
513
|
+
## Example Projects
|
|
514
|
+
|
|
515
|
+
See `test-claim-window/` for a complete example implementing:
|
|
516
|
+
- Procedure grid with scrolling
|
|
517
|
+
- Provider names and procedure codes
|
|
518
|
+
- Multi-column data rendering
|
|
519
|
+
- Scroll task generation
|
|
520
|
+
|
|
521
|
+
## Configuration Reference
|
|
522
|
+
|
|
523
|
+
```yaml
|
|
524
|
+
# config/dataset.yaml
|
|
525
|
+
name_prefix: "my-dataset"
|
|
526
|
+
seed: 1337
|
|
527
|
+
|
|
528
|
+
tasks:
|
|
529
|
+
scroll-grid: 100
|
|
530
|
+
click-button: 50
|
|
531
|
+
|
|
532
|
+
task_config:
|
|
533
|
+
min_rows: 15
|
|
534
|
+
max_rows: 28
|
|
535
|
+
tolerance: 50
|
|
536
|
+
|
|
537
|
+
train_split: 0.8
|
|
538
|
+
system_prompt: "compact"
|
|
539
|
+
output_dir: "datasets/my-dataset"
|
|
540
|
+
```
|
|
541
|
+
|
|
542
|
+
## Contributing
|
|
543
|
+
|
|
544
|
+
1. Fork the repository
|
|
545
|
+
2. Create a feature branch
|
|
546
|
+
3. Make your changes:
|
|
547
|
+
- Generalize hardcoded values rather than replacing them with your own
|
|
548
|
+
- Add tests for new functionality
|
|
549
|
+
- Ensure all quality checks pass
|
|
550
|
+
4. Submit a pull request
|
|
551
|
+
|
|
552
|
+
**Code quality requirements:**
|
|
553
|
+
- Lexical complexity checks
|
|
554
|
+
- Syntax linting
|
|
555
|
+
- Code formatting
|
|
556
|
+
- Copyright headers
|
|
557
|
+
|
|
558
|
+
AI-assisted code is welcome provided it includes tests and passes all checks.
|
|
559
|
+
|
|
560
|
+
## License
|
|
561
|
+
|
|
562
|
+
Copyright (c) 2025 Tylt LLC. All rights reserved.
|
|
563
|
+
|
|
564
|
+
This software is source-available for **research and educational purposes only**.
|
|
565
|
+
Commercial use requires a separate license agreement with Tylt LLC (1% of annual
|
|
566
|
+
gross revenue attributable to use of this software).
|
|
567
|
+
|
|
568
|
+
See [LICENSE](./LICENSE) for full terms.
|
|
569
|
+
|
|
570
|
+
For commercial licensing inquiries: hello@claimhawk.app
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
cudag/__init__.py,sha256=YKRNlwcwlFWzEgg1_zOphgmMxrDG-QUZcuyLOr1Z-Qw,6353
|
|
2
|
+
cudag/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
+
cudag/annotation/__init__.py,sha256=fwwigeFM92fqIsqNG5DIlQesWqOVInnkGUUvVN6Fm64,2169
|
|
4
|
+
cudag/annotation/codegen.py,sha256=ODinA_ZUppbPcclryjKjJMz8gckOk5jKU4eLTRhsnu0,21169
|
|
5
|
+
cudag/annotation/config.py,sha256=m0GjzCJh9VyGh27eWhIJ2C1vpAt5TQr9EFOGN3MGK1A,18136
|
|
6
|
+
cudag/annotation/loader.py,sha256=jnqwTZY_PcMGBuPNDQl3YMMHhKAFNV3tGwXZz2cyqhY,11612
|
|
7
|
+
cudag/annotation/scaffold.py,sha256=LEAmZ24Dga1AfrzivFv7tuuNpoVbOxS2r0XUiSuTM_o,4319
|
|
8
|
+
cudag/annotation/transcription.py,sha256=M-k7Mo3zeAuCCfvfkkh9E8c3U4mvMZLkMuKImTDqQdQ,9383
|
|
9
|
+
cudag/cli/__init__.py,sha256=EmYz700ooabNlgbp_qL9T-TS9Y7Q48ERU0mjxwC9uPo,229
|
|
10
|
+
cudag/cli/main.py,sha256=U-M33T45rrYA_7s4G3yw1NvGH7wVyWlEbuMDKf2gNWo,9640
|
|
11
|
+
cudag/cli/new.py,sha256=4j3Sn6F-FFu7EpND9yi3Xxjg_uEaRWsAtMz56FGnoyI,30086
|
|
12
|
+
cudag/core/__init__.py,sha256=7UCV51zVqgI1s0YU9GaWRfDmB4jfBXTWKdJyd9j1QKk,7606
|
|
13
|
+
cudag/core/button.py,sha256=rSL8XhkBWOW5FenS0ZL5TFc3Vqn7Cdw92Yu1N77pD6s,4401
|
|
14
|
+
cudag/core/canvas.py,sha256=-tFF4qzZGVCggDO84x5RtWHBGMqyCDNPNs7gXaX2vI4,5846
|
|
15
|
+
cudag/core/config.py,sha256=Rd9HLZchlvDMFFsfRRHftdxqm_RN1MfVuUIMfQoEOUo,2169
|
|
16
|
+
cudag/core/coords.py,sha256=xe0lB9GBjLvN-r8lUkhCRiYBn4x3vigRhFN9Sj7ejqw,6780
|
|
17
|
+
cudag/core/data_grid.py,sha256=6HRZS4-HHxsKb8si25t0sDdeMl2vHD5QyOXPEDmEKJI,26079
|
|
18
|
+
cudag/core/dataset.py,sha256=9bU8Rlh1tAxCB9qh9BTumUiAm6RDHJF4X1RCDV6Q9qg,25484
|
|
19
|
+
cudag/core/distribution.py,sha256=P6l_Pegh_XWChlf8FvqPrnYEcsG069vcw9BMqgcxYHQ,4295
|
|
20
|
+
cudag/core/drawing.py,sha256=ptIXcuKqPtHnGQk-ugH-SZX259jAzzrGPeZ6lpws7LU,2316
|
|
21
|
+
cudag/core/fonts.py,sha256=NADt8YBvw7sKXvluQOBfIoszXyI1ohFmGpmDe-uVKdA,4730
|
|
22
|
+
cudag/core/generator.py,sha256=7FtlWPnvBWFldgYMWLFGfwl7DI4c0vNbYRbbJp-36J4,5533
|
|
23
|
+
cudag/core/grid.py,sha256=UuUzDvcv079TY25t6z2DkV07Ih_tDy6ICDGY-5GVyqw,11286
|
|
24
|
+
cudag/core/grounding_task.py,sha256=73hMMpEWqh0dH-EGqhIVGUkgZYXPrnrdoqsHjhzIals,8076
|
|
25
|
+
cudag/core/icon.py,sha256=ugByhHA7yz6oLyO4VdayO3n0vFpPrI6iUvzYUNq3l3E,6024
|
|
26
|
+
cudag/core/iconlist_task.py,sha256=VUVz2pPQQvc4AzNTz191v0U8LucFLIoxAQbbNkNwduU,10866
|
|
27
|
+
cudag/core/models.py,sha256=5gQ6PGEX0Y5fq_kb4wegF_ipoQ6tH5aLcK7gr3Jd_08,32908
|
|
28
|
+
cudag/core/random.py,sha256=S04_odwIc0uVQ5dtabAbJjAf1_cWdtiQjoUmpZP_SU4,3641
|
|
29
|
+
cudag/core/renderer.py,sha256=ATWazwmoDFn_SUBvo7Y-6UkmNDmgRLpa3m6cKFmiP08,5818
|
|
30
|
+
cudag/core/screen.py,sha256=43MVX5vc7g0Fpdaaht_jszXpYnuCthspEH2TGkl3zXI,11620
|
|
31
|
+
cudag/core/scroll_task.py,sha256=f1Kj8PMRGL7SIwEGjUqkuA_DK5Q3V-HcThwrpfPSyjI,8670
|
|
32
|
+
cudag/core/scrollable_grid.py,sha256=FDEHiXohBBZL28w-81QEiHHrPFi7jS8KoUxjFbLFXXc,14396
|
|
33
|
+
cudag/core/state.py,sha256=PhDbTUktiDR1NCJTcl4uWzKkfjUDAGMAbCkzlc157y8,3121
|
|
34
|
+
cudag/core/task.py,sha256=aZe73dIsW1AIJTypjCn8O0LTNiKK6lQDkn8F_V97iaQ,9118
|
|
35
|
+
cudag/core/taskbar.py,sha256=RLuxqX277EJh-ve2dydO5RECH-6Uw8_g9wLX66almGk,11367
|
|
36
|
+
cudag/core/text.py,sha256=9kZ_OJQEoAO2BFSxjRJHbqZgaOKY8uL3XN0iWy2BAH0,5830
|
|
37
|
+
cudag/core/utils.py,sha256=_E87Yll6XGARuRwsLjaM_NZwWlI3TxB1vjAVRrAeYCE,2884
|
|
38
|
+
cudag/data/surnames.txt,sha256=lcoOLP2LMQC2tTDOwpM3qymg1caKVVL3VaowX8ZH7FQ,36095
|
|
39
|
+
cudag/modal_apps/__init__.py,sha256=_3lNMUDSGbQCUFvwRU3A3tEaBCAEwwXGLS1xefpKHdI,199
|
|
40
|
+
cudag/modal_apps/archive.py,sha256=HsQX9A7Fx3xZvENu2WuaXFETe8kC6ICyrGjBAsJEn-Q,3098
|
|
41
|
+
cudag/modal_apps/extract.py,sha256=3dr2PRvotxT1YECWsfOhIHG1HW632f-8wb1Yam892C0,4994
|
|
42
|
+
cudag/modal_apps/preprocess.py,sha256=2GUMg_yMpPGSvAnNAlab1OLHzjX-jKgWQ4qg2NgRWoo,18877
|
|
43
|
+
cudag/modal_apps/upload.py,sha256=FoLqcnhIo-g9YmJ5PXwP2hfP--G9sEv4F5elgLPNgE8,10189
|
|
44
|
+
cudag/prompts/SYSTEM_PROMPT.txt,sha256=O47lc5FKwkFlG0UnBJxxkW33GmnB4RWPMK1Fz9RcBeg,5035
|
|
45
|
+
cudag/prompts/__init__.py,sha256=J0TSDvc-IyQOjfYv_02T4mYx0XXaOVEREqIL937Y1Zk,779
|
|
46
|
+
cudag/prompts/system.py,sha256=meLjJM-Z8jA2QJm_bleLOoFSWucv1GKcKVDikX1Qsgk,1203
|
|
47
|
+
cudag/prompts/tools.py,sha256=ZFF1f8lNW1h6eLpHcx7EC_-byT03u3PUYqStuiTSuck,12181
|
|
48
|
+
cudag/schemas/filesystem.json,sha256=JOSwPtLJF88rdwg29bC0Hol4F0fCpXPCgpwBr3IwAII,2841
|
|
49
|
+
cudag/schemas/test_record.schema.json,sha256=1R2iWMIPSoQ9IvpoBrnF8VXoD7cHLMEEtw-HaHl7w4Y,3310
|
|
50
|
+
cudag/schemas/train_record.schema.json,sha256=FuMnSs3Fge_fQaqs7ja9YNIssLJnl-HJBJUSBB0MPCI,2606
|
|
51
|
+
cudag/server/__init__.py,sha256=szpInbvYju6Uj-4IIS_HIOXX8RLQza31NtMnF7y2lzM,745
|
|
52
|
+
cudag/server/app.py,sha256=tZ39ANXsXuswA-297DCzJKnwkMWNoPVLq_QFV52TYAI,7273
|
|
53
|
+
cudag/server/services/__init__.py,sha256=XHiNHuGGO04-5UJEKyfHDFu2OPcOEUtmBeY2Cn11Ipo,326
|
|
54
|
+
cudag/server/services/generator.py,sha256=tW3KTdGHhKwfR0Z8h8wXBU-fldZTt_5Ic0JI5UtnP_Y,4162
|
|
55
|
+
cudag/templates/scripts/archive.sh,sha256=NjUDNRoRJm0BrudhIbXZ9yrF4sZgCzkX6tNOrBKJPis,940
|
|
56
|
+
cudag/templates/scripts/build.sh,sha256=S0jkVf00FNscbu70_pHZcFmI1gZVP6Dq_pvukb1cGFk,402
|
|
57
|
+
cudag/templates/scripts/extract.sh,sha256=_lWclZ3Bzf0gK06yTRfzUGdb99QyxO6m47hoyIy8jzY,1372
|
|
58
|
+
cudag/templates/scripts/generate.sh,sha256=4Qk-Le-TYKRWDpurwgxTNwPg_88ABsiBh-I2zuKIRws,3241
|
|
59
|
+
cudag/templates/scripts/pre-commit.sh,sha256=IxntKRV8Cn1dO65jtQQBuYdXprWjRpOGb2_NFd6q_iQ,1339
|
|
60
|
+
cudag/templates/scripts/preprocess.sh,sha256=_vTh2R77XmkLKYJ0BD58Y3wV0q9HhXpVMkyS2QqkQrk,1187
|
|
61
|
+
cudag/templates/scripts/upload.sh,sha256=qfCgL1VbDZM7NNpba9CJmIEUgcSx_uB6LhT8Dwj26P8,1644
|
|
62
|
+
cudag/templates/scripts/verify.py,sha256=Czj12cr_8ECujrhyJLSW1hydQPYYN_AC0Gr6lJplmOE,14118
|
|
63
|
+
cudag/validation/__init__.py,sha256=64IJigqJuwwfrqmC23VWr1UOV6I8UftOYrygGtbuko8,948
|
|
64
|
+
cudag/validation/validate.py,sha256=j_g_XEuwHhxuZcpAhCayD7AAor9X7-EtvdOHqXeX2DQ,16298
|
|
65
|
+
cudag-0.3.10.dist-info/METADATA,sha256=PE_sESuWJpPHiCAYTFh0SpbzidnXXOpF901z2vTmFQU,16034
|
|
66
|
+
cudag-0.3.10.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
67
|
+
cudag-0.3.10.dist-info/entry_points.txt,sha256=RY3G6rHNUV1o4eFLJCvUYLwvDY0bxX6hxpGyxmvTpGM,45
|
|
68
|
+
cudag-0.3.10.dist-info/licenses/LICENSE,sha256=41uwv25dy2r4Xy0him2TddEXyPDdwlI7gqf9DhaWZOs,2402
|
|
69
|
+
cudag-0.3.10.dist-info/RECORD,,
|