| import os |
| import csv |
| import json |
| import asyncio |
| from openai import AsyncOpenAI |
| from dotenv import load_dotenv |
|
|
| load_dotenv() |
|
|
| |
| AI_API_KEY = os.getenv("QWEN_API_KEY", "your-api-key-here") |
| AI_BASE_URL = os.getenv("QWEN_BASE_URL", "https://dashscope-intl.aliyuncs.com/compatible-mode/v1") |
| TEACHER_MODEL_NAME = os.getenv("TEACHER_MODEL_NAME", "qwen3-coder-480b-a35b") |
|
|
| client = AsyncOpenAI( |
| api_key=AI_API_KEY, |
| base_url=AI_BASE_URL |
| ) |
|
|
| IEDID_DIR = "IEDID" |
| OUTPUT_FILE = "synthetic_slm_dataset.jsonl" |
|
|
| async def generate_synthetic_data(dialect, utterance, clarification): |
| system_prompt = ( |
| f"You are a master linguist specializing in {dialect} and data augmentation for SLM fine-tuning.\n" |
| f"I will provide a human-verified conversation pair.\n" |
| f"Dialect Utterance: '{utterance}'\n" |
| f"Standard English Meaning: '{clarification}'\n\n" |
| f"Generate 3 highly accurate, synthetically varied conversation pairs that capture the exact same " |
| f"linguistic rules, phonetic syntax, and cultural tone as the example.\n" |
| f"Respond ONLY in valid JSON array format, where each object has 'prompt' (Standard English) and 'completion' ({dialect})." |
| ) |
| |
| try: |
| response = await client.chat.completions.create( |
| model=TEACHER_MODEL_NAME, |
| messages=[ |
| {"role": "system", "content": system_prompt}, |
| {"role": "user", "content": "Generate 3 synthetic pairs in a JSON array."} |
| ], |
| temperature=0.7, |
| max_tokens=1024 |
| ) |
| |
| content = response.choices[0].message.content.strip() |
| |
| if content.startswith("```json"): |
| content = content[7:-3] |
| elif content.startswith("```"): |
| content = content[3:-3] |
| |
| data = json.loads(content) |
| |
| |
| |
| if isinstance(data, dict): |
| for key in data: |
| if isinstance(data[key], list): |
| return data[key] |
| return [] |
| |
| return data if isinstance(data, list) else [] |
| except Exception as e: |
| print(f"Error generating data for '{utterance}': {e}") |
| return [] |
|
|
| async def process_csv(filepath): |
| print(f"Processing {filepath}...") |
| dataset = [] |
| |
| with open(filepath, 'r', encoding='utf-8') as f: |
| reader = csv.DictReader(f) |
| rows = list(reader)[:10] |
| |
| for row in rows: |
| utterance = row.get('Utterance') |
| clarification = row.get('Clarification') |
| dialect = row.get('Dialect', 'Unknown Dialect') |
| |
| if not utterance or not clarification: |
| continue |
| |
| print(f" Distilling variations for: {utterance}") |
| synthetic_pairs = await generate_synthetic_data(dialect, utterance, clarification) |
| |
| for pair in synthetic_pairs: |
| if "prompt" in pair and "completion" in pair: |
| dataset.append({ |
| "system": f"You are an expert polyglot interpreter. Translate Standard English to {dialect}.", |
| "user": pair["prompt"], |
| "assistant": pair["completion"] |
| }) |
| |
| return dataset |
|
|
| PRIORITY_DIALECTS = [ |
| "African American Vernacular English", |
| "Nigerian Pidgin English", |
| "Gyeongsang Satoori", |
| "Jeolla Satoori", |
| "Chungcheong Satoori", |
| "Jeju Satoori", |
| "Gangwon Satoori", |
| "Hamgyong Satoori" |
| ] |
|
|
| async def main(): |
| print(f"Starting Knowledge Distillation Pipeline (Teacher Model: {TEACHER_MODEL_NAME})...") |
| all_synthetic_data = [] |
| |
| |
| if os.path.exists(IEDID_DIR): |
| for filename in os.listdir(IEDID_DIR): |
| |
| is_priority = any(dialect in filename for dialect in PRIORITY_DIALECTS) |
| if filename.endswith(".csv") and "minted" not in filename and is_priority: |
| filepath = os.path.join(IEDID_DIR, filename) |
| data = await process_csv(filepath) |
| all_synthetic_data.extend(data) |
| |
| |
| with open(OUTPUT_FILE, 'w', encoding='utf-8') as f: |
| for entry in all_synthetic_data: |
| f.write(json.dumps(entry) + '\n') |
| |
| print(f"\nSuccessfully generated {len(all_synthetic_data)} synthetic training pairs!") |
| print(f"Saved to {OUTPUT_FILE}. Ready for HuggingFace AutoTrain or LoRA fine-tuning.") |
|
|
| if __name__ == "__main__": |
| asyncio.run(main()) |
|
|