7.6 KiB
known_issue.md
이슈는 파이프라인 단계별로 묶는다. 단계: ① detect ② narration_text ③ motion ④ tts ⑤ bgm ⑥ i2v ⑦ render. 어느 단계에도 속하지 않으면 공통에 둔다.
① detect
recommended_mode — 죽은 필드
models/detect.py의 Regions.recommended_mode는 현재 아무 데서도 읽히지 않는다.
detect.py가 title_style == "calligraphy"이면 layered, 아니면 camera로 채우기만 한다.
원본 리포에는 렌더 경로가 둘 있었다.
layered— 포스터를 레이어로 분해해 제목 글자는 원본 픽셀 그대로 유지하고 배경만 움직인다. 붓글씨는 획이 조금만 흐트러져도 글자가 아니게 되므로 calligraphy를 이쪽으로 보냈다.camera— 포스터를 통째로 두고 카메라만 움직인다(팬·줌).
이식한 export에는 둘 다 없다. 레이어 렌더러는 애초에 제외됐고, 실제 렌더는 생성형 i2v이며
그 프롬프트는 오히려 Locked-off camera: the poster never moves로 카메라 이동을 금지한다.
판단 유보로 필드는 남겨둔다. 레이어 경로를 되살리지 않기로 하면 지운다.
GridBox 좌표 순서가 강제되지 않는다
answers/detect_answer.py의 GridBox는 x0 < x1, y0 < y1을 보장하지 않는다.
프롬프트에도 순서 조건이 없고 스키마에도 밸리데이터가 없다.
VLM이 뒤집어 답하면 detect.py의 tighten_box()가 right <= left or bottom <= top에 걸려
None을 돌려주고, 호출부는 VLM 원값을 그대로 쓰는 fallback으로 떨어진다.
그 결과 x0 > x1인 Box가 그대로 만들어지고, check_overlay()의 draw.rectangle에서
PIL이 예외를 낸다.
원본 CLI(detect_regions.py)에도 같은 구멍이 있다.
막으려면 프롬프트에 순서 조건을 넣거나 GridBox에 밸리데이터를 단다.
focal_points를 VLM이 실제 지점이 아니라 멋대로 잡는다
focal_points 좌표가 포스터를 보고 잰 값이 아니라 그럴듯하게 배치한 값으로 나온다. 관측된 형태는 균등 간격·동일 높이지만, 원인이 같다면 다른 양상으로도 나올 수 있다.
이유는 아마도 둘이다.
- 검증이 없다. 박스는 VLM이 대충 답해도
tighten_box()가 잉크 경계로 다시 잡아준다. focal_points는 그 후처리가 없어 VLM 값이 곧 최종값이다. - 틀릴 수 없는 답이다. 박스와 달리 focal은 정답 경계가 없어서, 모델이 지어내도 스키마도 후처리도 걸러내지 못한다.
프롬프트로 격자를 읽게 못박거나, focal도 박스로 받아 후처리를 태우는 방향이 있다. 후자는 잉크 기반이라 글자에는 듣고 그림에는 덜 듣는다.
② narration_text
models/narration.py가 없다
generate_narration()이 answers의 NarrationAnswer를 그대로 반환한다.
detect와 달리 후처리가 없어 LLM 응답이 곧 결과이고, 지금 모델을 만들면 필드를 그대로
베끼는 껍데기가 되기 때문이다.
대신 answers 타입이 이 단계의 공개 반환 타입이 되어 LLM 레이어가 위로 새어나간다.
API 레이어가 다른 형태를 요구하면 그때 models/narration.py를 만들고 변환을 넣는다.
metadata에서 괄호 내용이 사라진다
concert_poster_image 실측 — 포스터 표기와 metadata가 다르다.
| 필드 | 포스터 | metadata |
|---|---|---|
| date_text | 2023. 1. 26(THU) 7:30PM |
2023. 1. 26THU 7:30PM |
| place | 영도문화예술회관 봉래홀(대공연장) |
영도문화예술회관 봉래홀 |
둘 다 괄호가 걸렸다. 나레이션에만 걸리는 금지문자 규칙(( ) 금지)을 모델이 metadata까지
적용한 것으로 보인다. 밸리데이터는 나레이션만 검사하므로 그대로 통과한다.
영상에는 영향이 없다. date_text·place는 아카이브 메타태그일 뿐 TTS도 렌더도 쓰지 않는다. 문제는 신호 쪽이다 — 모델이 표기를 그대로 옮기지 않고 "정리"하고 있다는 뜻이고, 같은 메커니즘이 숫자·지명에 걸리면 연도 오독(2026→2036)처럼 조용히 틀린 값이 아카이브에 남는다.
프롬프트에서 metadata는 금지문자 규칙 대상이 아니며 괄호까지 그대로 옮기라고 못박아야 한다.
⑤ bgm
Suno가 요청한 길이를 무시하고 풀 트랙을 준다
festival_poster_image 실측 — [Song Duration: Around 15 seconds]를 넣었는데 128초짜리가
왔다. 트랙 선택은 목표 길이에 가장 가까운 것을 고르지만, 후보가 전부 길면 소용이 없다.
⑦이 그 트랙의 앞부분을 영상 길이만큼 잘라 쓴다. 어디가 쓸 만한 구간인지는 보지 않으므로 인트로가 걸리면 그대로 인트로가 깔린다.
⑥ i2v
CLI와 HTTP API가 서로 다른 모델을 준다
이식한 코드는 higgsfield CLI를 서브프로세스로 부른다. CLI 토큰 인증이라 머신마다 사람이
로그인해야 하고 컨테이너 배포가 막힌다. 공식 SDK(higgsfield-client)는 API 키를 쓰므로
그 문제가 없고 업로드도 presigned URL이라 로컬 파일이 필요 없다.
그런데 openapi.json 확인 결과 API에 Kling 3.0이 없다. 2.1과 2.5-turbo뿐이다.
| CLI | HTTP API | |
|---|---|---|
| 모델 | kling3_0 | kling-video 2.5-turbo까지 |
| duration | 정수 자유 (8 사용) | 5 또는 10만 |
| aspect_ratio | 지정 가능 | 파라미터 없음 |
| sound | off 지정 가능 | 파라미터 없음 |
| 비용 사전조회 | generate cost |
없음 |
duration 5/10이 걸림돌이다. 파이프라인 전체가 8초 고정을 전제로 한다 — ②의 "7초 안에 읽혀야 한다", ④ 타임라인, ⑤ BGM 길이가 모두 거기서 나왔다.
aspect_ratio·sound는 실질 문제가 아닐 수 있다. Kling은 9:16을 지정해도 입력 이미지 비율로 출력하고, 오디오는 렌더에서 새로 얹는다.
비용 사전조회가 없는 것은 실질 손실이다. max_credits 오설정 방어가 사라진다.
결정: CLI를 유지한다. 8초와 Kling 3.0을 지키는 쪽을 택했고, 서브프로세스·머신별 로그인· 컨테이너 제약은 그 대가로 안고 간다. API가 8초나 Kling 3.0을 지원하면 그때 다시 본다.
배포에 Node 런타임이 딸려온다
@higgsfield/cli가 npm 패키지라 파이썬 이미지에 바이너리 하나 때문에 Node를 통째로 넣어야
한다. 이미지 안에서 higgsfield auth login을 사람이 할 수 없으므로
~/.config/higgsfield/credentials.json을 볼륨이나 시크릿으로 주입하는 방식이 된다.
토큰 만료·계정 전환을 배포 파이프라인이 감당해야 한다.
CLI 버전을 고정하지 않았다
npm i -g @higgsfield/cli는 항상 최신을 깐다. utils/higgsfield.py가 --json을 주고도
정규식으로 stdout을 긁는 이유가 원본 주석에 있다 — "--json이 평문을 돌려줄 때가 있다".
출력 포맷이 바뀌면 parse_result_url과 parse_credits가 함께 깨진다.
계정 가드는 CLI 경로에만 필요하다
utils/higgsfield.py의 assert_account()는 CLI 토큰이 조용히 바뀌어 남의 크레딧이 빠지는
사고를 막는 장치다. API 키로 가면 키가 곧 계정이라 이 가드 자체가 불필요해진다.
higgsfield_account 설정도 같이 없어진다.
생성부를 실행 검증하지 못했다
이 머신에 higgsfield CLI가 없다. result_url·credits 정규식 파싱은 원본을 옮겼을 뿐
실제 CLI 출력으로 확인한 것이 아니다.