tomiconic commited on
Commit
d4be3bd
·
verified ·
1 Parent(s): e838a27

Delete llm_parser.py

Browse files
Files changed (1) hide show
  1. llm_parser.py +0 -167
llm_parser.py DELETED
@@ -1,167 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import json
4
- import os
5
- import re
6
- from functools import lru_cache
7
- from typing import Any
8
-
9
- from parser import PromptSpec, merge_prompt_specs, parse_prompt
10
-
11
- try:
12
- import spaces # type: ignore
13
- except Exception: # pragma: no cover
14
- class _SpacesShim:
15
- @staticmethod
16
- def GPU(*args, **kwargs):
17
- def decorator(fn):
18
- return fn
19
- return decorator
20
-
21
- spaces = _SpacesShim() # type: ignore
22
-
23
-
24
- DEFAULT_LOCAL_MODEL = os.getenv("PB3D_LOCAL_MODEL", "Qwen/Qwen2.5-1.5B-Instruct")
25
- MODEL_PRESETS = {
26
- "Qwen 2.5 1.5B": "Qwen/Qwen2.5-1.5B-Instruct",
27
- "SmolLM2 1.7B": "HuggingFaceTB/SmolLM2-1.7B-Instruct",
28
- }
29
-
30
- JSON_SCHEMA_HINT = {
31
- "object_type": ["cargo_hauler", "fighter", "shuttle", "freighter", "dropship", "drone"],
32
- "scale": ["small", "medium", "large"],
33
- "hull_style": ["boxy", "rounded", "sleek"],
34
- "engine_count": "integer 1-6",
35
- "wing_span": "float 0.0-0.6",
36
- "cargo_ratio": "float 0.0-0.65",
37
- "cockpit_ratio": "float 0.10-0.30",
38
- "fin_height": "float 0.0-0.3",
39
- "landing_gear": "boolean",
40
- "asymmetry": "float 0.0-0.2",
41
- "notes": "short string",
42
- }
43
-
44
-
45
- def _clamp(value: float, low: float, high: float) -> float:
46
- return max(low, min(high, value))
47
-
48
-
49
- @lru_cache(maxsize=2)
50
- def _load_generation_components(model_id: str):
51
- from transformers import AutoModelForCausalLM, AutoTokenizer
52
- import torch
53
-
54
- tokenizer = AutoTokenizer.from_pretrained(model_id, trust_remote_code=True)
55
- if tokenizer.pad_token is None:
56
- tokenizer.pad_token = tokenizer.eos_token
57
-
58
- has_cuda = torch.cuda.is_available()
59
- torch_dtype = torch.bfloat16 if has_cuda else torch.float32
60
- model = AutoModelForCausalLM.from_pretrained(
61
- model_id,
62
- torch_dtype=torch_dtype,
63
- device_map="auto",
64
- low_cpu_mem_usage=True,
65
- trust_remote_code=True,
66
- )
67
- return tokenizer, model
68
-
69
-
70
- @spaces.GPU(duration=45)
71
- def _generate_structured_json(prompt: str, model_id: str) -> dict[str, Any]:
72
- import torch
73
-
74
- tokenizer, model = _load_generation_components(model_id)
75
-
76
- system = (
77
- "You are a compact design parser for a procedural 3D generator. "
78
- "Convert the user request into a single JSON object and output JSON only."
79
- )
80
- user = (
81
- "Return a JSON object using this schema: "
82
- f"{json.dumps(JSON_SCHEMA_HINT)}\n"
83
- "Rules: choose the closest allowed enum values, stay conservative, infer hard-surface sci-fi vehicle structure, "
84
- "never explain anything, never use markdown fences, and keep notes brief.\n"
85
- f"Prompt: {prompt}"
86
- )
87
-
88
- messages = [
89
- {"role": "system", "content": system},
90
- {"role": "user", "content": user},
91
- ]
92
-
93
- if hasattr(tokenizer, "apply_chat_template"):
94
- rendered = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
95
- else:
96
- rendered = f"System: {system}\nUser: {user}\nAssistant:"
97
-
98
- inputs = tokenizer(rendered, return_tensors="pt")
99
- model_device = getattr(model, "device", None)
100
- if model_device is not None:
101
- inputs = {k: v.to(model_device) for k, v in inputs.items()}
102
-
103
- with torch.no_grad():
104
- output = model.generate(
105
- **inputs,
106
- max_new_tokens=220,
107
- do_sample=False,
108
- temperature=None,
109
- top_p=None,
110
- repetition_penalty=1.02,
111
- pad_token_id=tokenizer.pad_token_id,
112
- eos_token_id=tokenizer.eos_token_id,
113
- )
114
-
115
- new_tokens = output[0][inputs["input_ids"].shape[1]:]
116
- text = tokenizer.decode(new_tokens, skip_special_tokens=True).strip()
117
-
118
- match = re.search(r"\{.*\}", text, flags=re.S)
119
- if not match:
120
- raise ValueError("Local model did not return JSON.")
121
- return json.loads(match.group(0))
122
-
123
-
124
- def _normalize_llm_payload(payload: dict[str, Any], original_prompt: str) -> PromptSpec:
125
- def get_str(name: str, default: str) -> str:
126
- value = str(payload.get(name, default)).strip().lower()
127
- return value or default
128
-
129
- def get_int(name: str, default: int, low: int, high: int) -> int:
130
- try:
131
- return int(_clamp(int(payload.get(name, default)), low, high))
132
- except Exception:
133
- return default
134
-
135
- def get_float(name: str, default: float, low: float, high: float) -> float:
136
- try:
137
- return float(_clamp(float(payload.get(name, default)), low, high))
138
- except Exception:
139
- return default
140
-
141
- landing_raw = payload.get("landing_gear", True)
142
- if isinstance(landing_raw, bool):
143
- landing_gear = landing_raw
144
- else:
145
- landing_gear = str(landing_raw).strip().lower() in {"1", "true", "yes", "y"}
146
-
147
- return PromptSpec(
148
- object_type=get_str("object_type", "cargo_hauler"),
149
- scale=get_str("scale", "small"),
150
- hull_style=get_str("hull_style", "boxy"),
151
- engine_count=get_int("engine_count", 2, 1, 6),
152
- wing_span=get_float("wing_span", 0.2, 0.0, 0.6),
153
- cargo_ratio=get_float("cargo_ratio", 0.38, 0.0, 0.65),
154
- cockpit_ratio=get_float("cockpit_ratio", 0.18, 0.10, 0.30),
155
- fin_height=get_float("fin_height", 0.0, 0.0, 0.3),
156
- landing_gear=landing_gear,
157
- asymmetry=get_float("asymmetry", 0.0, 0.0, 0.2),
158
- notes=str(payload.get("notes", original_prompt)).strip() or original_prompt,
159
- )
160
-
161
-
162
- def parse_prompt_with_local_llm(prompt: str, model_id: str | None = None) -> PromptSpec:
163
- model_id = model_id or DEFAULT_LOCAL_MODEL
164
- heuristic = parse_prompt(prompt)
165
- payload = _generate_structured_json(prompt=prompt, model_id=model_id)
166
- llm_spec = _normalize_llm_payload(payload, original_prompt=prompt)
167
- return merge_prompt_specs(heuristic, llm_spec)