seed_data.py 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952
  1. # -*- coding: utf-8 -*-
  2. """初始化初中化学题库与知识图谱数据"""
  3. import sys
  4. import os
  5. sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
  6. from app import (
  7. app,
  8. db,
  9. Question,
  10. KnowledgePoint,
  11. KnowledgeRelation,
  12. CurriculumTopic,
  13. ChemistryQuestionBank,
  14. )
  15. def seed_questions():
  16. """初中化学题库示例"""
  17. if Question.query.first():
  18. print("题库已有数据,跳过")
  19. return
  20. data = [
  21. ("下列物质中,不属于电解质的是?", "NaCl", "CH₃COOH", "Cu (金属铜)", "NaOH", "C", "电解质"),
  22. ("下列关于化学反应速率的说法正确的是?", "反应速率是指反应物浓度的减少", "反应速率是指生成物浓度的增加",
  23. "反应速率可以用单位时间内反应物浓度的减少来表示", "反应速率与反应物的性质无关", "C", "化学反应速率"),
  24. ("下列属于氧化还原反应的是?", "CaCO₃ 高温分解", "NaOH + HCl = NaCl + H₂O",
  25. "2H₂ + O₂ 点燃 2H₂O", "AgNO₃ + NaCl = AgCl↓ + NaNO₃", "C", "氧化还原反应"),
  26. ("物质的量的单位是?", "g", "mol", "L", "m³", "B", "物质的量"),
  27. ("元素周期表中,同周期元素从左到右,原子半径变化规律是?", "逐渐增大", "逐渐减小",
  28. "先增大后减小", "不变", "B", "元素周期律"),
  29. ("下列物质能在氧气中燃烧并产生大量白烟的是?", "碳", "硫", "磷", "铁丝", "C", "氧气性质"),
  30. ("原子核由什么组成?", "质子和电子", "质子和中子", "中子和电子", "质子、中子和电子", "B", "原子结构"),
  31. ("酸溶液能使紫色石蕊试液变?", "红色", "蓝色", "无色", "紫色", "A", "酸碱指示剂"),
  32. ("催化剂在化学反应中的作用是?", "增加反应物", "减少生成物", "改变化学反应速率", "改变反应条件", "C", "催化剂"),
  33. ("离子反应发生的条件是?", "有沉淀、气体或水生成", "有催化剂", "加热", "加压", "A", "离子反应"),
  34. ]
  35. for content, a, b, c, d, correct, kp in data:
  36. db.session.add(Question(
  37. content=content, option_a=a, option_b=b, option_c=c, option_d=d,
  38. correct_option=correct, knowledge_point=kp or None
  39. ))
  40. db.session.commit()
  41. print("已插入 %d 道题目" % len(data))
  42. def seed_curriculum_topics():
  43. """初始化课程主题"""
  44. if CurriculumTopic.query.first():
  45. print("curriculum_topics 已有数据,跳过")
  46. return
  47. topics = [
  48. dict(name="物质分类", phase="初中", chapter="第一章 走进化学世界",
  49. description="区分纯净物、混合物、单质、化合物等"),
  50. dict(name="原子结构", phase="初中", chapter="第二章 走进原子世界",
  51. description="认识质子、中子、电子及核外电子排布"),
  52. dict(name="化学方程式", phase="初中", chapter="基本概念与化学方程式",
  53. description="化学反应的符号表示及配平"),
  54. dict(name="化学实验基础", phase="初中", chapter="化学实验基本方法",
  55. description="常用仪器、操作规范、安全意识"),
  56. dict(name="溶液与浓度", phase="初中", chapter="溶液",
  57. description="溶液配制、溶质质量分数等"),
  58. dict(name="金属及其化合物", phase="初中", chapter="金属活动性顺序",
  59. description="金属与酸、盐溶液的反应与置换"),
  60. dict(name="酸碱盐", phase="初中", chapter="酸碱盐",
  61. description="常见酸碱盐的性质及反应"),
  62. dict(name="气体制取与性质", phase="初中", chapter="常见气体",
  63. description="氧气、二氧化碳等的制取与性质"),
  64. dict(name="微观粒子模型", phase="初中", chapter="微观与宏观",
  65. description="分子、原子、离子等微观示意图"),
  66. dict(name="化学安全与环保", phase="初中", chapter="化学与生活",
  67. description="安全操作、事故应急与环保意识"),
  68. ]
  69. db.session.bulk_save_objects([CurriculumTopic(**t) for t in topics])
  70. db.session.commit()
  71. print("已插入 %d 个课程主题" % len(topics))
  72. def seed_chemistry_question_bank():
  73. """多题型统一题库(每类大约 10~20 题,后续可自行扩展)"""
  74. if ChemistryQuestionBank.query.first():
  75. print("chemistry_question_bank 已有数据,跳过")
  76. return
  77. questions = []
  78. # 1. 基础概念辨析题(choice)约 50 题
  79. choice_data = [
  80. dict(
  81. difficulty="easy",
  82. topic="物质分类",
  83. content="下列物质属于纯净物的是:A.空气 B.矿泉水 C.蒸馏水 D.泥水",
  84. answer_schema={
  85. "options": {"A": "空气", "B": "矿泉水", "C": "蒸馏水", "D": "泥水"},
  86. "correct": ["C"],
  87. },
  88. hint="纯净物只有一种微粒组成",
  89. ),
  90. dict(
  91. difficulty="medium",
  92. topic="原子结构",
  93. content="原子核中一定含有的粒子是:A.质子 B.中子 C.电子 D.离子",
  94. answer_schema={
  95. "options": {"A": "质子", "B": "中子", "C": "电子", "D": "离子"},
  96. "correct": ["A"],
  97. },
  98. hint="注意氢原子的特殊性",
  99. ),
  100. dict(
  101. difficulty="easy",
  102. topic="化学方程式",
  103. content="催化剂在化学反应中的作用是:A.提高产物质量 B.改变反应速率 C.增加反应物浓度 D.减少能量消耗",
  104. answer_schema={
  105. "options": {
  106. "A": "提高产物质量",
  107. "B": "改变反应速率",
  108. "C": "增加反应物浓度",
  109. "D": "减少能量消耗",
  110. },
  111. "correct": ["B"],
  112. },
  113. hint="只改变速率,不改反应前后物质总能量",
  114. ),
  115. dict(
  116. difficulty="easy",
  117. topic="物质分类",
  118. content="下列属于金属单质的是:A.Fe B.Fe₂O₃ C.NaCl D.H₂O",
  119. answer_schema={
  120. "options": {"A": "Fe", "B": "Fe₂O₃", "C": "NaCl", "D": "H₂O"},
  121. "correct": ["A"],
  122. },
  123. hint="元素与化合物的区分",
  124. ),
  125. dict(
  126. difficulty="easy",
  127. topic="物质分类",
  128. content="下列属于混合物的是:A.液氯 B.蒸馏水 C.干冰 D.生理盐水",
  129. answer_schema={
  130. "options": {
  131. "A": "液氯",
  132. "B": "蒸馏水",
  133. "C": "干冰",
  134. "D": "生理盐水",
  135. },
  136. "correct": ["D"],
  137. },
  138. hint="盐溶解在水中形成混合物",
  139. ),
  140. dict(
  141. difficulty="medium",
  142. topic="酸碱盐",
  143. content="能使紫色石蕊溶液变红的是:A.NaCl溶液 B.NaOH溶液 C.HCl溶液 D.蒸馏水",
  144. answer_schema={
  145. "options": {
  146. "A": "NaCl溶液",
  147. "B": "NaOH溶液",
  148. "C": "HCl溶液",
  149. "D": "蒸馏水",
  150. },
  151. "correct": ["C"],
  152. },
  153. hint="酸使石蕊变红,碱使石蕊变蓝",
  154. ),
  155. dict(
  156. difficulty="easy",
  157. topic="酸碱盐",
  158. content="下列属于碱的是:A.NaCl B.NaOH C.H₂SO₄ D.CO₂",
  159. answer_schema={
  160. "options": {"A": "NaCl", "B": "NaOH", "C": "H₂SO₄", "D": "CO₂"},
  161. "correct": ["B"],
  162. },
  163. hint="含有金属阳离子和 OH⁻ 的化合物",
  164. ),
  165. dict(
  166. difficulty="medium",
  167. topic="金属及其化合物",
  168. content="在金属活动性顺序中,能从 CuSO₄ 溶液中置换出铜的金属是:A.Cu B.Ag C.Fe D.Hg",
  169. answer_schema={
  170. "options": {"A": "Cu", "B": "Ag", "C": "Fe", "D": "Hg"},
  171. "correct": ["C"],
  172. },
  173. hint="Fe 比 Cu 活泼,可置换",
  174. ),
  175. dict(
  176. difficulty="easy",
  177. topic="化学安全与环保",
  178. content="下列行为有利于环境保护的是:A.露天焚烧垃圾 B.乱倒废酸 C.使用无磷洗衣粉 D.随意排放含重金属废水",
  179. answer_schema={
  180. "options": {
  181. "A": "露天焚烧垃圾",
  182. "B": "乱倒废酸",
  183. "C": "使用无磷洗衣粉",
  184. "D": "随意排放含重金属废水",
  185. },
  186. "correct": ["C"],
  187. },
  188. hint="无磷洗衣粉可减轻水体富营养化",
  189. ),
  190. dict(
  191. difficulty="easy",
  192. topic="化学安全与环保",
  193. content="下列做法中符合化学实验室安全要求的是:A.品尝药品判断其性质 B.用鼻子直接凑近药品闻气味 C.用手扇动少量气体再闻 D.把药品带回家继续做实验",
  194. answer_schema={
  195. "options": {
  196. "A": "品尝药品判断其性质",
  197. "B": "用鼻子直接凑近药品闻气味",
  198. "C": "用手扇动少量气体再闻",
  199. "D": "把药品带回家继续做实验",
  200. },
  201. "correct": ["C"],
  202. },
  203. hint="标准闻气体方法",
  204. ),
  205. ]
  206. # 补充自动生成的基础选择题示例,使 choice 题型接近 50 题
  207. base_choice_count = len(choice_data)
  208. for i in range(base_choice_count + 1, 51):
  209. choice_data.append(dict(
  210. difficulty="easy" if i <= 14 else "medium",
  211. topic="物质分类" if i % 2 == 0 else "酸碱盐",
  212. content=f"【选择题示例{i}】下列说法中正确的是?",
  213. answer_schema={
  214. "options": {
  215. "A": "这是一个占位示例选项 A",
  216. "B": "这是一个占位示例选项 B(正确)",
  217. "C": "这是一个占位示例选项 C",
  218. "D": "这是一个占位示例选项 D",
  219. },
  220. "correct": ["B"],
  221. },
  222. hint="用于系统演示的占位选择题,可后续替换为真实题目",
  223. ))
  224. for q in choice_data:
  225. questions.append(ChemistryQuestionBank(
  226. type="choice",
  227. difficulty=q["difficulty"],
  228. topic=q["topic"],
  229. content=q["content"],
  230. answer_schema=q["answer_schema"],
  231. hint=q.get("hint"),
  232. ))
  233. # 2. 化学方程式书写题(equation)约 50 题
  234. equation_data = [
  235. dict(
  236. difficulty="easy",
  237. topic="气体制取与性质",
  238. content="写出实验室用双氧水制氧气的化学方程式:",
  239. answer_schema={
  240. "expected_equation": "2H2O2 → 2H2O + O2↑",
  241. "conditions": "MnO2 作催化剂",
  242. },
  243. hint="注意配平和气体符号",
  244. ),
  245. dict(
  246. difficulty="easy",
  247. topic="金属及其化合物",
  248. content="写出铁在氧气中燃烧的化学方程式:",
  249. answer_schema={
  250. "expected_equation": "3Fe + 2O2 → Fe3O4",
  251. "conditions": "点燃",
  252. },
  253. hint="生成黑色固体 Fe3O4",
  254. ),
  255. dict(
  256. difficulty="easy",
  257. topic="气体制取与性质",
  258. content="写出碳酸钙与盐酸反应的化学方程式:",
  259. answer_schema={
  260. "expected_equation": "CaCO3 + 2HCl → CaCl2 + H2O + CO2↑",
  261. "conditions": "常温",
  262. },
  263. hint="实验室制备 CO2",
  264. ),
  265. dict(
  266. difficulty="easy",
  267. topic="酸碱盐",
  268. content="写出盐酸与氢氧化钠溶液反应的化学方程式:",
  269. answer_schema={
  270. "expected_equation": "HCl + NaOH → NaCl + H2O",
  271. "conditions": "溶液",
  272. },
  273. hint="典型中和反应",
  274. ),
  275. dict(
  276. difficulty="medium",
  277. topic="金属及其化合物",
  278. content="写出锌与稀盐酸反应的化学方程式:",
  279. answer_schema={
  280. "expected_equation": "Zn + 2HCl → ZnCl2 + H2↑",
  281. "conditions": "常温",
  282. },
  283. hint="金属与酸反应生成盐和氢气",
  284. ),
  285. dict(
  286. difficulty="medium",
  287. topic="金属及其化合物",
  288. content="写出铁与硫酸铜溶液反应的化学方程式:",
  289. answer_schema={
  290. "expected_equation": "Fe + CuSO4 → FeSO4 + Cu",
  291. "conditions": "常温",
  292. },
  293. hint="金属活动性顺序应用",
  294. ),
  295. dict(
  296. difficulty="medium",
  297. topic="酸碱盐",
  298. content="写出碳酸钠溶液与盐酸反应的化学方程式:",
  299. answer_schema={
  300. "expected_equation": "Na2CO3 + 2HCl → 2NaCl + H2O + CO2↑",
  301. "conditions": "溶液",
  302. },
  303. hint="注意 CO2 气体放出",
  304. ),
  305. dict(
  306. difficulty="medium",
  307. topic="酸碱盐",
  308. content="写出石灰水与二氧化碳反应的化学方程式:",
  309. answer_schema={
  310. "expected_equation": "Ca(OH)2 + CO2 → CaCO3↓ + H2O",
  311. "conditions": "微量 CO2",
  312. },
  313. hint="澄清石灰水变浑浊",
  314. ),
  315. ]
  316. # 补充自动生成的方程式题示例,使 equation 题型接近 50 题
  317. base_equation_count = len(equation_data)
  318. for i in range(base_equation_count + 1, 51):
  319. equation_data.append(dict(
  320. difficulty="easy" if i <= 14 else "medium",
  321. topic="化学方程式",
  322. content=f"【方程式示例{i}】写出一个常见的初中化学反应方程式:",
  323. answer_schema={
  324. "expected_equation": "示例:2H2 + O2 → 2H2O",
  325. "conditions": "可根据课堂情境自行设定",
  326. },
  327. hint="本题为占位示例,可后续替换为具体反应方程式",
  328. ))
  329. for q in equation_data:
  330. questions.append(ChemistryQuestionBank(
  331. type="equation",
  332. difficulty=q["difficulty"],
  333. topic=q["topic"],
  334. content=q["content"],
  335. answer_schema=q["answer_schema"],
  336. hint=q.get("hint"),
  337. ))
  338. # 3. 实验操作与安全常识题(experiment)约 50 题
  339. experiment_data = [
  340. dict(
  341. difficulty="easy",
  342. topic="化学实验基础",
  343. content="稀释浓硫酸的正确操作是?",
  344. answer_schema={
  345. "scenario": "稀释浓硫酸",
  346. "correct_operation": "将浓硫酸沿器壁慢慢倒入水中并不断搅拌",
  347. "key_point": "酸入水防飞溅",
  348. },
  349. hint="牢记“酸入水”原则",
  350. ),
  351. dict(
  352. difficulty="easy",
  353. topic="化学实验基础",
  354. content="检查装置气密性的常用方法是?",
  355. answer_schema={
  356. "scenario": "检查装置气密性",
  357. "correct_operation": "封闭系统后轻轻挤压或捂热容器,观察导管末端气泡变化",
  358. "key_point": "压强变化观察气泡",
  359. },
  360. hint="不能用明火直接检查",
  361. ),
  362. dict(
  363. difficulty="medium",
  364. topic="化学实验基础",
  365. content="蒸发结晶停止加热的合适时机是?",
  366. answer_schema={
  367. "scenario": "蒸发结晶",
  368. "correct_operation": "蒸发皿中出现大量晶体、溶液尚未全部蒸干时停止加热",
  369. "key_point": "防止暴沸和晶体飞溅",
  370. },
  371. hint="不能把水分完全蒸干",
  372. ),
  373. dict(
  374. difficulty="easy",
  375. topic="化学安全与环保",
  376. content="酒精灯着火后,应采用哪种方法灭火最安全?",
  377. answer_schema={
  378. "scenario": "酒精灯起火",
  379. "correct_operation": "用湿抹布或灯帽盖灭,隔绝空气",
  380. "key_point": "禁止向燃烧的灯内添加酒精",
  381. },
  382. hint="突出隔绝空气",
  383. ),
  384. dict(
  385. difficulty="easy",
  386. topic="化学安全与环保",
  387. content="强酸不慎溅到皮肤上,正确的处理方式是?",
  388. answer_schema={
  389. "scenario": "强酸溅到皮肤",
  390. "correct_operation": "立即用大量清水冲洗,再根据情况就医",
  391. "key_point": "大量清水冲洗稀释",
  392. },
  393. hint="不要先用碱液中和",
  394. ),
  395. dict(
  396. difficulty="medium",
  397. topic="化学实验基础",
  398. content="用量筒量取液体时,视线应如何放置?",
  399. answer_schema={
  400. "scenario": "量筒读数",
  401. "correct_operation": "视线与凹液面最低处所在水平线相平",
  402. "key_point": "避免视差",
  403. },
  404. hint="读弯月面最低点",
  405. ),
  406. dict(
  407. difficulty="medium",
  408. topic="化学实验基础",
  409. content="过滤操作中,滤纸应如何贴紧漏斗?",
  410. answer_schema={
  411. "scenario": "过滤",
  412. "correct_operation": "将滤纸润湿后贴紧漏斗内壁,过滤时液面低于滤纸边缘",
  413. "key_point": "防止液体从滤纸外流下",
  414. },
  415. hint="常见过滤规范",
  416. ),
  417. dict(
  418. difficulty="medium",
  419. topic="化学安全与环保",
  420. content="若不慎吸入较多氯气,正确的紧急处理方式是?",
  421. answer_schema={
  422. "scenario": "吸入有毒气体",
  423. "correct_operation": "迅速离开现场到空气新鲜处,必要时就医",
  424. "key_point": "远离气体来源并就医",
  425. },
  426. hint="强调撤离与就医",
  427. ),
  428. ]
  429. # 补充自动生成的实验与安全题示例,使 experiment 题型接近 50 题
  430. base_experiment_count = len(experiment_data)
  431. for i in range(base_experiment_count + 1, 51):
  432. experiment_data.append(dict(
  433. difficulty="easy" if i <= 14 else "medium",
  434. topic="化学实验基础" if i % 2 == 0 else "化学安全与环保",
  435. content=f"【实验与安全示例{i}】下列哪一项更符合规范的化学实验操作或安全要求?",
  436. answer_schema={
  437. "scenario": "实验室规范操作占位情境",
  438. "correct_operation": "选择符合课本要求的规范操作步骤",
  439. "key_point": "遵守实验室安全与操作规范",
  440. },
  441. hint="本题为占位示例,用于丰富题库数量,可后续替换为具体实验情境",
  442. ))
  443. for q in experiment_data:
  444. questions.append(ChemistryQuestionBank(
  445. type="experiment",
  446. difficulty=q["difficulty"],
  447. topic=q["topic"],
  448. content=q["content"],
  449. answer_schema=q["answer_schema"],
  450. hint=q.get("hint"),
  451. ))
  452. # 4. 计算类习题(calculation)约 50 题
  453. calculation_data = [
  454. dict(
  455. difficulty="medium",
  456. topic="溶液与浓度",
  457. content="将 20g 质量分数为 10% 的 NaCl 溶液稀释至 5%,需加水多少克?",
  458. answer_schema={
  459. "formula": "w = m溶质 / m溶液 × 100%",
  460. "steps": [
  461. "计算溶质质量:m溶质 = 20g × 10% = 2g",
  462. "设稀释后溶液质量为 m2,有 2 / m2 = 5% ⇒ m2 = 40g",
  463. "需加水质量 = 40g - 20g = 20g",
  464. ],
  465. "answer": 20.0,
  466. "unit": "g",
  467. },
  468. hint="注意溶质质量不变",
  469. ),
  470. dict(
  471. difficulty="medium",
  472. topic="气体制取与性质",
  473. content="电解 18g 水可制得氢气多少克?(相对分子质量:H2O=18,H2=2)",
  474. answer_schema={
  475. "formula": "2H2O → 2H2 + O2",
  476. "steps": [
  477. "由方程式知:36g 水生成 4g 氢气",
  478. "18g 水生成 x 克氢气,x = 4 × 18 / 36 = 2g",
  479. ],
  480. "answer": 2.0,
  481. "unit": "g",
  482. },
  483. hint="由化学方程式确定质量比",
  484. ),
  485. dict(
  486. difficulty="medium",
  487. topic="溶液与浓度",
  488. content="向 100g 质量分数为 5% 的 NaCl 溶液中加入 10g NaCl 固体,所得溶液的质量分数约为多少?",
  489. answer_schema={
  490. "formula": "w = m溶质 / m溶液 × 100%",
  491. "steps": [
  492. "原溶质质量:m1 = 100g × 5% = 5g",
  493. "加入溶质 10g,溶质总质量 m溶质 = 15g",
  494. "溶液总质量 m溶液 = 100g + 10g = 110g",
  495. "w ≈ 15 / 110 × 100% ≈ 13.6%",
  496. ],
  497. "answer": 13.6,
  498. "unit": "%",
  499. },
  500. hint="既改变分子也改变分母",
  501. ),
  502. dict(
  503. difficulty="medium",
  504. topic="溶液与浓度",
  505. content="配制 200g 质量分数为 10% 的 NaCl 溶液,需要 NaCl 和水各多少克?",
  506. answer_schema={
  507. "formula": "w = m溶质 / m溶液 × 100%",
  508. "steps": [
  509. "m溶质 = 200g × 10% = 20g",
  510. "m溶剂(水) = 200g - 20g = 180g",
  511. ],
  512. "answer": {"solute": 20.0, "solvent": 180.0},
  513. "unit": {"solute": "g", "solvent": "g"},
  514. },
  515. hint="先求溶质,再求溶剂",
  516. ),
  517. ]
  518. # 补充自动生成的计算题示例,使 calculation 题型接近 50 题
  519. base_calculation_count = len(calculation_data)
  520. for i in range(base_calculation_count + 1, 51):
  521. calculation_data.append(dict(
  522. difficulty="medium",
  523. topic="溶液与浓度" if i % 2 == 0 else "气体制取与性质",
  524. content=f"【计算题示例{i}】根据给出的相对分子质量和化学方程式,完成一题质量或质量分数计算。",
  525. answer_schema={
  526. "formula": "可结合题干给出的方程式与数据进行比例计算",
  527. "steps": [
  528. "写出对应的化学方程式并配平",
  529. "根据物质的量关系列出质量比或浓度表达式",
  530. "代入数据计算并保留合适有效数字",
  531. ],
  532. "answer": None,
  533. "unit": "",
  534. },
  535. hint="本题为占位示例,用于训练计算思路,可后续替换为具体数值题",
  536. ))
  537. for q in calculation_data:
  538. questions.append(ChemistryQuestionBank(
  539. type="calculation",
  540. difficulty=q["difficulty"],
  541. topic=q["topic"],
  542. content=q["content"],
  543. answer_schema=q["answer_schema"],
  544. hint=q.get("hint"),
  545. ))
  546. # 5. 物质推断题(inference)约 50 题
  547. inference_data = [
  548. dict(
  549. difficulty="medium",
  550. topic="金属及其化合物",
  551. content=(
  552. "A 为红色金属,B 能使澄清石灰水变浑浊,反应关系为:"
  553. "A + O₂ → B;B + Ca(OH)₂ → C。试推断 A、B、C 分别是什么物质?"
  554. ),
  555. answer_schema={
  556. "clues": "A 为红色金属;B 能使澄清石灰水变浑浊",
  557. "reaction_chain": "A + O2 → B; B + Ca(OH)2 → C",
  558. "answer": ["Cu", "CO2", "CaCO3"],
  559. },
  560. hint="结合颜色和使石灰水变浑浊的气体",
  561. ),
  562. dict(
  563. difficulty="medium",
  564. topic="金属及其化合物",
  565. content=(
  566. "X 与稀盐酸反应放出无色无味气体 Y,Y 能在空气中点燃呈淡蓝色火焰;"
  567. "金属 Z 能将 X 从其盐溶液中置换出来。试推断 X、Y、Z 分别可能是什么?"
  568. ),
  569. answer_schema={
  570. "clues": "X 与酸反应放氢气;Z 能置换 X",
  571. "reaction_chain": "X + 2HCl → XCl2 + H2↑; Z + XCl2 → ZCl2 + X",
  572. "answer": ["Zn", "H2", "Fe"],
  573. },
  574. hint="结合金属活动性顺序",
  575. ),
  576. dict(
  577. difficulty="medium",
  578. topic="酸碱盐",
  579. content=(
  580. "某白色固体 A 能溶于水,溶液能使紫色石蕊变红;"
  581. "A 溶液与一种无色溶液 B 反应生成白色沉淀 C。"
  582. "已知 B 中含有 Ba²⁺,推断 A、B、C 可能是什么?"
  583. ),
  584. answer_schema={
  585. "clues": "A 溶液显酸性;B 中含 Ba2+;生成白色沉淀",
  586. "reaction_chain": "2H+ + SO4(2-) + Ba2+ → BaSO4↓ + 2H+",
  587. "answer": ["H2SO4 或 NaHSO4 等酸性物质", "BaCl2 溶液", "BaSO4"],
  588. },
  589. hint="考虑生成难溶的硫酸钡沉淀",
  590. ),
  591. ]
  592. # 补充自动生成的物质推断题示例,使 inference 题型接近 50 题
  593. base_inference_count = len(inference_data)
  594. for i in range(base_inference_count + 1, 51):
  595. inference_data.append(dict(
  596. difficulty="medium",
  597. topic="金属及其化合物" if i % 2 == 0 else "酸碱盐",
  598. content=(
  599. f"【物质推断示例{i}】已知某些物质在反应中会生成气体或沉淀,"
  600. f"并且与金属活动性顺序或酸碱中和有关,请根据给出的线索推断相关物质。"
  601. ),
  602. answer_schema={
  603. "clues": "结合题干给出的颜色变化、气体放出或沉淀生成等信息",
  604. "reaction_chain": "围绕金属活动性顺序或酸碱中和建立推断链",
  605. "answer": [],
  606. },
  607. hint="本题为占位示例,用于训练推理链条,可后续替换为具体情境题",
  608. ))
  609. for q in inference_data:
  610. questions.append(ChemistryQuestionBank(
  611. type="inference",
  612. difficulty=q["difficulty"],
  613. topic=q["topic"],
  614. content=q["content"],
  615. answer_schema=q["answer_schema"],
  616. hint=q.get("hint"),
  617. ))
  618. # 6. 微观示意图分析题(diagram)约 50 题
  619. diagram_data = [
  620. dict(
  621. difficulty="easy",
  622. topic="微观粒子模型",
  623. content="下图为水分子分解示意图,该图可以解释哪一类化学变化?",
  624. answer_schema={
  625. "diagram_url": "img/molecule_H2O.png",
  626. "description": "水分子电解分解为氢气和氧气的微观示意",
  627. "analysis_question": "该图示可解释何种反应?",
  628. "key_insight": "水发生化学变化,分子分裂生成新物质",
  629. },
  630. hint="注意“分子分裂”为化学变化特征",
  631. ),
  632. dict(
  633. difficulty="easy",
  634. topic="微观粒子模型",
  635. content="下图为 NaCl 溶解电离的微观示意图,该溶液能导电的根本原因是?",
  636. answer_schema={
  637. "diagram_url": "img/ionization_NaCl.png",
  638. "description": "NaCl 晶体在水中电离为 Na⁺ 和 Cl⁻",
  639. "analysis_question": "为何溶液能导电?",
  640. "key_insight": "溶液中有大量可以自由移动的离子",
  641. },
  642. hint="区分金属导电与溶液导电机理",
  643. ),
  644. ]
  645. # 补充自动生成的微观示意图分析题示例,使 diagram 题型接近 50 题
  646. base_diagram_count = len(diagram_data)
  647. for i in range(base_diagram_count + 1, 51):
  648. diagram_data.append(dict(
  649. difficulty="easy" if i <= 14 else "medium",
  650. topic="微观粒子模型",
  651. content=f"【微观示意图示例{i}】根据给出的粒子示意图,判断该图反映的是物质状态变化、化学变化或电离过程之一。",
  652. answer_schema={
  653. "diagram_url": "img/example_micro_diagram.png",
  654. "description": "占位用微观粒子示意图,可表示分子间距、离子或原子的变化",
  655. "analysis_question": "图中反映的是哪一类微观变化?",
  656. "key_insight": "通过粒子种类、数目和排列方式的变化来判断物理或化学变化",
  657. },
  658. hint="本题为占位示例,可后续替换为具体教材中的微观粒子示意图",
  659. ))
  660. for q in diagram_data:
  661. questions.append(ChemistryQuestionBank(
  662. type="diagram",
  663. difficulty=q["difficulty"],
  664. topic=q["topic"],
  665. content=q["content"],
  666. answer_schema=q["answer_schema"],
  667. hint=q.get("hint"),
  668. ))
  669. db.session.bulk_save_objects(questions)
  670. db.session.commit()
  671. print("已向 chemistry_question_bank 插入 %d 道多题型习题" % len(questions))
  672. def seed_chemistry_hard_questions():
  673. """为多题型题库补充 hard 难度习题,每种题型不少于 10 道
  674. 已有的 hard 题会被保留,只在数量不足的题型上补齐到 10 道。
  675. """
  676. TARGET_COUNT = 10
  677. new_questions = []
  678. # 1. choice 题型:补足到 10 道 hard
  679. existing_choice = ChemistryQuestionBank.query.filter_by(
  680. difficulty="hard", type="choice"
  681. ).count()
  682. if existing_choice < TARGET_COUNT:
  683. for i in range(existing_choice + 1, TARGET_COUNT + 1):
  684. content = (
  685. f"【Hard 选择题 {i}】某反应前后有关物质的量或化合价发生变化,"
  686. f"下列说法中正确的是?"
  687. )
  688. answer_schema = {
  689. "options": {
  690. "A": "只要有气体生成就是氧化还原反应",
  691. "B": "只要有沉淀生成就是氧化还原反应",
  692. "C": "判断是否为氧化还原反应要看元素化合价是否变化",
  693. "D": "化学方程式两边原子个数不同也可能是氧化还原反应",
  694. },
  695. "correct": ["C"],
  696. }
  697. new_questions.append(ChemistryQuestionBank(
  698. type="choice",
  699. difficulty="hard",
  700. topic="化学方程式",
  701. content=content,
  702. answer_schema=answer_schema,
  703. hint="掌握氧化还原反应的本质:元素化合价发生变化",
  704. ))
  705. # 2. equation 题型:补足到 10 道 hard
  706. existing_equation = ChemistryQuestionBank.query.filter_by(
  707. difficulty="hard", type="equation"
  708. ).count()
  709. if existing_equation < TARGET_COUNT:
  710. for i in range(existing_equation + 1, TARGET_COUNT + 1):
  711. content = (
  712. f"【Hard 方程式 {i}】写出一个既体现金属活动性顺序,"
  713. f"又能体现沉淀生成的离子反应的配平化学方程式。"
  714. )
  715. answer_schema = {
  716. "expected_equation": "示例:Fe + CuSO4 → FeSO4 + Cu",
  717. "conditions": "常温,溶液中",
  718. }
  719. new_questions.append(ChemistryQuestionBank(
  720. type="equation",
  721. difficulty="hard",
  722. topic="化学方程式",
  723. content=content,
  724. answer_schema=answer_schema,
  725. hint="结合金属活动性顺序与难溶盐沉淀的知识,自拟一个合理的反应方程式",
  726. ))
  727. # 3. experiment 题型:补足到 10 道 hard
  728. existing_experiment = ChemistryQuestionBank.query.filter_by(
  729. difficulty="hard", type="experiment"
  730. ).count()
  731. if existing_experiment < TARGET_COUNT:
  732. for i in range(existing_experiment + 1, TARGET_COUNT + 1):
  733. content = (
  734. f"【Hard 实验与安全 {i}】在设计验证某气体为 CO2 的实验时,"
  735. f"如何合理选择试剂、装置并避免误判?"
  736. )
  737. answer_schema = {
  738. "scenario": "验证某无色气体是否为 CO2",
  739. "correct_operation": (
  740. "选用澄清石灰水检验,并设置对照实验;"
  741. "控制气体通入速度,防止生成 Ca(HCO3)2 造成再次澄清导致误判"
  742. ),
  743. "key_point": "有对照、控制变量,考虑条件变化对现象的影响",
  744. }
  745. new_questions.append(ChemistryQuestionBank(
  746. type="experiment",
  747. difficulty="hard",
  748. topic="化学实验基础",
  749. content=content,
  750. answer_schema=answer_schema,
  751. hint="思考如何通过对照与控制变量排除干扰因素",
  752. ))
  753. # 4. calculation 题型:补足到 10 道 hard
  754. existing_calculation = ChemistryQuestionBank.query.filter_by(
  755. difficulty="hard", type="calculation"
  756. ).count()
  757. if existing_calculation < TARGET_COUNT:
  758. for i in range(existing_calculation + 1, TARGET_COUNT + 1):
  759. content = (
  760. f"【Hard 计算题 {i}】某 100g NaCl 溶液,质量分数为 15%,"
  761. f"蒸发部分水并加入 10g NaCl 固体后,溶液质量分数变为 25%,"
  762. f"求蒸发水的质量。"
  763. )
  764. answer_schema = {
  765. "formula": "w = m溶质 / m溶液 × 100%",
  766. "steps": [
  767. "原溶质质量 m1 = 100g × 15% = 15g",
  768. "加入固体 NaCl 10g 后,溶质总质量 m溶质 = 25g",
  769. "设蒸发水质量为 x,则溶液终质量 m2 = 100 + 10 - x = 110 - x",
  770. "由 25 / (110 - x) × 100% = 25%,得 25 / (110 - x) = 0.25",
  771. "解得 110 - x = 100 ⇒ x = 10(g)",
  772. ],
  773. "answer": 10.0,
  774. "unit": "g",
  775. }
  776. new_questions.append(ChemistryQuestionBank(
  777. type="calculation",
  778. difficulty="hard",
  779. topic="溶液与浓度",
  780. content=content,
  781. answer_schema=answer_schema,
  782. hint="同时注意溶质和溶剂质量的变化,建立方程求解",
  783. ))
  784. # 5. inference 题型:补足到 10 道 hard
  785. existing_inference = ChemistryQuestionBank.query.filter_by(
  786. difficulty="hard", type="inference"
  787. ).count()
  788. if existing_inference < TARGET_COUNT:
  789. for i in range(existing_inference + 1, TARGET_COUNT + 1):
  790. content = (
  791. f"【Hard 物质推断 {i}】某白色固体 A 溶于水后溶液呈碱性,"
  792. f"与稀盐酸反应放出无色无味气体 B,B 能在空气中点燃呈淡蓝色火焰;"
  793. f"A 溶液与硫酸铜溶液反应生成蓝色沉淀 C。推断 A、B、C 分别是什么。"
  794. )
  795. answer_schema = {
  796. "clues": (
  797. "溶液呈碱性且与稀盐酸反应放出氢气;"
  798. "能与 CuSO4 生成蓝色沉淀"
  799. ),
  800. "reaction_chain": (
  801. "A + 2HCl → B↑ + 相应盐;"
  802. "A 溶液 + CuSO4 → C↓ + 其他产物"
  803. ),
  804. "answer": ["A:NaOH 或类似强碱", "B:H2", "C:Cu(OH)2"],
  805. }
  806. new_questions.append(ChemistryQuestionBank(
  807. type="inference",
  808. difficulty="hard",
  809. topic="酸碱盐",
  810. content=content,
  811. answer_schema=answer_schema,
  812. hint="结合气体性质和沉淀颜色,多步推断相关物质",
  813. ))
  814. # 6. diagram 题型:补足到 10 道 hard
  815. existing_diagram = ChemistryQuestionBank.query.filter_by(
  816. difficulty="hard", type="diagram"
  817. ).count()
  818. if existing_diagram < TARGET_COUNT:
  819. for i in range(existing_diagram + 1, TARGET_COUNT + 1):
  820. content = (
  821. f"【Hard 微观示意图 {i}】给出某反应前后微观粒子示意图:"
  822. f"反应前为双原子分子与单原子金属颗粒的混合,"
  823. f"反应后生成新的离子晶体。根据图示判断该反应类型并说明理由。"
  824. )
  825. answer_schema = {
  826. "diagram_url": "img/hard_example_micro_diagram.png",
  827. "description": "金属与酸或盐溶液反应生成新晶体和气体/离子的示意图",
  828. "analysis_question": "判断反应类型(置换、复分解等),并从微观角度解释",
  829. "key_insight": "从粒子种类和数目变化判断是否有新物质生成及反应类型",
  830. }
  831. new_questions.append(ChemistryQuestionBank(
  832. type="diagram",
  833. difficulty="hard",
  834. topic="微观粒子模型",
  835. content=content,
  836. answer_schema=answer_schema,
  837. hint="结合微观粒子变化与反应类型的宏观特征进行分析",
  838. ))
  839. if not new_questions:
  840. print("chemistry_question_bank 各题型的 hard 难度习题数量已达到或超过 10 道,跳过")
  841. return
  842. db.session.bulk_save_objects(new_questions)
  843. db.session.commit()
  844. print("已向 chemistry_question_bank 追加 %d 道 hard 难度习题" % len(new_questions))
  845. def seed_knowledge_points():
  846. """从题目与知识图谱中同步知识点到 knowledge_points 表"""
  847. if KnowledgePoint.query.first():
  848. return
  849. names = set()
  850. for (kp,) in db.session.query(Question.knowledge_point).filter(
  851. Question.knowledge_point.isnot(None),
  852. Question.knowledge_point != "",
  853. ).distinct().all():
  854. if kp:
  855. names.add(kp)
  856. for s, p, o in [
  857. ("电解质", "定义", "在水溶液或熔融状态下能够导电的化合物"),
  858. ("氧化还原反应", "特征", "有元素化合价发生变化的反应"),
  859. ("物质的量", "单位", "mol(摩尔)"),
  860. ("原子", "结构", "原子核和核外电子"),
  861. ]:
  862. names.add(s)
  863. if isinstance(o, str):
  864. names.add(o)
  865. for name in names:
  866. if not KnowledgePoint.query.filter_by(name=name).first():
  867. db.session.add(KnowledgePoint(name=name))
  868. db.session.commit()
  869. print("已同步 %d 个知识点到 knowledge_points" % len(names))
  870. def seed_knowledge_graph():
  871. """初中化学知识图谱三元组"""
  872. if KnowledgeRelation.query.first():
  873. print("知识图谱已有数据,跳过")
  874. return
  875. data = [
  876. ("电解质", "定义", "在水溶液或熔融状态下能够导电的化合物"),
  877. ("电解质", "包含", "酸、碱、盐"),
  878. ("非电解质", "定义", "在水溶液和熔融状态下都不导电的化合物"),
  879. ("非电解质", "举例", "蔗糖、酒精"),
  880. ("氧化还原反应", "特征", "有元素化合价发生变化的反应"),
  881. ("氧化还原反应", "包含", "氧化反应和还原反应"),
  882. ("物质的量", "单位", "mol(摩尔)"),
  883. ("物质的量", "表示", "含有一定数目粒子的集合体"),
  884. ("元素周期律", "内容", "元素的性质随原子序数递增呈周期性变化"),
  885. ("元素周期律", "表现", "原子半径、金属性、非金属性等"),
  886. ("离子反应", "条件", "有沉淀、气体或弱电解质生成"),
  887. ("化学反应速率", "定义", "单位时间内反应物或生成物浓度的变化"),
  888. ("催化剂", "特点", "能改变化学反应速率而本身质量和化学性质不变"),
  889. ("原子", "结构", "原子核和核外电子"),
  890. ("原子核", "组成", "质子和中子"),
  891. ]
  892. for s, p, o in data:
  893. db.session.add(KnowledgeRelation(subject=s, predicate=p, obj=o))
  894. db.session.commit()
  895. print("已插入 %d 条知识图谱三元组" % len(data))
  896. def main():
  897. with app.app_context():
  898. seed_questions()
  899. seed_knowledge_graph()
  900. seed_knowledge_points()
  901. seed_curriculum_topics()
  902. seed_chemistry_question_bank()
  903. seed_chemistry_hard_questions()
  904. print("初始化完成")
  905. if __name__ == "__main__":
  906. main()