最近基于 FastAPI 构建异步后端、SQLite 轻量化存储、Dify 赋能 AI 辅助能力,同时优化阅读体验、解决 TXT 解析、AI 输出处理等方面完成了一个简易的小说阅读平台的开发,想和大家分享一下整个开发过程中的收获与思考。。


一、缘起:为什么要做这个项目?

作为一个小说爱好者,我一直觉得市面上的阅读平台要么广告太多,要么阅读体验不够个性化。同时,作为一个写作者,我也希望有更好的工具来辅助创作。

于是,我决定自己动手,打造一个集阅读与创作于一体的小说平台。核心目标很简单:

  1. 为读者:提供干净、舒适的阅读体验
  2. 为作者:提供智能的写作辅助工具
  3. 为自己:实践全栈开发能力

二、技术选型

后端框架:FastAPI

选择 FastAPI 的原因:

  • 异步支持:对于 IO 密集型的应用场景(如数据库查询、AI 调用)更高效
  • 类型提示:配合 Pydantic,代码更健壮,调试更方便
  • 自动文档:自动生成 Swagger UI,API 调试事半功倍

数据库:SQLite + SQLAlchemy

考虑到这是一个单体应用,且需要轻量化部署,我选择了 SQLite:

  • 零配置:开箱即用,无需额外安装数据库服务
  • 文件存储:数据以文件形式保存,便于备份和迁移
  • ORM 层:SQLAlchemy 提供数据访问抽象

AI 引擎:Dify

这是项目最核心的亮点之一。我选择了 Dify 作为 AI 引擎:

  1. 双模式支持:Workflow(结构化分析)+ Chatflow(开放式对话)
  2. 低代码配置:可视化配置工作流,无需复杂 API 调用
  3. 私有化部署:数据安全可控

认证方案:JWT + pbkdf2_sha256

使用 python-jose 签发 JWT 令牌,passlib 库的 pbkdf2_sha256 算法进行密码加密。


三、项目架构

我采用了经典的分层架构:

┌─────────────────────────────────────────────────────────┐
│                    前端层 (Frontend)                    │
│  HTML / CSS / JavaScript / 静态资源                    │
│  首页 | 书城 | 阅读页 | AI写作 | 管理后台              │
└──────────────────────────────┬──────────────────────────┘
                               │ HTTP/JSON
                               ▼
┌─────────────────────────────────────────────────────────┐
│                    API 层 (FastAPI)                    │
│  Auth 认证  │  Novels 小说  │  AI 助手  │  Carousel 轮播 │
└──────────────────────────────┬──────────────────────────┘
                               │ 依赖注入
                               ▼
┌─────────────────────────────────────────────────────────┐
│                   业务层 (Services)                    │
│  auth_service 用户认证  │  dify_service AI 交互        │
└──────────────────────────────┬──────────────────────────┘
                               │ SQLAlchemy
                               ▼
┌─────────────────────────────────────────────────────────┐
│                   数据层 (CRUD)                        │
│  User │ Novel │ Chapter │ Favorite │ Comment │ Carousel │
└──────────────────────────────┬──────────────────────────┘
                               │ SQLite
                               ▼
┌─────────────────────────────────────────────────────────┐
│                   AI 引擎层 (Dify)                     │
│  Workflow (小说分析)  │  Chatflow (AI辅助写作)         │
└─────────────────────────────────────────────────────────┘

四、数据库设计

核心实体关系

User (用户) ──1:N──▶ Novel (小说)
Novel (小说) ──1:N──▶ Chapter (章节)
User (用户) ──1:N──▶ Favorite (收藏)
User (用户) ──1:N──▶ Comment (评论)
User (用户) ──1:N──▶ ReadingHistory (阅读历史)
Novel (小说) ──1:N──▶ CarouselItem (轮播项)

数据表清单

表名 核心字段 说明
users id, username, email, hashed_password, is_admin 用户信息
novels id, title, author_id, author_name, genre, description, views, word_count, reader_target, status 小说信息
chapters id, novel_id, title, chapter_number, content 章节内容
reading_history id, user_id, novel_id, chapter_id, last_read_at 阅读记录
favorites id, user_id, novel_id, added_at 收藏记录
comments id, user_id, novel_id, content, created_at 评论信息
carousel_items id, item_type, display_order, title, cover_url 轮播项目
carousel_config id, config_key, config_value 轮播配置

数据库索引优化

为提升查询性能,在以下字段添加了索引:

novels 表author_id, author_name, genre, status, views, reader_target, created_at, updated_at

chapters 表novel_id, title, chapter_number, created_at

reading_history 表user_id, novel_id, chapter_id, last_read_at

favorites 表user_id, novel_id, added_at

comments 表user_id, novel_id, created_at


五、核心功能详解

5.1 用户认证模块

使用 JWT 进行身份验证,支持用户注册、登录、权限控制:

# 密码加密使用 pbkdf2_sha256
pwd_context = CryptContext(schemes=["pbkdf2_sha256"], deprecated="auto")

# JWT 令牌生成
def create_access_token(data: dict, expires_delta: Optional[timedelta] = None):
    to_encode = data.copy()
    if expires_delta:
        expire = datetime.utcnow() + expires_delta
    else:
        expire = datetime.utcnow() + timedelta(minutes=15)
    to_encode.update({"exp": expire})
    return jwt.encode(to_encode, settings.SECRET_KEY, algorithm=settings.ALGORITHM)

权限分为两级:

  • 普通用户:浏览、阅读、收藏、评论
  • 管理员:小说管理、轮播管理、上传小说

5.2 小说管理模块

支持小说的 CRUD 操作,以及 TXT 文件批量上传:

# TXT 文件上传接口
@router.post("/upload-novel/")
async def upload_novel(
    title: str = Form(...),
    file: UploadFile = File(...),
    separator: str = Form("第.*章"),
    ...
):
    # 文件大小限制(10MB)
    MAX_FILE_SIZE = 10 * 1024 * 1024
    # 章节数限制(5000章)
    MAX_CHAPTERS = 5000
    
    # 读取文件内容
    text = content.decode('utf-8', errors='replace')
    # 按分隔符解析章节
    chapters = parse_novel_chapters(text, separator)

章节解析逻辑使用正则表达式,支持用户自定义分隔符(默认按 “第x章” 分割)。

5.3 阅读体验模块

阅读器提供了丰富的个性化设置:

设置项 可选值 说明
字体大小 12px ~ 36px 步进 1px
阅读主题 默认 / 夜间 / 护眼 / 粉色 / 蓝色 / 护眼黄 背景色 + 文字色
行间距 1.5 ~ 3.0 步进 0.1
字体样式 系统默认 / 宋体 / 黑体 / 楷体 CSS font-family
翻页方式 点击翻页 / 滑动翻页 交互模式

所有设置保存在 localStorage,下次打开自动恢复。

键盘快捷键支持

  • / 空格:下一页/下一章
  • :上一页/上一章
  • Esc:返回小说详情
  • +/-:调整字体大小
  • T:打开设置面板

5.4 用户交互模块

  • 收藏功能:添加/取消收藏,检查是否已收藏
  • 评论系统:发表评论,查看评论列表
  • 阅读历史:自动记录阅读进度,按时间倒序排列
  • 离线阅读:支持下载小说到本地,无网络时也可阅读

5.5 AI 小说分析模块(Workflow)

通过 Dify Workflow 实现小说深度分析,支持对话历史记录:

# 发送 6 个变量到 Dify Workflow
inputs = {
    "query": request.query,
    "novel_title": novel_info["title"],
    "novel_author": novel_info["author"],
    "novel_description": novel_info["description"],
    "novel_genre": novel_info["genre"],
    "chapter_content": chapter_content[:5000]
}

# 调用 Workflow API,支持 conversation_id 传递
result = await dify_client.run_workflow(inputs, user=str(current_user.id))
return result  # 返回 answer 和 conversation_id

Workflow 会按照预设的流程,调用 LLM 进行结构化分析,返回分析报告。

5.6 AI 辅助写作模块(Chatflow)

通过 Dify Chatflow 提供四种写作辅助模式:

模式 接口 必填参数 说明
续写 continue_writing context, style 基于前文继续创作
大纲生成 generate_outline title, genre, description 生成故事大纲
角色设计 design_character context 设计人物设定
文本润色 polish_text text, style 提升文字质量
# 前端路由分发
if mode == "continue":
    answer = await dify_client.continue_writing(request.context, request.style or "")
elif mode == "outline":
    answer = await dify_client.generate_outline(request.title, request.genre or "", request.description or "")
elif mode == "character":
    answer = await dify_client.design_character(request.context)
elif mode == "polish":
    answer = await dify_client.polish_text(request.text, request.style or "")

5.7 轮播管理模块

支持两种轮播类型:

  • 名人堂(hall_of_fame):展示作家信息,包括代表作、经典语录、创作理念
  • 巅峰榜(top_list):展示热门小说排行

管理员可通过后台管理轮播项目和配置显示数量。

5.8 书城筛选模块

提供多维度的筛选功能:

读者筛选:全部 / 男生 / 女生
分类筛选:全部 / 主题 / 角色 / 情节(根据读者选择动态变化)
状态筛选:全部 / 已完结 / 连载中
字数筛选:全部 / 30万以下 / 30-50万 / 50-100万 / 100-200万 / 200万以上

六、性能优化

6.1 数据库查询优化

问题:N+1 查询问题,循环查询作者信息导致性能下降。

解决方案:使用 SQLAlchemy 的 joinedload 预加载关联数据:

def get_novels_with_author(db: Session, skip: int = 0, limit: int = 100):
    return db.query(Novel).options(
        joinedload(Novel.author)
    ).order_by(Novel.updated_at.desc()).offset(skip).limit(limit).all()

6.2 雪花特效性能优化

问题:雪花特效动态创建/删除 DOM 元素,性能消耗大。

解决方案:使用对象池复用 DOM 元素:

const snowflakePool = [];
const MAX_SNOWFLAKES = 30;
let snowflakeIndex = 0;

function getSnowflakeElement() {
    let el;
    if (snowflakePool.length < MAX_SNOWFLAKES) {
        el = document.createElement('div');
        el.className = 'snowflake';
        snowflakePool.push(el);
    } else {
        el = snowflakePool[snowflakeIndex % MAX_SNOWFLAKES];
        snowflakeIndex++;
    }
    return el;
}

七、遇到的挑战与解决方案

挑战一:TXT 文件章节分割

问题:用户上传的 TXT 文件格式不一,章节标题格式多样。

解决方案:使用正则表达式配合用户自定义分隔符:

def parse_novel_chapters(text: str, separator: str) -> list:
    pattern = re.compile(rf'({separator})')
    parts = pattern.split(text)
    # 遍历分割结果,提取章节标题和内容
    for i, part in enumerate(parts):
        if re.match(rf'^{separator}$', part.strip()):
            # 匹配到章节标题
            ...
        else:
            # 章节内容
            ...

默认分隔符为 第.*章,用户也可以自定义,如 第.*节第.*回 等。

挑战二:AI 输出格式处理

问题:Dify 返回的内容带有 Markdown 格式符号,需要清洗后展示。

解决方案

function cleanMarkdown(text) {
    if (!text) return '';
    return text
        .replace(/^#{1,6}\s+/gm, '')       // 移除标题标记
        .replace(/\*\*(.+?)\*\*/g, '$1')    // 移除粗体
        .replace(/\*(.+?)\*/g, '$1')        // 移除斜体
        .replace(/`(.+?)`/g, '$1')          // 移除代码标记
        .replace(/^[-*+]\s+/gm, '• ')       // 无序列表转圆点
        .replace(/^\d+\.\s+/gm, '')         // 有序列表
        .replace(/^\s*[-*_]{3,}\s*$/gm, '') // 分隔线
        .replace(/^\s*>\s+/gm, '')          // 引用标记
        .replace(/\*/g, '')                  // 移除剩余星号
        .trim();
}

挑战三:异步 AI 调用

问题:AI 调用可能耗时较长(最长 120 秒超时),需要异步处理。

解决方案

# 使用 httpx.AsyncClient 进行异步 HTTP 请求
async with httpx.AsyncClient(timeout=120.0) as client:
    response = await client.post(
        self.workflow_url,
        json=payload,
        headers=self.workflow_headers
    )

挑战四:Workflow 与 Chatflow 的区分

问题:Dify 的 Workflow 和 Chatflow 返回格式不同,需要分别处理。

解决方案

# Workflow 返回格式:data.outputs.answer
if "data" in data and "outputs" in data["data"]:
    if "answer" in data["data"]["outputs"]:
        result = data["data"]["outputs"]["answer"]

# Chatflow 返回格式:answer
data.get("answer", "抱歉,没有收到回复")

八、API 端点一览

用户认证

方法 路径 说明
POST /token 登录获取 JWT 令牌
POST /users/ 用户注册
GET /users/me/ 获取当前用户信息

小说管理

方法 路径 说明
GET /novels/ 获取小说列表(分页)
GET /novels/search/ 搜索小说
GET /novels/filter/ 按条件筛选小说
GET /novels/top/ 热门小说排行
GET /novels/top-authors/ 热门作者排行
GET /novels/{id} 获取小说详情
POST /novels/ 创建小说(管理员)
PUT /novels/{id} 更新小说(管理员)
DELETE /novels/{id} 删除小说(管理员)
POST /upload-novel/ 上传 TXT 小说(管理员)
GET /genres/ 获取所有小说类型

章节

方法 路径 说明
GET /novels/{id}/chapters/ 获取章节列表
GET /chapters/{id} 阅读章节(需登录)
POST /novels/{id}/chapters/ 添加章节

收藏与阅读历史

方法 路径 说明
GET /reading-history/ 获取阅读历史
POST /favorites/{novel_id} 收藏小说
DELETE /favorites/{novel_id} 取消收藏
GET /favorites/ 获取收藏列表
GET /favorites/check/{novel_id} 检查是否已收藏

评论

方法 路径 说明
GET /novels/{id}/comments/ 获取小说评论
POST /novels/{id}/comments/ 发表评论

AI 助手

方法 路径 说明
POST /dify/chat AI 小说分析(Workflow)
POST /dify/writing AI 辅助写作(Chatflow)
POST /dify/summary/{novel_id} 生成小说简介

轮播图

方法 路径 说明
GET /carousel/items/ 获取轮播项目
POST /carousel/items/ 创建轮播项目(管理员)
PUT /carousel/items/{id} 更新轮播项目(管理员)
DELETE /carousel/items/{id} 删除轮播项目(管理员)
GET /carousel/config/{key} 获取轮播配置
PUT /carousel/config/{key} 更新轮播配置(管理员)

封面上传

方法 路径 说明
POST /novels/{id}/cover 上传小说封面(管理员)
POST /carousel/items/{id}/cover 上传轮播封面(管理员)

九、总结与感悟

技术亮点

  1. AI 与传统业务的结合:将 Dify 的 Workflow 和 Chatflow 无缝集成到小说平台中
  2. 阅读体验优化:6 种阅读主题、字体大小/行间距/字体样式可调,支持键盘快捷键
  3. 书城多维筛选:读者、分类、状态、字数四级筛选
  4. 双轮播系统:名人堂展示作家风采,巅峰榜展示热门小说
  5. 性能优化:数据库查询优化(解决 N+1 问题)、雪花特效对象池复用
  6. 对话历史记录:AI 分析支持多轮对话上下文保持

技术难点

  1. Workflow vs Chatflow 的选择:Workflow 适合结构化的小说分析任务,Chatflow 适合开放式的写作辅助对话,两者的 API 返回格式不同,需要分别处理
  2. TXT 章节智能分割:支持用户自定义分隔符,兼容多种章节标题格式
  3. AI 输出清洗:对 Markdown 内容进行多层清洗,确保前端展示整洁
  4. 异步超时处理:AI 调用设置 120 秒超时,避免长时间阻塞
  5. 数据库性能优化:使用 joinedload 预加载关联数据,添加数据库索引提升查询效率

未来规划

  • 支持 EPUB/MOBI 格式导入
  • 添加社交分享功能
  • 实现个性化推荐算法
  • 支持更多功能
Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐