AvaLovelace commited on
Commit
def3000
·
1 Parent(s): 27e7d1f

Squash commits

Browse files
.gitattributes CHANGED
@@ -33,3 +33,5 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ *.jpg filter=lfs diff=lfs merge=lfs -text
37
+ *.png filter=lfs diff=lfs merge=lfs -text
.gitignore ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Python-generated files
2
+ __pycache__/
3
+ *.py[oc]
4
+ build/
5
+ dist/
6
+ wheels/
7
+ *.egg-info
8
+
9
+ # Virtual environments
10
+ .venv
11
+
12
+ # Gurobi files
13
+ gurobi.lic
14
+
15
+ # LDraw files
16
+ ldraw
17
+ complete.zip
18
+
19
+ .idea
20
+ .gradio
21
+ out
.gitmodules ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ [submodule "ImportLDraw"]
2
+ path = ImportLDraw
3
+ url = https://github.com/sgebbie/ImportLDraw.git
4
+ branch = bugfix/material-fabric-warning
.python-version ADDED
@@ -0,0 +1 @@
 
 
1
+ 3.11
ImportLDraw ADDED
@@ -0,0 +1 @@
 
 
1
+ Subproject commit 7fe64deef48c8f726e44a30341d04b5fa396ff35
README.md CHANGED
@@ -1,13 +1,76 @@
1
  ---
2
- title: LegoGPT Demo
3
- emoji: 📉
4
- colorFrom: gray
5
- colorTo: red
6
  sdk: gradio
7
  sdk_version: 5.29.0
8
- app_file: app.py
9
- pinned: false
10
- short_description: Official demo for LegoGPT.
11
  ---
12
 
13
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
+ title: LegoGPT-Demo
3
+ emoji: 🧱
4
+ short_description: Generate stable LEGO structures from text prompts.
5
+ app_file: app.py
6
  sdk: gradio
7
  sdk_version: 5.29.0
8
+ python_version: 3.11
9
+ models:
10
+ - AvaLovelace/LegoGPT
11
  ---
12
 
13
+ # LegoGPT Demo
14
+
15
+ Gradio demo for LegoGPT.
16
+
17
+ ## Prerequisites
18
+
19
+ - **Llama-3.2-1B-Instruct:** LegoGPT is fine-tuned from meta-llama/Llama-3.2-1B-Instruct, a gated model. Request access
20
+ to the model [here](https://huggingface.co/meta-llama/Llama-3.2-1B-Instruct), then generate
21
+ a [Hugging Face user access token](https://huggingface.co/docs/hub/en/security-tokens).
22
+ - *If running locally,* set your access token as an environment variable: `export HF_TOKEN=<your_token>`
23
+ - *If running on Hugging Face Spaces,* set your access token as the `HF_TOKEN` secret in the Settings tab of your
24
+ Space.
25
+
26
+ The model will be
27
+ automatically downloaded upon running the code.
28
+ - **Gurobi:** Running stability analysis requires a [Gurobi licence](https://www.gurobi.com/downloads/) to use Gurobi.
29
+ Academics may request a free licence from the Gurobi
30
+ website [here](https://www.gurobi.com/academia/academic-program-and-licenses/).
31
+ - *If running locally,* place the Gurobi licence file in your *home directory* or
32
+ another [recommended location](https://support.gurobi.com/hc/en-us/articles/360013417211-Where-do-I-place-the-Gurobi-license-file-gurobi-lic).
33
+ - *If running on Hugging Face Spaces,* the licence type must be **Web License Service (WLS)**. Set the
34
+ `WLSACCESSID`, `WLSSECRET`, and `LICENSEID` secrets in the Settings tab of your Space to their values in your
35
+ Gurobi licence file.
36
+ - **ImportLDraw:** Rendering LEGO visualizations requires ImportLDraw, provided as a Git submodule.
37
+ - *If running locally,* follow these instructions to install ImportLDraw:
38
+ - Download [Git LFS](https://git-lfs.com), then run `git lfs install`.
39
+ - Install Git submodules with `git submodule update --init`.
40
+ - Download the [LDraw parts library](https://library.ldraw.org/library/updates/complete.zip) and
41
+ extract it in your *home directory*:
42
+ `(cd ~ && wget https://library.ldraw.org/library/updates/complete.zip && unzip complete.zip)`.
43
+ - If you wish to put the LDraw parts library in a different directory, set the environment variable
44
+ `LDRAW_LIBRARY_PATH` to the path of the `ldraw` directory: `export LDRAW_LIBRARY_PATH=path/to/ldraw`.
45
+ - *If running on Hugging Face Spaces,* ImportLDraw and the LDraw parts library will automatically be downloaded and
46
+ installed by the `app.py` script.
47
+
48
+ ## Running locally
49
+
50
+ Install the Python project manager [uv](https://docs.astral.sh/uv). Then run the demo with:
51
+
52
+ ```zsh
53
+ uv run app.py
54
+ ```
55
+
56
+ ## Running on Hugging Face Spaces
57
+
58
+ Make sure the origin of this repo is set to your Space:
59
+
60
+ ```zsh
61
+ git remote set-url origin git@hf.co:spaces/<your_username>/<your_space_name>
62
+ ```
63
+
64
+ Then commit and push your changes to your Space with
65
+
66
+ ```
67
+ git add -A && git commit -m "Update" && git push
68
+ ```
69
+
70
+ > [!NOTE]
71
+ > If you've changed the dependencies in `pyproject.toml`, update the `requirements.txt` file accordingly:
72
+ > ```zsh
73
+ > uv export --format requirements-txt --no-hashes > requirements.txt
74
+ > ```
75
+ > Then, `git commit` and `git push` the changes to your Space. You may have to restart the Space for the changes to take
76
+ > effect.
app.py ADDED
@@ -0,0 +1,150 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ import os
3
+ import subprocess
4
+ import time
5
+ import uuid
6
+ import zipfile
7
+ from dataclasses import fields
8
+ from urllib.request import urlretrieve
9
+
10
+ import gradio as gr
11
+ import transformers
12
+ from legogpt.models import LegoGPT, LegoGPTConfig
13
+
14
+
15
+ def setup():
16
+ # Set up Gurobi licence
17
+ licence_filename = 'gurobi.lic'
18
+ licence_lines = []
19
+ for secret_name in ['WLSACCESSID', 'WLSSECRET', 'LICENSEID']:
20
+ secret = os.environ.get(secret_name)
21
+ if not secret:
22
+ raise ValueError(f'Env variable {secret_name} not found. Please set it in the Hugging Face Space settings.')
23
+ licence_lines.append(f'{secret_name}={secret}\n')
24
+ with open(licence_filename, 'w') as f:
25
+ f.writelines(licence_lines)
26
+ os.environ['GRB_LICENSE_FILE'] = os.path.abspath(licence_filename)
27
+
28
+ # Download LDraw part library and set LDraw library path
29
+ ldraw_zip_url = 'https://library.ldraw.org/library/updates/complete.zip'
30
+ ldraw_zip_filename = 'complete.zip'
31
+ urlretrieve(ldraw_zip_url, ldraw_zip_filename)
32
+ with zipfile.ZipFile(ldraw_zip_filename) as zip_ref:
33
+ zip_ref.extractall()
34
+ os.environ['LDRAW_LIBRARY_PATH'] = os.path.abspath('ldraw')
35
+
36
+
37
+ def main():
38
+ if os.environ.get('IS_HF_SPACE') == '1':
39
+ print('Running in Hugging Face Space, setting up environment...')
40
+ setup()
41
+
42
+ model_cfg = LegoGPTConfig(max_regenerations=10)
43
+ model = LegoGPT(model_cfg)
44
+
45
+ def generate_lego(
46
+ prompt: str,
47
+ temperature: float | None,
48
+ seed: int | None,
49
+ max_bricks: int | None,
50
+ max_brick_rejections: int | None,
51
+ max_regenerations: int | None,
52
+ ):
53
+ # Set model parameters
54
+ if temperature is not None: model.temperature = temperature
55
+ if max_bricks is not None: model.max_bricks = max_bricks
56
+ if max_brick_rejections is not None: model.max_brick_rejections = max_brick_rejections
57
+ if max_regenerations is not None: model.max_regenerations = max_regenerations
58
+ if seed is not None: transformers.set_seed(seed)
59
+
60
+ # Generate LEGO
61
+ print(f'Generating LEGO for prompt: "{prompt}"')
62
+ start_time = time.time()
63
+ output = model(prompt)
64
+
65
+ # Write output LDR to file
66
+ output_dir = os.path.abspath('out')
67
+ output_uuid = str(uuid.uuid4())
68
+ os.makedirs(output_dir, exist_ok=True)
69
+ ldr_filename = os.path.join(output_dir, f'{output_uuid}.ldr')
70
+ with open(ldr_filename, 'w') as f:
71
+ f.write(output['lego'].to_ldr())
72
+ print(f'Finished generation in {time.time() - start_time:.1f}s!')
73
+
74
+ # Render LEGO model to image
75
+ print('Rendering image...')
76
+ start_time = time.time()
77
+ img_filename = os.path.join(output_dir, f'{output_uuid}.png')
78
+ subprocess.run(['python', 'render_lego.py', '--in_file', ldr_filename, '--out_file', img_filename],
79
+ check=True) # Run render as a subprocess to prevent issues with Blender
80
+ print(f'Finished rendering in {time.time() - start_time:.1f}s!')
81
+
82
+ return img_filename, output['lego']
83
+
84
+ # Define inputs and outputs
85
+ in_prompt = gr.Textbox(label='Prompt', placeholder='Enter a prompt to generate a LEGO model.')
86
+ in_temperature = gr.Slider(0.01, 2.0, value=model_cfg.temperature, step=0.01,
87
+ label='Temperature', info=get_help_string('temperature'))
88
+ in_seed = gr.Number(value=42, label='Seed', info='Random seed for generation.', precision=0, step=1)
89
+ in_bricks = gr.Number(value=model_cfg.max_bricks, label='Max bricks', info=get_help_string('max_bricks'),
90
+ precision=0, minimum=1, step=1)
91
+ in_rejections = gr.Number(value=model_cfg.max_brick_rejections, label='Max brick rejections',
92
+ info=get_help_string('max_brick_rejections'), precision=0, minimum=0, step=1)
93
+ in_regenerations = gr.Number(value=model_cfg.max_regenerations, label='Max regenerations',
94
+ info=get_help_string('max_regenerations'), precision=0, minimum=0, step=1)
95
+ out_img = gr.Image(label='Output image', format='png')
96
+ out_txt = gr.Textbox(label='Output LEGO bricks', lines=5, max_lines=5, show_copy_button=True,
97
+ info='The LEGO structure in text format. Each line of the form "hxw (x,y,z)" represents a '
98
+ '1-unit-tall rectangular brick with dimensions hxw placed at coordinates (x,y,z).')
99
+
100
+ # Define Gradio interface
101
+ demo = gr.Interface(
102
+ fn=generate_lego,
103
+ title='LegoGPT Demo',
104
+ description='Official demo for [LegoGPT](https://avalovelace1.github.io/LegoGPT/), the first approach for generating physically stable LEGO brick models from text prompts.\n\n'
105
+ 'The model is restricted to creating structures made of 1-unit-tall cuboid bricks on a 20x20x20 grid. It was trained on a dataset of 21 object categories: '
106
+ '*basket, bed, bench, birdhouse, bookshelf, bottle, bowl, bus, camera, car, chair, guitar, jar, mug, piano, pot, sofa, table, tower, train, vessel.* '
107
+ 'Performance on prompts from outside these categories may be limited. This demo does not include texturing or coloring.',
108
+ inputs=[in_prompt],
109
+ additional_inputs=[in_temperature, in_seed, in_bricks, in_rejections, in_regenerations],
110
+ outputs=[out_img, out_txt],
111
+ flagging_mode='never',
112
+ )
113
+ with demo:
114
+ with gr.Row():
115
+ examples = get_examples()
116
+ dummy_name = gr.Textbox(visible=False, label='Name')
117
+ dummy_out_img = gr.Image(visible=False, label='Result')
118
+ gr.Examples(
119
+ examples=[[name, example['prompt'], example['temperature'], example['seed'], example['output_img']]
120
+ for name, example in examples.items()],
121
+ inputs=[dummy_name, in_prompt, in_temperature, in_seed, dummy_out_img],
122
+ outputs=[out_img, out_txt],
123
+ fn=lambda *args: (args[-1], examples[args[0]]['output_txt']),
124
+ run_on_click=True,
125
+ )
126
+ demo.launch(share=True)
127
+
128
+
129
+ def get_help_string(field_name: str) -> str:
130
+ """
131
+ :param field_name: Name of a field in LegoGPTConfig.
132
+ :return: Help string for the field.
133
+ """
134
+ data_fields = fields(LegoGPTConfig)
135
+ name_field = next(f for f in data_fields if f.name == field_name)
136
+ return name_field.metadata['help']
137
+
138
+
139
+ def get_examples(example_dir: str = os.path.abspath('examples')) -> dict[str, dict[str, str]]:
140
+ examples_file = os.path.join(example_dir, 'examples.json')
141
+ with open(examples_file) as f:
142
+ examples = json.load(f)
143
+
144
+ for example in examples.values():
145
+ example['output_img'] = os.path.join(example_dir, example['output_img'])
146
+ return examples
147
+
148
+
149
+ if __name__ == '__main__':
150
+ main()
examples/60066a5369f1354e631a23fef2ba638b.png ADDED

Git LFS Details

  • SHA256: 706b3d3619baefcbcf3b7c499edc1ca2c191ce2320023edf39b9760d4f86bc5a
  • Pointer size: 131 Bytes
  • Size of remote file: 304 kB
examples/60790035c8126a677645b4fdaedbc34.png ADDED

Git LFS Details

  • SHA256: 122104faa792c2b67c3db76edf628ac48392ecda0f67f4eb65cd2a4fbe1bb329
  • Pointer size: 131 Bytes
  • Size of remote file: 281 kB
examples/8981c0ffae1af00a50fc88ed745bdb67.png ADDED

Git LFS Details

  • SHA256: 282ba0f03f8aa30d4d7fb877a0301cccb90827878663c2800f1ef8c6086e6fe7
  • Pointer size: 131 Bytes
  • Size of remote file: 300 kB
examples/9c1b0058dfe027cbf519adc9991b5f11.png ADDED

Git LFS Details

  • SHA256: 33381d3131983982800c69f2fa9c27170e20276b78d17ac567f4d340498d2e38
  • Pointer size: 131 Bytes
  • Size of remote file: 290 kB
examples/e488826128fe3854b300c4ca2f51c01b.png ADDED

Git LFS Details

  • SHA256: 552559db477ac9f059a590235cb6f932ee9bc3e4406fa8d79c229a76f7e54bbf
  • Pointer size: 131 Bytes
  • Size of remote file: 279 kB
examples/e5c8853f28328d0c2511f68da65f4c4.png ADDED

Git LFS Details

  • SHA256: b5b22bcaf4de18a738360abee297e50a1c9097e0a9c5576545ec74dbcc1a68e0
  • Pointer size: 131 Bytes
  • Size of remote file: 291 kB
examples/examples.json ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "table": {
3
+ "prompt": "Table featuring a flat rectangular surface over four evenly spaced legs.",
4
+ "temperature": 0.6,
5
+ "seed": 42,
6
+ "output_img": "9c1b0058dfe027cbf519adc9991b5f11.png",
7
+ "output_txt": "1x2 (16,18,0)\n1x2 (16,13,0)\n2x2 (0,18,0)\n2x2 (0,13,0)\n1x2 (16,18,1)\n1x2 (16,13,1)\n2x2 (0,18,1)\n2x2 (0,13,1)\n1x1 (16,18,2)\n1x2 (16,13,2)\n2x1 (0,18,2)\n2x2 (0,13,2)\n1x2 (16,17,3)\n1x1 (16,14,3)\n2x2 (0,17,3)\n2x1 (0,14,3)\n1x2 (16,17,4)\n1x2 (16,14,4)\n2x2 (0,17,4)\n2x2 (0,14,4)\n1x2 (16,17,5)\n1x2 (16,14,5)\n2x2 (0,17,5)\n2x2 (0,14,5)\n1x1 (16,18,6)\n1x2 (16,16,6)\n1x1 (16,14,6)\n8x1 (8,17,6)\n2x1 (0,18,6)\n8x1 (0,17,6)\n2x1 (0,16,6)\n2x1 (0,14,6)\n2x6 (16,13,7)\n1x6 (15,13,7)\n2x6 (13,13,7)\n2x6 (11,13,7)\n8x1 (10,19,7)\n2x6 (9,13,7)\n6x2 (3,17,7)\n6x2 (3,15,7)\n6x2 (3,13,7)\n8x1 (2,19,7)\n1x6 (2,13,7)\n2x6 (0,14,7)\n2x1 (0,13,7)\n1x6 (17,14,8)\n2x6 (15,14,8)\n1x6 (14,14,8)\n2x6 (12,14,8)\n8x1 (10,13,8)\n4x2 (8,14,8)\n2x1 (8,13,8)\n6x2 (6,18,8)\n6x2 (6,16,8)\n2x2 (6,14,8)\n2x6 (4,14,8)\n2x6 (2,14,8)\n2x6 (0,14,8)\n8x1 (0,13,8)\n"
8
+ },
9
+ "sofa": {
10
+ "prompt": "Compact sofa with a geometric design.",
11
+ "temperature": 0.6,
12
+ "seed": 42,
13
+ "output_img": "8981c0ffae1af00a50fc88ed745bdb67.png",
14
+ "output_txt": "1x2 (16,17,0)\n1x1 (16,13,0)\n2x2 (0,17,0)\n2x1 (0,13,0)\n1x1 (17,18,1)\n1x6 (17,12,1)\n2x6 (15,12,1)\n1x6 (14,12,1)\n8x1 (9,18,1)\n1x1 (8,18,1)\n6x2 (8,16,1)\n6x2 (8,14,1)\n6x2 (8,12,1)\n6x2 (2,16,1)\n6x2 (2,14,1)\n6x2 (2,12,1)\n8x1 (0,18,1)\n2x6 (0,12,1)\n2x6 (16,13,2)\n2x1 (16,12,2)\n1x1 (15,18,2)\n2x6 (14,12,2)\n1x6 (13,12,2)\n2x6 (11,12,2)\n6x1 (9,18,2)\n2x6 (9,12,2)\n2x6 (7,13,2)\n2x6 (5,13,2)\n4x1 (5,12,2)\n1x1 (4,18,2)\n2x6 (3,12,2)\n2x1 (2,18,2)\n2x6 (1,12,2)\n2x1 (0,18,2)\n1x6 (0,12,2)\n1x6 (17,12,3)\n2x1 (16,18,3)\n1x1 (16,17,3)\n1x2 (15,17,3)\n2x4 (15,13,3)\n2x1 (15,12,3)\n2x1 (13,18,3)\n8x1 (5,18,3)\n1x1 (4,18,3)\n2x1 (2,18,3)\n2x6 (0,13,3)\n2x1 (0,12,3)\n1x1 (17,18,4)\n2x6 (16,12,4)\n1x2 (15,17,4)\n6x2 (9,18,4)\n1x2 (8,18,4)\n6x2 (2,18,4)\n2x1 (0,18,4)\n2x6 (0,12,4)\n2x1 (16,16,5)\n2x4 (16,12,5)\n6x2 (12,17,5)\n8x1 (9,19,5)\n1x1 (8,19,5)\n6x2 (6,17,5)\n8x1 (0,19,5)\n6x2 (0,17,5)\n2x1 (0,16,5)\n2x4 (0,12,5)\n1x2 (17,18,6)\n2x1 (16,17,6)\n4x2 (13,18,6)\n6x2 (7,18,6)\n1x2 (6,18,6)\n6x2 (0,18,6)\n2x1 (0,17,6)\n1x2 (16,18,7)\n2x2 (14,18,7)\n6x2 (8,18,7)\n6x2 (2,18,7)\n2x2 (0,18,7)\n"
15
+ },
16
+ "car": {
17
+ "prompt": "Small car featuring a rectangular body, flat top, and stepped edges.",
18
+ "temperature": 0.6,
19
+ "seed": 42,
20
+ "output_img": "60066a5369f1354e631a23fef2ba638b.png",
21
+ "output_txt": "1x2 (7,15,0)\n1x1 (7,13,0)\n1x2 (7,5,0)\n2x2 (6,7,0)\n1x1 (6,5,0)\n2x6 (5,11,0)\n2x2 (5,3,0)\n2x6 (3,11,0)\n2x6 (3,3,0)\n2x6 (1,11,0)\n6x2 (1,9,0)\n2x2 (1,3,0)\n1x2 (0,15,0)\n1x1 (0,13,0)\n2x2 (0,7,0)\n1x2 (0,5,0)\n1x1 (7,18,1)\n1x4 (7,8,1)\n2x6 (6,12,1)\n2x6 (6,2,1)\n1x1 (5,19,1)\n2x6 (4,12,1)\n2x2 (4,2,1)\n2x1 (3,19,1)\n2x6 (2,12,1)\n2x2 (2,2,1)\n6x2 (1,10,1)\n6x2 (1,8,1)\n2x6 (0,14,1)\n2x2 (0,12,1)\n1x4 (0,8,1)\n6x2 (0,6,1)\n6x2 (0,4,1)\n2x1 (0,3,1)\n1x1 (7,18,2)\n1x4 (7,13,2)\n1x1 (7,2,2)\n2x6 (6,7,2)\n2x2 (6,5,2)\n2x1 (6,3,2)\n2x6 (5,14,2)\n1x6 (5,7,2)\n1x2 (5,3,2)\n2x6 (3,14,2)\n2x6 (3,7,2)\n1x2 (3,5,2)\n2x2 (3,3,2)\n4x1 (3,2,2)\n1x1 (2,2,2)\n2x6 (1,14,2)\n6x1 (1,13,2)\n2x4 (1,9,2)\n2x6 (1,3,2)\n1x1 (0,18,2)\n1x4 (0,13,2)\n1x1 (0,12,2)\n1x1 (7,13,3)\n1x2 (7,11,3)\n1x8 (7,3,3)\n2x2 (6,18,3)\n2x1 (6,16,3)\n2x2 (6,14,3)\n1x1 (5,19,3)\n1x2 (5,15,3)\n1x1 (4,16,3)\n2x1 (3,19,3)\n1x2 (3,15,3)\n6x1 (1,17,3)\n2x2 (1,15,3)\n2x1 (1,14,3)\n1x1 (1,13,3)\n6x2 (1,11,3)\n6x2 (1,9,3)\n6x2 (1,7,3)\n6x2 (1,5,3)\n6x2 (1,3,3)\n2x1 (0,18,3)\n1x1 (0,15,3)\n1x1 (0,14,3)\n1x1 (0,12,3)\n1x1 (7,18,4)\n2x6 (6,12,4)\n2x2 (6,10,4)\n1x1 (4,9,4)\n4x1 (3,18,4)\n1x2 (3,16,4)\n4x2 (2,10,4)\n1x1 (1,18,4)\n2x6 (1,12,4)\n1x1 (1,11,4)\n1x1 (1,10,4)\n1x1 (0,12,4)\n"
22
+ },
23
+ "train": {
24
+ "prompt": "Train with rectangular body and geometric components.",
25
+ "temperature": 0.6,
26
+ "seed": 42,
27
+ "output_img": "e5c8853f28328d0c2511f68da65f4c4.png",
28
+ "output_txt": "1x2 (3,17,0)\n1x2 (3,13,0)\n2x2 (2,2,0)\n2x2 (1,17,0)\n2x2 (1,13,0)\n1x2 (0,17,0)\n4x1 (0,6,0)\n2x2 (0,2,0)\n1x1 (3,18,1)\n1x2 (3,16,1)\n1x2 (3,12,1)\n1x2 (3,2,1)\n2x2 (2,14,1)\n2x6 (2,6,1)\n1x1 (2,3,1)\n2x1 (1,18,1)\n2x2 (1,16,1)\n1x2 (1,14,1)\n1x6 (1,6,1)\n2x1 (1,2,1)\n1x1 (0,18,1)\n1x2 (0,16,1)\n2x2 (0,12,1)\n1x2 (0,10,1)\n1x8 (0,2,1)\n1x2 (3,9,2)\n1x1 (3,2,2)\n2x6 (2,13,2)\n2x4 (2,5,2)\n2x1 (1,2,2)\n2x6 (0,13,2)\n4x2 (0,11,2)\n1x2 (0,9,2)\n2x4 (0,5,2)\n4x2 (0,3,2)\n1x1 (0,2,2)\n1x8 (3,10,3)\n1x6 (3,4,3)\n2x6 (1,12,3)\n2x6 (1,6,3)\n2x2 (1,4,3)\n4x1 (0,18,3)\n1x8 (0,10,3)\n1x6 (0,4,3)\n4x2 (0,2,3)\n2x6 (2,10,4)\n2x6 (2,3,4)\n4x1 (0,18,4)\n4x2 (0,16,4)\n2x6 (0,10,4)\n4x1 (0,9,4)\n2x6 (0,3,4)\n1x2 (2,17,5)\n1x4 (2,11,5)\n2x2 (1,9,5)\n2x2 (0,17,5)\n2x2 (0,13,5)\n2x2 (0,11,5)\n1x2 (0,9,5)\n"
29
+ },
30
+ "chair-1": {
31
+ "prompt": "Square-seated chair featuring an upright, rectangular backrest and straight legs.",
32
+ "temperature": 0.6,
33
+ "seed": 42,
34
+ "output_img": "e488826128fe3854b300c4ca2f51c01b.png",
35
+ "output_txt": "1x2 (7,18,0)\n1x2 (7,11,0)\n2x2 (0,18,0)\n2x2 (0,11,0)\n1x2 (7,18,1)\n1x2 (7,11,1)\n2x2 (0,18,1)\n2x2 (0,11,1)\n1x1 (7,18,2)\n1x2 (7,11,2)\n2x1 (0,18,2)\n2x2 (0,11,2)\n1x2 (7,17,3)\n1x2 (7,11,3)\n2x2 (0,17,3)\n2x2 (0,11,3)\n1x2 (7,17,4)\n1x2 (7,11,4)\n2x2 (0,17,4)\n2x2 (0,11,4)\n1x2 (7,17,5)\n1x2 (7,11,5)\n2x2 (0,17,5)\n2x2 (0,11,5)\n1x1 (7,18,6)\n1x2 (7,11,6)\n2x1 (6,17,6)\n1x1 (6,12,6)\n1x1 (1,12,6)\n6x1 (0,17,6)\n2x1 (0,18,6)\n1x1 (0,12,6)\n2x1 (0,11,6)\n1x6 (7,13,7)\n6x2 (2,11,7)\n6x1 (1,18,7)\n1x1 (1,17,7)\n1x4 (1,13,7)\n1x6 (0,13,7)\n2x2 (0,11,7)\n1x2 (7,17,8)\n1x1 (7,16,8)\n2x2 (7,14,8)\n1x2 (7,12,8)\n1x1 (6,18,8)\n4x1 (2,18,8)\n6x2 (1,16,8)\n6x2 (1,14,8)\n6x2 (1,12,8)\n2x1 (0,18,8)\n1x6 (0,12,8)\n2x6 (6,13,9)\n2x1 (6,12,9)\n2x6 (4,13,9)\n2x6 (2,13,9)\n4x1 (2,12,9)\n1x1 (1,18,9)\n1x6 (1,12,9)\n1x2 (7,17,10)\n6x2 (1,17,10)\n6x2 (2,17,11)\n1x2 (1,17,11)\n1x2 (7,17,12)\n6x2 (1,17,12)\n6x2 (2,17,13)\n1x2 (1,17,13)\n1x2 (7,17,14)\n6x2 (1,17,14)\n6x2 (2,17,15)\n1x2 (1,17,15)\n1x2 (7,18,16)\n6x2 (1,18,16)\n6x2 (2,18,17)\n1x2 (1,18,17)\n"
36
+ },
37
+ "chair-2": {
38
+ "prompt": "Compact chair with a tall backrest and serrated seat.",
39
+ "temperature": 0.6,
40
+ "seed": 42,
41
+ "output_img": "60790035c8126a677645b4fdaedbc34.png",
42
+ "output_txt": "1x2 (7,17,0)\n1x2 (7,13,0)\n2x2 (0,17,0)\n2x2 (0,13,0)\n1x2 (7,17,1)\n1x2 (7,13,1)\n2x2 (0,17,1)\n2x2 (0,13,1)\n1x1 (7,18,2)\n1x6 (7,12,2)\n2x2 (0,17,2)\n2x2 (0,13,2)\n1x2 (7,17,3)\n1x2 (7,12,3)\n2x2 (0,17,3)\n2x2 (0,12,3)\n1x2 (7,17,4)\n1x2 (7,12,4)\n2x2 (0,17,4)\n2x2 (0,12,4)\n1x2 (7,17,5)\n1x2 (7,12,5)\n2x2 (0,17,5)\n2x2 (0,12,5)\n1x1 (7,18,6)\n1x6 (7,12,6)\n4x1 (3,17,6)\n4x1 (3,13,6)\n1x1 (2,17,6)\n1x1 (2,13,6)\n2x1 (0,18,6)\n2x6 (0,12,6)\n1x1 (7,18,7)\n1x1 (7,12,7)\n6x1 (2,17,7)\n6x1 (2,13,7)\n2x1 (0,18,7)\n2x6 (0,12,7)\n1x1 (7,18,8)\n1x1 (7,12,8)\n2x1 (0,18,8)\n2x1 (0,12,8)\n1x8 (7,11,9)\n1x1 (6,18,9)\n1x1 (6,17,9)\n1x6 (6,11,9)\n4x1 (2,18,9)\n4x1 (2,11,9)\n2x6 (0,13,9)\n2x2 (0,11,9)\n1x2 (7,17,10)\n2x6 (6,11,10)\n1x6 (5,11,10)\n2x6 (3,11,10)\n6x2 (1,17,10)\n2x6 (1,11,10)\n1x1 (0,18,10)\n1x6 (0,12,10)\n1x1 (7,18,11)\n6x1 (1,18,11)\n1x2 (7,18,12)\n1x2 (6,18,12)\n4x2 (2,18,12)\n1x1 (1,18,12)\n1x1 (7,18,13)\n6x1 (2,19,13)\n1x1 (1,19,13)\n6x1 (1,18,13)\n1x2 (7,18,14)\n6x2 (1,18,14)\n6x2 (2,18,15)\n1x2 (1,18,15)\n1x2 (7,18,16)\n6x2 (1,18,16)\n1x2 (5,18,17)\n2x2 (3,18,17)\n"
43
+ }
44
+ }
pyproject.toml ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [project]
2
+ name = "legogpt-demo"
3
+ version = "0.1.0"
4
+ description = "LegoGPT demo webapp"
5
+ readme = "README.md"
6
+ requires-python = ">=3.11"
7
+ dependencies = [
8
+ "bpy<=4.3.0", # lower version of bpy needed to run on Hugging Face A100
9
+ "gradio>=5.29.0",
10
+ "legogpt",
11
+ ]
12
+
13
+ [tool.uv.sources]
14
+ legogpt = { git = "https://github.com/AvaLovelace1/LegoGPT.git" }
render_lego.py ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ from legogpt.render_lego import main as render_lego_main
2
+
3
+ if __name__ == '__main__':
4
+ render_lego_main()
requirements.txt ADDED
@@ -0,0 +1,91 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # This file was autogenerated by uv via the following command:
2
+ # uv export --format requirements-txt --no-hashes
3
+ accelerate==1.6.0
4
+ aiofiles==24.1.0
5
+ annotated-types==0.7.0
6
+ anyio==4.9.0
7
+ audioop-lts==0.2.1 ; python_full_version >= '3.13'
8
+ bpy==4.3.0
9
+ certifi==2025.4.26
10
+ cffi==1.17.1 ; platform_python_implementation == 'PyPy'
11
+ charset-normalizer==3.4.2
12
+ click==8.1.8 ; sys_platform != 'emscripten'
13
+ colorama==0.4.6 ; sys_platform == 'win32'
14
+ cython==3.1.0
15
+ fastapi==0.115.12
16
+ ffmpy==0.5.0
17
+ filelock==3.18.0
18
+ fsspec==2025.3.0
19
+ gradio==5.29.0
20
+ gradio-client==1.10.0
21
+ groovy==0.1.2
22
+ gurobipy==12.0.2
23
+ h11==0.16.0
24
+ httpcore==1.0.9
25
+ httpx==0.28.1
26
+ huggingface-hub==0.30.2
27
+ idna==3.10
28
+ jinja2==3.1.6
29
+ legogpt @ git+https://github.com/AvaLovelace1/LegoGPT.git@c95d35119d98ee4833d2c74d8d6046e5835c2c1c
30
+ markdown-it-py==3.0.0 ; sys_platform != 'emscripten'
31
+ markupsafe==3.0.2
32
+ mdurl==0.1.2 ; sys_platform != 'emscripten'
33
+ mpmath==1.3.0
34
+ networkx==3.4.2
35
+ numpy==1.26.4
36
+ nvidia-cublas-cu12==12.6.4.1 ; platform_machine == 'x86_64' and sys_platform == 'linux'
37
+ nvidia-cuda-cupti-cu12==12.6.80 ; platform_machine == 'x86_64' and sys_platform == 'linux'
38
+ nvidia-cuda-nvrtc-cu12==12.6.77 ; platform_machine == 'x86_64' and sys_platform == 'linux'
39
+ nvidia-cuda-runtime-cu12==12.6.77 ; platform_machine == 'x86_64' and sys_platform == 'linux'
40
+ nvidia-cudnn-cu12==9.5.1.17 ; platform_machine == 'x86_64' and sys_platform == 'linux'
41
+ nvidia-cufft-cu12==11.3.0.4 ; platform_machine == 'x86_64' and sys_platform == 'linux'
42
+ nvidia-cufile-cu12==1.11.1.6 ; platform_machine == 'x86_64' and sys_platform == 'linux'
43
+ nvidia-curand-cu12==10.3.7.77 ; platform_machine == 'x86_64' and sys_platform == 'linux'
44
+ nvidia-cusolver-cu12==11.7.1.2 ; platform_machine == 'x86_64' and sys_platform == 'linux'
45
+ nvidia-cusparse-cu12==12.5.4.2 ; platform_machine == 'x86_64' and sys_platform == 'linux'
46
+ nvidia-cusparselt-cu12==0.6.3 ; platform_machine == 'x86_64' and sys_platform == 'linux'
47
+ nvidia-nccl-cu12==2.26.2 ; platform_machine == 'x86_64' and sys_platform == 'linux'
48
+ nvidia-nvjitlink-cu12==12.6.85 ; platform_machine == 'x86_64' and sys_platform == 'linux'
49
+ nvidia-nvtx-cu12==12.6.77 ; platform_machine == 'x86_64' and sys_platform == 'linux'
50
+ orjson==3.10.18
51
+ packaging==25.0
52
+ pandas==2.2.3
53
+ peft==0.15.2
54
+ pillow==11.2.1
55
+ psutil==7.0.0
56
+ pycparser==2.22 ; platform_python_implementation == 'PyPy'
57
+ pydantic==2.11.4
58
+ pydantic-core==2.33.2
59
+ pydub==0.25.1
60
+ pygments==2.19.1 ; sys_platform != 'emscripten'
61
+ python-dateutil==2.9.0.post0
62
+ python-multipart==0.0.20
63
+ pytz==2025.2
64
+ pyyaml==6.0.2
65
+ regex==2024.11.6
66
+ requests==2.32.3
67
+ rich==14.0.0 ; sys_platform != 'emscripten'
68
+ ruff==0.11.8 ; sys_platform != 'emscripten'
69
+ safehttpx==0.1.6
70
+ safetensors==0.5.3
71
+ semantic-version==2.10.0
72
+ setuptools==80.4.0 ; (python_full_version >= '3.12' and platform_machine != 'x86_64') or (python_full_version >= '3.12' and sys_platform != 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')
73
+ shellingham==1.5.4 ; sys_platform != 'emscripten'
74
+ six==1.17.0
75
+ sniffio==1.3.1
76
+ starlette==0.46.2
77
+ sympy==1.14.0
78
+ tokenizers==0.21.1
79
+ tomlkit==0.13.2
80
+ torch==2.7.0
81
+ tqdm==4.67.1
82
+ transformers==4.51.3
83
+ triton==3.3.0 ; platform_machine == 'x86_64' and sys_platform == 'linux'
84
+ typer==0.15.3 ; sys_platform != 'emscripten'
85
+ typing-extensions==4.13.2
86
+ typing-inspection==0.4.0
87
+ tzdata==2025.2
88
+ urllib3==2.4.0
89
+ uvicorn==0.34.2 ; sys_platform != 'emscripten'
90
+ websockets==15.0.1
91
+ zstandard==0.23.0
uv.lock ADDED
The diff for this file is too large to render. See raw diff