Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 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 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 | 1x 1x 4x 4x 1x 1x 4x 4x 4x 4x 4x 1x 1x 60x 60x 1x 3x 3x 3x 3x 3x 1x 1x 47x 47x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 14x 13x 13x 13x 13x 13x 13x 13x 13x 13x 13x 13x 13x 13x 13x 1x 14x 1x 13x 13x 1x 2x 2x 1x 2x 2x 1x 2x 2x 2x 2x 2x 2x 2x 2x 1x 4x 4x 4x 4x 4x 4x 4x 1x 1x 1x 1x | /**
* 书籍类型配置(黄金数 φ=1.618,基数13万)
* 规模值为精确字数,AI 生成时自行理解 ±20% 浮动
*/
// 通用浮动比例(可调整)
export const FLOAT_RATIO = 0.2; // 20%
// AI 生成时字数上限(基数 × 1.2)
export const getWordUpperLimit = (baseWords: number): number => {
return Math.round(baseWords * (1 + FLOAT_RATIO));
};
// 每章字数浮动比例(可调整)
export const CHAPTER_WORDS_FLOAT_RATIO = 0.5; // 50%
// 章节数浮动范围(根据 FLOAT_RATIO 计算,允许 ±20%)
export const getChapterRange = (targetChapters: number): { min: number; max: number } => {
return {
min: Math.floor(targetChapters * (1 - FLOAT_RATIO)),
max: Math.ceil(targetChapters * (1 + FLOAT_RATIO)),
};
};
// 根据总字数计算章节数(每章约 2千 字,可调整)
const WORDS_PER_CHAPTER = 2000;
export const calcChapters = (totalWords: number): number => {
return Math.max(1, Math.round(totalWords / WORDS_PER_CHAPTER));
};
// 每章字数浮动范围
export const getChapterWordsRange = (baseWords: number = WORDS_PER_CHAPTER): { min: number; max: number } => {
return {
min: Math.round(baseWords * (1 - CHAPTER_WORDS_FLOAT_RATIO)),
max: Math.round(baseWords * (1 + CHAPTER_WORDS_FLOAT_RATIO)),
};
};
// 每分钟音频对应的文本字数(可调整)
const WORDS_PER_MINUTE = 200;
// 根据总字数计算音频时长(分钟)
export const calcAudioMinutes = (totalWords: number): number => {
return Math.round(totalWords / WORDS_PER_MINUTE);
};
export interface BookTypeConfig {
key: string;
label: string;
description: string;
chapters: number;
totalWords: number;
chapterWords: number;
audioMinutes: number;
structureFormat: string;
readingDifficulty: string;
isShortArticle: boolean;
}
// 音频分钟数计算:totalWords / 200
export const BOOK_TYPE_CONFIG: Record<string, BookTypeConfig> = {
'340000': { key: '340000', label: '上2', description: '上2,约34万字', chapters: calcChapters(340000), totalWords: 340000, chapterWords: 9700, audioMinutes: calcAudioMinutes(340000), structureFormat: '单章完整', readingDifficulty: '高', isShortArticle: false },
'210000': { key: '210000', label: '上1', description: '上1,约21万字', chapters: calcChapters(210000), totalWords: 210000, chapterWords: 7800, audioMinutes: calcAudioMinutes(210000), structureFormat: '单章完整', readingDifficulty: '中高', isShortArticle: false },
'130000': { key: '130000', label: '标准', description: '标准,约13万字', chapters: calcChapters(130000), totalWords: 130000, chapterWords: 7600, audioMinutes: calcAudioMinutes(130000), structureFormat: '单章完整', readingDifficulty: '中', isShortArticle: false },
'80000': { key: '80000', label: '下1', description: '下1,约8万字', chapters: calcChapters(80000), totalWords: 80000, chapterWords: 6700, audioMinutes: calcAudioMinutes(80000), structureFormat: '单章完整', readingDifficulty: '中低', isShortArticle: false },
'50000': { key: '50000', label: '下2', description: '下2,约5万字', chapters: calcChapters(50000), totalWords: 50000, chapterWords: 5600, audioMinutes: calcAudioMinutes(50000), structureFormat: '单章完整', readingDifficulty: '低', isShortArticle: false },
'31000': { key: '31000', label: '下3', description: '下3,约3.1万字', chapters: calcChapters(31000), totalWords: 31000, chapterWords: 4400, audioMinutes: calcAudioMinutes(31000), structureFormat: '单章完整', readingDifficulty: '低', isShortArticle: false },
'19000': { key: '19000', label: '下4', description: '下4,约1.9万字', chapters: calcChapters(19000), totalWords: 19000, chapterWords: 3800, audioMinutes: calcAudioMinutes(19000), structureFormat: '单章完整', readingDifficulty: '低', isShortArticle: false },
'12000': { key: '12000', label: '下5', description: '下5,约1.2万字', chapters: calcChapters(12000), totalWords: 12000, chapterWords: 3000, audioMinutes: calcAudioMinutes(12000), structureFormat: '单章完整', readingDifficulty: '低', isShortArticle: false },
'7000': { key: '7000', label: '下6', description: '下6,约7千字', chapters: calcChapters(7000), totalWords: 7000, chapterWords: 2300, audioMinutes: calcAudioMinutes(7000), structureFormat: '全文', readingDifficulty: '极低', isShortArticle: true },
'4000': { key: '4000', label: '下7', description: '下7,约4千字', chapters: calcChapters(4000), totalWords: 4000, chapterWords: 2000, audioMinutes: calcAudioMinutes(4000), structureFormat: '全文', readingDifficulty: '极低', isShortArticle: true },
'3000': { key: '3000', label: '下8', description: '下8,约3千字', chapters: calcChapters(3000), totalWords: 3000, chapterWords: 3000, audioMinutes: calcAudioMinutes(3000), structureFormat: '全文', readingDifficulty: '极低', isShortArticle: true },
'2000': { key: '2000', label: '下9', description: '下9,约2千字', chapters: calcChapters(2000), totalWords: 2000, chapterWords: 2000, audioMinutes: calcAudioMinutes(2000), structureFormat: '全文', readingDifficulty: '极低', isShortArticle: true },
'1000': { key: '1000', label: '下10', description: '下10,约1千字', chapters: calcChapters(1000), totalWords: 1000, chapterWords: 1000, audioMinutes: calcAudioMinutes(1000), structureFormat: '全文', readingDifficulty: '极低', isShortArticle: true },
};
// 可被 AI 自动检测的类型
export const DETECTABLE_TYPES = ['340000', '210000', '130000', '80000', '50000', '31000', '19000', '12000', '7000', '4000', '3000', '2000', '1000'];
// 获取单个类型配置
export function getBookTypeConfig(key: string): BookTypeConfig {
// 如果 key 是数字字符串(如 '200', '3000'),直接计算
if (/^\d+$/.test(key)) {
const wordCount = parseInt(key);
return {
key: key,
label: '自定义',
description: `约${wordCount}字`,
chapters: calcChapters(wordCount),
totalWords: wordCount,
chapterWords: calcChapterWords(wordCount),
audioMinutes: calcAudioMinutes(wordCount),
structureFormat: '单章完整',
readingDifficulty: '中',
isShortArticle: wordCount <= 10000,
};
}
return BOOK_TYPE_CONFIG[key] || BOOK_TYPE_CONFIG['130000'];
}
// 根据字数计算每章字数
const calcChapterWords = (totalWords: number): number => {
return Math.round(totalWords / calcChapters(totalWords));
};
// 获取所有类型配置(供前端显示)
export function getAllBookTypes(): BookTypeConfig[] {
return Object.values(BOOK_TYPE_CONFIG);
}
// 获取可检测的类型列表
export function getDetectableTypes(): BookTypeConfig[] {
return DETECTABLE_TYPES.map(key => BOOK_TYPE_CONFIG[key]);
}
// 兼容旧接口的 getScaleConfig(返回单个值,AI自行理解±20%浮动)
export function getScaleConfig(key: string) {
const config = getBookTypeConfig(key);
return {
chapters: config.chapters,
totalWords: config.totalWords,
chapterWords: config.chapterWords,
isShortArticle: config.isShortArticle,
};
}
// 兼容旧接口的 estimateBookWords
export function estimateBookWords(key: string): { min: number; max: number; avg: number } {
const config = getBookTypeConfig(key);
return {
min: config.totalWords,
max: config.totalWords,
avg: config.totalWords,
};
}
// ============================================
// 字数安全限制(三层防护体系)
// ============================================
/** 全局绝对上限:50 万字
* 前端最大可选为「上2」34 万字,×1.5 安全系数 = 51 万,取整 50 万
* 任何用户/任何类型均不可突破 */
export const GLOBAL_ABSOLUTE_WORD_LIMIT = 500_000;
/**
* 获取全局字数上限
* 与类型/会员等级无关,所有用户统一硬上限 50 万字
* 用户有多少余额就能写多少字,但不得超过此上限
*/
export function getBookWordLimit(): number {
return GLOBAL_ABSOLUTE_WORD_LIMIT;
}
|