分类: 数字出版

  • 遇到了微信小程序的视频资质问题

    这一直是一个潜在的隐患,微信小程序不止小程序,就连放个正文也容易被识别成小说啥的,需要提供互联网出版资质,当然,这不是腾讯自己的问题,但作为一个平台,没有解决好这些问题,还是可以指责的,何况小程序每年还要收300元的巨额认证费。

    而对于一个独立数字出版人来说,尽管有自己的公司,但几乎任何资质都不可能办理下来,也不太可能在搞好自己的技术研发的同时,去兼顾这么多额外的事务。

    于是,我只好决定把微信小程序蜷缩为一个搜索入口,其他功能都迁移到H5中。如此一来,也就不再纠结那些在微信小程序因为兼容问题不好做的功能,可以在H5里面堂堂正正做人。

  • 剑桥词典 +Plus 平台上的一款在线单词游戏

    剑桥词典 +Plus 平台上的一款在线单词游戏

    1. 功能概述

    Word Scramble 是剑桥词典 +Plus 平台上的一款在线单词游戏,玩家需要在限定时间内根据给定的单词定义,将一组打乱的字母重新排列组成正确的单词。该游戏旨在帮助英语学习者提升词汇和拼写能力,同时通过游戏化的方式增加趣味性。以下是主要功能:

    • 核心玩法:显示单词定义和一组打乱的字母,玩家需在规定时间内拼出正确单词。
    • 计时机制:玩家需要在限定时间内完成单词拼写,增加挑战性。
    • 交互反馈:提供即时反馈(正确/错误),并可能记录玩家的历史成绩。
    • 多语言支持:支持多种语言界面(如中文、英语、西班牙语等),便于全球用户使用。
    • 用户账户功能:允许用户注册/登录以保存游戏进度、创建词汇表或参与社区活动。
    • 其他功能:提供词汇表创建、分享功能,以及与语法和图片测验的链接。

    2. 技术实现分析

    基于网页游戏的特性,Word Scramble 可能采用了以下技术栈和实现方式:

    (1) 前端技术

    • HTML/CSS/JavaScript:
      • HTML:用于构建游戏的基本结构,如显示定义、字母块、输入区域和计时器。
      • CSS:负责界面样式,包括响应式设计(适配桌面、平板和手机)。游戏可能使用现代 CSS(如 Flexbox 或 Grid)来布局字母块和交互元素,并通过动画(如 CSS 动画或 transitions)增强用户体验。
      • JavaScript:核心交互逻辑通过 JavaScript 实现。例如:
        • 动态生成打乱字母:通过算法随机打乱单词的字母序列。
        • 计时器逻辑:使用 setInterval 或 requestAnimationFrame 实现倒计时功能。
        • 用户输入处理:监听用户拖动字母或键盘输入,实时验证拼写的正确性。
        • 反馈动画:通过 JavaScript 操作 DOM 或使用动画库(如 GSAP)实现正确/错误反馈的动态效果。
      • 前端框架:可能使用 React、Vue.js 或 Angular 等框架来管理复杂的状态(如游戏进度、用户输入、计时器状态等),提高开发效率和代码可维护性。
    • 响应式设计:
      • 游戏支持多种设备(桌面、平板、手机),可能使用媒体查询(Media Queries)或 Bootstrap 等框架确保界面适配不同屏幕尺寸。
      • 触摸事件(如拖放字母)可能通过 touchstart、touchmove 等 API 实现移动端交互。
    • 音效与动画:
      • 游戏包含动画和音效(如点击字母时的声音或完成单词时的提示音)。音效可能通过 HTML5 的 <audio> 标签或 Web Audio API 实现。
      • 动画可能通过 CSS 或 JavaScript 库(如 Lottie 或 GSAP)实现,增强沉浸感。

    (2) 后端技术

    • 内容管理系统 (CMS):
      • 根据参考信息,剑桥词典团队与 Alternative View Studios 合作开发了游戏和内容管理系统(CMS)。CMS 用于管理每日更新的单词定义和打乱的字母组合。
      • 后端可能使用 Python(Django/Flask)、Node.js 或 PHP 等技术生成动态内容,并通过 API 提供给前端。
      • 数据库(如 MySQL、PostgreSQL 或 MongoDB)存储单词库、定义、用户数据(如分数、词汇表)等intregration of the word list functionality with the game itself is uncertain, as the provided references do not explicitly detail this integration. However, it is reasonable to infer that the word lists created or shared via the Cambridge Dictionary +Plus platform could be used as a source for the words and definitions in the Word Scramble game. The game likely pulls from a curated database of words and their definitions, which could be linked to the platform’s word list feature, allowing for dynamic content updates and personalized user experiences.

    (3) 数据管理与词库

    • 单词与定义数据库:
      • 游戏依赖剑桥词典的词汇数据库,包含单词、定义和翻译。数据库可能按难度(如初级、中级、高级)分类,确保游戏适合不同英语水平用户。
      • 每日更新的定义可能通过后端 CMS 自动抽取或人工 curation,确保内容新鲜且多样化。
      • 打乱字母的算法可能在后端或前端实现。一种可能的算法是:javascriptfunction shuffleWord(word) { let letters = word.split(''); for (let i = letters.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [letters[i], letters[j]] = [letters[j], letters[i]]; // 交换字母 } return letters.join(''); }该算法随机打乱单词的字母序列,确保每次游戏的字母顺序不同。
    • 用户数据:
      • 用户登录后,游戏可能通过 API 存储玩家的历史成绩、进度或自定义词汇表到数据库。用户数据可能通过 JWT(JSON Web Token)或 session-based 认证机制管理。

    (4) API 交互

    • 前端通过 RESTful API 或 GraphQL 与后端通信,获取每日单词、定义、验证用户输入的正确性等。
    • 示例 API 端点:
      • GET /api/word-scramble/daily-word:获取每日单词和定义。
      • POST /api/word-scramble/submit:提交用户拼写的单词并验证。
      • GET /api/user/word-lists:获取用户创建的词汇表。
    • API 可能使用 HTTPS 确保数据传输安全,并通过 rate-limiting 或 throttling 防止滥用。

    (5) 多语言支持

    • 游戏支持多种语言界面(如中文、英语、西班牙语等)。这可能通过以下方式实现:
      • 国际化 (i18n):使用类似 i18next 或 react-i18next 的库管理多语言文本。
      • 动态语言切换:通过检测用户浏览器语言或提供语言选择器,动态加载对应语言的 UI 文本。
      • 后端 API 可能返回特定语言的定义和提示,确保游戏内容与用户语言一致。

    (6) 用户账户与社区功能

    • 用户可注册/登录以访问 Cambridge Dictionary +Plus 的功能(如创建词汇表、分享内容)。
    • 登录可能通过 OAuth、SAML 或自定义认证机制实现,用户数据存储在安全的数据库中。
    • 词汇表功能允许用户创建、下载和分享单词列表,可能通过以下流程:
      • 用户通过 UI 创建词汇表,数据通过 API 提交到后端。
      • 后端将词汇表存储到数据库,并生成可分享的链接。
      • 社区词汇表可能通过审核机制(如人工或自动)确保内容质量。

    (7) 性能优化

    • 前端优化:
      • 使用代码分割(code splitting)或懒加载(lazy loading)减少初始加载时间。
      • 缓存静态资源(如 CSS、JS、图片)到 CDN(如 Cloudflare、AWS CloudFront)以加速加载。
    • 后端优化:
      • 使用数据库索引优化单词查询性能。
      • 缓存常用单词和定义(如使用 Redis 或 Memcached)以减少数据库负载。
    • SEO 和可访问性:
      • 游戏页面可能包含元标签(如 <meta name=”description”>)以优化搜索引擎排名。
      • 遵循 WCAG(Web Content Accessibility Guidelines)标准,确保游戏对残障人士友好(如支持键盘导航、屏幕阅读器)。

    3. 用户体验设计

    • 游戏流程:
      1. 用户进入游戏页面,系统加载每日单词和定义。
      2. 显示打乱的字母块(可能支持拖放或点击选择),并启动计时器。
      3. 用户提交答案后,系统验证并显示结果(正确/错误)。
      4. 提供“重玩”或“下一题”选项,鼓励用户继续挑战。
    • 反馈机制:
      • 正确答案可能触发正面反馈(如绿色勾选、庆祝动画)。
      • 错误答案可能显示提示或正确答案,帮助用户学习。
    • 游戏化元素:
      • 计时器增加紧迫感,激励玩家快速思考。
      • 每日更新鼓励用户反复访问,类似“每日挑战”模式。
      • 可能的积分或排行榜系统(虽然参考信息未明确提及),增加竞争性。

    4. 可能的挑战与解决方案

    • 挑战 1:跨设备兼容性:
      • 问题:不同设备的屏幕尺寸和输入方式(如触摸 vs 鼠标)可能影响体验。
      • 解决方案:使用响应式设计和测试多设备兼容性,确保触摸和键盘输入流畅。
    • 挑战 2:单词难度控制:
      • 问题:如何确保单词难度适合不同英语水平用户?
      • 解决方案:从数据库中按难度分级抽取单词,或允许用户选择难度级别。
    • 挑战 3:性能与延迟:
      • 问题:高并发用户访问可能导致 API 或页面加载缓慢。
      • 解决方案:使用 CDN、数据库优化和负载均衡(如 AWS ELB)确保性能。

    5. 总结

    Word Scramble 是一款结合教育与娱乐的在线游戏,通过现代 Web 技术(HTML/CSS/JavaScript、可能的框架如 React)、后端 CMS 和数据库、以及 API 驱动的内容更新实现。其多语言支持、响应式设计和用户账户功能增强了全球用户的使用体验。游戏通过每日更新的单词和定义、计时挑战以及交互反馈,成功吸引英语学习者反复参与,同时通过词汇表功能与剑桥词典 +Plus 平台深度整合。

    参考资料:

    • 剑桥词典 +Plus 平台信息
    • 游戏设计与开发信息
  • 基于 Vue3 的 monorepo 架构设计一个数字阅读前端项目

    基于 Vue3 的 monorepo 架构设计一个数字阅读前端项目

    基于 Vue3 的 monorepo 架构设计一个数字阅读前端项目,需要清晰的模块划分和合理的目录结构,以支持图书搜索、用户登录、用户中心、数字图书模板以及特色应用场景(如汉字笔画练习、中英文字词听写、普通话语音测评等)。以下是一个详细的项目结构设计,采用 monorepo 方式,使用 apps、packages 和 shared-components 文件夹来组织子模块,同时考虑 Vue3 的组件化开发和复用性。


    项目设计目标

    1. 模块化:通过 monorepo 架构,将不同功能模块(如搜索、用户中心、特色场景)拆分为独立子模块,便于维护和扩展。
    2. 复用性:将通用组件、工具函数和类型定义放在 shared-components 和 packages 中,供多个 apps 复用。
    3. 可扩展性:支持多种数字图书模板和特色应用场景,确保新功能可以轻松接入。
    4. 开发效率:使用 pnpm(推荐用于 monorepo)管理依赖,结合 Vite 作为构建工具,提升开发体验。

    技术栈

    • 框架:Vue3(组合式 API)
    • 构建工具:Vite
    • 包管理:pnpm(支持 monorepo 的 workspace 功能)
    • 状态管理:Pinia
    • 路由:Vue Router
    • UI 组件库:可选(如 Element Plus 或 Naive UI),或基于 shared-components 自定义
    • 类型检查:TypeScript
    • 代码规范:ESLint + Prettier
    • 测试:Vitest + Vue Test Utils
    • 部署:支持静态部署(如 Vercel)或 SSR(如 Nuxt 3,可选)

    项目结构

    以下是项目的目录结构,分为 apps(应用入口)、packages(工具库和业务逻辑)、shared-components(通用组件)三大模块,并包含配置文件和文档。

    digital-reading-project/
    ├── apps/
    │   ├── book-search/                    # 图书搜索应用
    │   │   ├── src/
    │   │   │   ├── components/           # 搜索相关组件
    │   │   │   ├── views/                # 页面视图
    │   │   │   ├── router/               # 路由配置
    │   │   │   ├── store/                # Pinia 状态管理
    │   │   │   ├── assets/               # 静态资源
    │   │   │   ├── App.vue               # 应用根组件
    │   │   │   └── main.ts               # 入口文件
    │   │   ├── vite.config.ts            # Vite 配置文件
    │   │   ├── package.json              # 应用依赖
    │   │   └── tsconfig.json             # TypeScript 配置
    │   ├── user-center/                    # 用户中心应用(登录、个人资料等)
    │   │   ├── src/
    │   │   │   ├── components/           # 用户中心相关组件
    │   │   │   ├── views/                # 页面视图(如个人资料、设置)
    │   │   │   ├── router/
    │   │   │   ├── store/
    │   │   │   ├── assets/
    │   │   │   ├── App.vue
    │   │   │   └── main.ts
    │   │   ├── vite.config.ts
    │   │   ├── package.json
    │   │   └── tsconfig.json
    │   ├── digital-books/                  # 数字图书模板应用
    │   │   ├── src/
    │   │   │   ├── templates/            # 多种图书模板
    │   │   │   │   ├── novel/          # 小说阅读模板
    │   │   │   │   ├── textbook/       # 教材阅读模板
    │   │   │   │   └── comic/          # 漫画阅读模板
    │   │   │   ├── components/
    │   │   │   ├── views/
    │   │   │   ├── router/
    │   │   │   ├── store/
    │   │   │   ├── assets/
    │   │   │   ├── App.vue
    │   │   │   └── main.ts
    │   │   ├── vite.config.ts
    │   │   ├── package.json
    │   │   └── tsconfig.json
    │   ├── special-scenes/                 # 特色应用场景
    │   │   ├── src/
    │   │   │   ├── scenes/
    │   │   │   │   ├── hanzi-practice/ # 汉字笔画练习
    │   │   │   │   ├── dictation/      # 中英文字词听写
    │   │   │   │   └── mandarin-test/  # 普通话语音测评
    │   │   │   ├── components/
    
    
    │   │   │   ├── views/
    │   │   │   ├── router/
    │   │   │   ├── store/
    │   │   │   ├── assets/
    │   │   │   ├── App.vue
    │   │   │   └── main.ts
    │   │   ├── vite.config.ts
    │   │   ├── package.json
    │   │   └── tsconfig.json
    ├── packages/
    │   ├── api-client/                     # API 请求封装
    │   │   ├── src/
    │   │   │   ├── index.ts              # 导出 API 方法
    │   │   │   ├── book.ts               # 图书相关 API
    │   │   │   ├── user.ts               # 用户相关 API
    │   │   │   └── special.ts            # 特色场景 API
    │   │   ├── package.json
    │   │   └── tsconfig.json
    │   ├── utils/                          # 通用工具函数
    │   │   ├── src/
    │   │   │   ├── index.ts              # 导出工具函数
    │   │   │   ├── format.ts             # 格式化工具(如时间、文本)
    │   │   │   ├── storage.ts            # 本地存储封装
    │   │   │   └── audio.ts              # 音频处理工具(如语音测评)
    │   │   ├── package.json
    │   │   └── tsconfig.json
    │   ├── types/                          # TypeScript 类型定义
    │   │   ├── src/
    │   │   │   ├── index.ts              # 导出类型
    │   │   │   ├── book.ts               # 图书相关类型
    │   │   │   ├── user.ts               # 用户相关类型
    │   │   │   └── scene.ts              # 特色场景类型
    │   │   ├── package.json
    │   │   └── tsconfig.json
    ├── shared-components/                  # 通用组件
    │   ├── src/
    │   │   ├── index.ts                  # 导出所有组件
    │   │   ├── Button.vue                # 通用按钮
    │   │   ├── Input.vue                 # 通用输入框
    │   │   ├── Modal.vue                 # 通用模态框
    │   │   ├── Reader.vue                # 通用阅读器组件
    │   │   ├── AudioPlayer.vue           # 音频播放器
    │   │   └── StrokeCanvas.vue          # 汉字笔画画布
    │   ├── package.json
    │   ├── vite.config.ts
    │   └── tsconfig.json
    ├── scripts/                            # 构建和部署脚本
    │   ├── build-all.ts                  # 构建所有应用的脚本
    │   └── deploy.ts                     # 部署脚本
    ├── docs/                               # 项目文档
    │   ├── README.md                     # 项目说明
    │   └── architecture.md               # 架构说明
    ├── .eslintrc.js                       # ESLint 配置
    ├── .prettierrc                        # Prettier 配置
    ├── pnpm-workspace.yaml                # pnpm monorepo 配置文件
    ├── tsconfig.json                      # 全局 TypeScript 配置
    ├── vite.config.ts                     # 全局 Vite 配置(可选)
    └── package.json                       # 根目录依赖

    目录结构说明

    1. apps 目录

    apps 包含独立的应用入口,每个应用是一个完整的 Vue3 项目,使用 Vite 构建,共享 packages 和 shared-components 的内容。

    • book-search:
      • 功能:图书搜索、分类浏览、搜索历史。
      • 组件:搜索框、结果列表、筛选器。
      • 路由:/search(搜索页)、/category(分类页)。
      • 状态管理:Pinia 存储搜索关键词和结果。
      • API 调用:通过 packages/api-client 获取图书数据。
    • user-center:
      • 功能:用户登录、注册、个人资料管理、阅读记录。
      • 组件:登录表单、用户头像、设置面板。
      • 路由:/login、/register、/profile。
      • 状态管理:Pinia 存储用户信息和认证状态。
      • API 调用:通过 packages/api-client 处理用户相关请求。
    • digital-books:
      • 功能:支持多种数字图书模板(如小说、教材、漫画)。
      • 子目录 templates:
        • novel:小说阅读模板,支持翻页、字体调整、夜间模式。
        • textbook:教材模板,支持目录导航、笔记功能。
        • comic:漫画模板,支持图片缩放、左右翻页。
      • 组件:阅读器(基于 shared-components/Reader.vue)、目录、书签。
      • 路由:/book/:id(阅读页面)、/book/:id/toc(目录页)。
      • 状态管理:Pinia 存储阅读进度和设置。
    • special-scenes:
      • 功能:特色应用场景,如汉字笔画练习、中英文字词听写、普通话语音测评。
      • 子目录 scenes:
        • hanzi-practice:基于 Canvas 的汉字笔画练习,使用 shared-components/StrokeCanvas.vue。
        • dictation:中英文字词听写,支持音频播放(基于 shared-components/AudioPlayer.vue)和输入验证。
        • mandarin-test:普通话语音测评,使用 Web Speech API 或第三方语音服务,结合 packages/utils/audio.ts。
      • 路由:/scene/hanzi、/scene/dictation、/scene/mandarin。
      • 状态管理:Pinia 存储练习进度和评分。

    2. packages 目录

    packages 包含可复用的工具库和业务逻辑模块,供多个 apps 使用。

    • api-client:
      • 封装 Axios 或 Fetch 请求,提供图书、用户、特色场景的 API 方法。
      • 示例:book.ts 包含 searchBooks、getBookDetail 方法;user.ts 包含 login、getProfile 方法。
      • 使用 TypeScript 定义请求和响应类型,引用 packages/types。
    • utils:
      • 通用工具函数,如时间格式化、本地存储封装、音频处理。
      • 示例:audio.ts 提供音频播放和录制功能,支持语音测评场景。
    • types:
      • 定义 TypeScript 类型和接口,如图书、用户、场景的数据结构。
      • 示例:book.ts 定义 Book 接口,包含 id、title、author 等字段。

    3. shared-components 目录

    shared-components 包含通用 Vue 组件,支持跨应用复用。

    • Button.vue:通用按钮,支持不同样式和禁用状态。
    • Input.vue:通用输入框,支持搜索、表单等场景。
    • Modal.vue:通用模态框,用于登录、提示等。
    • Reader.vue:通用阅读器组件,支持小说、教材、漫画的渲染。
    • AudioPlayer.vue:音频播放器,用于听写和语音测评。
    • StrokeCanvas.vue:基于 Canvas 的汉字笔画练习组件。

    4. 根目录配置

    • pnpm-workspace.yaml:yamlpackages: - 'apps/*' - 'packages/*' - 'shared-components'定义 monorepo 的 workspace,允许 apps 和 packages 互相引用。
    • tsconfig.json: 配置路径别名(如 @shared 指向 shared-components)和 TypeScript 选项。
    • vite.config.ts: 全局 Vite 配置,定义共享的插件和优化选项,子应用可继承或覆盖。
    • scripts:
      • build-all.ts:使用 pnpm -r build 构建所有应用。
      • deploy.ts:自动化部署脚本(可选)。
    • docs:
      • README.md:项目概述、安装和运行说明。
      • architecture.md:详细描述 monorepo 架构和模块职责。

    实现细节

    1. Monorepo 管理

    • 使用 pnpm 管理依赖,确保 apps 和 packages 的依赖隔离。
    • 在 package.json 中配置脚本:json{ "scripts": { "dev:search": "pnpm --filter book-search dev", "dev:user": "pnpm --filter user-center dev", "build": "pnpm -r build", "test": "pnpm -r test" } }

    2. 组件复用

    • shared-components 中的组件通过 index.ts 导出,供 apps 按需引入:ts// shared-components/src/index.ts export { default as Button } from './Button.vue'; export { default as Reader } from './Reader.vue';
    • 在 apps 中通过路径别名引入:tsimport { Button } from '@shared';

    3. API 封装

    • packages/api-client 使用 Axios 封装请求:ts// packages/api-client/src/book.ts import axios from 'axios'; import type { Book } from '@types'; export async function searchBooks(query: string): Promise<Book[]> { const response = await axios.get('/api/books', { params: { query } }); return response.data; }

    4. 特色场景实现

    • 汉字笔画练习:
      • 使用 StrokeCanvas.vue 实现 Canvas 画板,记录用户笔画并与标准笔顺比较。
      • 数据通过 packages/api-client/special.ts 获取汉字笔顺信息。
    • 中英文字词听写:
      • 使用 AudioPlayer.vue 播放单词音频,用户输入答案后通过 packages/api-client 校验。
    • 普通话语音测评:
      • 使用 Web Speech API 录制用户语音,结合 packages/utils/audio.ts 进行预处理。
      • 调用第三方语音测评 API(如科大讯飞)进行评分。

    5. 路由和状态管理

    • 每个 app 使用 Vue Router 管理页面跳转,Pinia 管理状态。
    • 示例(book-search 的路由):ts// apps/book-search/src/router/index.ts import { createRouter, createWebHistory } from 'vue-router'; import SearchView from '../views/SearchView.vue'; const router = createRouter({ history: createWebHistory(), routes: [ { path: '/search', component: SearchView }, { path: '/category', component: () => import('../views/CategoryView.vue') }, ], }); export default router;

    6. 测试

    • 使用 Vitest 和 Vue Test Utils 编写单元测试,覆盖组件和工具函数。
    • 示例测试(shared-components/Button.vue):tsimport { mount } from '@vue/test-utils'; import Button from '@shared/Button.vue'; describe('Button', () => { it('renders correctly', () => { const wrapper = mount(Button, { props: { label: 'Click Me' } }); expect(wrapper.text()).toContain('Click Me'); }); });

    开发流程

    1. 初始化项目:
      • 初始化 monorepo:pnpm init 和 pnpm-workspace.yaml。
      • 为每个 app 和 package 创建 package.json 和 vite.config.ts。
    2. 开发通用组件:
      • 在 shared-components 中开发通用组件,先实现基础功能(如 Button、Input)。
      • 逐步添加复杂组件(如 Reader、StrokeCanvas)。
    3. 开发工具库:
      • 在 packages 中实现 API 客户端、工具函数和类型定义。
      • 使用 TypeScript 确保类型安全。
    4. 开发应用:
      • 从 book-search 开始,逐步实现其他 apps。
      • 复用 shared-components 和 packages 的内容。
    5. 测试和部署:
      • 编写单元测试,确保组件和工具函数的稳定性。
      • 使用 scripts/build-all.ts 构建所有应用,部署到 Vercel 或其他平台。

    可扩展性考虑

    • 新增图书模板:在 apps/digital-books/templates 中添加新模板目录(如 magazine),复用 Reader.vue。
    • 新增特色场景:在 apps/special-scenes/scenes 中添加新场景目录,复用现有组件和工具。
    • 多语言支持:在 packages/utils 中添加 i18n 工具,使用 Vue I18n 实现多语言切换。
    • 性能优化:使用 Vite 的按需加载和 Tree Shaking,减少打包体积。

    总结

    这个 monorepo 架构将数字阅读项目的功能模块化,清晰划分了 apps(应用入口)、packages(工具库)和 shared-components(通用组件)。通过 pnpm 和 Vite 管理依赖和构建,结合 Vue3 和 TypeScript 实现高效开发。每个子模块(图书搜索、用户中心、数字图书、特色场景)独立维护,同时复用通用代码,确保项目可扩展和易维护。

  • 基于Markdown的电子书方案:MDEpub

    一个基于 Markdown 的电子书方案,类似 EPUB 标准并原生支持 Mermaid 和 Markmap 等可视化和交互功能,解决 Markdown 的轻量特性与电子书格式的结构化需求之间的平衡,同时确保对 Mermaid(流程图、时序图等)和 Markmap(思维导图)等工具的原生支持。以下是一个详细的设计方案,涵盖架构、实现方法、可视化支持和交互功能。

    1. 设计目标

    • 基于 Markdown:以 Markdown 作为主要内容创作格式,保持简洁和易用。
    • 类似 EPUB 的结构:支持电子书所需的元数据、目录、样式和多文件组织,类似 EPUB 的 OPF 和 NCX 文件。
    • 原生支持 Mermaid 和 Markmap:直接解析和渲染 Mermaid 和 Markmap 代码块为可视化内容(例如 SVG 或交互式 HTML)。
    • 交互性:支持在电子书中嵌入交互式图表(如可缩放的流程图或动态思维导图)。
    • 跨平台兼容:生成的电子书可在多种阅读器上运行,同时支持 Web 浏览器查看。
    • 可扩展性:允许扩展其他可视化工具(如 PlantUML、D3.js 等)。

    2. 方案架构

    基于 Markdown 的电子书格式(暂称为 MDEpub,Markdown-based ePub)可以分为以下核心组件:

    2.1 文件结构

    类似 EPUB,MDEpub 使用文件夹结构组织内容:

    mdepub-book/
    ├── meta.yaml           # 元数据(标题、作者、语言等)
    ├── toc.md              # 目录(类似 EPUB 的 NCX)
    ├── content/            # 内容文件夹
    │   ├── chapter1.md     # 章节 1(Markdown 文件)
    │   ├── chapter2.md     # 章节 2
    │   └── assets/         # 静态资源(图片、CSS、JS 等)
    ├── styles.css          # 全局样式
    └── config.json         # 构建配置(例如 Mermaid/Markmap 渲染设置)
    • meta.yaml:定义电子书元数据,类似 EPUB 的 content.opf。yamltitle: 示例电子书 author: 作者姓名 language: zh-CN publisher: 出版社 date: 2025-05-28
    • toc.md:定义目录结构,支持嵌套章节。markdown# 目录 - [第一章](content/chapter1.md) - [第二章](content/chapter2.md) - [子章节](content/chapter2.md#section1)
    • content/:存放 Markdown 章节,包含 Mermaid 和 Markmap 代码块。
    • assets/:存储图片、字体、CSS、JS(如 Mermaid 和 Markmap 的运行时库)。
    • styles.css:自定义样式,控制电子书外观。
    • config.json:配置可视化工具的参数(例如 Mermaid 主题、Markmap 样式)。

    2.2 Markdown 扩展

    为支持 Mermaid 和 Markmap,扩展 Markdown 语法,允许在代码块中指定渲染参数。例如:

    markdown

    # 第一章
    
    ## 流程图
    ```mermaid {theme: "dark", format: "svg"}
    graph TD
        A[开始] --> B{判断}
        B -->|是| C[执行]
        B -->|否| D[结束]

    思维导图

    markmap {height: “300px”, zoom: true}

    # 思维导图
    ## 分支1
    ### 子节点1
    ## 分支2
    - 使用 `{}` 指定渲染参数(如主题、高度、交互性)。
    - 支持标准 Markdown 语法,同时兼容 Mermaid 和 Markmap 的特定代码块。
    
    #### **2.3 输出格式**
    MDEpub 的最终输出是一个压缩包(类似 EPUB 的 ZIP 格式),包含:
    - **HTML 文件**:每个 Markdown 章节转换为独立的 HTML 文件,嵌入 Mermaid 和 Markmap 的渲染结果(SVG 或交互式 JS)。
    - **元数据文件**:基于 `meta.yaml` 生成的 XML 或 JSON。
    - **目录文件**:基于 `toc.md` 生成的导航文件(类似 NCX 或 HTML TOC)。
    - **资源文件**:CSS、JS、图片等,包含 Mermaid 和 Markmap 的运行时库。
    - **容器文件**:定义文件结构的元文件,类似 EPUB 的 `mimetype``META-INF/container.xml`。
    
    ---
    
    ### 3. **实现方法**
    以下是实现 MDEpub 的核心步骤和技术选型:
    
    #### **3.1 解析 Markdown**
    - **工具**:使用 [marked](https://marked.js.org/) 或 [markdown-it](https://github.com/markdown-it/markdown-it) 解析 Markdown 文件,转换为 HTML。
    - **扩展插件**:
      - **Mermaid**:集成 `@mermaid-js/mermaid` 解析代码块,渲染为 SVG 或交互式 HTML。
      - **Markmap**:集成 `markmap-lib``markmap-view`,将 Markmap 代码块渲染为 SVG 或交互式思维导图。
    - **自定义代码块**:扩展 Markdown 解析器,识别 `mermaid``markmap` 代码块,并调用对应渲染器。
    
    #### **3.2 渲染可视化内容**
    - **Mermaid**:
      - 使用 Mermaid CLI 或 `@mermaid-js/mermaid` 将代码块渲染为 SVG(静态)或嵌入 JS 代码(交互式)。
      - 示例(Node.js 环境):
        ```javascript
        import mermaid from 'mermaid';
        mermaid.initialize({ theme: 'dark' });
        const svg = await mermaid.render('graph', 'graph TD A-->B');
        ```
      - 将 SVG 嵌入 HTML,或包含 Mermaid JS 库以支持交互(例如点击放大)。
    - **Markmap**:
      - 使用 `markmap-lib` 解析 Markmap 代码,生成 SVG 或 HTML+JS。
      - 示例:
        ```javascript
        import { Markmap } from 'markmap-view';
        const mm = Markmap.create(svgElement, { height: 300, zoom: true });
        mm.setData(markmapData);
        ```
      - 支持交互功能(如缩放、展开/折叠节点)。
    - **嵌入方式**:
      - **静态**:将 SVG 直接嵌入 HTML,适合离线阅读器。
      - **动态**:嵌入 Mermaid/Markmap 的 JS 运行时,生成交互式图表,适合 Web 浏览器或支持 JS 的阅读器。
    
    #### **3.3 生成电子书**
    - **构建工具**:开发一个 CLI 工具(例如 `mdepub-cli`),基于 Node.js,执行以下步骤:
      1. 读取 `meta.yaml``toc.md`,生成元数据和导航。
      2. 解析 `content/` 下的 Markdown 文件,转换为 HTML。
      3. 处理 Mermaid 和 Markmap 代码块,渲染为 SVG 或交互式 HTML。
      4. 合并 CSS 和 JS 资源,生成最终文件结构。
      5. 打包为 ZIP 文件,添加 `mimetype`(例如 `application/mdepub+zip`)。
    - **示例命令**```bash
      mdepub build mdepub-book/ -o book.mdepub

    3.4 阅读器支持

    • 静态模式:生成 SVG 的 MDEpub 文件可被大多数 EPUB 阅读器(如 Calibre、iBooks)支持。
    • 交互模式:包含 JS 的 MDEpub 需要支持 HTML5 和 JavaScript 的阅读器(如 Web 浏览器、Readium、或自定义阅读器)。
    • 自定义阅读器:开发一个基于 Web 的阅读器(使用 Electron 或 PWA),加载 MDEpub 文件,运行 Mermaid 和 Markmap 的 JS 代码,实现交互。

    4. 支持 Mermaid 和 Markmap 的关键技术

    4.1 Mermaid

    • 渲染:将 Mermaid 代码渲染为 SVG(静态)或 HTML+JS(交互)。
    • 交互性:
      • 支持点击节点高亮、缩放等功能。
      • 需要在 MDEpub 中嵌入 mermaid.min.js(约 1.5MB,压缩后更小)。
    • 样式:通过 config.json 或代码块参数自定义主题(如 dark、forest)。
    • 兼容性:SVG 输出兼容大多数阅读器;交互模式需 JS 支持。

    4.2 Markmap

    • 渲染:将 Markmap 代码渲染为 SVG 或交互式 HTML(使用 D3.js 和 markmap-view)。
    • 交互性:
      • 支持节点展开/折叠、缩放、拖拽。
      • 需要嵌入 markmap-view 和 d3 的 JS 库(约 200KB 压缩后)。
    • 样式:支持自定义颜色、字体、节点样式。
    • 兼容性:类似 Mermaid,SVG 适合静态阅读,交互模式需 JS 支持。

    4.3 其他可视化工具

    • 扩展性:通过插件机制支持其他工具,如 PlantUML、Vega-Lite 等。
    • 实现:为每种工具开发独立的 Markdown 代码块解析器和渲染器,输出 SVG 或 JS。

    5. 优势与挑战

    优势

    • 简洁性:Markdown 作为输入格式,易于编写和维护。
    • 可视化支持:原生支持 Mermaid 和 Markmap,无需外部转换。
    • 交互性:通过 JS 提供动态图表,增强阅读体验。
    • 灵活性:可扩展支持其他可视化工具。
    • 跨平台:兼容现有 EPUB 阅读器(静态模式)和 Web 浏览器(交互模式)。

    挑战

    • 阅读器兼容性:许多 EPUB 阅读器不支持 JavaScript,交互模式可能受限。
    • 文件大小:嵌入 Mermaid 和 Markmap 的 JS 库会增加文件体积。
    • 性能:复杂图表可能导致渲染时间增加,尤其在低端设备上。
    • 标准推广:MDEpub 作为新格式,需要开发专用阅读器或推广兼容性。

    6. 实现工具与工作流

    6.1 开发工具

    • Node.js:核心开发环境,用于解析 Markdown 和渲染图表。
    • markdown-it:Markdown 解析器,支持自定义插件。
    • Mermaid:用于流程图等渲染。
    • Markmap:用于思维导图渲染。
    • archiver:Node.js 库,用于打包 MDEpub 文件为 ZIP。
    • esbuild:压缩和打包 JS/CSS 资源。

    6.2 工作流

    1. 编写:在 mdepub-book/ 中编写 Markdown 文件,包含 Mermaid 和 Markmap 代码块。
    2. 配置:设置 meta.yaml、toc.md 和 config.json。
    3. 构建:运行 mdepub build 命令,生成 MDEpub 文件。
    4. 预览:使用 Web 浏览器或自定义阅读器预览。
    5. 发布:分发 .mdepub 文件,或转换为标准 EPUB(静态模式)。

    6.3 示例命令

    bash

    # 初始化项目
    mdepub init my-book
    # 构建 MDEpub
    mdepub build my-book/ -o my-book.mdepub
    # 预览(启动本地 Web 服务器)
    mdepub preview my-book/
    # 转换为标准 EPUB(静态)
    mdepub export my-book/ -o my-book.epub --static

    7. 与 EPUB 的对比

    特性EPUBMDEpub
    输入格式XHTML, XML, CSSMarkdown
    Mermaid 支持需外部转换原生支持(SVG/JS)
    Markmap 支持需外部转换原生支持(SVG/JS)
    交互性有限(需特定阅读器)强(支持 JS 的交互式图表)
    兼容性广泛(标准阅读器)需专用阅读器或浏览器
    文件大小较小(静态内容)可能较大(含 JS 库)
    开发复杂性高(XML 结构复杂)低(Markdown 简单)

    8. 未来扩展

    • 插件系统:支持更多可视化工具(如 PlantUML、Chart.js)。
    • 云服务:提供在线编辑器和渲染服务,类似 GitBook。
    • 阅读器开发:开发跨平台的 MDEpub 阅读器(基于 Electron 或 Web)。
    • 标准推广:提交 MDEpub 作为开源标准,邀请社区贡献。

    9. 快速原型实现

    以下是一个简单的 Node.js 脚本,展示如何将包含 Mermaid 和 Markmap 的 Markdown 转换为 MDEpub 核心组件:

    javascript

    const fs = require('fs');
    const markdownIt = require('markdown-it')();
    const mermaid = require('mermaid');
    const { Markmap } = require('markmap-view');
    const archiver = require('archiver');
    
    // 初始化 Mermaid
    mermaid.initialize({ startOnLoad: false });
    
    // 自定义 Markdown 插件
    markdownIt.use((md) => {
      md.renderer.rules.fence_custom = {
        mermaid: async (tokens, idx) => {
          const code = tokens[idx].content;
          const { svg } = await mermaid.render('graph', code);
          return `<div class="mermaid">${svg}</div>`;
        },
        markmap: (tokens, idx) => {
          const code = tokens[idx].content;
          return `<div class="markmap" data-markmap="${encodeURIComponent(code)}"></div>`;
        }
      };
    });
    
    // 解析 Markdown 文件
    const mdContent = fs.readFileSync('content/chapter1.md', 'utf-8');
    const htmlContent = markdownIt.render(mdContent);
    
    // 生成 HTML 文件
    fs.writeFileSync('output/chapter1.html', `
    <!DOCTYPE html>
    <html>
    <head>
      <link rel="stylesheet" href="styles.css">
      <script src="mermaid.min.js"></script>
      <script src="d3.min.js"></script>
      <script src="markmap-view.min.js"></script>
    </head>
    <body>
      ${htmlContent}
      <script>
        // 初始化 Markmap
        document.querySelectorAll('.markmap').forEach(el => {
          const data = decodeURIComponent(el.dataset.markmap);
          const mm = Markmap.create(el, { height: 300 });
          mm.setData(data);
        });
      </script>
    </body>
    </html>
    `);
    
    // 打包为 MDEpub
    const output = fs.createWriteStream('book.mdepub');
    const archive = archiver('zip');
    archive.pipe(output);
    archive.directory('output/', false);
    archive.finalize();

    10. 总结

    通过设计一个基于 Markdown 的电子书格式(MDEpub),可以实现类似 EPUB 的功能,同时原生支持 Mermaid 和 Markmap 的可视化和交互功能。核心是扩展 Markdown 解析器,集成 Mermaid 和 Markmap 渲染器,生成包含 SVG 或交互式 HTML 的电子书文件。MDEpub 结合 Markdown 的简洁性和可视化工具的强大功能,适合技术文档、教程和交互式电子书。下一步是开发 CLI 工具和专用阅读器,优化兼容性和性能。

  • 在Ubuntu24上部署JupyterHub + JupyterLab + DockerSpawner

    在 Ubuntu 系统上部署 JupyterHub、JupyterLab 和 DockerSpawner 的详细方案,涵盖环境准备、安装、配置和部署步骤。目标是创建一个多用户 Jupyter 环境,每个用户通过 DockerSpawner 运行独立的 JupyterLab 容器,确保隔离性和可扩展性。本方案基于官方文档和社区最佳实践,也适用于 Ubuntu 20.04 或 22.04。

    总体上分两种情况,一种是直接在服务器上启动JupyterHub,另一种是在docker中启动JupyterHub,后者隔离效果更好,推荐使用,但是绑定服务器目录时需要注意。以下方案中会作出区分说明。


    1. 环境准备

    1.1 系统要求

    • 操作系统:Ubuntu 20.04 LTS 或 22.04 LTS(推荐服务器版)。
    • 硬件要求:
      • 最低配置:2核CPU,4GB内存,20GB磁盘空间。
      • 推荐配置:4核CPU,8GB内存,50GB+磁盘空间(根据用户数量和数据存储需求调整)。
    • 网络:确保服务器可以访问互联网以拉取 Docker 镜像和安装依赖。
    • 权限:需要 root 或 sudo 权限。

    1.2 安装基本工具

    更新系统并安装必要的工具:

    bash

    sudo apt update && sudo apt upgrade -y

    下面这一步并非必要,主要用于在服务器上直接启动JupyterHub。

    bash

    sudo apt install -y curl git python3 python3-pip python3-venv

    1.3 安装 Docker

    安装 Docker 和 Docker Compose,用于运行 JupyterHub 和用户容器:

    bash

    # 安装 Docker
    sudo apt install -y docker.io
    sudo systemctl start docker
    sudo systemctl enable docker
    
    # 验证 Docker 安装
    docker --version
    
    # 安装 Docker Compose
    sudo curl -L "https://github.com/docker/compose/releases/download/v2.20.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
    sudo chmod +x /usr/local/bin/docker-compose
    
    # 验证 Docker Compose 安装
    docker-compose --version
    
    # 将当前用户添加到 docker 组(避免每次使用 docker 需要 sudo)
    sudo usermod -aG docker $USER
    newgrp docker

    上面这一步需要重新登录或者重启才能生效。其中docker-compose也可以不装,新版的docker中自带docker compose命令。

    2. 安装 JupyterHub 和依赖(这是服务器直接部署JupyterHub,使用docker的话可以跳过)

    2.1 创建虚拟环境

    为了隔离 JupyterHub 的 Python 依赖,创建一个虚拟环境:

    bash

    python3 -m venv /opt/jupyterhub
    source /opt/jupyterhub/bin/activate

    2.2 安装 JupyterHub 和 DockerSpawner

    在虚拟环境中安装 JupyterHub 和相关包:

    bash

    pip install --upgrade pip
    pip install jupyterhub jupyterlab dockerspawner
    • jupyterhub:核心服务,用于管理多用户环境。
    • jupyterlab:为用户提供 JupyterLab 界面。
    • dockerspawner:用于在 Docker 容器中启动单用户 JupyterLab 实例。

    2.3 安装 Node.js(可选,JupyterLab 依赖)

    JupyterLab 需要 Node.js 来支持扩展和前端功能:

    bash

    sudo apt install -y nodejs npm

    3. 配置 JupyterHub(这个配置文件是用于服务器直接部署,docker部署的话其中的设置有所区别)

    3.1 创建 JupyterHub 配置文件

    生成默认配置文件(也可以跳过,直接复制下面的配置文件内容进去,默认配置文件很长,看起来不方便):

    bash

    mkdir /opt/jupyterhub
    jupyterhub --generate-config -f /opt/jupyterhub/jupyterhub_config.py

    配置文件位于 /opt/jupyterhub/etc/jupyterhub_config.py,以下是关键配置步骤。

    3.2 配置 DockerSpawner

    编辑 jupyterhub_config.py,添加以下内容以启用 DockerSpawner 和 JupyterLab:

    python

    c = get_config()
    import os
    import sys
    from dockerspawner import DockerSpawner
    
    # 设置 DockerSpawner
    c.JupyterHub.spawner_class = 'dockerspawner.DockerSpawner'
    c.DockerSpawner.image = 'jupyter/minimal-notebook:x86_64-python-3.11.6'
    c.DockerSpawner.network_name = 'jupyterhub-network'
    
    # 设置 JupyterLab 作为默认界面
    c.Spawner.default_url = '/lab'
    
    # 持久化存储配置
    notebook_dir = '/home/jovyan/work'
    c.DockerSpawner.notebook_dir = notebook_dir
    c.DockerSpawner.volumes = { 
        '/mnt/raid/jupyterhub_persistent/{username}': notebook_dir,
        '/mnt/raid/jupyterhub_shared': '/home/jovyan/shared'
    }
    # 上面路径中的/mnt/raid是我自己服务器的一个地址,可以替换。注意这个地址不管在服务器直接运行JupyterHub还是在docker中,都是设置为服务器上的地址,因为是绑定给用户容器的。
    
    # 动态创建用户目录
    def create_dir_hook(spawner):
        username = spawner.user.name
        volume_path = os.path.join('/mnt/raid/jupyterhub_persistent', username)
        if not os.path.exists(volume_path):
            os.mkdir(volume_path, 0o755)
            os.chown(volume_path, 1000, 100)  # jovyan 用户的 UID 和 GID
    c.Spawner.pre_spawn_hook = create_dir_hook
    
    # 资源限制
    c.DockerSpawner.extra_host_config = {
        'mem_limit': '16g',  # 每个容器 64GB,10 个用户平分 640GB
        'cpu_period': 100000,
        'cpu_quota': 1000000,  # 每个容器 1 核心,10 个用户共 10 核心
    }
    
    # 如果本地端口有冲突可以设置,否则不设置
    c.JupyterHub.bind_url = 'http://:8090'
    c.JupyterHub.hub_connect_ip = '127.0.0.1'
    c.JupyterHub.hub_ip = '0.0.0.0'
    c.JupyterHub.hub_port = 9000
    
    # 可选:设置认证,根据需要选择认证方式,建议用这种自定义用户比较方便,不用系统的用户
    c.JupyterHub.authenticator_class = 'nativeauthenticator.NativeAuthenticator'
    c.NativeAuthenticator.enable_signup = True
    c.NativeAuthenticator.open_signup = True
    c.Authenticator.admin_users = {'admin'}
    
    # 可选:自动停止闲置服务器
    c.JupyterHub.services = [
    #    {
    #        'name': 'cull_idle',
    #        'admin': True,
    #        'command': 'python3 /opt/jupyterhub/cull_idle_servers.py --timeout=3600'.split(),
    #    },
        {
            "name": "jupyterhub-idle-culler-service",
            "command": [
                sys.executable,
                "-m", "jupyterhub_idle_culler",
                "--timeout=3600",
            ],
             "admin": True,
        }
    ]
    

    3.3 创建 Docker 网络

    为 JupyterHub 和用户容器创建一个专用的 Docker 网络:

    bash

    docker network create jupyterhub-network

    3.4 配置认证

    JupyterHub 默认使用 PAM 认证(基于系统用户)。若需要简单测试,可以配置 Native Authenticator 允许用户自注册:

    bash

    pip install jupyterhub-nativeauthenticator

    在 jupyterhub_config.py 中添加:

    python

    c.JupyterHub.authenticator_class = 'nativeauthenticator.NativeAuthenticator'
    c.Authenticator.admin_users = {'admin'}  # 设置管理员用户

    若使用其他认证方式(如 OAuth、LDAP),请参考 JupyterHub 官方文档配置对应 Authenticator。

    3.5 数据持久化

    为确保用户数据持久化,DockerSpawner 使用 Docker 卷(如上配置)。每个用户的卷命名为 jupyterhub-user-{username},存储在 /home/jovyan/work 目录。

    若需要共享数据目录,可以挂载主机路径:

    python

    c.DockerSpawner.volumes = {
        'jupyterhub-user-{username}': notebook_dir,
        '/path/on/host/shared': '/home/jovyan/shared'
    }

    确保主机路径权限正确:

    bash

    sudo chown :1000 /path/on/host/shared
    sudo chmod g+rws /path/on/host/shared
    sudo setfacl -d -m g::rwx /path/on/host/shared

    4. 使用 Docker Compose 部署

    为简化管理,使用 Docker Compose 部署 JupyterHub 和相关服务。

    4.1 创建 docker-compose.yml

    在 /opt/jupyterhub 目录下创建 docker-compose.yml:

    yaml

    version: '3.8'
    services:
      jupyterhub:
        build:
          context: .
          dockerfile: Dockerfile
        container_name: jupyterhub
        restart: unless-stopped
        ports:
          - "9000:8000"
        volumes:
          - /opt/jupyterhub/srv:/srv/jupyterhub # 这里单独设置了一个srv以跟docker中的srv对应,区别于服务器直接部署的配置,测试时方便区分
          - /var/run/docker.sock:/var/run/docker.sock
          - /mnt/raid/jupyterhub/jupyterhub_persistent:/jupyterhub/jupyterhub_persistent
          - /mnt/raid/jupyterhub/jupyterhub_shared:/jupyterhub/jupyterhub_shared
        environment:
          - DOCKER_HOST=unix:///var/run/docker.sock
          - DOCKER_NOTEBOOK_IMAGE=jupyter/scipy-notebook:latest
          - DOCKER_NETWORK_NAME=jupyterhub-network
        networks:
          - jupyterhub-network
    
    networks:
      jupyterhub-network:
        external: true
    

    用户环境定制

    若需要自定义用户镜像,创建 Dockerfile:

    因为启用了nativeauthenticator所以默认的镜像不行,需要自己通过Dockerfile加上。同时也指定自己的jupyterhub_config

    Dockerfile

    # Use the official JupyterHub base image
    FROM jupyterhub/jupyterhub:latest
    
    # Install dockerspawner and nativeauthenticator
    RUN pip install --no-cache-dir \
        dockerspawner \
        jupyterhub-nativeauthenticator \
        jupyterhub-idle-culler
    
    # Create directory for persistent storage (if needed inside the hub container)
    RUN mkdir -p /jupyterhub/jupyterhub_persistent /jupyterhub/jupyterhub_shared
    RUN chmod -R 755 /jupyterhub
    
    # Copy the jupyterhub_config.py into the container
    COPY jupyterhub_config.py /srv/jupyterhub/jupyterhub_config.py
    
    # Expose the default JupyterHub port
    EXPOSE 8000
    
    # Set working directory
    WORKDIR /srv/jupyterhub
    
    # Start JupyterHub
    CMD ["jupyterhub", "-f", "/srv/jupyterhub/jupyterhub_config.py"]
    

    4.2 用docker部署并启动 JupyterHub(这是方式二)

    bash

    cd /opt/jupyterhub
    docker-compose up -d

    4.3 验证部署

    • 访问 http://<服务器IP>:8000,应看到 JupyterHub 登录页面。
    • 使用管理员账户(如 admin)登录,测试创建用户和启动 JupyterLab 容器。
    • 检查 Docker 容器:bashdocker ps应看到 jupyterhub 容器和用户容器(如 jupyter-<username>)。

    4.4 日志查看

    若遇到问题,查看日志:

    bash

    docker logs jupyterhub

    5. 高级配置

    5.1 HTTPS 配置(不建议,建议另外通过caddy代理并设置ssl)

    为生产环境,建议配置 HTTPS:

    1. 使用 Let’s Encrypt 获取免费 SSL 证书:bashsudo apt install -y certbot python3-certbot-nginx certbot certonly --standalone -d <your-domain>
    2. 在 jupyterhub_config.py 中配置 SSL:pythonc.JupyterHub.ssl_key = '/etc/letsencrypt/live/<your-domain>/privkey.pem' c.JupyterHub.ssl_cert = '/etc/letsencrypt/live/<your-domain>/fullchain.pem' c.JupyterHub.port = 443
    3. 更新 docker-compose.yml,将端口改为 443:443。

    5.2 GPU 支持

    若需要 GPU 支持,确保主机安装了 NVIDIA 驱动和 nvidia-container-toolkit:

    bash

    sudo apt install -y nvidia-driver-<version> nvidia-container-toolkit

    在 jupyterhub_config.py 中添加:

    python

    c.DockerSpawner.extra_host_config = {'runtime': 'nvidia'}

    使用支持 GPU 的镜像,如 jupyter/tensorflow-notebook。

    5.3 用户环境定制

    若需要自定义用户镜像,创建 Dockerfile:

    dockerfile

    FROM jupyter/scipy-notebook:latest
    RUN pip install numpy pandas matplotlib
    CMD ["jupyterhub-singleuser"]

    构建并推送到 Docker Hub 或本地仓库:

    bash

    docker build -t my-jupyterlab-image .
    docker tag my-jupyterlab-image <your-dockerhub-username>/my-jupyterlab-image:latest
    docker push <your-dockerhub-username>/my-jupyterlab-image:latest

    在 jupyterhub_config.py 中更新:

    python

    c.DockerSpawner.image = '<your-dockerhub-username>/my-jupyterlab-image:latest'

    6. 常见问题排查

    • “Spawn failed” 错误:
      • 检查 docker logs jupyterhub 是否有 KeyError 或权限问题。
      • 确保 Docker 网络 jupyterhub-network 已创建。
      • 验证 DOCKER_NOTEBOOK_IMAGE 是否可拉取。
    • 用户容器无法访问数据库:
      • 确保数据库容器在同一 Docker 网络中:bashdocker network connect jupyterhub-network <database-container>
    • 权限问题:
      • 检查卷挂载路径权限,确保用户 jovyan(UID 1000)有写权限。
    • JupyterLab 不显示:
      • 确认 c.Spawner.default_url = ‘/lab’ 已设置。
      • 确保镜像中已安装 JupyterLab:bashdocker run -it <image> pip show jupyterlab

    7. 维护与备份

    • 备份用户数据:
      • 用户数据存储在 Docker 卷中,查看卷:bashdocker volume ls
      • 备份卷:bashdocker run --rm -v jupyterhub-user-<username>:/data -v /backup:/backup busybox tar cvf /backup/user-<username>.tar /data
    • 更新 JupyterHub:
      • 停止服务:docker-compose down
      • 更新镜像:docker pull jupyterhub/jupyterhub:latest
      • 重新启动:docker-compose up -d
    • 清理无用容器:bashdocker container prune

    8. 参考资源


    通过以上步骤,您可以在 Ubuntu 上成功部署一个支持 JupyterLab 和 DockerSpawner 的 JupyterHub 环境,适合教学、科研或团队协作场景。如需进一步定制或遇到具体问题,请提供更多细节,我可以为您提供针对性指导!

  • 出版行业如何选择大模型

    过年期间deepseek吵得很热闹,不过就我看到的信息,更像是一次冲喜,毕竟要过除夕了。我不太相信惊喜,二十年前在武汉的某博士沙龙上我突发灵感得到的结论,一切惊喜都可视作异常。回京后,做了下简单的测试,拿一个简单地问题去问这几个模型,这个问题还不算很苛刻,只是想看看训练时的语料审查有多么严重。

    按结果的省略程度排序依次是:

    1. deepseek
    2. qwen
    3. mistral

    拿出版行业来说,尽管审查也是一个很重的任务,但这个任务是由编辑来承担的,大模型没有权力直接来操刀,否则很容易造成失真,编辑就没法干活了。即使有deepseek无审查版也不行,因为那个无审查只是推理时无审查,并不能解决训练阶段的语料审查。

    所以,这个可以当作出版行业大模型的一个选择条件,如果是2C我没有什么意见,安全第一,但是从编辑专业角度而言,必须选择一个中立的大模型来作为基础模型。这几个里面,没有哪个合适的,勉强选择的话只有mistral可以考虑,但这家伙中立的过分了,其实作为专业模型,我们不需要大模型给出态度和立场。

    所以,行业模型还要从更基础的模型来做。

  • Monorepo+federation+defineAsyncComponent构建一栈式主分前端架构

    构建一栈式主分前端架构,结合 Monorepo、Federation 和 defineAsyncComponent 是一种现代且高效的开发模式,特别适用于大型项目或微前端架构。

    以下是如何将这些技术结合起来实现这一架构的详细步骤:

    1. Monorepo(单仓库多包管理)

    定义: Monorepo 是一种将多个相关的代码库存储在一个单一的版本控制系统中的方法。它允许你更方便地管理和协调多个项目的依赖关系和版本更新。

    工具选择:
    •Lerna:用于管理多个 npm 包。
    •Yarn Workspaces 或 npm workspaces:用于处理多个包之间的依赖关系。(我选的是pnpm,虽然我觉得pnpm这个词打起来最费劲,但我在.zshrc里面给它设置成了p)
    •Nx:不仅支持包管理,还提供了丰富的工具链来优化构建和测试流程。
    优点:
    •统一的代码风格和配置。
    •更容易进行跨项目依赖管理。
    •提高了团队协作效率,减少了重复工作。

    用Monorepo关键的地方有两个:

    1)配置package.json里面的”scripts”,根据调试和打包的组合配置参数。

    2)配置dependencies,将共用的部分放到项目根,不过这一点没有上面那条那么重要,属于优化。

    1. Federation(模块联邦)

    定义: 模块联邦允许多个独立的应用程序或微前端共享模块,而不需要通过传统的打包方式。实现步骤:
    •设置主机应用(Host App):
    •使用 Webpack 5 的 ModuleFederationPlugin 配置远程模块。
    •示例配置: new ModuleFederationPlugin({
    name: ‘hostApp’,
    filename: ‘remoteEntry.js’,
    remotes: {
    remoteApp: ‘remoteApp@http://localhost:3001/remoteEntry.js’,
    },
    shared: [‘react’, ‘react-dom’],
    });

    •设置远程应用(Remote App):
    •同样使用 ModuleFederationPlugin 暴露模块。
    •示例配置: new ModuleFederationPlugin({
    name: ‘remoteApp’,
    filename: ‘remoteEntry.js’,
    exposes: {
    ‘./Button’: ‘./src/Button’,
    },
    shared: [‘react’, ‘react-dom’],
    });

    优点:
    •独立部署和开发。
    •模块级别的共享,减少冗余代码。
    •动态加载远程模块,提升性能。

    当然,我用的是vue,上面是钉钉ai助理给的代码,没有仔细看。后面我会整理代码发布到github上供参考。

    1. defineAsyncComponent(异步组件)

    定义:defineAsyncComponent 是 Vue 3 提供的一个 API,用于定义异步组件。它可以按需加载组件,从而优化初始加载时间和性能。实现步骤:
    •在 Vue 项目中使用 defineAsyncComponent 加载远程组件。 import { defineAsyncComponent } from ‘vue’;

    const RemoteButton = defineAsyncComponent(() =>
    import(‘remoteApp/Button’)
    );

    export default {
    components: {
    RemoteButton,
    },
    };

    优点:
    •按需加载,减少初始加载时间。
    •提升用户体验,特别是在网络条件不佳的情况下。
    综合应用项目结构示例:monorepo/
    ├── packages/
    │ ├── host-app/
    │ │ ├── src/
    │ │ └── webpack.config.js
    │ ├── remote-app/
    │ │ ├── src/
    │ │ └── webpack.config.js
    │ └── shared-components/
    │ ├── src/
    │ └── webpack.config.js
    └── package.json
    构建与部署
    •构建:使用 Lerna 或 Nx 进行统一构建。
    •部署:可以分别部署主机应用和远程应用,确保每个应用可以独立更新和维护。
    总结通过结合 Monorepo、Federation 和 defineAsyncComponent,你可以创建一个高效、可扩展的一栈式主分前端架构。这种方式不仅提高了开发效率,还能有效管理和优化大型项目的复杂度。如果你有更多具体的技术问题或需要进一步的帮助,请随时告诉我!(部分内容由AI生成)

    实际上,我没有采用ssr的架构,而是采用普通的vite。

    实际的目录结构如下:

    /apps/one-main
      package.json
    /packages/one-basic
      package.json
    package.json
    pnpm-workspace.yaml

    one-main作为我的主应用,one-basic作为的分应用之一,后续还会有one-beau之类的,主应用是作为门户提供最终用户访问的门面的,分应用有两个作用,提供remote-component组件以及对remote-component的单独演示,同时也方便调试。

    总体上one-main和one-basic也是同构的,都是采用了https://starchart.cc/xiangshu233/vue3-vant4-mobile这个脚手架,我计划将其中的UI替换为naive-ui,我更喜欢这个简洁的风格。

    简单来说,Monorepo是为了这一组代码库方便联调,Federation提供应用间(远程)组件共享,defineAsyncComponent实现动态加载(远程)组件,将远程组件参数化。最终实现的是一个有限灵活度的模板可配置电子书系统。

    本方案的代码库:https://github.com/futuremeng/one-momorepo

  • 增加一个新的Title:武汉大学出版研究院兼职研究员

    武汉大学出版研究院 https://iop.whu.edu.cn/info/1401/3101.htm

    姓名:孟繁永

    职务:兼职研究员

    研究领域:数字出版,人工智能,数字人文

    研究兴趣:利用开源技术搭建低成本轻量化数字出版平台,探索以知识服务为核心目标的数据结构设计、知识加工技术和人工智能应用。

    研究成果:

    1. 许洁;袁小群;朱瑞;孟繁永. 基于大模型的轻量级智能出版知识服务:理论基础与实现路径[J]. 中国数字出版, 2024 ,v.2;No.2 (01) :25-35.

    项目经验:

    [主导]语文出版社一书一码融媒体出版平台,2020-2024

    [主导]《党建》杂志期刊发行数字化平台,2020-2021

    [主导]中国铁建地产集团数据中台与运营可视化,2019-2020

    [主导]工商出版社工商法律法规大数据平台,2019-2020

    [主导]法律出版社“微版云”数字资源管理云平台,2018-2019

    [主导]中国新闻出版研究院希普思会议会展数字化运营平台,2018-2019

    [主导]学习出版社《全民经典朗读范本》融媒体出版平台,2017

    [主导]中国新闻出版研究院“编辑邦”出版人知识社群,2016-2017

    [参与]中国少年儿童新闻出版总社中少快乐阅读平台,2012-2015

    [参与]长江出版集团ERP试点,2009-2010

  • 原版原式电子书制作工具推荐:名编辑电子杂志大师

    推荐理由:支持H5版本输出,效果还不错,支持添加音视频等富媒体资源。

    缺点:使用中有一些bug,官方软件更新不积极。

    配套:为了给使用这个软件的客户提供支持,我做了配套的音频切割工具,有需要的可以微信我了解。

    软件功能:

    最好用的电子杂志制作软件功能
    PDF/图片转换成翻页电子杂志

    基本任何格式的设计稿或文档都能输出为PDF或图片格式,直接导入名编辑,即可转换为精美的3D翻书式电子杂志。另外,名编辑对PDF的识别、分割、切割能力非常强,无需借助其他软件。

    最好用的电子杂志制作软件功能
    批量转换多个PDF文件

    您可以同时批量转换多个PDF文件。导入PDF文件,设置需要导入的页面范围和选择模板、主题,然后能一口气生成多个电子书或者合并为一本电子杂志了。

    最好用的电子杂志制作软件功能
    添加多媒体文件

    您可以在电子杂志里添加形状、文本、链接、图片、视频、flash或声音文件。

    最好用的电子杂志制作软件功能
    设置背景音乐

    在名编辑中,您可以设置背景音乐,并且可以选择循环播放或单曲播放等多种播放模式。

    最好用的电子杂志制作软件功能
    添加图片播放器

    当您有很多图片需要在某个页面展示时,您可以在翻页电子杂志的页面添加图片幻灯片播放器,展示您需要展示的图片。

    最好用的电子杂志制作软件功能
    自定义背景图片、颜色背景和flash动态背景

    您可以设置任何您喜欢的背景图片,设置纯色背景或者渐变色背景。如果您觉得图片背景不够绚丽,您还可以用flash动态背景。名编辑电子杂志大师提供了许多免费的场景,同时也可以导入您自己的flash文件作为背景。

    最好用的电子杂志制作软件功能
    输出HTML/EXE/Zip/Mac App/手机版本

    HTML用于上传网络;*.EXE和*.Zip可直接发给客户在自己电脑上阅读;*.App用于在苹果电脑本地离线阅读;手机版输出的HTML5格式可在手机在线阅读、离线阅读。另外也可录制到CD。

    最好用的电子杂志制作软件功能
    上传到网上在线阅读,支持手机/平板/电脑

    当您用我们的电子杂志制作软件制作了HTML格式的电子杂志后,您可以通过FTP上传到服务器空间,同时支持手机、平板和电脑在线阅读。

    最好用的电子杂志制作软件功能
    在线上传功能

    一键上传制作好的电子杂志,并生成链接以及二维码用于微信分享,微信公众号推广,提供书橱功能实现同一个链接页面上展示多本书(需另外付费)

    最好用的电子杂志制作软件功能
    离线阅读:支持电脑/iPad/iPhone/安卓apk

    名编辑电子杂志能输出离线阅读的电子杂志:支持Windows电脑、苹果电脑、iPad、iPhone和安卓apk。

    最好用的电子杂志制作软件功能
    嵌入到网页

    用名编辑电子杂志大师制作的翻页电子杂志能够很方便的嵌入到您的个人页面、公司页面或者政府公共页面。

    最好用的电子杂志制作软件功能
    内置模板、主题和动态背景

    为了更方便用户制作精美的翻页电子杂志,名编辑电子杂志大师软件自带了许多主题模板和动态背景,用户可以双击主题应用不同的电子杂志风格。

    最好用的电子杂志制作软件功能
    导入PDF中的超链接

    在导入PDF文件的同时,PDF里面的内容也可以一并导入到翻页电子书中,包括文本、图片、书签和PDF中的网页链接、页面链接、邮箱链接等内容。

    最好用的电子杂志制作软件功能
    保存编辑文件

    在制作电子杂志过程中,如果没编辑完成,或是因为有其他的事情不得暂时不终止杂志制作,用户可以把设置中的杂志导出为工程文件(FLB),下次可以导入再继续编辑。

    最好用的电子杂志制作软件功能
    预览效果

    您在制作电子杂志的过程中,可以预览电子杂志输出后的效果。

    最好用的电子杂志制作软件功能
    设置电子杂志厚度、边缘大小、页面阴影

    在名编辑电子杂志大师中,您可以设置电子杂志的厚度、边缘大小、页面阴影,让您的电子杂志外观以及翻页效果看起来更真实。

    最好用的电子杂志制作软件功能
    设置硬皮封面

    根据自己的需要,设置成硬皮的封面,电子杂志外观看起来就更真实了。

    最好用的电子杂志制作软件功能
    设置多语言浏览界面

    名编辑提供了英语,意大利,阿拉伯语,日语,韩语等十几种语言,您设置一种语言或者多种语言让您的读者可以自由切换。

    最好用的电子杂志制作软件功能
    定义电子杂志页面清晰度

    在名编辑电子杂志大师中,有5个清晰度档次供您选择:超清、高清、清晰、普清和一般。用户可以根据自己的需求,自行选取导入页面的画质。

    最好用的电子杂志制作软件功能
    渲染引擎功能

    设置不同的渲染引擎可以避免一些特定PDF在转换中变形、扭曲。如果您在导入PDF过程整出现了PDF导入失败,PDF导入信息有丢失或者PDF导入不完整,您可以尝试修改PDF导入渲染引擎。

    最好用的电子杂志制作软件功能
    导入PDF中的目录

    如果您的PDF文件已经设置了目录,可以通过选取导入目录选项导入到电子杂志中,如果源PDF文件未设置目录,可以用软件新建目录。

    最好用的电子杂志制作软件功能
    添加标签书签功能

    标签书签不同于目录,它不能从PDF页面中直接导入,但是您可以制作一个类似于书签按钮。点击标签按钮,就可以直接进入标签指定页面。

    最好用的电子杂志制作软件功能
    自动分割一个页面为两个页面

    您之前制作的PDF书籍,可能是两个页面并列为一个页面,名编辑可以探测导入的PDF页面宽度,自动分割为两个页面。

    最好用的电子杂志制作软件功能
    添加密码保护

    您可以给整本电子杂志添加密码,或者给单独几页、多少页之后的内容添加密码。读者需要输入密码才能继续阅读。

    最好用的电子杂志制作软件功能
    搜索功能

    导入PDF中的文字,文字信息就能够被搜索,以及可以定义最低搜索字符。

    最好用的电子杂志制作软件功能
    设置工具栏图标

    如果您觉得我们软件默认的工具栏图标不好看,您可以自己上传图标,设置自己喜欢的图标。

    最好用的电子杂志制作软件功能
    添加水印功能

    添加文字,图片,动态日期等水印到电子杂志页面。

    最好用的电子杂志制作软件功能
    添加图片或者SWF水印文件到打印页面

    添加这个功能后,用户在浏览电子杂志时页面不会出现水印,但是如果要打印出来,则打印出来的东西都会带有水印。这样可以保护您的版权。

    最好用的电子杂志制作软件功能
    添加带链接的Logo等信息

    您可以在翻页电子杂志窗口中添加图片或者swf格式的Logo、标题、作者等个人信息,从而树立公司形象,标注版权。并且可以添加链接,点击进入指定链接页面。

    最好用的电子杂志制作软件功能
    添加功能按钮

    您可以通过页面管理器功能中的添加按钮选项,在电子杂志一些页面添加功能按钮,指定按钮的功能为打开链接、跳至某一页面、调用Javascript 脚本、打开弹出窗口播放flash/视频、打开幻灯片等等。

    最好用的电子杂志制作软件功能
    设置右翻书或者左翻书的阅读模式

    阿拉伯或者中国古书就是向左翻页的模式。

    最好用的电子杂志制作软件功能
    放大、缩小、全屏

    我们提供了放大、缩小和全屏浏览模式,来提高用户在阅读时候的体验。可以通过双击翻页书页面来进行放大和缩小,或者通过放大、缩小、全屏功能按钮来进行操作。

    最好用的电子杂志制作软件功能
    卡通人物解说员助手功能

    在电子杂志窗口显示卡通人物解说员助手,您可以直接插入或者录制声音给解说员在相应的页面配音。

    最好用的电子杂志制作软件功能
    设置页码展示以及开始页面

    在电子杂志浏览界面窗口设置页码展示效果,以及设置电子杂志开始页面。

    最好用的电子杂志制作软件功能
    设置下载,打印,分享等功能
    最好用的电子杂志制作软件功能
    可选择分享某个页面

    可以分享整本书(也就是别人打开后第一页开始阅读),也可以分享某个页面开始阅读(别人打开后就能直接看到这个页面)

  • 山河大学出版社简介

    山河大学出版社成立于2023年,是一家依托于山河大学的专业出版机构。山河大学是一所具有悠久历史和良好声誉的高等学府,致力于培养优秀的人才,拥有广泛的学科领域和强大的科研实力。作为山河大学出版社,我们致力于为读者提供高质量、实用的图书,为学术研究和人才培养做出自己的贡献。

    山河大学出版社是一家以图书、杂志、教材等出版物为主要业务的公司。我们的出版品种涵盖了各个学科领域,包括社会科学、自然科学、医学、工程技术、农业、经济、管理、教育等。我们的图书内容丰富,形式多样,既包括了传统的纸质出版物,也包括了数字化出版、在线阅读等现代出版形式。我们致力于为读者提供最全面、最丰富、最优质的服务,以满足读者的不同需求。

    作为一家新的出版社,我们深知自己的责任和使命。我们坚持以读者为中心,以质量为根本,以服务为宗旨,努力为读者提供更好的阅读体验和更丰富的知识储备。我们的出版作品都将经过严格的审核和编辑,确保品质和内容的准确性。同时,我们也将积极引进和出版国外的优秀图书,推动文化交流和知识共享。
    在未来的发展中,山河大学出版社将继续秉承“团结协作、开拓创新、质量第一、服务读者”的理念,努力为读者和社会做出更大的贡献。我们将进一步加强与各学科领域专家的合作,打造更多优秀的学术作品。同时,我们也将不断创新数字出版等现代出版形式,开拓新的业务领域,提升出版物的传播和推广效果。

    此外,山河大学出版社还将积极参与社会公益活动,将出版物的利润部分用于社会公益事业,为推进教育、科学和文化事业做出自己的贡献。我们坚信,只有和社会各界共同努力,才能让读者享受到更好的阅读体验和更丰富的知识储备。

    山河大学出版社将秉承“团结协作、开拓创新、质量第一、服务读者”的理念,为读者提供更多优质的图书和服务,为学术研究和人才培养做出贡献。我们期待与广大读者和社会各界共同努力,共创美好未来!

    【以上文字来自于ChatGLM2】