| 1 | """Deterministic, CPU-only synthetic signal demo with two reusable result pages."""
|
|---|
| 2 |
|
|---|
| 3 | import argparse
|
|---|
| 4 | import hashlib
|
|---|
| 5 | import math
|
|---|
| 6 | from pathlib import Path
|
|---|
| 7 | import random
|
|---|
| 8 | import struct
|
|---|
| 9 | import zlib
|
|---|
| 10 |
|
|---|
| 11 | try:
|
|---|
| 12 | import luna_repro as repro
|
|---|
| 13 | except ModuleNotFoundError as error:
|
|---|
| 14 | if error.name != 'luna_repro':
|
|---|
| 15 | raise
|
|---|
| 16 | from sdk import luna_repro as repro # Repository-hosted interactive demo.
|
|---|
| 17 |
|
|---|
| 18 | SEED = 20261011
|
|---|
| 19 |
|
|---|
| 20 |
|
|---|
| 21 | def _png(series):
|
|---|
| 22 | """Small standard-library chart; all pixels derive from synthetic inputs."""
|
|---|
| 23 | width, height = 640, 240
|
|---|
| 24 | pixels = bytearray([250, 251, 253] * width * height)
|
|---|
| 25 |
|
|---|
| 26 | def point(x, y, color):
|
|---|
| 27 | if 0 <= x < width and 0 <= y < height:
|
|---|
| 28 | offset = 3 * (y * width + x)
|
|---|
| 29 | pixels[offset:offset + 3] = bytes(color)
|
|---|
| 30 |
|
|---|
| 31 | colors = [(30, 90, 170), (180, 90, 20), (15, 140, 110)]
|
|---|
| 32 | for values, color in zip(series, colors):
|
|---|
| 33 | for index in range(1, len(values)):
|
|---|
| 34 | x0, x1 = int((index - 1) * (width - 40) / (len(values) - 1)) + 20, int(index * (width - 40) / (len(values) - 1)) + 20
|
|---|
| 35 | y0, y1 = int(height / 2 - values[index - 1] * 65), int(height / 2 - values[index] * 65)
|
|---|
| 36 | steps = max(abs(x1 - x0), abs(y1 - y0), 1)
|
|---|
| 37 | for step in range(steps + 1):
|
|---|
| 38 | x, y = round(x0 + (x1 - x0) * step / steps), round(y0 + (y1 - y0) * step / steps)
|
|---|
| 39 | point(x, y, color)
|
|---|
| 40 | point(x, y + 1, color)
|
|---|
| 41 |
|
|---|
| 42 | def chunk(kind, data):
|
|---|
| 43 | return struct.pack(">I", len(data)) + kind + data + struct.pack(">I", zlib.crc32(kind + data) & 0xffffffff)
|
|---|
| 44 |
|
|---|
| 45 | scanlines = b"".join(b"\x00" + pixels[row * width * 3:(row + 1) * width * 3] for row in range(height))
|
|---|
| 46 | return b"\x89PNG\r\n\x1a\n" + chunk(b"IHDR", struct.pack(">IIBBBBB", width, height, 8, 2, 0, 0, 0)) + chunk(b"IDAT", zlib.compress(scanlines, 9)) + chunk(b"IEND", b"")
|
|---|
| 47 |
|
|---|
| 48 |
|
|---|
| 49 | def build_pages(project, *, endpoint=None, token=None, outbox=None):
|
|---|
| 50 | rng = random.Random(SEED)
|
|---|
| 51 | reference = [math.sin(index / 12) for index in range(120)]
|
|---|
| 52 | noisy = [value + rng.gauss(0, 0.25) for value in reference]
|
|---|
| 53 | smooth = [sum(noisy[max(0, index - 2):index + 3]) / len(noisy[max(0, index - 2):index + 3]) for index in range(len(noisy))]
|
|---|
| 54 | pages = []
|
|---|
| 55 | for label, values in (("baseline", noisy), ("smoothed", smooth)):
|
|---|
| 56 | rmse = math.sqrt(sum((actual - expected) ** 2 for actual, expected in zip(values, reference)) / len(reference))
|
|---|
| 57 | page = repro.page(project, "합성 신호 / Synthetic signal · " + label, description="결정적 CPU 합성 예제입니다. Pasa·Teeth3DS+ 연구 성능이 아닙니다. Deterministic CPU toy; not Pasa or Teeth3DS+ performance.", endpoint=endpoint, token=token, metadata={"tags": ["synthetic", "CPU", label]}, evidence={"origin": "synthetic", "execution_status": "completed", "evaluation_status": "completed"}, outbox=outbox)
|
|---|
| 58 | page.section("metrics", "실제 계산한 합성 지표 / Computed toy metrics").metrics({"RMSE": rmse, "samples": len(reference), "seed": SEED})
|
|---|
| 59 | chart = _png((reference, noisy, values))
|
|---|
| 60 | page.section("comparison", "신호 비교 / Signal comparison").image(chart, "파랑: 기준 · 주황: 잡음 · 초록: 선택 방법 / Blue: reference; orange: noisy; green: selected method").text("합성 입력과 이미지 SHA256 / Synthetic chart SHA256: " + hashlib.sha256(chart).hexdigest())
|
|---|
| 61 | page.section("samples", "일부 결과 / Selected samples").table(["index", "reference", "prediction"], [[index, reference[index], values[index]] for index in range(10)])
|
|---|
| 62 | pages.append(page)
|
|---|
| 63 | return pages
|
|---|
| 64 |
|
|---|
| 65 |
|
|---|
| 66 | def main():
|
|---|
| 67 | parser = argparse.ArgumentParser(description=__doc__)
|
|---|
| 68 | parser.add_argument("--project", required=True, help="Project UUID from LUNA")
|
|---|
| 69 | parser.add_argument("--output", default=".luna-repro/toy")
|
|---|
| 70 | parser.add_argument("--publish", action="store_true", help="Explicitly send via environment endpoint/token")
|
|---|
| 71 | args = parser.parse_args()
|
|---|
| 72 | for index, page in enumerate(build_pages(args.project)):
|
|---|
| 73 | page.save(Path(args.output) / ("toy-%d.json" % (index + 1)))
|
|---|
| 74 | if args.publish:
|
|---|
| 75 | receipt = page.publish()
|
|---|
| 76 | print(receipt.get("url") or receipt["message"])
|
|---|
| 77 | print("Two synthetic result bundles saved; no GPU or AI call.")
|
|---|
| 78 |
|
|---|
| 79 |
|
|---|
| 80 | if __name__ == "__main__":
|
|---|
| 81 | main()
|
|---|