mindmap-studio / backend /dataset_generator_distilled.py
kazutab's picture
Upload folder using huggingface_hub
22510af verified
Raw
History Blame
5.22 kB
import os
import json
import time
import requests
import wikipediaapi
from tqdm import tqdm
# LM Studioのローカルサーバー設定
LM_STUDIO_URL = "http://127.0.0.1:1234/v1/chat/completions"
# 教師モデルへのプロンプト(システム命令)
SYSTEM_PROMPT = """あなたは超優秀な情報整理AI(マインドマップ職人)です。
ユーザーから提供された長文テキストを深く読み解き、内容を論理的に構造化して、マインドマップ用のMarkdownを出力してください。
【厳格なルール】
1. 出力は必ずMarkdownの階層構造(#、##、###、および箇条書き - )のみとすること。
2. 一番上の階層(#)は、そのテキストの主題(メインテーマ)を1つだけ記述すること。
3. 下位の階層(##、###)で、大項目・中項目を整理すること。
4. 具体的な要素や詳細な情報は、箇条書き(- )を用いて末端の枝として表現すること。
5. Markdown以外の説明文、挨拶、感想、「以下に示します」などの前置きは一切出力してはならない(厳禁)。
6. 「概要」や「利用状況」など、テキストにない見出しを適当にでっち上げないこと。テキストに沿った見出しを作ること。
"""
USER_INSTRUCTION = "以下の長文から論理構造を抽出し、Markdown形式の目次(マインドマップ)を出力してください。"
def generate_teacher_output(text):
"""LM StudioのAPIを叩いて、教師モデルにマインドマップを作らせる"""
payload = {
"messages": [
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": f"{USER_INSTRUCTION}\n\n【対象テキスト】\n{text}"}
],
"temperature": 0.2, # 創造性よりも正確性を重視
"max_tokens": -1
}
try:
response = requests.post(LM_STUDIO_URL, json=payload, timeout=300)
if response.status_code == 200:
result = response.json()
return result['choices'][0]['message']['content'].strip()
else:
print(f"API Error: {response.status_code}")
return None
except Exception as e:
print(f"Connection Error: {e}")
return None
def fetch_random_wikipedia_text(count=10):
"""Wikipediaからランダムな記事のテキストを取得する(見出し構造は使わない)"""
wiki_wiki = wikipediaapi.Wikipedia(
user_agent='MindMapStudio_DistillationGen/1.0',
language='ja',
extract_format=wikipediaapi.ExtractFormat.WIKI
)
print(f"Wikipediaからランダムに {count} 件の記事タイトルを取得中...")
titles = set()
while len(titles) < count:
limit = min(50, count - len(titles))
url = f"https://ja.wikipedia.org/w/api.php?action=query&list=random&rnnamespace=0&rnlimit={limit}&format=json"
headers = {'User-Agent': 'MindMapStudio_DistillationGen/1.0'}
try:
res = requests.get(url, headers=headers).json()
for q in res.get("query", {}).get("random", []):
titles.add(q["title"])
except Exception:
time.sleep(1)
print("記事のテキストをダウンロード中...")
texts = []
for title in tqdm(list(titles)):
try:
page = wiki_wiki.page(title)
if page.exists() and len(page.text) > 500:
# 最初の2000文字程度を学習用テキストとする(長すぎるとAPIが遅くなるため)
text = page.text[:2000]
texts.append(text)
except Exception:
pass
return texts
def generate_distilled_dataset(num_samples=10, output_file="mindmap_dataset_distilled.jsonl"):
print("=== 教師モデルによるデータセット蒸留(Knowledge Distillation)を開始 ===")
texts = fetch_random_wikipedia_text(num_samples)
print(f"合計 {len(texts)} 件の有効なテキストを取得しました。")
print("LM Studio (Teacher) に推論させています...")
with open(output_file, 'w', encoding='utf-8') as f:
for text in tqdm(texts):
teacher_md = generate_teacher_output(text)
if teacher_md:
# AIがMarkdownのコードブロック(```markdown)を含めてしまった場合は除去
teacher_md = teacher_md.replace("```markdown\n", "").replace("```\n", "").replace("```", "").strip()
data = {
"instruction": USER_INSTRUCTION,
"input": text,
"output": teacher_md
}
f.write(json.dumps(data, ensure_ascii=False) + '\n')
f.flush()
else:
print("\n警告: APIは成功しましたが、出力(content)が空でした。")
print(f"完了!蒸留データセットを {output_file} に保存しました。")
if __name__ == "__main__":
# 本番用データセットの生成(500件)
generate_distilled_dataset(500)