| from langchain.messages import SystemMessage, HumanMessage |
| from modules import model_open_router |
| import os |
| import re |
|
|
| |
| SYSTEM_PROMPT = """ |
| You are an expert in APA 7th edition reference formatting. |
| |
| STRICT RULES: |
| |
| - Output ONLY the formatted reference (no explanations). |
| - Each reference must be on a new line. |
| - Do NOT invent missing data. |
| - Use (n.d.) if date is missing. |
| - Keep original language (Arabic stays Arabic, English stays English). |
| |
| GENERAL FORMAT RULES: |
| |
| 1. Author: |
| - Format: Last name, Initial(s). |
| - Multiple authors: |
| - 2 authors: Author1, A. A., & Author2, B. B. |
| - 3+ authors: Author1, A. A., et al. |
| |
| 2. Year: |
| - Must be in parentheses: (2023) |
| |
| 3. Title: |
| - Sentence case (only first word capitalized in English) |
| - Italicize book/journal titles conceptually |
| |
| 4. Books: |
| Author. (Year). Title (Edition). City: Publisher. |
| |
| 5. Journal articles: |
| Author. (Year). Title. Journal Name, Volume(Issue), pages. |
| |
| 6. Conference papers: |
| Author. (Year). Title. Conference Name, Location, Date. |
| |
| 7. Theses: |
| Author. (Year). Title [Thesis type], Institution. |
| |
| 8. Websites: |
| - With author: |
| Author. (Year). Title. URL |
| - Without author: |
| Title. (Year). URL |
| |
| 9. Arabic references: |
| - Keep Arabic format |
| - Use same structure: |
| المؤلف. (السنة). العنوان. المدينة: الناشر. |
| |
| 10. Page numbers: |
| - Use pp. for English |
| - Use ص for Arabic |
| |
| 11. Missing data: |
| - Use (n.d.) |
| - Use [Missing Info] only if critical |
| |
| 12. Fix: |
| - spelling |
| - punctuation |
| - ordering |
| |
| OUTPUT: |
| - Clean APA formatted references only |
| - No bullets |
| - No numbering |
| """ |
|
|
|
|
| |
| def normalize_references_batch(refs_list, model,batch_size=2): |
| batches = [] |
|
|
| for i in range(0, len(refs_list), batch_size): |
| chunk = refs_list[i : i + batch_size] |
| batches.append("\n".join(chunk)) |
|
|
| results = [] |
|
|
| for batch in batches: |
| try: |
| messages = [ |
| SystemMessage(content=SYSTEM_PROMPT), |
| HumanMessage(content=f"Format in APA 7:\n{batch}"), |
| ] |
|
|
| response = model.invoke(messages) |
|
|
| formatted = [ |
| line.strip() for line in response.content.split("\n") if line.strip() |
| ] |
|
|
| results.extend(formatted) |
|
|
| except Exception as e: |
| print(f"Error in batch: {e}") |
|
|
| |
| results.extend(batch.split("\n")) |
|
|
| return results |
|
|
|
|
| |
| def extract_references(book_json): |
| refs = [] |
|
|
| for chapter in book_json.get("chapters", []): |
| for section in chapter.get("sections", []): |
| for plan in section.get("plans", {}).values(): |
| for chunk in plan.get("rag_context", {}).get("chunks", []): |
| ref = chunk.get("reference_apa") |
| if ref: |
| refs.append(ref) |
|
|
| book_name = book_json.get("book_title", "<Book Title>") |
|
|
| return refs, book_name |
|
|
|
|
| |
| def remove_duplicates(refs): |
| return list(dict.fromkeys(refs)) |
|
|
|
|
| |
| def save_refs_to_html(refs_list, book_name): |
| """ |
| تحويل قائمة المراجع إلى ملف HTML منسق أكاديمياً مع اسم الكتاب |
| """ |
| html_content = f""" |
| <!DOCTYPE html> |
| <html lang="ar" dir="rtl"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>قائمة المراجع - APA 7th Edition</title> |
| <style> |
| @import url('https://fonts.googleapis.com/css2?family=Amiri&family=Lato&display=swap'); |
| |
| body {{ |
| font-family: 'Amiri', serif; |
| line-height: 1.8; |
| background-color: #f4f7f6; |
| color: #333; |
| padding: 40px; |
| max-width: 900px; |
| margin: auto; |
| }} |
| |
| .container {{ |
| background: white; |
| padding: 50px; |
| box-shadow: 0 4px 15px rgba(0,0,0,0.1); |
| border-radius: 8px; |
| }} |
| |
| .book-title {{ |
| text-align: center; |
| font-size: 22px; |
| color: #555; |
| margin-bottom: 10px; |
| }} |
| |
| h1 {{ |
| text-align: center; |
| color: #2c3e50; |
| border-bottom: 2px solid #2c3e50; |
| padding-bottom: 10px; |
| margin-bottom: 40px; |
| font-size: 28px; |
| }} |
| |
| .reference-list {{ |
| list-style-type: none; |
| padding: 0; |
| }} |
| |
| .reference-item {{ |
| margin-bottom: 20px; |
| padding-right: 30px; |
| text-indent: -30px; |
| text-align: justify; |
| word-wrap: break-word; |
| }} |
| |
| .reference-item a {{ |
| color: #2980b9; |
| text-decoration: none; |
| font-family: 'Lato', sans-serif; |
| font-size: 0.9em; |
| }} |
| |
| .reference-item a:hover {{ |
| text-decoration: underline; |
| }} |
| |
| @media print {{ |
| body {{ background: white; padding: 0; }} |
| .container {{ box-shadow: none; border: none; }} |
| }} |
| </style> |
| </head> |
| <body> |
| <div class="container"> |
| <div class="book-title">{book_name}</div> |
| <h1>قائمة المراجع (APA 7th Edition)</h1> |
| <ul class="reference-list"> |
| """ |
|
|
| for ref in refs_list: |
| import re |
|
|
| url_pattern = r"(https?://\S+)" |
| formatted_ref = re.sub( |
| url_pattern, r'<br><a href="\1" target="_blank">\1</a>', ref |
| ) |
|
|
| html_content += f'<li class="reference-item">{formatted_ref}</li>\n' |
|
|
| html_content += """ |
| </ul> |
| </div> |
| </body> |
| </html> |
| """ |
|
|
| return html_content |
|
|
|
|
| |
| def run_references(book_json): |
| refs, book_name = extract_references(book_json) |
| print(f"Extracted: {len(refs)}") |
|
|
| refs = remove_duplicates(refs) |
| print(f"Unique: {len(refs)}") |
| |
| |
| model = model_open_router() |
| fixed = normalize_references_batch(refs, model) |
| print(f"Formatted: {len(fixed)}") |
|
|
| html = save_refs_to_html(fixed, book_name) |
|
|
| return html |
|
|