6767}
6868
6969_STYLE_HINT_RE = re .compile (r"토스|신뢰|고급|깔끔|스타트업|모바일|saas|premium|trust|clean|mobile|startup" , re .IGNORECASE )
70+ _LABELED_ANSWER_RE = re .compile (
71+ r"(?:^|[.;\n]\s*)(project|product|service|audience|target user|target users|goal|conversion goal|vibe|impression|style|stack|tech stack|references?|avoid|accessibility|asset policy)\s*:\s*(.*?)(?=(?:[.;\n]\s*)(?:project|product|service|audience|target user|target users|goal|conversion goal|vibe|impression|style|stack|tech stack|references?|avoid|accessibility|asset policy)\s*:|$)" ,
72+ re .IGNORECASE | re .DOTALL ,
73+ )
74+ _LABELED_FIELD_MAP = {
75+ "project" : "project" ,
76+ "product" : "project" ,
77+ "service" : "project" ,
78+ "audience" : "audience" ,
79+ "target user" : "audience" ,
80+ "target users" : "audience" ,
81+ "goal" : "goal" ,
82+ "conversion goal" : "goal" ,
83+ "vibe" : "vibe" ,
84+ "impression" : "vibe" ,
85+ "style" : "vibe" ,
86+ "stack" : "stack" ,
87+ "tech stack" : "stack" ,
88+ "reference" : "references" ,
89+ "references" : "references" ,
90+ "avoid" : "avoid" ,
91+ "accessibility" : "accessibility" ,
92+ "asset policy" : "asset_policy" ,
93+ }
7094
7195
7296def write (path : Path , content : str ) -> None :
@@ -97,16 +121,22 @@ def write_session(root: Path, session: dict[str, Any]) -> None:
97121
98122def extract_answers_from_text (text : str ) -> dict [str , str ]:
99123 answers : dict [str , str ] = {}
124+ for match in _LABELED_ANSWER_RE .finditer (text ):
125+ raw_key = match .group (1 ).lower ().strip ()
126+ field = _LABELED_FIELD_MAP .get (raw_key )
127+ value = match .group (2 ).strip (" .;\n \t " )
128+ if field and value :
129+ answers [field ] = value
100130 lowered = text .lower ()
101131 if "ai 회의록" in lowered or "회의록" in text :
102- answers [ "project" ] = "AI 회의록 서비스"
132+ answers . setdefault ( "project" , "AI 회의록 서비스" )
103133 if "데모" in text :
104- answers [ "goal" ] = "데모 요청"
134+ answers . setdefault ( "goal" , "데모 요청" )
105135 elif "가입" in text :
106- answers [ "goal" ] = "가입"
136+ answers . setdefault ( "goal" , "가입" )
107137 elif "문의" in text :
108- answers [ "goal" ] = "문의"
109- if _STYLE_HINT_RE .search (text ):
138+ answers . setdefault ( "goal" , "문의" )
139+ if _STYLE_HINT_RE .search (text ) and "vibe" not in answers :
110140 answers ["vibe" ] = text .strip ()
111141 return answers
112142
@@ -206,7 +236,8 @@ def render_ready_summary(session: dict[str, Any]) -> str:
206236 f"- 목표: { answers .get ('goal' , '' )} " ,
207237 f"- 무드: { answers .get ('vibe' , '' )} " ,
208238 "" ,
209- "더 다듬고 싶으면 레퍼런스, 피해야 할 스타일, 브랜드 제약을 추가로 알려주세요." ,
239+ "더 다듬고 싶으면 레퍼런스, 피해야 할 스타일, 브랜드/에셋 제약을 추가로 알려주세요." ,
240+ "에셋 사용을 명시적으로 허용하지 않으면 외부 소스는 원칙 참고로만 사용합니다." ,
210241 "문서 생성을 시작하려면 `@artic start`를 실행하세요." ,
211242 ]
212243 else :
@@ -219,7 +250,8 @@ def render_ready_summary(session: dict[str, Any]) -> str:
219250 f"- Goal: { answers .get ('goal' , '' )} " ,
220251 f"- Vibe: { answers .get ('vibe' , '' )} " ,
221252 "" ,
222- "Add references, avoided styles, or brand constraints if you want to refine the brief." ,
253+ "Add references, avoided styles, brand constraints, or asset policy if you want to refine the brief." ,
254+ "If you do not explicitly allow asset usage, external sources stay reference-principles only." ,
223255 "To generate Artic design docs, run `@artic start`." ,
224256 ]
225257 return "\n " .join (lines )
0 commit comments