diff --git a/about/index.html b/about/index.html index b0bc0c3..9a0058a 100644 --- a/about/index.html +++ b/about/index.html @@ -14,7 +14,7 @@ -
+
Waterloo, NY — Finger Lakes Region @@ -29,7 +29,7 @@
- Lahr Carpet Cleaning technician at work + Lahr Carpet Cleaning technician at work
@@ -98,7 +98,7 @@

We serve homes, rental properties, offices, and commercial spaces throughout Seneca, Ontario, Schuyler, and Yates counties. If you are not sure we cover your area, give us a call at 315-719-1218.

- Clean living room carpet in Finger Lakes home + Clean living room carpet in Finger Lakes home
diff --git a/assets/images/hero/hero-carpet-cleaning.jpg b/assets/images/hero/hero-carpet-cleaning.jpg new file mode 100644 index 0000000..8c5cf1f Binary files /dev/null and b/assets/images/hero/hero-carpet-cleaning.jpg differ diff --git a/assets/js/components.js b/assets/js/components.js index e012203..8d3ee6d 100644 --- a/assets/js/components.js +++ b/assets/js/components.js @@ -5,7 +5,6 @@
diff --git a/commercial/offices/index.html b/commercial/offices/index.html index 82d7bb0..641469d 100644 --- a/commercial/offices/index.html +++ b/commercial/offices/index.html @@ -14,7 +14,7 @@ -
+
Waterloo, Seneca Falls & the Finger Lakes @@ -67,7 +67,7 @@

We use truck-mounted hot water extraction that pulls deep soil out of office carpet rather than pushing it around. The result lasts longer and dries faster than portable equipment. Your office is ready for the morning crew, not still damp when they arrive.

Book Now
-
+
diff --git a/commercial/property-management/index.html b/commercial/property-management/index.html index c2c2e6b..b6c1d6c 100644 --- a/commercial/property-management/index.html +++ b/commercial/property-management/index.html @@ -14,7 +14,7 @@ -
+
Waterloo, Seneca Falls & the Finger Lakes @@ -67,7 +67,7 @@

We work with both residential and commercial property managers. From single-family rental homes to multi-unit apartment buildings and commercial office suites, we bring the same professional extraction process and reliable communication to every job in your portfolio.

Book Now
-
+
diff --git a/commercial/retail-showrooms/index.html b/commercial/retail-showrooms/index.html index 7db9f95..fff521f 100644 --- a/commercial/retail-showrooms/index.html +++ b/commercial/retail-showrooms/index.html @@ -14,7 +14,7 @@ -
+
Waterloo, Seneca Falls & the Finger Lakes @@ -67,7 +67,7 @@

We serve businesses from Waterloo to Seneca Falls and throughout the wine country corridor. Our scheduling is flexible enough to work around tasting room hours, gallery events, and seasonal traffic spikes.

Book Now
-
+
diff --git a/commercial/vacation-rentals/index.html b/commercial/vacation-rentals/index.html index c7b38ab..e1e2e27 100644 --- a/commercial/vacation-rentals/index.html +++ b/commercial/vacation-rentals/index.html @@ -14,7 +14,7 @@ -
+
Waterloo, Seneca Falls & the Finger Lakes @@ -67,7 +67,7 @@

We communicate clearly, arrive when scheduled, and send confirmation when the job is done. Set up a recurring program and take carpet cleaning off your mental list entirely.

Book Now
-
+
diff --git a/index.html b/index.html index 5609178..ed8b1ad 100644 --- a/index.html +++ b/index.html @@ -3,7 +3,10 @@ - Lahr Carpet Cleaning | Professional Carpet & Upholstery Cleaning in Waterloo, NY + Lahr Carpet Cleaning | Residential & Commercial Carpet Cleaning — Finger Lakes, NY + + + @@ -277,6 +280,13 @@
+
+
+

Find Us

+
+ +
+ diff --git a/service-area/index.html b/service-area/index.html index 11fb645..d6fa054 100644 --- a/service-area/index.html +++ b/service-area/index.html @@ -14,7 +14,7 @@ -
+
Seneca, Ontario, Schuyler & Yates Counties diff --git a/services/add-ons/index.html b/services/add-ons/index.html index d3c36c7..90d27e9 100644 --- a/services/add-ons/index.html +++ b/services/add-ons/index.html @@ -14,7 +14,7 @@
-
+
Waterloo, Seneca Falls & the Finger Lakes @@ -67,7 +67,7 @@

These treatments are optional. Not every home needs them. We will tell you honestly at the time of booking whether an add-on makes sense for your situation.

Book Now
-
+
diff --git a/services/area-rugs/index.html b/services/area-rugs/index.html index b147b16..e390688 100644 --- a/services/area-rugs/index.html +++ b/services/area-rugs/index.html @@ -14,7 +14,7 @@ -
+
Waterloo, Seneca Falls & the Finger Lakes @@ -67,7 +67,7 @@

If your rug smells, looks flat, or has visible staining, professional cleaning will make a clear difference. A rug that looks too far gone often surprises its owner after a thorough clean.

Book Now
-
+
diff --git a/services/carpet-cleaning/index.html b/services/carpet-cleaning/index.html index 234aede..f0025aa 100644 --- a/services/carpet-cleaning/index.html +++ b/services/carpet-cleaning/index.html @@ -14,7 +14,7 @@ -
+
Waterloo, Seneca Falls & the Finger Lakes @@ -67,7 +67,7 @@

Every job follows the same approach: assess the carpet, pre-treat problem areas, extract thoroughly, and leave the space cleaner than we found it. That consistency is what keeps customers coming back.

Book Now
-
+
diff --git a/services/commercial/index.html b/services/commercial/index.html index 35e5e8b..b3ffc20 100644 --- a/services/commercial/index.html +++ b/services/commercial/index.html @@ -14,7 +14,7 @@ -
+
Waterloo, Seneca Falls & the Finger Lakes @@ -67,7 +67,7 @@

Every job uses professional hot water extraction equipment. No rental-grade machines, no shortcuts. You get clean carpets the first time, with a before and after walk-through so you know exactly what was done.

Book Now
-
+
diff --git a/services/floors/index.html b/services/floors/index.html index b9fe845..167f8f1 100644 --- a/services/floors/index.html +++ b/services/floors/index.html @@ -14,7 +14,7 @@ -
+
Waterloo, Seneca Falls & the Finger Lakes @@ -67,7 +67,7 @@

If your floors look dull or your grout lines have darkened despite regular mopping, professional cleaning will show you the difference. Book the service and see what the floor actually looks like clean.

Book Now
-
+
diff --git a/services/upholstery/index.html b/services/upholstery/index.html index d63e58d..8cac322 100644 --- a/services/upholstery/index.html +++ b/services/upholstery/index.html @@ -14,7 +14,7 @@ -
+
Waterloo, Seneca Falls & the Finger Lakes @@ -67,7 +67,7 @@

If your furniture smells, looks dull, or shows visible soil on the armrests and seat cushions, cleaning will make a visible difference. Book the appointment and see the result for yourself.

Book Now
-
+
diff --git a/tools/build-paced-reel.py b/tools/build-paced-reel.py index 92a33a3..2c80801 100644 --- a/tools/build-paced-reel.py +++ b/tools/build-paced-reel.py @@ -18,34 +18,32 @@ os.makedirs(TMP_DIR, exist_ok=True) CLIPS = [ "v3-shot-02", # 1 - wine spill on sofa "shot-05-extraction-couch",# 2 - extraction couch - "shot-03-technician", # 3 - technician - "v3-shot-03", # 4 - dirty stained carpet close-up - "v3-shot-06", # 5 - living room clean carpet pan - "v3-shot-07", # 6 - restaurant carpet glide - "v3-shot-05", # 7 - office lobby carpet pan - "v2-shot-05-clean-stairs", # 8 - clean bright staircase - "v2-shot-07-restaurant", # 9 - restaurant carpet - "v2-shot-06-office", # 10 - bright office carpet - "shot-01-wide-room", # 11 - wide room establishing - "shot-05-clean-reveal", # 12 - clean reveal - "shot-04-extraction-carpet",# 13 - final reveal + "v3-shot-03", # 3 - dirty stained carpet close-up + "v3-shot-06", # 4 - living room clean carpet pan + "v3-shot-07", # 5 - restaurant carpet glide + "v3-shot-05", # 6 - office lobby carpet pan + "v2-shot-05-clean-stairs", # 7 - clean bright staircase + "v2-shot-07-restaurant", # 8 - restaurant carpet + "v2-shot-06-office", # 9 - bright office carpet + "shot-01-wide-room", # 10 - wide room establishing + "shot-05-clean-reveal", # 11 - clean reveal + "shot-04-extraction-carpet",# 12 - final reveal ] # Duration for each clip DURATIONS = [ 4.5, # 1 wine spill — cut at 4.5s 5.0, # 2 - 5.0, # 3 - 4.0, # 4 --- building pace --- + 4.0, # 3 --- building pace --- + 4.0, # 4 4.0, # 5 - 4.0, # 6 + 3.5, # 6 3.5, # 7 - 3.5, # 8 - 2.5, # 9 --- rapid --- + 2.5, # 8 --- rapid --- + 2.5, # 9 2.5, # 10 2.5, # 11 - 2.5, # 12 - 6.0, # 13 final reveal — hold + 6.0, # 12 final reveal — hold ] paced_clips = [] diff --git a/tools/gen-hero-images.py b/tools/gen-hero-images.py new file mode 100644 index 0000000..f293de7 --- /dev/null +++ b/tools/gen-hero-images.py @@ -0,0 +1,244 @@ +""" +Generate unique hero images for every page via ComfyUI SDXL. +No people. No machines. Residential = warm home scenes. Commercial = professional spaces. +Run in tmux: python3 tools/gen-hero-images.py +""" +import json, time, urllib.request, os, random + +COMFY = "http://localhost:8188" +OUT_DIR = os.path.join(os.path.dirname(os.path.dirname(__file__)), "assets", "images", "hero") +CKPT = "sd_xl_base_1.0.safetensors" + +NEG = ( + "people, person, human, hands, feet, boots, shoes, worker, cleaner, technician, " + "machine, vacuum cleaner, equipment, steam, city skyline, apartment building exterior, " + "urban, dirty, stain, text, watermark, logo, blurry, low quality, cartoon, anime, " + "illustration, render, CGI" +) + +IMAGES = [ + { + "filename": "hero-carpet-cleaning.jpg", + "positive": ( + "wide shot of a bright residential living room in an upstate New York home, " + "thick plush beige carpet throughout, warm afternoon sunlight through large windows, " + "comfortable couch and coffee table, Finger Lakes farmhouse style interior, " + "no people, ultra-realistic architectural photography, 16:9 wide" + ), + }, + { + "filename": "hero-stairs.jpg", + "positive": ( + "wide shot of a clean carpeted staircase inside a suburban American home, " + "light grey carpet runner on dark wood stairs, white painted banister, " + "bright natural light from above, no people, no equipment, " + "ultra-realistic interior photography, 16:9" + ), + }, + { + "filename": "hero-upholstery.jpg", + "positive": ( + "bright cozy living room in a residential home, large comfortable fabric sofa " + "in warm neutral tones, clean armchair beside it, plush carpet beneath, " + "afternoon light, Finger Lakes countryside visible through window, " + "no people, ultra-realistic interior photography, 16:9" + ), + }, + { + "filename": "hero-floors.jpg", + "positive": ( + "wide shot of a clean hardwood floor hallway in a spacious suburban American home, " + "light oak floors gleaming, white walls, natural light streaming through windows, " + "no people, no equipment, ultra-realistic interior photography, 16:9" + ), + }, + { + "filename": "hero-area-rugs.jpg", + "positive": ( + "beautiful oriental area rug centered in a bright residential living room, " + "rich warm tones of deep red and gold, hardwood floor surrounding the rug, " + "cozy farmhouse interior, natural light, Finger Lakes region home decor, " + "no people, ultra-realistic interior photography, 16:9" + ), + }, + { + "filename": "hero-add-ons.jpg", + "positive": ( + "bright clean residential bedroom interior, freshly cleaned light beige carpet, " + "white walls, large window with sheer curtains, simple wooden bed frame, " + "crisp natural morning light, Finger Lakes home style, " + "no people, no machines, ultra-realistic interior photography, 16:9" + ), + }, + { + "filename": "hero-commercial.jpg", + "positive": ( + "wide shot of a modern commercial office building lobby interior, " + "clean dark grey commercial carpet throughout, professional corporate space, " + "glass entrance doors, white walls, recessed lighting, " + "no people, no equipment, architectural photography, ultra-realistic, 16:9" + ), + }, + { + "filename": "hero-offices.jpg", + "positive": ( + "modern open-plan corporate office interior, clean grey carpet tiles, " + "rows of empty desks, glass partitions, professional overhead lighting, " + "large windows with daylight, no people, no equipment, " + "architectural photography, ultra-realistic, 16:9" + ), + }, + { + "filename": "hero-vacation-rentals.jpg", + "positive": ( + "bright cozy vacation rental cottage living room interior, Finger Lakes region style, " + "clean beige carpet, wooden ceiling beams, stone fireplace, comfortable furniture, " + "large window with lake view in distance, warm inviting atmosphere, " + "no people, ultra-realistic interior photography, 16:9" + ), + }, + { + "filename": "hero-hotels.jpg", + "positive": ( + "long elegant hotel corridor interior, clean patterned burgundy carpet runner, " + "warm wall sconce lighting along white walls, numbered wooden room doors, " + "soft warm glow, upscale hospitality interior, no people, no equipment, " + "professional architectural photography, ultra-realistic, 16:9" + ), + }, + { + "filename": "hero-retail.jpg", + "positive": ( + "upscale retail showroom interior, clean light grey carpet flooring, " + "modern minimalist display fixtures, bright track lighting overhead, " + "white walls, large storefront windows with natural light, " + "no people, no equipment, architectural photography, ultra-realistic, 16:9" + ), + }, + { + "filename": "hero-property-management.jpg", + "positive": ( + "clean move-in ready apartment unit living room, fresh neutral carpet, " + "white walls, bright windows, empty space ready for tenants, " + "no furniture, no people, no equipment, " + "real estate photography style, ultra-realistic, 16:9" + ), + }, + { + "filename": "hero-about.jpg", + "positive": ( + "warm exterior view of a classic upstate New York suburban home, " + "green lawn, mature trees, clear blue sky, Finger Lakes region, " + "inviting residential property, no people, no vehicles, " + "professional real estate photography, ultra-realistic, 16:9" + ), + }, + { + "filename": "hero-service-area.jpg", + "positive": ( + "scenic Finger Lakes region landscape, rolling green hills, vineyards in distance, " + "calm lake water reflecting sky, late afternoon golden hour light, " + "upstate New York countryside, no people, no vehicles, " + "professional landscape photography, ultra-realistic, 16:9" + ), + }, + { + "filename": "hero-living-room.jpg", + "positive": ( + "spacious bright residential living room in a Finger Lakes area home, " + "plush clean light grey carpet, white walls, large sectional sofa, " + "afternoon sunlight through bay windows, warm cozy family atmosphere, " + "no people, ultra-realistic interior photography, 16:9" + ), + }, + { + "filename": "hero-clean-result.jpg", + "positive": ( + "close-up wide angle of immaculate freshly cleaned residential carpet, " + "uniform plush beige pile, bright natural light raking across the surface, " + "showing deep clean texture, no people, no machines, " + "ultra-realistic macro photography, 16:9" + ), + }, +] + + +def build_workflow(positive, seed=None): + if seed is None: + seed = random.randint(0, 2**32) + return { + "3": {"class_type": "KSampler", "inputs": { + "cfg": 7.5, "denoise": 1.0, + "latent_image": ["5", 0], "model": ["4", 0], + "negative": ["7", 0], "positive": ["6", 0], + "sampler_name": "dpmpp_2m", "scheduler": "karras", + "seed": seed, "steps": 30, + }}, + "4": {"class_type": "CheckpointLoaderSimple", "inputs": {"ckpt_name": CKPT}}, + "5": {"class_type": "EmptyLatentImage", "inputs": {"batch_size": 1, "height": 576, "width": 1024}}, + "6": {"class_type": "CLIPTextEncode", "inputs": {"clip": ["4", 1], "text": positive}}, + "7": {"class_type": "CLIPTextEncode", "inputs": {"clip": ["4", 1], "text": NEG}}, + "8": {"class_type": "VAEDecode", "inputs": {"samples": ["3", 0], "vae": ["4", 2]}}, + "9": {"class_type": "SaveImage", "inputs": {"filename_prefix": "hero_gen", "images": ["8", 0]}}, + } + + +def queue_prompt(workflow): + data = json.dumps({"prompt": workflow}).encode() + req = urllib.request.Request(f"{COMFY}/prompt", data=data, + headers={"Content-Type": "application/json"}) + with urllib.request.urlopen(req) as resp: + return json.loads(resp.read())["prompt_id"] + + +def wait_for_result(prompt_id, timeout=900): + start = time.time() + while time.time() - start < timeout: + try: + with urllib.request.urlopen(f"{COMFY}/history/{prompt_id}") as resp: + hist = json.loads(resp.read()) + if prompt_id in hist: + outputs = hist[prompt_id].get("outputs", {}) + for node_out in outputs.values(): + if "images" in node_out: + return node_out["images"] + except Exception: + pass + time.sleep(5) + return None + + +def download_image(img_info, out_path): + fname = img_info["filename"] + subfolder = img_info.get("subfolder", "") + img_type = img_info.get("type", "output") + url = f"{COMFY}/view?filename={fname}&subfolder={subfolder}&type={img_type}" + with urllib.request.urlopen(url) as resp: + data = resp.read() + try: + from PIL import Image + import io + img = Image.open(io.BytesIO(data)).convert("RGB") + img.save(out_path, "JPEG", quality=92) + print(f" OK: {os.path.basename(out_path)} ({os.path.getsize(out_path)//1024}KB)", flush=True) + except ImportError: + png_path = out_path.replace(".jpg", ".png") + with open(png_path, "wb") as f: + f.write(data) + print(f" OK (PNG): {png_path}", flush=True) + + +total = len(IMAGES) +for i, spec in enumerate(IMAGES): + out_path = os.path.join(OUT_DIR, spec["filename"]) + print(f"\n[{i+1}/{total}] {spec['filename']}", flush=True) + workflow = build_workflow(spec["positive"]) + prompt_id = queue_prompt(workflow) + print(f" queued {prompt_id[:8]}...", flush=True) + images = wait_for_result(prompt_id) + if images: + download_image(images[0], out_path) + else: + print(f" FAILED (timeout)", flush=True) + +print("\nAll done.", flush=True)