400 lines
17 KiB
Python
400 lines
17 KiB
Python
"""教材与在线课程种子数据(两张表分别写入)。
|
||
|
||
教材以《盖尔范德中学生数学思维丛书》(中国科学技术大学出版社)为基础;
|
||
书号 / 出版信息均核对公开书目信息,课程使用官方站点链接。
|
||
"""
|
||
from __future__ import annotations
|
||
|
||
from sqlalchemy.orm import Session
|
||
|
||
from models import Chapter, ChapterKnowledge, Course, Knowledge, Question, Textbook
|
||
from services.knowledge_service import (
|
||
ensure_knowledge_resource,
|
||
set_chapter_knowledge_names,
|
||
)
|
||
|
||
|
||
# 现有题库知识点与《函数和图像》章节的对应关系(按丛书内容就近归类)
|
||
KNOWLEDGE_CHAPTER_MAP = {
|
||
"函数概念": "引言",
|
||
"函数值": "引言",
|
||
"定义域": "引言",
|
||
"正负性": "引言",
|
||
"零点": "第4章 二次三项式",
|
||
"偶函数": "第6章 幂函数",
|
||
"奇函数": "第6章 幂函数",
|
||
"图像对称性": "第6章 幂函数",
|
||
}
|
||
|
||
DEFAULT_CHAPTER_KNOWLEDGE = {
|
||
"引言": ["函数概念", "函数值", "定义域", "正负性"],
|
||
"第4章 二次三项式": ["零点"],
|
||
"第6章 幂函数": ["偶函数", "奇函数", "图像对称性"],
|
||
"第1章 三角函数": ["三角函数"],
|
||
"第2章 三角形中的三角比": ["三角比", "直角三角形"],
|
||
"第3章 三角比之间的关系": ["三角恒等式", "同角关系"],
|
||
"第4章 三角形内的关系": ["正弦定理", "余弦定理"],
|
||
"第5章 角与旋转": ["任意角", "弧度制"],
|
||
"第6章 弧度法": ["弧度制", "弧长与扇形"],
|
||
"第7章 加法公式": ["和角公式", "差角公式"],
|
||
"第8章 三角恒等式": ["倍角公式", "三角恒等式"],
|
||
"第9章 三角函数的图形": ["三角函数图像", "周期函数"],
|
||
"第10章 反函数与三角方程": ["反三角函数", "三角方程"],
|
||
"点与直线:走进射影几何": ["点线面的基本关系", "几何变换"],
|
||
"平行线:走进仿射几何": ["平行与垂直"],
|
||
"面积:走进辛几何": ["面积与周长"],
|
||
"圆:走进欧氏几何": ["圆"],
|
||
"绪论": ["数轴", "平面直角坐标系"],
|
||
"第1章 直线上点的坐标": ["数轴", "实数", "两点间距离"],
|
||
"第2章 平面里点的坐标": [
|
||
"平面直角坐标系",
|
||
"两点间距离",
|
||
"曲线与方程",
|
||
],
|
||
"第3章 三维空间里点的坐标": ["平面直角坐标系", "点线面的基本关系"],
|
||
"第4章 引言": ["平面直角坐标系", "曲线与方程"],
|
||
"第5章 四维空间": ["平面直角坐标系", "曲线与方程"],
|
||
"第6章 四维方体": ["平面直角坐标系", "曲线与方程"],
|
||
}
|
||
|
||
# 在线课程 / 视频与知识点的默认关联(知识点 → 课程资源反向链接)。
|
||
COURSE_KNOWLEDGE_MAP = {
|
||
"Khan Academy · Algebra 1: Functions": [
|
||
"函数与图像",
|
||
"函数概念",
|
||
"函数值",
|
||
"定义域",
|
||
"值域",
|
||
"零点",
|
||
"单调性",
|
||
"奇偶性",
|
||
"偶函数",
|
||
"奇函数",
|
||
"图像对称性",
|
||
"一次函数",
|
||
"函数图像与变换",
|
||
],
|
||
"3Blue1Brown · Essence of Calculus": [
|
||
"极限与连续",
|
||
"导数与微分",
|
||
"一元函数积分",
|
||
],
|
||
"国家中小学智慧教育平台 · 高中数学(人教A版)": [
|
||
"二次函数",
|
||
"抛物线",
|
||
"幂函数",
|
||
"三角函数",
|
||
"任意角",
|
||
"弧度制",
|
||
"三角比",
|
||
"同角三角函数关系",
|
||
"和角与差角公式",
|
||
"三角恒等式",
|
||
"三角函数图像",
|
||
"解三角形",
|
||
"直线方程",
|
||
],
|
||
}
|
||
|
||
# 以正式出版目录为准的官方章节模板(中文书名/ISBN 来自中国科学技术大学出版社版本)。
|
||
OFFICIAL_PRIMARY_CHAPTERS = [
|
||
{"name": "引言", "summary": "函数、自变量、定义域与函数值:从真实图像理解函数。"},
|
||
{"name": "第1章 例子", "summary": "不同函数图像的直观例子与作图方法。"},
|
||
{"name": "第2章 线性函数", "summary": "一次函数的图像、斜率与直线。"},
|
||
{"name": "第3章 函数 y=|x|", "summary": "绝对值函数的图像与性质,关于 y 轴对称的典型例子。"},
|
||
{"name": "第4章 二次三项式", "summary": "二次函数图像、配方、判别式与零点。"},
|
||
{"name": "第5章 分式线性函数", "summary": "y=1/x 类函数图像与渐近行为。"},
|
||
{"name": "第6章 幂函数", "summary": "y=x、y=x²、y=x³ 等幂函数的奇偶性与对称性。"},
|
||
{"name": "第7章 有理函数", "summary": "更一般的有理函数图像与性质综合。"},
|
||
]
|
||
|
||
OFFICIAL_TRIG_CHAPTERS = [
|
||
{"name": "第1章 三角函数", "summary": "从角与旋转进入三角函数,建立正弦、余弦、正切的基本概念。"},
|
||
{"name": "第2章 三角形中的三角比", "summary": "在直角三角形中定义正弦、余弦与正切,理解锐角三角比。"},
|
||
{"name": "第3章 三角比之间的关系", "summary": "同角三角比的关系、互余关系与基本恒等式推导。"},
|
||
{"name": "第4章 三角形内的关系", "summary": "正弦定理、余弦定理以及三角形中边角关系的应用。"},
|
||
{"name": "第5章 角与旋转", "summary": "把角推广到任意旋转角,定义任意角的三角函数。"},
|
||
{"name": "第6章 弧度法", "summary": "引入弧度制,理解弧长、扇形与角度制换算。"},
|
||
{"name": "第7章 加法公式", "summary": "两角和与差的三角函数公式及其几何与代数证明。"},
|
||
{"name": "第8章 三角恒等式", "summary": "倍角、半角与和差化积等常用三角恒等式。"},
|
||
{"name": "第9章 三角函数的图形", "summary": "正弦、余弦、正切函数的图像、周期与变换。"},
|
||
{"name": "第10章 反函数与三角方程", "summary": "反三角函数的基本概念与三角方程的求解方法。"},
|
||
]
|
||
|
||
OFFICIAL_COORDINATE_CHAPTERS = [
|
||
{"name": "绪论", "summary": "用坐标把几何问题转化为代数问题的方法引言。"},
|
||
{"name": "第1章 直线上点的坐标", "summary": "数轴、数的绝对值与两点之间的距离。"},
|
||
{"name": "第2章 平面里点的坐标", "summary": "坐标平面、坐标间关系、距离公式、确定平面图形与其他坐标系。"},
|
||
{"name": "第3章 三维空间里点的坐标", "summary": "空间坐标轴与坐标平面,确定空间中的图形。"},
|
||
{"name": "第4章 引言", "summary": "从三维推广到四维空间的动机:几何、计算与物理。"},
|
||
{"name": "第5章 四维空间", "summary": "四维空间中的坐标轴、坐标平面与距离问题。"},
|
||
{"name": "第6章 四维方体", "summary": "球与方体的定义、四维方体的结构与相关问题。"},
|
||
]
|
||
|
||
OFFICIAL_GEOMETRY_CHAPTERS = [
|
||
{"name": "点与直线:走进射影几何", "summary": "从点与直线的位置关系出发理解射影几何的基本思想。"},
|
||
{"name": "平行线:走进仿射几何", "summary": "以平行关系为线索建立仿射几何的直观框架。"},
|
||
{"name": "面积:走进辛几何", "summary": "通过面积概念与保持面积变换认识辛几何。"},
|
||
{"name": "圆:走进欧氏几何", "summary": "以圆为核心回到经典欧氏几何的结构与性质。"},
|
||
]
|
||
|
||
COURSES = [
|
||
{
|
||
"name": "Khan Academy · Algebra 1: Functions",
|
||
"provider": "Khan Academy",
|
||
"url": "https://www.khanacademy.org/math/algebra/x2f8bb11595b61c86:functions",
|
||
"grade": "初中衔接 / 高中",
|
||
"description": (
|
||
"函数单元含函数求值、定义域值域、函数图像与性质等大量免费练习,"
|
||
"英文界面,适合配合盖尔范德丛书做自动化巩固。"
|
||
),
|
||
},
|
||
{
|
||
"name": "3Blue1Brown · Essence of Calculus",
|
||
"provider": "3Blue1Brown",
|
||
"url": "https://www.youtube.com/playlist?list=PLZHQObOWTQDMsr9K-rj53DwVRMYO3t5Yr",
|
||
"grade": "高中高年级 / 大学先修",
|
||
"description": (
|
||
"微积分本质系列:从几何直觉理解导数与积分,适合函数图像直觉建立后"
|
||
"进入微积分阶段使用。"
|
||
),
|
||
},
|
||
{
|
||
"name": "国家中小学智慧教育平台 · 高中数学(人教A版)",
|
||
"provider": "教育部教育技术与资源发展中心",
|
||
"url": "https://basic.smartedu.cn/syncClassroom",
|
||
"grade": "高中全学段",
|
||
"description": (
|
||
"官方免费同步课程与配套课件,可按教材版本与册次点播,"
|
||
"适合做课内进度对照。"
|
||
),
|
||
},
|
||
]
|
||
|
||
# 官方章节模板 → 教材:按 ISBN 绑定,seed 在空库或补齐时据此写入章节目录。
|
||
OFFICIAL_CHAPTERS_BY_ISBN = {
|
||
"9787312050053": OFFICIAL_PRIMARY_CHAPTERS, # 函数和图像
|
||
"9787312057793": OFFICIAL_GEOMETRY_CHAPTERS, # 几何
|
||
"9787312046957": OFFICIAL_TRIG_CHAPTERS, # 三角函数
|
||
"9787312050060": OFFICIAL_COORDINATE_CHAPTERS, # 坐标方法
|
||
}
|
||
|
||
|
||
CATALOG = [
|
||
{
|
||
"name": "函数和图像(盖尔范德中学生数学思维丛书)",
|
||
"author": "I. M. Gelfand, E. G. Glagoleva, E. E. Shnol 著;麻希南、胡长青 译",
|
||
"publisher": "中国科学技术大学出版社",
|
||
"isbn": "9787312050053",
|
||
"edition": "2020年12月第1版",
|
||
"grade": "初中至高中低年级",
|
||
"link": "",
|
||
"description": (
|
||
"本系统的主教材。以大量真实图像(地震图、心电图等)引入函数,"
|
||
"强调“画图就是看见公式”,系统训练函数概念、图像与性质直觉;"
|
||
"英译本 Functions and Graphs 由 Dover 出版。现有函数与对称性题库"
|
||
"以本书为依据。"
|
||
),
|
||
"chapters": OFFICIAL_PRIMARY_CHAPTERS,
|
||
},
|
||
{
|
||
"name": "代数(盖尔范德中学生数学思维丛书)",
|
||
"author": "I. M. Gelfand, A. Shen 著;胡长青、麻希南 译",
|
||
"publisher": "中国科学技术大学出版社",
|
||
"isbn": "9787312048937",
|
||
"edition": "2020年第1版",
|
||
"grade": "初中至高中低年级",
|
||
"link": "",
|
||
"description": (
|
||
"用问题驱动的叙述串联自然数、负数、代数式与方程,"
|
||
"重视“为什么可以这样变形”的代数思维,适合作为代数学基础。"
|
||
),
|
||
"chapters": [],
|
||
},
|
||
{
|
||
"name": "几何(盖尔范德中学生数学思维丛书)",
|
||
"author": "I. M. Gelfand 等 著",
|
||
"publisher": "中国科学技术大学出版社",
|
||
"isbn": "9787312057793",
|
||
"edition": "2023年第1版",
|
||
"grade": "初中至高中低年级",
|
||
"link": "",
|
||
"description": (
|
||
"以直观可视的方式从图形构造逐步建立几何,突出“先看见、再证明”"
|
||
"的思维路线。"
|
||
),
|
||
"chapters": OFFICIAL_GEOMETRY_CHAPTERS,
|
||
},
|
||
{
|
||
"name": "三角函数(盖尔范德中学生数学思维丛书)",
|
||
"author": "I. M. Gelfand, M. Saul 著;王作勤 译",
|
||
"publisher": "中国科学技术大学出版社",
|
||
"isbn": "9787312046957",
|
||
"edition": "2020年第1版",
|
||
"grade": "初中至高中低年级",
|
||
"link": "",
|
||
"description": (
|
||
"从初等几何直觉进入正弦、余弦与正切,解释周期与波动现象的数学本质。"
|
||
),
|
||
"chapters": OFFICIAL_TRIG_CHAPTERS,
|
||
},
|
||
{
|
||
"name": "坐标方法(盖尔范德中学生数学思维丛书)",
|
||
"author": "I. M. Gelfand, E. G. Glagoleva, A. A. Kirillov 著;王作勤 译",
|
||
"publisher": "中国科学技术大学出版社",
|
||
"isbn": "9787312050060",
|
||
"edition": "2020年12月第1版",
|
||
"grade": "初中至高中低年级",
|
||
"link": "",
|
||
"description": (
|
||
"讲解如何用坐标把几何问题转化为代数问题,是解析几何与函数图像"
|
||
"方法的基础。"
|
||
),
|
||
"chapters": OFFICIAL_COORDINATE_CHAPTERS,
|
||
},
|
||
]
|
||
|
||
|
||
def ensure_catalog(db: Session, force_sync: bool = False) -> None:
|
||
"""写入默认教材目录。
|
||
|
||
空库(或 ``--force``)时按下述顺序全量登记教材与官方章节;存量库只
|
||
*补齐缺失的章节*,既不覆盖管理员改过的教材信息,也不改动已有章节顺序,
|
||
因此可以随每次启动安全重放。
|
||
"""
|
||
_ensure_courses(db)
|
||
if db.query(Textbook).count() == 0 or force_sync:
|
||
for position, item in enumerate(CATALOG):
|
||
textbook = _upsert_textbook(db, item, position)
|
||
_backfill_chapters(db, textbook, item["chapters"])
|
||
else:
|
||
for item in CATALOG:
|
||
textbook = (
|
||
db.query(Textbook).filter(Textbook.name == item["name"]).first()
|
||
)
|
||
if textbook is None:
|
||
continue
|
||
_backfill_chapters(db, textbook, item["chapters"])
|
||
db.flush()
|
||
_link_unassigned_questions(db)
|
||
_sync_default_chapter_knowledge(db)
|
||
_sync_default_course_resources(db)
|
||
db.commit()
|
||
|
||
|
||
def _upsert_textbook(db: Session, item: dict, position: int) -> Textbook:
|
||
textbook = db.query(Textbook).filter(Textbook.name == item["name"]).first()
|
||
if textbook is None:
|
||
textbook = Textbook(name=item["name"], position=position)
|
||
db.add(textbook)
|
||
db.flush()
|
||
textbook.author = item["author"]
|
||
textbook.publisher = item["publisher"]
|
||
textbook.isbn = item["isbn"]
|
||
textbook.edition = item["edition"]
|
||
textbook.grade = item["grade"]
|
||
textbook.link = item["link"]
|
||
textbook.description = item["description"]
|
||
textbook.position = position
|
||
return textbook
|
||
|
||
|
||
def _backfill_chapters(db: Session, textbook: Textbook, chapters: list[dict]) -> None:
|
||
"""按官方目录补齐缺失章节(已有的同名章节原样保留)。"""
|
||
if not chapters:
|
||
return
|
||
existing = {
|
||
chapter.name
|
||
for chapter in db.query(Chapter)
|
||
.filter(Chapter.textbook_id == textbook.id)
|
||
.all()
|
||
}
|
||
position = len(existing)
|
||
for chapter in chapters:
|
||
if chapter["name"] in existing:
|
||
continue
|
||
db.add(
|
||
Chapter(
|
||
textbook_id=textbook.id,
|
||
name=chapter["name"],
|
||
position=position,
|
||
summary=chapter["summary"],
|
||
)
|
||
)
|
||
position += 1
|
||
|
||
|
||
def _link_unassigned_questions(db: Session) -> None:
|
||
"""把尚未归入章节的题目按知识点-章节映射挂到主教材对应章节。
|
||
|
||
只处理 ``chapter_id`` 为空的题目:管理员手工挂过或改过的题目不动,
|
||
重放种子脚本不会冲掉人工维护结果。
|
||
"""
|
||
primary = db.query(Textbook).filter(Textbook.name == CATALOG[0]["name"]).first()
|
||
if primary is None:
|
||
return
|
||
chapter_map = {
|
||
chapter.name: chapter
|
||
for chapter in db.query(Chapter)
|
||
.filter(Chapter.textbook_id == primary.id)
|
||
.all()
|
||
}
|
||
pending = db.query(Question).filter(Question.chapter_id.is_(None)).all()
|
||
for question in pending:
|
||
chapter = chapter_map.get(KNOWLEDGE_CHAPTER_MAP.get(question.knowledge_name, ""))
|
||
if chapter is not None:
|
||
question.chapter_id = chapter.id
|
||
|
||
|
||
def _sync_default_chapter_knowledge(db: Session) -> None:
|
||
"""仅为还没有知识点关联的章节写入默认知识点(不覆盖管理员维护)。"""
|
||
for chapter in db.query(Chapter).all():
|
||
linked = (
|
||
db.query(ChapterKnowledge)
|
||
.filter(ChapterKnowledge.chapter_id == chapter.id)
|
||
.count()
|
||
)
|
||
if linked:
|
||
continue
|
||
names = DEFAULT_CHAPTER_KNOWLEDGE.get(chapter.name, [])
|
||
if names:
|
||
set_chapter_knowledge_names(db, chapter.id, names)
|
||
|
||
|
||
def _ensure_courses(db: Session) -> None:
|
||
"""课程表为空时写入默认在线课程;管理员删掉后不再自动恢复。"""
|
||
if db.query(Course).count() > 0:
|
||
return
|
||
for position, item in enumerate(COURSES):
|
||
db.add(
|
||
Course(
|
||
name=item["name"],
|
||
provider=item["provider"],
|
||
url=item["url"],
|
||
grade=item["grade"],
|
||
description=item["description"],
|
||
position=position,
|
||
)
|
||
)
|
||
db.commit()
|
||
|
||
|
||
def _sync_default_course_resources(db: Session) -> None:
|
||
"""把在线课程 / 视频挂到对应知识点,作为知识点详情里的反向资源链接。"""
|
||
for course_name, knowledge_names in COURSE_KNOWLEDGE_MAP.items():
|
||
course = db.query(Course).filter(Course.name == course_name).first()
|
||
if course is None or not course.url:
|
||
continue
|
||
for name in knowledge_names:
|
||
knowledge = db.query(Knowledge).filter(Knowledge.name == name).first()
|
||
if knowledge is None:
|
||
continue
|
||
ensure_knowledge_resource(
|
||
db,
|
||
knowledge.id,
|
||
kind="video",
|
||
title=course.name,
|
||
url=course.url,
|
||
course_id=course.id,
|
||
)
|