sns-auto-builder 1.1.0 → 1.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sns-auto-builder",
3
- "version": "1.1.0",
3
+ "version": "1.1.2",
4
4
  "description": "인스타 카드뉴스 자동 제작 빌더. Claude Code + ChatGPT 웹을 그대로 써서 API 키 없이 돌아갑니다.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -286,9 +286,12 @@ async function sendPrompt(page, text) {
286
286
  // 여러 장이 나왔으면 경고를 남긴다 — 프롬프트가 다장 생성을 유도했다는 신호다.
287
287
  const SETTLE_MS = 12_000; // 개수가 이만큼 안 늘면 그 턴은 끝난 것으로 본다
288
288
 
289
- // 응답하는 동안 뜨는 "답변 중지" 버튼. 생성 중이라는 뜻이지만 **끝났다는 뜻으로는 못 쓴다** —
290
- // 답변이 다 나온 뒤에도 이 버튼이 5분 넘게 남아 있는 걸 실측했다. 그래서 이 신호로는
291
- // 절대 막지 않는다(막으면 멀쩡한 실행이 영원히 끝난다). 빨리 실패할 때만 참고한다.
289
+ // 응답하는 동안 뜨는 "답변 중지" 버튼.
290
+ //
291
+ // 보통은 응답이 끝나면 사라지지만, **안 사라진 굳는 경우가 있다** (생성 중에 페이지를
292
+ // 새로고침하면 그렇게 된다 — 실측). 그 상태에서는 Enter 가 아예 안 먹고 입력칸에 글자만
293
+ // 남는다. 그래서 이 신호로 실행을 막지는 않고(막으면 영원히 안 끝난다), 굳었으면
294
+ // clearBusy 로 풀고 간다.
292
295
  const STOP_BTN = '[data-testid="stop-button"]';
293
296
  const IDLE_GRACE_MS = 20_000; // 버튼이 실제로 사라진 뒤 이만큼 더 봤는데도 이미지가 없으면 실패
294
297
  const IDLE_WAIT_MS = 90_000; // 앞 턴을 기다려보는 상한. 넘으면 경고만 하고 그냥 보낸다
@@ -329,7 +332,10 @@ const readPageError = (page) => page.evaluate((needles) => {
329
332
  // 저장돼, 3장만 만들어졌는데 4장이 나온 것처럼 끝난 적이 있다.
330
333
  async function waitForNewImage(page, before, timeoutMs, used = new Set()) {
331
334
  const deadline = Date.now() + timeoutMs;
332
- let fresh = [], lastChange = 0, sawOnlyUsed = false, idleSince = 0;
335
+ // sawStreaming: 턴이 **실제로 시작된 본** 뒤에만 "끝났다" 판정을 믿는다.
336
+ // 전송 직후엔 stop 버튼이 아직 안 떠서, 그걸 끝난 걸로 보면 이미지 생성(25~40초)
337
+ // 도중에 20초 만에 실패 처리해버린다.
338
+ let fresh = [], lastChange = 0, sawOnlyUsed = false, idleSince = 0, sawStreaming = false;
333
339
  while (Date.now() < deadline) {
334
340
  const all = (await fileIds(page)).filter((id) => !before.includes(id));
335
341
  const now = all.filter((id) => !used.has(id));
@@ -341,12 +347,17 @@ async function waitForNewImage(page, before, timeoutMs, used = new Set()) {
341
347
  }
342
348
  if (now.length !== fresh.length) { fresh = now; lastChange = Date.now(); }
343
349
 
344
- // 턴이 끝났는지를 **먼저** 본다. 12초 settle 은 stop 버튼을 못 읽을 때의 보조 장치다.
345
350
  const streaming = await isStreaming(page);
346
- if (streaming) idleSince = 0;
347
- else if (!idleSince) idleSince = Date.now();
348
-
349
- if (fresh.length && (idleSince || Date.now() - lastChange >= SETTLE_MS)) {
351
+ if (streaming) { sawStreaming = true; idleSince = 0; }
352
+ else if (sawStreaming && !idleSince) idleSince = Date.now();
353
+
354
+ // 반환 조건은 **개수가 SETTLE_MS 동안 변한 것** 하나뿐이다.
355
+ //
356
+ // stop 버튼이 사라졌다고 바로 집으면 안 된다. ChatGPT 는 최종 이미지 전에 미리보기를
357
+ // 먼저 띄우는데, 그걸 최종본으로 착각하면 뒤늦게 나온 진짜 최종본을 **다음 장이**
358
+ // 가져가 전체가 한 칸씩 밀린다 (4번 자리에 3번 그림이 들어간 적이 있다).
359
+ // 미리보기가 최종본으로 바뀌면 개수가 변하므로 타이머가 다시 돌아 안전하다.
360
+ if (fresh.length && Date.now() - lastChange >= SETTLE_MS) {
350
361
  if (fresh.length > 1) {
351
362
  console.warn(` (경고) 한 프롬프트에 ${fresh.length}장이 생성됨 — 첫 장만 사용합니다.`);
352
363
  }