import requests
import time
import random
import json
import os
categories = [
{"name": "结婚登记与条件", "desc": "涉及结婚年龄、自愿原则、禁止近亲结婚、疾病限制、登记程序及法律效力等。"},
{"name": "夫妻权利义务", "desc": "涵盖共同财产管理、相互扶养义务、姓名权、生育权及日常家事代理权等。"},
{"name": "离婚程序与条件", "desc": "包括协议离婚冷静期、诉讼离婚标准、分居认定、感情破裂证明及调解程序等。"},
{"name": "财产分割", "desc": "涉及共同财产界定、个人财产保护、债务承担、房产分割规则及隐匿财产追责等。"},
{"name": "子女抚养与监护权", "desc": "包含抚养费计算标准、探视权实施、非婚生子女权益、抚养关系变更及教育责任等。"},
{"name": "家庭暴力与保护令", "desc": "涵盖暴力行为认定、人身保护令申请、证据收集、紧急庇护措施及刑事责任关联等。"},
{"name": "继承权与婚姻关系", "desc": "涉及配偶继承顺位、遗嘱效力、遗产分割冲突、再婚继承权及代位继承问题等。"},
{"name": "无效婚姻与可撤销婚姻", "desc": "包括重婚无效、胁迫婚姻撤销、隐瞒疾病撤销的程序及法律后果等。"},
{"name": "涉外婚姻", "desc": "涉及跨国婚姻登记、域外结婚效力认定、财产跨境分割及国际子女抚养公约适用等。"},
{"name": "法律责任与救济措施", "desc": "包含虚假登记处罚、拒不执行判决后果、损害赔偿计算及强制执行程序等。"}
]
SYSTEM_PROMPT_TEMPLATE = (
"你是一位婚姻法方面的专家,根据【{category}】的定义,"
"针对其中夫妻权利义务方面的规定,向学生提供20道练习题,"
"你能提出哪些问题?每个问题单独一行,"
"只允许输出问题本身,不允许输出任何其他字符。"
)
# 每个类别目标生成数量
TARGET_COUNT_PER_CATEGORY = 5
# 每次生成数量
BATCH_SIZE = 2
def callServer(systemPrompt, userPrompt, model="deepseek-ai/DeepSeek-V3.2"):
url = "https://api.siliconflow.cn/v1/chat/completions"
headers = {
"Authorization": f"Bearer sk-cgteigkshpgccdbsfzefmvdjpaicjmydidliorsnjorbqclg",
"Content-Type": "application/json"
}
payload = {
"model": model,
"messages": [
{"role": "system", "content": systemPrompt},
{"role": "user", "content": userPrompt}
],
"temperature": 0.6,
"max_tokens": 4000
}
success = True
msg = "OK"
think = ""
result = ""
try:
response = requests.post(url, json=payload, headers=headers)
response.raise_for_status()
resp_json = response.json()
msg_dict = resp_json['choices'][0]['message']
# V3.2 没有 reasoning_content 字段,安全获取
think = msg_dict.get('reasoning_content', '')
result = msg_dict['content']
except Exception as e:
success = False
msg = "API调用异常:" + str(e)
return success, msg, think, result
def callServerStimu(systemPrompt, userPrompt, model="deepseek-ai/DeepSeek-V3.2"):
time.sleep(random.randint(1, 3))
success = True
msg = "OK"
think = ''
result = '\n'.join([f'关于{userPrompt[:15]}的练习题第{i+1}题?' for i in range(20)])
return success, msg, think, result
def loadExistingQuestions(targetFile):
"""读取已有结果文件,用于断点续传和去重"""
existing = {} # {category_name: set(question_str)}
existing_ids = {} # {category_name: count}
if os.path.exists(targetFile):
with open(targetFile, 'r', encoding='utf-8') as f:
for line in f:
line = line.strip()
if not line:
continue
try:
data = json.loads(line)
cate = data.get("category", "")
instr = data.get("instruction", "")
if cate and instr:
if cate not in existing:
existing[cate] = set()
existing_ids[cate] = 0
existing[cate].add(instr)
existing_ids[cate] = max(existing_ids[cate], data.get("id", 0))
except json.JSONDecodeError:
continue
return existing, existing_ids
def generateQuestions(targetFile, useStimu=False):
# 加载已有数据(断点续传 + 去重)
existingQuestions, existingIds = loadExistingQuestions(targetFile)
# 初始化各类别的去重集合和当前最大ID
questionSets = {}
currentId = 1
for cat in categories:
name = cat["name"]
if name in existingQuestions:
questionSets[name] = existingQuestions[name]
if name in existingIds:
currentId = max(currentId, existingIds[name] + 1)
else:
questionSets[name] = set()
print(f"断点续传:已有数据,当前起始ID = {currentId}")
# 以追加模式打开文件,增量写入
fileExisted = os.path.exists(targetFile)
with open(targetFile, 'a', encoding='utf-8') as f:
if not fileExisted:
f.write("")
for cat in categories:
name = cat["name"]
desc = cat["desc"]
systemPrompt = SYSTEM_PROMPT_TEMPLATE.format(category=name)
currentCount = len(questionSets[name])
batchNum = 0
maxBatches = TARGET_COUNT_PER_CATEGORY // BATCH_SIZE # 25轮
print(f"\n{'='*60}")
print(f"类别: {name} | 已有: {currentCount} | 目标: {TARGET_COUNT_PER_CATEGORY}")
print(f"{'='*60}")
# 如果已有数量已达标,跳过
if currentCount >= TARGET_COUNT_PER_CATEGORY:
print(f" {name} 已达到目标数量,跳过")
continue
while currentCount < TARGET_COUNT_PER_CATEGORY and batchNum < maxBatches:
batchNum += 1
# 构造user prompt,告知已有数量,引导生成不同问题
userPrompt = (
f"类别:{name}\n"
f"描述:{desc}\n\n"
f"请根据以上类别描述,针对{name}方面的规定,生成20道练习题。"
f"要求每道题角度不同,尽量覆盖该类别的各个方面。"
)
if useStimu:
success, msg, think, result = callServerStimu(systemPrompt, userPrompt)
else:
success, msg, think, result = callServer(systemPrompt, userPrompt)
print(f" [{name}] 第 {batchNum}/{maxBatches} 轮: success={success}, msg={msg}")
if success:
lines = result.strip().split('\n')
newCount = 0
for line in lines:
line = line.strip()
# 去除可能的序号前缀(如 "1." "2、" 等)
if len(line) > 0:
# 去掉开头数字序号
cleaned = line
for prefix in ['1.', '2.', '3.', '4.', '5.', '6.', '7.', '8.', '9.', '10.',
'11.', '12.', '13.', '14.', '15.', '16.', '17.', '18.', '19.', '20.',
'1、', '2、', '3、', '4、', '5、', '6、', '7、', '8、', '9、', '10、',
'11、', '12、', '13、', '14、', '15、', '16、', '17、', '18、', '19、', '20、',
'1)', '2)', '3)', '4)', '5)', '6)', '7)', '8)', '9)', '10)',
'11)', '12)', '13)', '14)', '15)', '16)', '17)', '18)', '19)', '20)']:
if cleaned.startswith(prefix):
cleaned = cleaned[len(prefix):].strip()
break
if len(cleaned) > 0 and cleaned not in questionSets[name]:
questionSets[name].add(cleaned)
record = {
"id": currentId,
"category": name,
"instruction": cleaned
}
f.write(json.dumps(record, ensure_ascii=False) + '\n')
f.flush()
currentId += 1
newCount += 1
currentCount = len(questionSets[name])
print(f" 新增有效问题: {newCount} | 累计去重后: {currentCount}/{TARGET_COUNT_PER_CATEGORY}")
else:
print(f" think: {think}")
print(f" result: {result}")
# 避免请求过于频繁
time.sleep(1)
print(f" {name} 完成,共 {currentCount} 道题目")
total = sum(len(questionSets[cat["name"]]) for cat in categories)
print(f"\n{'='*60}")
print(f"全部完成!共生成 {total} 道题目,已保存到 {targetFile}")
print(f"{'='*60}")
return total
if __name__ == "__main__":
targetFile = "../data/testDataTemp/queryData.jsonl"
# useStimu=True 可用模拟模式测试流程,不消耗API额度
generateQuestions(targetFile, useStimu=False)