# מפענח מסמכים אוניברסלי ## כותרת מפענח מסמכים אוניברסלי המופעל על ידי `unstructured` — קבלת פורמטים נפוצים של מסמכים באמצעות שירות יחיד, עם תיעוד מלא של מקור הנתונים ושילוב עם ספריית ניהול מסמכים, תוך רישום מיקומי המקור כמטא-דאטה של גרף ידע למעקב מקצה לקצה. ## בעיה ל-TrustGraph כיום יש מפענח ספציפי ל-PDF. תמיכה בפורמטים נוספים (DOCX, XLSX, HTML, Markdown, טקסט רגיל, PPTX וכו') דורשת או כתיבת מפענח חדש לכל פורמט או אימוץ ספריית חילוץ אוניברסלית. לכל פורמט יש מבנה שונה — חלקם מבוססי דפים, חלקם לא — ושרשרת התיעוד חייבת לתעד היכן בכל המסמך המקורי הגיע כל חלק של הטקסט שחולץ. ## גישה ### ספרייה: `unstructured` יש להשתמש ב-`unstructured.partition.auto.partition()` שמזהה באופן אוטומטי את הפורמט מסוג MIME או סיומת הקובץ ומחלצת אלמנטים מובנים (כותרת, טקסט, טבלה, פריט רשימה וכו'). כל אלמנט מכיל מטא-דאטה, כולל: - `page_number` (לפורמטים מבוססי דפים כמו PDF, PPTX) - `element_id` (ייחודי לכל אלמנט) - `coordinates` (מלבן תחום עבור PDF) - `text` (תוכן הטקסט שחולץ) - `category` (סוג אלמנט: כותרת, טקסט, טבלה וכו') ### סוגי אלמנטים `unstructured` מחלץ אלמנטים מסוגים שונים ממסמכים. לכל אלמנט יש קטגוריה ומטא-דאטה נלווים: **אלמנטים טקסטואליים:** - `Title` — כותרות סעיפים - `NarrativeText` — פסקאות גוף - `ListItem` — פריטי רשימה/רשימות ממוספרות - `Header`, `Footer` — כותרות/כותרות שוליים של עמודים - `FigureCaption` — כיתובים עבור תמונות/גרפיקה - `Formula` — ביטויים מתמטיים - `Address`, `EmailAddress` — פרטי התקשרות - `CodeSnippet` — בלוקי קוד (מ-Markdown) **טבלאות:** - `Table` — נתונים טבלאיים מובנים. `unstructured` מספק גם `element.text` (טקסט רגיל) וגם `element.metadata.text_as_html` (תגית HTML מלאה של `` עם שורות, עמודות וכותרות). עבור פורמטים עם מבנה טבלה מוגדר (DOCX, XLSX, HTML), החילוץ אמין מאוד. עבור PDF, זיהוי טבלאות תלוי באסטרטגיית `hi_res` עם ניתוח פריסה. **תמונות:** - `Image` — תמונות מוטמעות שזוהו באמצעות ניתוח פריסה (דורש אסטרטגיית `hi_res`). עם `extract_image_block_to_payload=True`, מחזיר את נתוני התמונה כ-base64 ב-`element.metadata.image_base64`. טקסט OCR מהתמונה זמין ב-`element.text`. ### טיפול בטבלאות טבלאות הן פלט ברמה ראשונה. כאשר המפענח נתקל באלמנט `Table`, הוא שומר על מבנה ה-HTML במקום לפשט לטקסט רגיל. זה נותן למחלץ ה-LLM במעלה הזרם קלט טוב יותר לשליפה של ידע מובנה מנתונים טבלאיים. הטקסט של העמוד/הסעיף מורכב באופן הבא: - אלמנטים טקסטואליים: טקסט רגיל, המחוברים עם שורות חדשות. - אלמנטים של טבלאות: תגית טבלה HTML מ-`text_as_html`, עטופה בתגית `
` כך שה-LLM יכול להבחין בין טבלאות לבין טקסט רגיל. לדוגמה, עמוד עם כותרת, פסקה וטבלה מייצר: ``` סקירה פיננסית ההכנסות גדלו ב-15% שנה אחר שנה, הודות לאימוץ ארגוני.
רבעון 1רבעון 2
רבעוןהכנסותצמיחה
$12 מיליון12%
$14 מיליון17%
``` זה שומר על מבנה הטבלה במהלך חלוקה לחלקים ולתוך צינור החילוץ, שבו ה-LLM יכול לחלץ קשרים ישירות מתאים מובנים ולא לנחש על התאמת עמודות מרווח לבן. ### טיפול בתמונות תמונות מחולצות ומאוחסנות בספריית הניהול כמסמכים משניים עם `document_type="image"` ו-ID `urn:image:{uuid}`. הם מקבלים משולשים של תיעוד מסוג `tg:Image`, המקושרים לעמוד/סעיף האב שלהם באמצעות `prov:wasDerivedFrom`. מטא-דאטה של תמונה (קואורדינטות, מימדים, `element_id`) נרשמים בתיעוד. **חשוב, תמונות אינן מופצות כפלט של `TextDocument`.** הן מאוחסנות בלבד — אינן נשלחות במעלה הזרם למחלק או לכל צינור עיבוד טקסט. זה מכוון: 1. אין עדיין צינור לעיבוד תמונות (שילוב מודל ראייה הוא עבודה עתידית) 2. העברת נתוני תמונה ב-base64 או פיסות OCR לצינור חילוץ הטקסט תיצור משולשים של גרף ידע "זבל". תמונות גם אינן נכללות בטקסט העמוד המורכב — כל אלמנטי `Image` מושמטים בשקט כאשר מחברים טקסט של אלמנטים עבור עמוד/סעיף. שרשרת התיעוד רושמת שתמונות קיימות ואיפה שהן הופיעו במסמך, כך שניתן יהיה לשלוף אותן על ידי צינור עיבוד תמונות עתידי מבלי לטעון מחדש את המסמך. #### עבודה עתידית - הכוונת ישויות `tg:Image` למודל ראייה לתיאור, פרשנות דיאגרמות או חילוץ נתוני תרשימים. - אחסון תיאורי תמונה כמסמכים טקסטואליים שמוזנים לצינור החלוקה/חילוץ הסטנדרטי. - קישור ידע שנחצה חזרה לתמונות מקור באמצעות תיעוד. ### אסטרטגיות סעיפים לפורמטים מבוססי דפים (PDF, PPTX, XLSX), אלמנטים תמיד מקובצים לפי עמוד/שקופית/גיליון תחילה. עבור פורמטים שאינם מבוססי דפים (DOCX, HTML, Markdown וכו'), למפענח יש אסטרטגיה לחלוקת המסמך לסעיפים. זה מוגדר בזמן ריצה באמצעות `--section-strategy`. כל אסטרטגיה היא פונקציית קיבוץ על רשימת האלמנטים של `unstructured`. הפלט הוא רשימת קבוצות אלמנטים; שאר הצינור (הרכבת טקסט, אחסון בספריית הניהול, תיעוד, פליטת `TextDocument`) זהים ללא קשר לאסטרטגיה. #### `whole-document` (ברירת מחדל) פליטת כל המסמך כסעיף יחיד. תן למחלק במעלה הזרם לטפל בכל החלוקה. - גישה פשוטה, נקודת התחלה טובה. - עשויה ליצור `TextDocument` גדול מאוד עבור קבצים גדולים, אך המחלק מטפל בכך. - הטוב ביותר כאשר אתה רוצה הקשר מרבי לכל סעיף. #### `heading` פיצול בכותרות (`Title`). כל סעיף הוא כותרת וכל התוכן עד לכותרת ברמה שווה או גבוהה יותר. כותרות מקוננות יוצרות סעיפים מקוננים. - מייצר יחידות מגובשות מבחינה נושאית. - עובד היטב עבור מסמכים מובנים (דוחות, מדריכים, מפרטים). - נותן למחלץ ה-LLM הקשר של כותרת יחד עם התוכן. - חוזר ל-`whole-document` אם לא נמצאות כותרות. #### `element-type` פיצול כאשר סוג האלמנט משתנה באופן משמעותי — במיוחד, התחלה של סעיף חדש במעברים בין טקסט נרטיבי לטבלאות. אלמנטים עוקבים מאותה קטגוריה רחבה (טקסט, טקסט, טקסט או טבלה, טבלה) נשארים מקובצים. - שומר על טבלאות כסעיפים עצמאיים. - טוב למסמכים עם תוכן מעורב (דוחות עם טבלאות נתונים). - לטבלאות יש תשומת לב חילוץ ייעודית. #### `count` קיבוץ מספר קבוע של אלמנטים לכל סעיף. ניתן להגדרה באמצעות `--section-element-count` (ברירת מחדל: 20). - פשוט וצפוי. - לא מכבד את מבנה המסמך. - שימושי כברירת מחדל או לניסויים. #### `size` צבירת אלמנטים עד שמגיעים לגבול תווים, ואז התחלת סעיף חדש. מכבד את גבולות האלמנטים — לעולם לא מפצל באמצע אלמנט. ניתן להגדרה באמצעות `--section-max-size` (ברירת מחדל: 4000 תווים). - מייצר גדלים בערך אחידים של סעיפים. - מכבד את גבולות האלמנטים (בניגוד למחלק במעלה הזרם). - פשרה טובה בין שליטה במבנה ובגודל. - אם אלמנט יחיד חורג מהגבול, הוא הופך לסעיף משלו. #### אינטראקציה עם פורמטים מבוססי דפים עבור פורמטים מבוססי דפים, הקיבוץ לפי עמוד תמיד מקבל עדיפות. אסטרטגיות סעיפים יכולות באופן אופציונלי להחיל *בתוך* עמוד אם הוא גדול מאוד (לדוגמה, עמוד PDF עם טבלה עצומה), דבר ששולט על ידי `--section-within-pages` (ברירת מחדל: false). כאשר זה כוזב, כל עמוד תמיד סעיף אחד ללא קשר לגודל. ### זיהוי פורמט למפענח יש צורך לדעת את סוג MIME של המסמך כדי להעביר ל-`partition()` של `unstructured`. שתי אפשרויות: - **נתיב ספריית הניהול** (`document_id` מוגדר): אחסון מטא-דאטה של מסמך מהספרייה תחילה — זה נותן לנו את `kind` (סוג MIME) שנרשם בזמן ההעלאה. ואז אחסון תוכן מסמך. שתי קריאות לספריית הניהול, אך אחזור המטא-דאטה קל משקל. - **נתיב מקומי** (תאימות לאחור, `data` מוגדר): אין מטא-דאטה זמין על ההודעה. השתמש ב-`python-magic` כדי לזהות את הפורמט מתוך בתים של תוכן כגיבוי. אין צורך בשינויים בסכימת `Document` — ספריית הניהול כבר מאחסנת את סוג ה-MIME. ### ארכיטקטורה שירות `universal-decoder` יחיד שמבצע את הפעולות הבאות: 1. מקבל הודעת `Document` (מקומית או באמצעות הפניה לספריית הניהול). 2. אם נתיב ספריית הניהול: אחסון מטא-דאטה של מסמך (קבלת סוג MIME), ואז אחסון תוכן. אם נתיב מקומי: זיהוי פורמט מתוך בתים של תוכן. 3. קריאה ל-`partition()` כדי לחלץ אלמנטים. 4. קיבוץ אלמנטים: לפי עמוד עבור פורמטים מבוססי דפים, לפי אסטרטגיית סעיף מוגדרת עבור פורמטים שאינם מבוססי דפים. 5. עבור כל עמוד/סעיף: - יצירת ID `urn:page:{uuid}` או `urn:section:{uuid}`. - הרכבת טקסט עמוד: טקסט רגיל, טבלאות כ-HTML, תמונות מושמטות. - חישוב ההיסט מוחלט של כל אלמנט בתוך טקסט העמוד. - שמירה בספריית הניהול כתיעוד משני. - יצירת משולשים של תיעוד עם מטא-דאטה מיקומי. - שליחת `TextDocument` במעלה הזרם לחלוקה. 6. עבור כל אלמנט תמונה: - יצירת ID `urn:image:{uuid}`. - שמירת נתוני תמונה בספריית הניהול כתיעוד משני. - יצירת משולשים של תיעוד (מאוחסנים בלבד, אינם נשלחים במעלה הזרם). ### טיפול בפורמטים | פורמט | סוג MIME | מבוסס עמוד | הערות | |---|---|---|---| | PDF | application/pdf | כן | קיבוץ לפי עמוד | | DOCX | application/vnd.openxmlformats... | לא | משתמש באסטרטגיית סעיף | | PPTX | application/vnd.openxmlformats... | כן | קיבוץ לפי שקופית | | XLSX/XLS | application/vnd.openxmlformats... | כן | קיבוץ לפי גיליון | | HTML | text/html | לא | משתמש באסטרטגיית סעיף | | Markdown | text/markdown | לא | משתמש באסטרטגיית סעיף | | רגיל | text/plain | לא | משתמש באסטרטגיית סעיף | | CSV | text/csv | לא | משתמש באסטרטגיית סעיף | | RST | text/x-rst | לא | משתמש באסטרטגיית סעיף | | RTF | application/rtf | לא | משתמש באסטרטגיית סעיף | | ODT | application/vnd.oasis... | לא | משתמש באסטרטגיית סעיף | | TSV | text/tab-separated-values | לא | משתמש באסטרטגיית סעיף | ### מטא-דאטה של תיעוד כל ישות עמוד/סעיף רושמת מטא-דאטה מיקומי כמשולשים של תיעוד בגרף `GRAPH_SOURCE`, ומאפשרת מעקב מלא מהמשולשים של גרף ידע חזרה למיקומי המסמך המקוריים. #### שדות קיימים (כבר ב-`derived_entity_triples`) - `page_number` — מספר עמוד/גיליון/שקופית (מוגדר מ-1, רק עבור פורמטים מבוססי עמודים) - `char_offset` — היסט מוחלט של תווים של עמוד/סעיף זה בתוך הטקסט המלא של המסמך. - `char_length` — אורך התווים של הטקסט של עמוד/סעיף זה. #### שדות חדשים (הרחבת `derived_entity_triples`) - `mime_type` — פורמט מסמך מקורי (לדוגמה, `application/pdf`) - `element_types` — רשימה מופרדת בפסיקים של קטגוריות `unstructured` של אלמנטים (לדוגמה, `title, paragraph, table`). - `provenance` — מידע על מקור הנתונים.