""" تقسیمِ متنِ درس به تکه‌های مستقل + خلاصه‌سازیِ آموزشیِ هر تکه. برداشتِ پاک‌سازی‌شده از subjects/services/chunker.py مخزنِ Rag_backend: - به‌جای HttpError نینجا، از استثناهای معمولی استفاده می‌کنیم (لایه‌ی view در DRF تبدیلش می‌کنه). - کلاینت lazy است. """ import json from django.conf import settings from . import clients class ChunkingError(RuntimeError): pass def split_text_into_chunks(text: str, chunk_size: int = 400, overlap: int = 100) -> list[str]: if not text: return [] chunks: list[str] = [] start = 0 text_length = len(text) step = max(chunk_size - overlap, 1) while start < text_length: end = min(start + chunk_size, text_length) chunks.append(text[start:end]) start += step return chunks def _strip_code_fence(raw: str) -> str: raw = raw.strip() if raw.startswith('```json'): raw = raw[len('```json'):] elif raw.startswith('```'): raw = raw[len('```'):] if raw.endswith('```'): raw = raw[:-3] return raw.strip() def summarize_chunk(chunk_text: str) -> str: """خلاصه‌ی مستقل و آموزشیِ یک تکه به فارسی.""" prompt = f""" You are an expert Persian educational summarizer. Summarize the following text clearly and independently. - The summary must be self-contained. - Capture all key educational points. - Write in natural Persian (Farsi). Text: {chunk_text} Return JSON only: {{"summary": "خلاصه کامل این بخش در فارسی"}} """ client = clients.get_openai_client() response = client.chat.completions.create( model=settings.OPENAI_CHAT_MODEL, messages=[ {'role': 'system', 'content': 'You are a helpful assistant that always outputs valid JSON.'}, {'role': 'user', 'content': prompt}, ], max_tokens=400, temperature=0.4, top_p=0.9, ) raw = _strip_code_fence(response.choices[0].message.content or '') try: data = json.loads(raw) except json.JSONDecodeError as exc: raise ChunkingError(f'خروجیِ خلاصه‌سازی JSON معتبر نبود: {raw[:300]}') from exc summary = data.get('summary') if not summary: raise ChunkingError(f'کلیدِ summary در خروجی نبود: {raw[:300]}') return summary def chunk_and_summarize(text: str, chunk_size: int = 400, overlap: int = 100) -> list[dict]: """[{order, original_text, summary}, ...]""" result = [] for index, original in enumerate(split_text_into_chunks(text, chunk_size, overlap), start=1): result.append({ 'order': index, 'original_text': original, 'summary': summarize_chunk(original), }) return result