File size: 3,099 Bytes
2a06dbe
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
58debbc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2a06dbe
 
58debbc
2a06dbe
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#!/usr/bin/env python3
"""
์‹œ๋‚˜๋ฆฌ์˜ค ์ƒ์„ฑ๊ธฐ ๊ณตํ†ต ํ—ฌํผ (๋ ˆ์ด์–ด ํŒŒ์ผ ์ถœ๋ ฅ).

build_<scenario>_scenario.py๊ฐ€ TAXโ†’build_intents/actions/behavior_intents๋กœ ๋งŒ๋“  ์‚ฐ์ถœ์„
engine ๋ ˆ์ด์–ด ํŒŒ์ผ์— ๊ธฐ๋กํ•œ๋‹ค. L0๋Š” ์ „์ฒด ๊ต์ฒด, L3/L2๋Š” ํ•ด๋‹น ํ‚ค๋งŒ ๊ต์ฒด(ํ˜•์ œ ์„น์…˜ ๋ณด์กด).
"""
from __future__ import annotations

import json
from pathlib import Path


def load_json(path: Path) -> dict:
    return json.load(open(path, encoding="utf-8")) if path.exists() else {}


# ํ•œ ๋…ธ๋“œ๋ฅผ ์ธ๋ผ์ธ(ํ•œ ์ค„)์œผ๋กœ ์œ ์ง€ํ•  ์ตœ๋Œ€ ํญ. ์ดˆ๊ณผํ•˜๋ฉด ์ž์‹๋ณ„๋กœ ํŽผ์นœ๋‹ค.
# worker-v3/engine/L1_feature.json์˜ "ํ•ญ ๋‹จ์œ„ ์ธ๋ผ์ธ" ์†๋ง›์„ ์ž๋™ ์žฌํ˜„ํ•˜๋Š” ๊ธฐ์ค€.
_INLINE_WIDTH = 100


def compact_json(data, *, indent: int = 2, width: int = _INLINE_WIDTH) -> str:
    """
    "ํ•ญ(leaf) ๋‹จ์œ„ ์ธ๋ผ์ธ" JSON ์ง๋ ฌํ™”.

    ํ‘œ์ค€ indent=2๋Š” ์ž‘์€ ๋ฐฐ์—ดยทleaf ๊ฐ์ฒด๊นŒ์ง€ ํ•œ ์›์†Œ์”ฉ ํŽผ์ณ ์ˆ˜์‹ ํŒŒ์•…์ด ์–ด๋ ต๋‹ค.
    ์ด ํฌ๋งคํ„ฐ๋Š” ๋…ธ๋“œ๋ฅผ ๋จผ์ € ํ•œ ์ค„(json.dumps)๋กœ ๋งŒ๋“ค์–ด๋ณด๊ณ , width ์ดํ•˜๋ฉด ์ธ๋ผ์ธ ์œ ์ง€,
    ์ดˆ๊ณผํ•˜๋ฉด dict/list์˜ ์ž์‹๋ณ„๋กœ ์ค„๋ฐ”๊ฟˆ ํŽผ์นœ๋‹ค. โ†’ terms/steps/rule ๋งต ๊ฐ™์€ ๊ตฌ์กฐ๋Š”
    ํ•ญ๋‹น ํ•œ ์ค„, linear[1,0]ยท์ž‘์€ leaf ๊ฐ์ฒด๋Š” ํ•œ ์ค„๋กœ ๋ชจ์ธ๋‹ค. (๊ฐ’์€ ํ‘œ์ค€๊ณผ 1:1 ๋™์ผ)
    """
    def fmt(node, level: int) -> str:
        pad = " " * (indent * level)
        child_pad = " " * (indent * (level + 1))

        # ์ธ๋ผ์ธ ํ›„๋ณด: ํ•œ ์ค„๋กœ ํ•ฉ์ณค์„ ๋•Œ ํญ ์ดํ•˜๋ฉด ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉ (์Šค์นผ๋ผ๋Š” ํ•ญ์ƒ ์ธ๋ผ์ธ)
        inline = json.dumps(node, ensure_ascii=False, separators=(", ", ": "))
        if not isinstance(node, (dict, list)) or len(pad) + len(inline) <= width:
            return inline

        if isinstance(node, dict):
            if not node:
                return "{}"
            items = [f'{child_pad}{json.dumps(k, ensure_ascii=False)}: {fmt(v, level + 1)}'
                     for k, v in node.items()]
            return "{\n" + ",\n".join(items) + "\n" + pad + "}"

        # list
        if not node:
            return "[]"
        items = [child_pad + fmt(v, level + 1) for v in node]
        return "[\n" + ",\n".join(items) + "\n" + pad + "]"

    return fmt(data, 0)


def dump_json(path: Path, data: dict) -> None:
    path.parent.mkdir(parents=True, exist_ok=True)
    path.write_text(compact_json(data) + "\n", encoding="utf-8")
    print(f"Wrote {path}")


def emit_layers(eng_dir: Path, *, taxonomy: dict, context_library: dict, behavior_signals: dict) -> None:
    """
    L0_taxonomy.json ์ „์ฒด ๊ต์ฒด + L3_serving.json์˜ context_library + L2_inference.json์˜
    ranker.behavior_signals ํ‚ค๋งŒ ๊ต์ฒด(context_manager/action_signal/calibrator ๋“ฑ ํ˜•์ œ ๋ณด์กด).
    """
    dump_json(eng_dir / "L0_taxonomy.json", taxonomy)

    l3 = load_json(eng_dir / "L3_serving.json")
    l3["context_library"] = context_library
    dump_json(eng_dir / "L3_serving.json", l3)

    l2 = load_json(eng_dir / "L2_inference.json")
    l2.setdefault("ranker", {})["behavior_signals"] = behavior_signals
    dump_json(eng_dir / "L2_inference.json", l2)