codebee 0.1.72 → 0.1.73
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/CHANGELOG.md +6 -0
- package/README.md +4 -4
- package/app/core/flows.py +1 -1
- package/app/core/jobs.py +4 -1
- package/app/core/manager.py +68 -3
- package/app/core/market.py +2 -2
- package/app/core/paihang.py +8 -1
- package/app/core/planner.py +2 -0
- package/app/core/plugins.py +34 -0
- package/app/core/publish/flow.py +54 -3
- package/app/core/publish/manager.py +215 -28
- package/app/core/publish/qimao.py +30 -0
- package/app/core/skillpacks/fanqie-novel.md +66 -48
- package/app/core/skillpacks/qimao-signing.md +70 -59
- package/app/main.py +24 -28
- package/app/ui/app.js +270 -79
- package/app/ui/i18n.js +17 -2
- package/app/ui/index.html +3 -3
- package/app/ui/style.css +7049 -7040
- package/package.json +1 -1
|
@@ -382,6 +382,108 @@ def probe_form_async(plat):
|
|
|
382
382
|
|
|
383
383
|
|
|
384
384
|
# ---------------------------------------------------------------- 动作:建书
|
|
385
|
+
_ALT_COUNT = 3 # 撞名后自动换名最多试 3 个候选
|
|
386
|
+
_ALT_TIMEOUT = 90 # 候选书名一次轻调用的墙钟(发布线程内,不能久等)
|
|
387
|
+
_TITLE_MAX = 15 # 两平台书名统一截 15 字(bookmeta._norm 同口径)
|
|
388
|
+
|
|
389
|
+
|
|
390
|
+
def _mech_titles(base):
|
|
391
|
+
"""机械变体兜底(模型不可用时的最后手段):最小改动、不重构词——
|
|
392
|
+
同音字(了→啦)、去「我的」前缀、加「纪事」尾。丑但能建成书,
|
|
393
|
+
烧在发布线程里的几万字稿费比书名门面贵得多。"""
|
|
394
|
+
out, seen = [], {base}
|
|
395
|
+
for v in (base.replace("了", "啦", 1),
|
|
396
|
+
base[2:] if base.startswith("我的") else "",
|
|
397
|
+
(base + "纪事") if len(base) <= 13 else ""):
|
|
398
|
+
v = str(v or "").strip()[:_TITLE_MAX]
|
|
399
|
+
if len(v) >= 4 and v not in seen:
|
|
400
|
+
out.append(v)
|
|
401
|
+
seen.add(v)
|
|
402
|
+
return out
|
|
403
|
+
|
|
404
|
+
|
|
405
|
+
def _alt_titles(plat, data, task, logs):
|
|
406
|
+
"""撞名候选队列:编排者基于原名+简介一次轻调用重出书名,失败静默
|
|
407
|
+
降级机械变体——候选生成绝不能阻断建书主流程。"""
|
|
408
|
+
base = str(data.get("book_name") or "").strip()
|
|
409
|
+
if not base:
|
|
410
|
+
return []
|
|
411
|
+
out = []
|
|
412
|
+
try:
|
|
413
|
+
from .. import modelhub, planner, runner
|
|
414
|
+
orch = modelhub.resolve_orchestrator()
|
|
415
|
+
if orch:
|
|
416
|
+
prov, model = orch
|
|
417
|
+
prompt = (
|
|
418
|
+
"你是网文编辑。原书名《%s》在平台重名被拒,请为同一本书重起"
|
|
419
|
+
" %d 个新书名:每个 15 字内;保持原题材气质与钩子感;避开原名"
|
|
420
|
+
"的核心词组合与「我的XX藏不住」式高频套路组合;书名里带一个本"
|
|
421
|
+
"书独有的专名(人名/金手指/设定词)最不易再撞。只输出一个 "
|
|
422
|
+
"```json 字符串数组,如 [\"书名1\",\"书名2\"],不要输出其它内容。"
|
|
423
|
+
"\n\n## 简介(截选)\n%s"
|
|
424
|
+
% (base, _ALT_COUNT + 2, str(data.get("summary") or "")[:300]))
|
|
425
|
+
res = modelhub.chat(prov["id"], model, prompt,
|
|
426
|
+
max_tokens=600, timeout=_ALT_TIMEOUT)
|
|
427
|
+
planner._log_usage("publish", "create_book", task or {"id": ""}, res,
|
|
428
|
+
model=model,
|
|
429
|
+
provider=prov.get("name", prov.get("id", "")),
|
|
430
|
+
provider_id=prov.get("id", ""))
|
|
431
|
+
if res["ok"]:
|
|
432
|
+
arr = runner.extract_json(res.get("text") or "")
|
|
433
|
+
if isinstance(arr, dict):
|
|
434
|
+
arr = arr.get("titles") or arr.get("candidates") or []
|
|
435
|
+
if isinstance(arr, list):
|
|
436
|
+
for x in arr:
|
|
437
|
+
t = str(x or "").strip().replace("\n", " ")[:_TITLE_MAX]
|
|
438
|
+
if len(t) >= 2 and t != base and t not in out:
|
|
439
|
+
out.append(t)
|
|
440
|
+
if out:
|
|
441
|
+
logs.append("候选书名(编排者 %s):%s"
|
|
442
|
+
% (model, "、".join(out[:5])))
|
|
443
|
+
except Exception as e:
|
|
444
|
+
logs.append("候选书名生成降级(%s)" % str(e)[:100])
|
|
445
|
+
for v in _mech_titles(base):
|
|
446
|
+
if v not in out:
|
|
447
|
+
out.append(v)
|
|
448
|
+
return out[:_ALT_COUNT + 2]
|
|
449
|
+
|
|
450
|
+
|
|
451
|
+
def _sync_renamed_book(task_id, plat, task, data, new_name, logs):
|
|
452
|
+
"""建书撞名自动换名后的全链路同步。
|
|
453
|
+
|
|
454
|
+
只换建书表单里的字、bookmeta/大纲/归档还留旧名的话:下轮发章按旧书名
|
|
455
|
+
对账、用户点「重生成作品信息」又把旧名改回去——马甲案同款错位复发。
|
|
456
|
+
这里把 bookmeta data、归档 Markdown、最新批次大纲的 book_title 统一到
|
|
457
|
+
新名(台账 title 由调用方 save_book 落)。任一环节失败只记日志,
|
|
458
|
+
不拦建书成功主流程。"""
|
|
459
|
+
try:
|
|
460
|
+
from pathlib import Path as _Path
|
|
461
|
+
from .. import bookmeta as _bm
|
|
462
|
+
from .. import store as _store
|
|
463
|
+
data["book_name"] = new_name
|
|
464
|
+
cur = _store.get_task(task_id)
|
|
465
|
+
prev = ((cur or {}).get("book_meta") or {}).get(plat) or {}
|
|
466
|
+
if isinstance(prev.get("data"), dict):
|
|
467
|
+
payload = dict(prev)
|
|
468
|
+
payload["data"] = dict(prev["data"], book_name=new_name)
|
|
469
|
+
_store.set_book_meta(task_id, plat, payload)
|
|
470
|
+
fp = _Path(task.get("workdir") or "") / _bm.PLATFORMS[plat]["file"]
|
|
471
|
+
if str(fp.parent) and fp.parent.is_dir():
|
|
472
|
+
fp.write_text(_bm.render_markdown(cur, plat, payload["data"]),
|
|
473
|
+
encoding="utf-8")
|
|
474
|
+
logs.append("作品信息与归档已同步新书名《%s》" % new_name)
|
|
475
|
+
# 大纲书名:续写链继承与「一键重生成」素材都读最新批次大纲,
|
|
476
|
+
# 不同步会让下次重生成把书名改回旧名
|
|
477
|
+
for r in _store.task_runs(task_id):
|
|
478
|
+
o = r.get("outline")
|
|
479
|
+
if isinstance(o, dict) and o.get("chapters") and o.get("book_title"):
|
|
480
|
+
_store.update_run(r["id"], outline=dict(o, book_title=new_name))
|
|
481
|
+
logs.append("大纲书名已同步为《%s》" % new_name)
|
|
482
|
+
break
|
|
483
|
+
except Exception as e:
|
|
484
|
+
logs.append("书名同步部分失败(不拦建书):%s" % str(e)[:120])
|
|
485
|
+
|
|
486
|
+
|
|
385
487
|
def _create_preflight(plat, data):
|
|
386
488
|
"""建书前置闸:平台表单对必填字段有硬校验(番茄简介 50-500 字),过不了
|
|
387
489
|
校验时页面不跳转、流程只能误报「未登录或改版」——开浏览器之前先拦下,
|
|
@@ -462,33 +564,101 @@ def create_book_async(task_id, plat, auto_submit=False, force=False,
|
|
|
462
564
|
metadata={"platform": plat, "action": "create_book"})
|
|
463
565
|
|
|
464
566
|
def run():
|
|
567
|
+
final_name = book_name
|
|
465
568
|
try:
|
|
466
569
|
b, page = _open_page(plat)
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
# book_id:创建成功后平台跳书籍详情/编辑器,从 URL 提取
|
|
475
|
-
# (番茄 book-info/<id>;七猫 information?id=<id>)。url_any 过了
|
|
476
|
-
# 但页面还在跳转链上时再等几轮;提取落空把最终 URL 记进日志,
|
|
477
|
-
# 别再静默登记空 id(发章只能兜底找书,直达编辑器就废了)。
|
|
570
|
+
# 书名全平台唯一(2026-09-30 马甲案):撞名是建书常见死法,撞了
|
|
571
|
+
# 原样报「疑似未建成」会白烧几万字稿费。试名队列=原名+自动候选
|
|
572
|
+
# (编排者重出→机械变体兜底);同名书恰在本账号下时对账复用不换
|
|
573
|
+
# 名。人工提交模式(auto_submit=false)不自动换名——用户在页面
|
|
574
|
+
# 上自己点提交,撞名他自己看得见。
|
|
575
|
+
names = [book_name]
|
|
576
|
+
cands_ready = False
|
|
478
577
|
book_id = ""
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
578
|
+
i = 0
|
|
579
|
+
while i < len(names) and i < 1 + _ALT_COUNT + 2:
|
|
580
|
+
name = names[i]
|
|
581
|
+
i += 1
|
|
582
|
+
final_name = name
|
|
583
|
+
if i > 1:
|
|
584
|
+
logs.append("第 %d 次尝试,书名《%s》" % (i, name))
|
|
585
|
+
values = mod.values_create_book(dict(data, book_name=name))
|
|
586
|
+
steps = _with_tag_steps(load_flow(plat, "create_book"),
|
|
587
|
+
mod.tag_groups(data), values, mod)
|
|
588
|
+
try:
|
|
589
|
+
flow.run_flow(page, steps, values=values, config=mod.CONFIG,
|
|
590
|
+
auto_submit=auto_submit, dup_check=auto_submit,
|
|
591
|
+
shot=lambda n: page.screenshot(
|
|
592
|
+
ledger.shot_path(plat, task_id, n)),
|
|
593
|
+
log=logs.append)
|
|
594
|
+
except flow.TitleDupError as e:
|
|
595
|
+
# 事前预检命中:平台实时校验已喊重名,点提交必被拒
|
|
596
|
+
logs.append(str(e))
|
|
597
|
+
bid = _resolve_book_id(plat, page, {"title": name})
|
|
598
|
+
if bid:
|
|
599
|
+
book_id, final_name = bid, name
|
|
600
|
+
logs.append("同名书就在本账号下,已复用 book_id=%s" % bid)
|
|
485
601
|
break
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
602
|
+
if not cands_ready:
|
|
603
|
+
names = names + _alt_titles(plat, data, task, logs)
|
|
604
|
+
cands_ready = True
|
|
605
|
+
if i >= len(names):
|
|
606
|
+
break # 候选没准备出来(模型+机械全空)
|
|
607
|
+
continue
|
|
608
|
+
# book_id:创建成功后平台跳书籍详情/编辑器,从 URL 提取
|
|
609
|
+
# (番茄 book-info/<id>;七猫 information?id=<id>)。url_any 过了
|
|
610
|
+
# 但页面还在跳转链上时再等几轮;提取落空把最终 URL 记进日志,
|
|
611
|
+
# 别再静默登记空 id(发章只能兜底找书,直达编辑器就废了)。
|
|
612
|
+
try:
|
|
613
|
+
for _try in range(6):
|
|
614
|
+
m_url = re.search(r"book-info/(\d+)|information\?id=(\d+)",
|
|
615
|
+
str(page.url() or ""))
|
|
616
|
+
if m_url:
|
|
617
|
+
book_id = m_url.group(1) or m_url.group(2)
|
|
618
|
+
break
|
|
619
|
+
time.sleep(0.8)
|
|
620
|
+
if not book_id:
|
|
621
|
+
logs.append("book_id 提取落空,最终页面:%s"
|
|
622
|
+
% str(page.url() or "")[:120])
|
|
623
|
+
except Exception:
|
|
624
|
+
pass
|
|
625
|
+
if book_id:
|
|
626
|
+
break
|
|
627
|
+
if not auto_submit:
|
|
628
|
+
# 人工提交模式:按书名对账兜底即止,不自动换名
|
|
629
|
+
bid = _resolve_book_id(plat, page, {"title": name})
|
|
630
|
+
if bid:
|
|
631
|
+
book_id = bid
|
|
632
|
+
logs.append("book_id 提取落空,已按书名在平台对账找回 %s" % bid)
|
|
633
|
+
break
|
|
634
|
+
# 自动提交被平台静默拒绝(不跳转)时,toast 常喊重名——抓
|
|
635
|
+
# 回来判定,别落进「疑似未建成」的糊涂账
|
|
636
|
+
hint = ""
|
|
637
|
+
for _try in range(3):
|
|
638
|
+
hint = flow.dup_hint(page)
|
|
639
|
+
if hint:
|
|
640
|
+
break
|
|
641
|
+
time.sleep(1.0)
|
|
642
|
+
if hint:
|
|
643
|
+
logs.append("页面提示:%s" % hint[:120])
|
|
644
|
+
bid = _resolve_book_id(plat, page, {"title": name})
|
|
645
|
+
if bid:
|
|
646
|
+
book_id, final_name = bid, name
|
|
647
|
+
logs.append("同名书就在本账号下,已复用 book_id=%s" % bid)
|
|
648
|
+
break
|
|
649
|
+
if not cands_ready:
|
|
650
|
+
names = names + _alt_titles(plat, data, task, logs)
|
|
651
|
+
cands_ready = True
|
|
652
|
+
continue
|
|
653
|
+
# 非撞名失败:按书名对账兜底(原有逻辑),找不回就明说未建成
|
|
654
|
+
bid = _resolve_book_id(plat, page, {"title": name})
|
|
655
|
+
if bid:
|
|
656
|
+
book_id = bid
|
|
657
|
+
logs.append("book_id 提取落空,已按书名在平台对账找回 %s" % bid)
|
|
658
|
+
break
|
|
659
|
+
if book_id and final_name != book_name:
|
|
660
|
+
# 换名成功(或复用同名旧书):书名全链路同步到新名
|
|
661
|
+
_sync_renamed_book(task_id, plat, task, data, final_name, logs)
|
|
492
662
|
operation_status = "confirmed" if book_id else "unknown"
|
|
493
663
|
if book_id:
|
|
494
664
|
operations.confirm(operation_id, remote_receipt=book_id,
|
|
@@ -496,18 +666,23 @@ def create_book_async(task_id, plat, auto_submit=False, force=False,
|
|
|
496
666
|
else:
|
|
497
667
|
operations.mark_unknown(
|
|
498
668
|
operation_id,
|
|
499
|
-
"
|
|
669
|
+
"建书流程走完,但平台作品列表按书名未找到《%s》,书很可能未建成;"
|
|
670
|
+
"请到平台作品管理确认,若已存在可人工登记" % final_name,
|
|
500
671
|
metadata={"platform": plat, "action": "create_book"})
|
|
501
|
-
ledger.record(plat, "create_book", task_id=task_id, title=
|
|
672
|
+
ledger.record(plat, "create_book", task_id=task_id, title=final_name,
|
|
502
673
|
book_id=book_id, ok=bool(book_id),
|
|
503
674
|
error=((("" if book_id else
|
|
504
|
-
"
|
|
675
|
+
"建书流程走完但未取得 book_id,且平台按书名未找到"
|
|
676
|
+
"《%s》,疑似未建成\n" % final_name)
|
|
505
677
|
+ "\n".join(logs))[:2000] or None),
|
|
506
678
|
shot=str(ledger.shot_path(plat, task_id, "")),
|
|
507
679
|
operation_id=operation_id, operation_status=operation_status,
|
|
508
680
|
remote_receipt=book_id)
|
|
509
|
-
|
|
510
|
-
|
|
681
|
+
if book_id:
|
|
682
|
+
# 未取得 id 不落台账:空条目会让界面亮「已建书」、校准盲跑,
|
|
683
|
+
# 而发章/下次建书各自有按书名对账的兜底,空条目只剩害处。
|
|
684
|
+
ledger.save_book(task_id, plat, {"book_id": book_id, "title": final_name,
|
|
685
|
+
"source": "create"})
|
|
511
686
|
_set(plat, status="connected", error="")
|
|
512
687
|
except Exception as e:
|
|
513
688
|
operations.finish_exception(operation_id, e)
|
|
@@ -856,6 +1031,18 @@ def sync_published(task_id, plat, manual=False):
|
|
|
856
1031
|
page = b.first_page(create=True)
|
|
857
1032
|
except Exception as e:
|
|
858
1033
|
return False, "浏览器未连接,点「连接平台」后再校准"
|
|
1034
|
+
if not str(book.get("book_id") or "").strip():
|
|
1035
|
+
# book_id 空的登记(人工登记/未验证建书结果)别拿去拼 URL 盲跑:
|
|
1036
|
+
# 空 id 会落到作品列表页,数章节必然 0 行,报一句误导人的「可能改版」。
|
|
1037
|
+
# 先按书名对账,找回补账再校准;找不回就明说书可能没建成。
|
|
1038
|
+
bid = _resolve_book_id(plat, page, book)
|
|
1039
|
+
if bid:
|
|
1040
|
+
book = dict(book, book_id=bid)
|
|
1041
|
+
ledger.save_book(task_id, plat, book) # 合并语义:保留 remote_*
|
|
1042
|
+
else:
|
|
1043
|
+
return False, ("平台作品列表按书名未找到《%s》,这本书可能尚未建成;"
|
|
1044
|
+
"请到平台作品管理确认,若已存在可人工登记"
|
|
1045
|
+
% (book.get("title") or ""))
|
|
859
1046
|
try:
|
|
860
1047
|
page.navigate(mod.chapter_manage_url(book), timeout=40)
|
|
861
1048
|
time.sleep(4.0) # SPA 表格慢渲染
|
|
@@ -125,6 +125,36 @@ def chapter_manage_url(book):
|
|
|
125
125
|
return CONFIG["book_manage"]
|
|
126
126
|
|
|
127
127
|
|
|
128
|
+
def resolve_book_id(page, book):
|
|
129
|
+
"""登记缺 book_id 时按书名在作品管理页找回:点书名卡进详情,从 URL 提取。
|
|
130
|
+
|
|
131
|
+
与番茄同款对账通道(fanqie.resolve_book_id);找不回返回空串不拦死。"""
|
|
132
|
+
import re
|
|
133
|
+
import time
|
|
134
|
+
from . import flow as _flow
|
|
135
|
+
title = str((book or {}).get("title") or "").strip()
|
|
136
|
+
if not title:
|
|
137
|
+
return ""
|
|
138
|
+
try:
|
|
139
|
+
page.navigate(CONFIG["book_manage"], timeout=30)
|
|
140
|
+
except Exception:
|
|
141
|
+
return ""
|
|
142
|
+
r = None
|
|
143
|
+
for _try in range(6): # 列表慢渲染
|
|
144
|
+
r = page.call(_flow._click_match_js(), [title], 300)
|
|
145
|
+
if (r or {}).get("ok"):
|
|
146
|
+
break
|
|
147
|
+
time.sleep(1.0)
|
|
148
|
+
if not (r or {}).get("ok"):
|
|
149
|
+
return ""
|
|
150
|
+
time.sleep(2.5) # 跳转收尾
|
|
151
|
+
m = re.search(r"manage\?id=(\d+)|draft\?id=(\d+)|information\?id=(\d+)",
|
|
152
|
+
str(page.url() or ""))
|
|
153
|
+
if not m:
|
|
154
|
+
return ""
|
|
155
|
+
return m.group(1) or m.group(2) or m.group(3) or ""
|
|
156
|
+
|
|
157
|
+
|
|
128
158
|
def draft_url(book):
|
|
129
159
|
"""草稿箱页(发章真发布链中转站)。"""
|
|
130
160
|
bid = str((book or {}).get("book_id") or "")
|
|
@@ -1,63 +1,69 @@
|
|
|
1
1
|
# 番茄小说写作与流量守则(内置经验包)
|
|
2
2
|
|
|
3
|
-
来源:番茄作家社区与作者群体的通行经验汇编 + 平台公开运营机制(2025
|
|
3
|
+
来源:番茄作家社区与作者群体的通行经验汇编 + 平台公开运营机制(2025,B/C 级经验材料);
|
|
4
|
+
可复查入口:[番茄作家后台](https://fanqienovel.com/main/writer/)(当前政策以登录后页面为准)。
|
|
4
5
|
签约字数、保底金额、全勤门槛、审核时长等**政策数字随年份调整,一律以「番茄作家后台」当前规则为准**,
|
|
5
6
|
本包不固化具体数值。这是写作参考,不是官方规则,也不是爆款预测;不以格式检查推断过签/起量概率。
|
|
6
7
|
|
|
7
|
-
##
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
-
|
|
11
|
-
|
|
12
|
-
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
-
|
|
29
|
-
-
|
|
30
|
-
|
|
8
|
+
## 证据等级与使用边界(2026-09-30 更新)
|
|
9
|
+
|
|
10
|
+
- **A级:当前后台/合同/官方公告**:用于确认投稿、签约、更新、版权和内容红线;公开经验不能覆盖当前页面。
|
|
11
|
+
- **B级:多作者经验、编辑反馈或后台数据**:只作为可检验的诊断假设,必须写明样本、章节范围和下一步实验。
|
|
12
|
+
- **C级:单个案例、固定字数或传闻算法权重**:不作硬门槛,不宣称推荐、签约或收入因果;没有样本就保留为待验证。
|
|
13
|
+
- 质量报告按“文本质量 → 平台适配 → 当前政策”分层。每个结论都给出证据位置、未知项和可逆改动;完读率、追读率等数字是定位线索,不是文学评分。
|
|
14
|
+
|
|
15
|
+
### 番茄与通用质量底线
|
|
16
|
+
|
|
17
|
+
先检查具体事件是否触发主角主动选择,并产生可见后果、阶段性兑现和新的问题;再检查人物动机、因果连续性、文风一致、移动端可读性与内容安全。算法指标不能替代逐章阅读,也不能把“数据暂时好”写成质量已证实。
|
|
18
|
+
|
|
19
|
+
## 〇、与传统编辑平台的差异(工作假设,非权重说明)
|
|
20
|
+
- 番茄可按“数据参与分发”的工作假设来设计实验;这不等于知道算法权重,也不等于签约后完全无人审查。
|
|
21
|
+
“签约只是门票、完读率/追读率影响后续分发”是作者社区的工作假设,不能据此断言推荐权重或作品成败。
|
|
22
|
+
- 作者社区常用“免费阅读、碎片时间、切换成本低”描述部分读者场景;这是受众假设,不代表所有番茄读者。
|
|
23
|
+
可按“书名 → 简介/标签 → 第一章 → 前三章”检查作品承诺是否连贯,但不预设各环节转化率。
|
|
24
|
+
- 作者材料通常将番茄描述为免费阅读与广告变现模式,合同也可能包含保底/全勤;具体收入来源、结算和资格以当前平台说明及合同为准。
|
|
25
|
+
追读、留存和阅读时长可以帮助定位问题,但不能直接换算成收益、推荐因果,也不能推出“追读率 > 文笔”或任何平台保证。
|
|
26
|
+
|
|
27
|
+
## 一、新书观察:流量池与数据指标
|
|
28
|
+
- “先小范围试读、再按数据扩大分发”是作者对新书的常用工作假设;推荐路径和权重不可见,不能写成算法事实。
|
|
29
|
+
- “前 30 天”只能作为一个可调整的早期观察窗口;具体窗口随频道、发书节奏和样本量变化,不是定生死的硬线。
|
|
30
|
+
- 后台常见观察指标(名称与定义以作家后台实际展示为准):完读、追读、留存、平均阅读时长;
|
|
31
|
+
报告使用平台给出的定义,不根据经验帖自行推导指标口径。它们是诊断线索,不能代替因果证据。
|
|
32
|
+
- 数据异常可先按段落提出假设:第一章完读偏低就复查开篇,中段下滑就复查节奏/兑现,
|
|
33
|
+
章末流失就复查钩子与承诺回收;题材、流量、样本量和发布节奏也可能影响结果,需逐项复验。
|
|
34
|
+
- 反恐慌纪律:头几天样本小、噪声大,不要用单日波动证明改稿有效;达到可解释的样本后,按段落和读者反馈做小步实验。是否重写、重开或继续,需结合作者成本、合同和目标,不给“48 小时/两周切书”固定建议。
|
|
35
|
+
|
|
36
|
+
## 二、开篇(前三章观察框架,不是平台硬门槛)
|
|
37
|
+
- 作者经验常用**前三章**做完读与追读对照:第一章交代钩子、第二章兑现核心设定、
|
|
38
|
+
第三章完成一个故事单元;缺一章不等于必然失败,须结合样本与正文证据。
|
|
39
|
+
- 前 100/600 字可作为阅读负担取样点:记录主角、冲突和困境何时出现,不把位置数字当硬门槛。
|
|
40
|
+
- 世界观说明文、慢热日常、多视角群像和倒叙解谜可列为待验证风险;不能直接把某种写法归因成数据崩溃。
|
|
31
41
|
|
|
32
42
|
## 三、节奏与爽点
|
|
33
|
-
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
-
|
|
38
|
-
追读率就会肉眼可见地掉。
|
|
39
|
-
- 跨平台通用的铁律仍然有效:主角主观能动性红线、打压为爆发服务、反派不能无脑。
|
|
43
|
+
- **每章应有可感知的变化、情绪波动或兑现,并留下可追问的下一步**;1800-2500 字可作为一次节奏实验的起点,按题材、章节目标和后台数据调整,**不作硬门槛**。
|
|
44
|
+
- 建议先用一句话说明主线目标和下一步;多线叙事、慢热铺垫可列为待验证风险,
|
|
45
|
+
先用章节目标、读者反馈和后台分段数据复核,不预设结果。
|
|
46
|
+
- 早期长线应安排一次完整的大兑现(打脸/升级/身份跃迁等),具体章节不固定;连续多个章节无兑现时,先回到事件、选择、后果链查找原因,不把数据变化直接归因于某个数字。
|
|
47
|
+
- 跨平台复查维度:主角是否有选择,阻碍是否有因果,对手是否有动机;具体呈现不强制一种人物模板。
|
|
40
48
|
|
|
41
49
|
## 四、题材、书名、标签与简介
|
|
42
|
-
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
书名、简介、标签三者对题材的表达必须一致(算法按这些做人群匹配)。
|
|
50
|
+
- 经验材料提及过的题材仅作历史参照,不当当前热度结论;开书前按当季榜单和作者后台实际类目复核,
|
|
51
|
+
再判断题材与目标读者是否匹配。
|
|
52
|
+
- **分类/标签是作者常用的匹配入口假设**:挂错分类可能造成承诺与读者预期错位,但实际推荐机制不可见。
|
|
53
|
+
书名、简介、标签三者应与正文题材一致;不要把一致性检查写成已知算法规则。
|
|
47
54
|
- 书名策略:长尾、带情绪、带题材关键词;简介三要素:身份处境 + 核心冲突 + 悬念钩子。
|
|
48
55
|
|
|
49
|
-
##
|
|
50
|
-
-
|
|
51
|
-
|
|
52
|
-
- 存稿 ≥10 万字再发书;新书期若存稿允许,日双更冲数据——推荐系统吃"活跃 + 追读"信号。
|
|
56
|
+
## 五、更新纪律(可持续性优先)
|
|
57
|
+
- **稳定更新是可检验的生产策略,不是推荐保证**:断更会影响读者预期,但全勤和推荐条件必须以当前合同/后台为准。
|
|
58
|
+
- 存稿量、日更频率和是否双更按作者的可持续产能、章节质量和当前规则设定;“10 万字存稿”等经验数字不作硬门槛。
|
|
53
59
|
- 卡文宁可降纲不降质:拆未来 3 章的单元(目标→行动→阻碍→反转),别水字数糊弄——
|
|
54
|
-
|
|
60
|
+
水章可能在完读或读者反馈中暴露,但必须记录样本和改动范围再下结论。
|
|
55
61
|
|
|
56
62
|
## 六、签约与合同
|
|
57
63
|
- 申请门槛(字数)、审核时长以作家后台当前规则为准;常见审核材料 = 开篇正文 + 大纲,
|
|
58
64
|
大纲别只写一句"后面上架爆火",要有明确的阶段目标与兑现节点。
|
|
59
|
-
-
|
|
60
|
-
|
|
65
|
+
- 分成、保底及其他合作模式以当前后台可选项和合同为准;签前逐条核对影视/动漫/版权衍生授权范围、
|
|
66
|
+
独家义务、违约与解约条款,不沿用经验帖中的金额或比例。
|
|
61
67
|
- 拒签自救:先归因(题材带匹配?开篇数据思维?大纲兑现链缺失?),改完再申;
|
|
62
68
|
同一作品反复无修改重投没有意义。
|
|
63
69
|
|
|
@@ -69,12 +75,24 @@
|
|
|
69
75
|
- **细节刻画力度**:每个爽点/反转标记"特写镜头",五感 + 微动作 + 环境反馈把爆发那几秒写厚,
|
|
70
76
|
铺垫在前、放大在中、余波在后;过渡章才可一笔带过。**"每章一小爽"不配特写等于没写**。
|
|
71
77
|
|
|
72
|
-
##
|
|
78
|
+
## 八、后台数据诊断卡(仅在样本足够时使用)
|
|
79
|
+
|
|
80
|
+
| 观察到的信号 | 先检查的文本假设 | 可逆动作 | 复验方式 |
|
|
81
|
+
| --- | --- | --- | --- |
|
|
82
|
+
| 第一章完读偏低 | 冲突/主角/承诺是否晚于读者耐心 | 只改开篇一个变量 | 对照后续同类章节或下一批样本 |
|
|
83
|
+
| 中段明显下滑 | 目标、阻碍和兑现是否断档 | 收紧一个故事单元 | 看后续章节完读与反馈是否同步改善 |
|
|
84
|
+
| 章末到下一章流失 | 章尾问题是否可追问、前文承诺是否兑现 | 重写章尾或补回收 | 观察下一章首段和追读变化 |
|
|
85
|
+
| 标签/简介点击与阅读不匹配 | 作品承诺与正文是否错位 | 先修承诺或分类,不同时改正文 | 记录改动范围后再看数据 |
|
|
86
|
+
|
|
87
|
+
没有样本、后台指标含义不明或同时改了多个变量时,结论标为“证据不足”,不宣称掌握推荐权重。
|
|
88
|
+
|
|
89
|
+
## 九、开书/投稿前自检清单
|
|
73
90
|
- [ ] 书名/标签/简介一致表达题材,分类挂对
|
|
74
91
|
- [ ] 第 1 章前 100 字冲突进场;前三章 = 钩子 + 设定兑现 + 完整爽点闭环
|
|
75
|
-
- [ ]
|
|
92
|
+
- [ ] 每章有可感知的变化/情绪或兑现,章尾留下可追问的问题;字数仅作节奏实验,不作硬门槛
|
|
76
93
|
- [ ] 主线一句话讲得清,单线推进,无慢热铺垫章节
|
|
77
|
-
- [ ]
|
|
78
|
-
- [ ]
|
|
94
|
+
- [ ] 早期长线有一次大兑现闭环的规划(章节位置可调整)
|
|
95
|
+
- [ ] 存稿和日更承诺可持续,并已核对当前合同/后台(不套用固定数字)
|
|
79
96
|
- [ ] 文笔三词(风格统一/流畅/细节力度)逐章自查过
|
|
80
97
|
- [ ] 合同衍生授权与独家条款已看清
|
|
98
|
+
- [ ] 后台数据只用于分段诊断,未把单次波动写成算法权重或签约结论
|