From d441a0f277043d7f512b058541cf820e0d49a868 Mon Sep 17 00:00:00 2001 From: 732642856 <732642856@qq.com> Date: Thu, 2 Jul 2026 17:26:19 +0800 Subject: [PATCH] Add extraction results manifest --- ...racter_level_external_manifest_latest.json | 2 +- ...haracter_level_external_manifest_latest.md | 2 +- ...aracter_level_extraction_queue_latest.json | 2 +- ...character_level_extraction_queue_latest.md | 2 +- ...acter_level_extraction_results_latest.json | 1227 +++++++++++++++++ ...aracter_level_extraction_results_latest.md | 33 + ...acter_level_inventory_manifest_latest.json | 52 +- ...aracter_level_inventory_manifest_latest.md | 10 +- progress.md | 9 + scripts/character_level_inventory_manifest.py | 206 ++- ...test_character_level_inventory_manifest.py | 39 + 11 files changed, 1562 insertions(+), 22 deletions(-) create mode 100644 docs/research/character_level_extraction_results_latest.json create mode 100644 docs/research/character_level_extraction_results_latest.md diff --git a/docs/research/character_level_external_manifest_latest.json b/docs/research/character_level_external_manifest_latest.json index 50a4de18..a8f490e5 100644 --- a/docs/research/character_level_external_manifest_latest.json +++ b/docs/research/character_level_external_manifest_latest.json @@ -1,7 +1,7 @@ { "scope": "external", "status": "pass", - "generated_at": "2026-07-02T09:12:09.488794+00:00", + "generated_at": "2026-07-02T09:23:43.522488+00:00", "mode": { "heavy_ocr": false, "whole_machine_scan": false, diff --git a/docs/research/character_level_external_manifest_latest.md b/docs/research/character_level_external_manifest_latest.md index d2af4822..54bbee39 100644 --- a/docs/research/character_level_external_manifest_latest.md +++ b/docs/research/character_level_external_manifest_latest.md @@ -2,7 +2,7 @@ - status: pass - scope: external -- generated_at: 2026-07-02T09:12:09.488794+00:00 +- generated_at: 2026-07-02T09:23:43.522488+00:00 - total_files: 883 - unhashed_files: 0 - unclassified_files: 0 diff --git a/docs/research/character_level_extraction_queue_latest.json b/docs/research/character_level_extraction_queue_latest.json index dd5b5efe..a812a855 100644 --- a/docs/research/character_level_extraction_queue_latest.json +++ b/docs/research/character_level_extraction_queue_latest.json @@ -1,7 +1,7 @@ { "scope": "extraction-queue", "status": "pass", - "generated_at": "2026-07-02T09:12:17.049464+00:00", + "generated_at": "2026-07-02T09:24:04.124961+00:00", "mode": { "heavy_ocr": false, "whole_machine_scan": false, diff --git a/docs/research/character_level_extraction_queue_latest.md b/docs/research/character_level_extraction_queue_latest.md index 483cd75e..2c928c58 100644 --- a/docs/research/character_level_extraction_queue_latest.md +++ b/docs/research/character_level_extraction_queue_latest.md @@ -2,7 +2,7 @@ - status: pass - scope: extraction-queue -- generated_at: 2026-07-02T09:12:17.049464+00:00 +- generated_at: 2026-07-02T09:24:04.124961+00:00 - queued_files: 66 - unhashed_files: 0 - Heavy OCR: disabled diff --git a/docs/research/character_level_extraction_results_latest.json b/docs/research/character_level_extraction_results_latest.json new file mode 100644 index 00000000..6f16458e --- /dev/null +++ b/docs/research/character_level_extraction_results_latest.json @@ -0,0 +1,1227 @@ +{ + "scope": "extraction-results", + "status": "pass", + "generated_at": "2026-07-02T09:25:00.613875+00:00", + "mode": { + "heavy_ocr": false, + "whole_machine_scan": false, + "external_high_relevance_scan": true, + "semantic_promotion": false, + "boundary": "Extraction results store text hashes and counts only. Extracted private text is not copied into the repo truth chain." + }, + "summary": { + "total_files": 66, + "unhashed_files": 0, + "stored_text_payload_fields": 0 + }, + "result_counts": { + "extraction_failed": 1, + "ocr_blocked_missing_engine": 53, + "text_extracted": 12 + }, + "method_counts": { + "docx": 11, + "pdfplumber": 2, + "pytesseract": 53 + }, + "post_extraction_classification_counts": { + "extracted_candidate_for_review": 10, + "extracted_private_reference_only": 3, + "extracted_reference_only": 53 + }, + "results": [ + { + "source_scope": "external", + "path": "/Users/wuyongnaren/Desktop/一楠印度占星 Level 3 综合解盘.docx", + "suffix": ".docx", + "byte_count": 19165, + "sha256": "cee1d2837d7e1d396fe3b6ba06012e16e0dad3d2d68554e5116d25789170b64b", + "extraction_status": "document_text_extraction_queued", + "classification": "external_historical_report", + "priority": "priority_2", + "promotion_status": "external_reference_only", + "extraction_result": "text_extracted", + "extraction_method": "docx", + "blocked_reason": null, + "extracted_character_count": 6369, + "extracted_line_count": 152, + "text_sha256": "1f03273efddcafd345cdfe542a118d5eacee5da554bded430dbfe4cb3b6e8571", + "post_extraction_classification": "extracted_private_reference_only" + }, + { + "source_scope": "external", + "path": "/Users/wuyongnaren/Desktop/印度占星修正版研究结论v3-高压基建后的反转兑现模型.docx", + "suffix": ".docx", + "byte_count": 21966, + "sha256": "b8d1b8c9bae94d7b1102db321543ef34cf4d4b5d7b822c3365e059903be40fb4", + "extraction_status": "document_text_extraction_queued", + "classification": "external_historical_report", + "priority": "priority_2", + "promotion_status": "external_reference_only", + "extraction_result": "text_extracted", + "extraction_method": "docx", + "blocked_reason": null, + "extracted_character_count": 7753, + "extracted_line_count": 446, + "text_sha256": "dafb672b74f9aa3b05ecaa5118ae5a72f612f96750640d2396e1c654dcb29dfb", + "post_extraction_classification": "extracted_private_reference_only" + }, + { + "source_scope": "external", + "path": "/Users/wuyongnaren/Downloads/jyotish_training.agent.final.docx", + "suffix": ".docx", + "byte_count": 186879, + "sha256": "a0d83aa8a70f9966cbe79945c4416906e1382c9093998c23d73bd395b02f23fe", + "extraction_status": "document_text_extraction_queued", + "classification": "external_book_or_document", + "priority": "priority_1", + "promotion_status": "external_reference_only", + "extraction_result": "text_extracted", + "extraction_method": "docx", + "blocked_reason": null, + "extracted_character_count": 145078, + "extracted_line_count": 1203, + "text_sha256": "9607ceaafa8a38abd5943037b7a66113db4fee6abb6d77a246924c7770242049", + "post_extraction_classification": "extracted_candidate_for_review" + }, + { + "source_scope": "external", + "path": "/Users/wuyongnaren/WorkBuddy/2026-06-09-20-03-34/jyotish-fragments/training/jyotish_training.agent.final.docx", + "suffix": ".docx", + "byte_count": 186879, + "sha256": "a0d83aa8a70f9966cbe79945c4416906e1382c9093998c23d73bd395b02f23fe", + "extraction_status": "document_text_extraction_queued", + "classification": "external_historical_report", + "priority": "priority_2", + "promotion_status": "external_reference_only", + "extraction_result": "text_extracted", + "extraction_method": "docx", + "blocked_reason": null, + "extracted_character_count": 145078, + "extracted_line_count": 1203, + "text_sha256": "9607ceaafa8a38abd5943037b7a66113db4fee6abb6d77a246924c7770242049", + "post_extraction_classification": "extracted_private_reference_only" + }, + { + "source_scope": "external", + "path": "/Users/wuyongnaren/文件仓库/印度占星文章/1印度占星.docx", + "suffix": ".docx", + "byte_count": 6142110, + "sha256": "210a09d764f8fe17ded6c908d5073648908892a99ae853f983e6f516ccc0164d", + "extraction_status": "document_text_extraction_queued", + "classification": "external_book_or_document", + "priority": "priority_1", + "promotion_status": "external_reference_only", + "extraction_result": "text_extracted", + "extraction_method": "docx", + "blocked_reason": null, + "extracted_character_count": 30716, + "extracted_line_count": 711, + "text_sha256": "9d02544ecab01e9dad012ec53336f0404ba316896e3ae5fd8efa7b2e7271330f", + "post_extraction_classification": "extracted_candidate_for_review" + }, + { + "source_scope": "external", + "path": "/Users/wuyongnaren/文件仓库/印度占星文章/2印度占星.docx", + "suffix": ".docx", + "byte_count": 3031411, + "sha256": "16979422e7621475243e2739fda00767d1a9dc367f7f10153fe36d8af6e15c6d", + "extraction_status": "document_text_extraction_queued", + "classification": "external_book_or_document", + "priority": "priority_1", + "promotion_status": "external_reference_only", + "extraction_result": "text_extracted", + "extraction_method": "docx", + "blocked_reason": null, + "extracted_character_count": 17967, + "extracted_line_count": 362, + "text_sha256": "91cfc9364387007753bce62360ee7d546aa6357935775a32dc867f2d3bf09dde", + "post_extraction_classification": "extracted_candidate_for_review" + }, + { + "source_scope": "external", + "path": "/Users/wuyongnaren/文件仓库/印度占星文章/3印度占星.docx", + "suffix": ".docx", + "byte_count": 2149772, + "sha256": "59ee274246547f4afb581ec26f5a4aad03ba2095309d66c40a60a51d1244df92", + "extraction_status": "document_text_extraction_queued", + "classification": "external_book_or_document", + "priority": "priority_1", + "promotion_status": "external_reference_only", + "extraction_result": "text_extracted", + "extraction_method": "docx", + "blocked_reason": null, + "extracted_character_count": 29017, + "extracted_line_count": 954, + "text_sha256": "47c4c9cfcfdc2bbd024d845c1c95eec9546d1d8c462fb25626e6b449d957d3cc", + "post_extraction_classification": "extracted_candidate_for_review" + }, + { + "source_scope": "external", + "path": "/Users/wuyongnaren/文件仓库/印度占星文章/4印度占星.docx", + "suffix": ".docx", + "byte_count": 5572637, + "sha256": "e789430dc1df6ab7054a5b28f0665da325e7c5eb2e6daac39f1f17ac29ba7629", + "extraction_status": "document_text_extraction_queued", + "classification": "external_book_or_document", + "priority": "priority_1", + "promotion_status": "external_reference_only", + "extraction_result": "extraction_failed", + "extraction_method": "docx", + "blocked_reason": "KeyError: \"There is no item named 'NULL' in the archive\"", + "extracted_character_count": 0, + "extracted_line_count": 0, + "text_sha256": null, + "post_extraction_classification": "extracted_candidate_for_review" + }, + { + "source_scope": "external", + "path": "/Users/wuyongnaren/文件仓库/印度占星文章/Tajika占星术是印度占星术体系之一.docx", + "suffix": ".docx", + "byte_count": 1338151, + "sha256": "254624594c26fc80ad5bfa9e9a880ac0cd81c9388b19721d5767dfa5c55e953c", + "extraction_status": "document_text_extraction_queued", + "classification": "external_book_or_document", + "priority": "priority_1", + "promotion_status": "external_reference_only", + "extraction_result": "text_extracted", + "extraction_method": "docx", + "blocked_reason": null, + "extracted_character_count": 23606, + "extracted_line_count": 577, + "text_sha256": "2f8b217e08b5c20afdfb328851bf5c719cd1ab98f2572d413ab359e6f16cef6f", + "post_extraction_classification": "extracted_candidate_for_review" + }, + { + "source_scope": "external", + "path": "/Users/wuyongnaren/文件仓库/印度占星文章/印度占星Jaimini系统的Darakaraka的理解和说明如何解释.docx", + "suffix": ".docx", + "byte_count": 44926, + "sha256": "f2db03d1c0392e2cdad66da9a731117c0ddf290cad7712b9c3de0d8234a17a29", + "extraction_status": "document_text_extraction_queued", + "classification": "external_book_or_document", + "priority": "priority_1", + "promotion_status": "external_reference_only", + "extraction_result": "text_extracted", + "extraction_method": "docx", + "blocked_reason": null, + "extracted_character_count": 20085, + "extracted_line_count": 600, + "text_sha256": "72bba68ca08007492181c01936290315500e052a21fc03562c03605eb0204048", + "post_extraction_classification": "extracted_candidate_for_review" + }, + { + "source_scope": "external", + "path": "/Users/wuyongnaren/文件仓库/印度占星文章/高地位配偶与婚后命运积极转变的占星规则与组合.docx", + "suffix": ".docx", + "byte_count": 1120887, + "sha256": "9cdd6996670ad46063c9582957c6d98269e069f96801ff340ce0c84de325d412", + "extraction_status": "document_text_extraction_queued", + "classification": "external_book_or_document", + "priority": "priority_1", + "promotion_status": "external_reference_only", + "extraction_result": "text_extracted", + "extraction_method": "docx", + "blocked_reason": null, + "extracted_character_count": 4507, + "extracted_line_count": 144, + "text_sha256": "1e620fb59e95ae4fe59b1181bc9fe34238115e1f138d1433f2e1b66c10051ed6", + "post_extraction_classification": "extracted_candidate_for_review" + }, + { + "source_scope": "external", + "path": "/Users/wuyongnaren/.workbuddy/skills/jyotish-vedic-astrology/assets/jyotish-logo.png", + "suffix": ".png", + "byte_count": 1496430, + "sha256": "4cb571aa402da3a730a73b6594ec88adf90f2d807018e23f96fd1bee426c23ed", + "extraction_status": "image_ocr_queued", + "classification": "external_skill_fragment", + "priority": "priority_1", + "promotion_status": "external_candidate", + "extraction_result": "ocr_blocked_missing_engine", + "extraction_method": "pytesseract", + "blocked_reason": "tesseract executable not found", + "extracted_character_count": 0, + "extracted_line_count": 0, + "text_sha256": null, + "post_extraction_classification": "extracted_reference_only" + }, + { + "source_scope": "external", + "path": "/Users/wuyongnaren/.workbuddy/skills/jyotish-vedic-astrology/references/open_source_sources/VedicAstro/VedicAstroLogo.png", + "suffix": ".png", + "byte_count": 151345, + "sha256": "e64022e2dde10d7ce378a69f8b7f035b084d56517f37eb8f6ecc4bd47fe0fe2a", + "extraction_status": "image_ocr_queued", + "classification": "external_skill_fragment", + "priority": "priority_1", + "promotion_status": "external_candidate", + "extraction_result": "ocr_blocked_missing_engine", + "extraction_method": "pytesseract", + "blocked_reason": "tesseract executable not found", + "extracted_character_count": 0, + "extracted_line_count": 0, + "text_sha256": null, + "post_extraction_classification": "extracted_reference_only" + }, + { + "source_scope": "external", + "path": "/Users/wuyongnaren/.workbuddy/skills/jyotish-vedic-astrology/references/open_source_sources/vedic-astro-skills/assets/alipay.jpg", + "suffix": ".jpg", + "byte_count": 164821, + "sha256": "f7d4dcf08239c738d5cd45d531401bdef92e4c1b7ea93965b7a7f51ab76dc8fc", + "extraction_status": "image_ocr_queued", + "classification": "external_skill_fragment", + "priority": "priority_1", + "promotion_status": "external_candidate", + "extraction_result": "ocr_blocked_missing_engine", + "extraction_method": "pytesseract", + "blocked_reason": "tesseract executable not found", + "extracted_character_count": 0, + "extracted_line_count": 0, + "text_sha256": null, + "post_extraction_classification": "extracted_reference_only" + }, + { + "source_scope": "external", + "path": "/Users/wuyongnaren/.workbuddy/skills/jyotish-vedic-astrology/references/open_source_sources/vedic-astro-skills/assets/wechat.jpg", + "suffix": ".jpg", + "byte_count": 71804, + "sha256": "e94c027499059e7fb2170474fb03e3be875b4251dfbea5fc7f39b370d6242a62", + "extraction_status": "image_ocr_queued", + "classification": "external_skill_fragment", + "priority": "priority_1", + "promotion_status": "external_candidate", + "extraction_result": "ocr_blocked_missing_engine", + "extraction_method": "pytesseract", + "blocked_reason": "tesseract executable not found", + "extracted_character_count": 0, + "extracted_line_count": 0, + "text_sha256": null, + "post_extraction_classification": "extracted_reference_only" + }, + { + "source_scope": "external", + "path": "/Users/wuyongnaren/Desktop/电脑相册/重复图片移动前备份清单_2026-05-20/file_backups/WorkBuddy/yinduzhanxing/assets/jyotish-logo.png", + "suffix": ".png", + "byte_count": 1496430, + "sha256": "4cb571aa402da3a730a73b6594ec88adf90f2d807018e23f96fd1bee426c23ed", + "extraction_status": "image_ocr_queued", + "classification": "external_historical_report", + "priority": "priority_2", + "promotion_status": "external_reference_only", + "extraction_result": "ocr_blocked_missing_engine", + "extraction_method": "pytesseract", + "blocked_reason": "tesseract executable not found", + "extracted_character_count": 0, + "extracted_line_count": 0, + "text_sha256": null, + "post_extraction_classification": "extracted_reference_only" + }, + { + "source_scope": "external", + "path": "/Users/wuyongnaren/Downloads/印度占星11页/IMG_3004.jpg", + "suffix": ".jpg", + "byte_count": 335978, + "sha256": "3e87432635d0b7d6181a5d251191ab397352bfc0908bedef4d07b135aa351012", + "extraction_status": "image_ocr_queued", + "classification": "external_archive_or_binary", + "priority": "priority_3", + "promotion_status": "external_index_only", + "extraction_result": "ocr_blocked_missing_engine", + "extraction_method": "pytesseract", + "blocked_reason": "tesseract executable not found", + "extracted_character_count": 0, + "extracted_line_count": 0, + "text_sha256": null, + "post_extraction_classification": "extracted_reference_only" + }, + { + "source_scope": "external", + "path": "/Users/wuyongnaren/Downloads/印度占星11页/IMG_3005.jpg", + "suffix": ".jpg", + "byte_count": 365592, + "sha256": "3743a89d6611dd8a3a344db2e9ca6877b6f1f610b48bd3cbb9486eb8a81f4195", + "extraction_status": "image_ocr_queued", + "classification": "external_archive_or_binary", + "priority": "priority_3", + "promotion_status": "external_index_only", + "extraction_result": "ocr_blocked_missing_engine", + "extraction_method": "pytesseract", + "blocked_reason": "tesseract executable not found", + "extracted_character_count": 0, + "extracted_line_count": 0, + "text_sha256": null, + "post_extraction_classification": "extracted_reference_only" + }, + { + "source_scope": "external", + "path": "/Users/wuyongnaren/Downloads/印度占星11页/IMG_3006.jpg", + "suffix": ".jpg", + "byte_count": 387356, + "sha256": "03689b8775950267002cbbf9b96bf5038217c692c311188429ee99903beea285", + "extraction_status": "image_ocr_queued", + "classification": "external_archive_or_binary", + "priority": "priority_3", + "promotion_status": "external_index_only", + "extraction_result": "ocr_blocked_missing_engine", + "extraction_method": "pytesseract", + "blocked_reason": "tesseract executable not found", + "extracted_character_count": 0, + "extracted_line_count": 0, + "text_sha256": null, + "post_extraction_classification": "extracted_reference_only" + }, + { + "source_scope": "external", + "path": "/Users/wuyongnaren/Downloads/印度占星11页/IMG_3007.jpg", + "suffix": ".jpg", + "byte_count": 457489, + "sha256": "d959e3b1625ec6d7d0a3129f8fd856f18b06de2d4b874bbc3322e1c9818b5aa3", + "extraction_status": "image_ocr_queued", + "classification": "external_archive_or_binary", + "priority": "priority_3", + "promotion_status": "external_index_only", + "extraction_result": "ocr_blocked_missing_engine", + "extraction_method": "pytesseract", + "blocked_reason": "tesseract executable not found", + "extracted_character_count": 0, + "extracted_line_count": 0, + "text_sha256": null, + "post_extraction_classification": "extracted_reference_only" + }, + { + "source_scope": "external", + "path": "/Users/wuyongnaren/Downloads/印度占星11页/IMG_3008.jpg", + "suffix": ".jpg", + "byte_count": 447919, + "sha256": "8999a66852d45b5e89b53823bff4aecb5b3fca935495572ee3422c1a067d2507", + "extraction_status": "image_ocr_queued", + "classification": "external_archive_or_binary", + "priority": "priority_3", + "promotion_status": "external_index_only", + "extraction_result": "ocr_blocked_missing_engine", + "extraction_method": "pytesseract", + "blocked_reason": "tesseract executable not found", + "extracted_character_count": 0, + "extracted_line_count": 0, + "text_sha256": null, + "post_extraction_classification": "extracted_reference_only" + }, + { + "source_scope": "external", + "path": "/Users/wuyongnaren/Downloads/印度占星11页/IMG_3009.jpg", + "suffix": ".jpg", + "byte_count": 436786, + "sha256": "e4a1eaa1730a22d96e4032bf405e0ed556395a0d9a27a2c5ec7265b8a3c3fdf8", + "extraction_status": "image_ocr_queued", + "classification": "external_archive_or_binary", + "priority": "priority_3", + "promotion_status": "external_index_only", + "extraction_result": "ocr_blocked_missing_engine", + "extraction_method": "pytesseract", + "blocked_reason": "tesseract executable not found", + "extracted_character_count": 0, + "extracted_line_count": 0, + "text_sha256": null, + "post_extraction_classification": "extracted_reference_only" + }, + { + "source_scope": "external", + "path": "/Users/wuyongnaren/Downloads/印度占星11页/IMG_3010.jpg", + "suffix": ".jpg", + "byte_count": 352127, + "sha256": "b6478c3db82ad67534fae2bcd52e29da9bb1ffa573271097e8449cfbf1be5537", + "extraction_status": "image_ocr_queued", + "classification": "external_archive_or_binary", + "priority": "priority_3", + "promotion_status": "external_index_only", + "extraction_result": "ocr_blocked_missing_engine", + "extraction_method": "pytesseract", + "blocked_reason": "tesseract executable not found", + "extracted_character_count": 0, + "extracted_line_count": 0, + "text_sha256": null, + "post_extraction_classification": "extracted_reference_only" + }, + { + "source_scope": "external", + "path": "/Users/wuyongnaren/Downloads/印度占星11页/IMG_3011.jpg", + "suffix": ".jpg", + "byte_count": 347111, + "sha256": "0d786f1284ff916f37055c77101559955e83eecba24b290eb80ab808e7a90ce4", + "extraction_status": "image_ocr_queued", + "classification": "external_archive_or_binary", + "priority": "priority_3", + "promotion_status": "external_index_only", + "extraction_result": "ocr_blocked_missing_engine", + "extraction_method": "pytesseract", + "blocked_reason": "tesseract executable not found", + "extracted_character_count": 0, + "extracted_line_count": 0, + "text_sha256": null, + "post_extraction_classification": "extracted_reference_only" + }, + { + "source_scope": "external", + "path": "/Users/wuyongnaren/Downloads/印度占星11页/IMG_3012.jpg", + "suffix": ".jpg", + "byte_count": 282794, + "sha256": "319b2ab6948d82e04eaf957caf5310c85f9c42db66f2c39f8e27bcca7528487a", + "extraction_status": "image_ocr_queued", + "classification": "external_archive_or_binary", + "priority": "priority_3", + "promotion_status": "external_index_only", + "extraction_result": "ocr_blocked_missing_engine", + "extraction_method": "pytesseract", + "blocked_reason": "tesseract executable not found", + "extracted_character_count": 0, + "extracted_line_count": 0, + "text_sha256": null, + "post_extraction_classification": "extracted_reference_only" + }, + { + "source_scope": "external", + "path": "/Users/wuyongnaren/Downloads/印度占星11页/IMG_3013.jpg", + "suffix": ".jpg", + "byte_count": 296069, + "sha256": "2253eebdc5a3f7b26400cffd3b0de32b33b29896783406b85a537957059c3115", + "extraction_status": "image_ocr_queued", + "classification": "external_archive_or_binary", + "priority": "priority_3", + "promotion_status": "external_index_only", + "extraction_result": "ocr_blocked_missing_engine", + "extraction_method": "pytesseract", + "blocked_reason": "tesseract executable not found", + "extracted_character_count": 0, + "extracted_line_count": 0, + "text_sha256": null, + "post_extraction_classification": "extracted_reference_only" + }, + { + "source_scope": "external", + "path": "/Users/wuyongnaren/Downloads/印度占星11页/IMG_3014.jpg", + "suffix": ".jpg", + "byte_count": 288473, + "sha256": "5d7e8abcd4cdb922d0da0fa987fd4264b57339230586b38570a360f2b1f6f1cd", + "extraction_status": "image_ocr_queued", + "classification": "external_archive_or_binary", + "priority": "priority_3", + "promotion_status": "external_index_only", + "extraction_result": "ocr_blocked_missing_engine", + "extraction_method": "pytesseract", + "blocked_reason": "tesseract executable not found", + "extracted_character_count": 0, + "extracted_line_count": 0, + "text_sha256": null, + "post_extraction_classification": "extracted_reference_only" + }, + { + "source_scope": "external", + "path": "/Users/wuyongnaren/文件仓库/印度占星文章/占星印度1/IMG_3223.JPG", + "suffix": ".jpg", + "byte_count": 6709612, + "sha256": "8a2f44bc4c57b8d352371101a662305b88d4f834d385c22a6f0b308c66119890", + "extraction_status": "image_ocr_queued", + "classification": "external_book_or_document", + "priority": "priority_1", + "promotion_status": "external_reference_only", + "extraction_result": "ocr_blocked_missing_engine", + "extraction_method": "pytesseract", + "blocked_reason": "tesseract executable not found", + "extracted_character_count": 0, + "extracted_line_count": 0, + "text_sha256": null, + "post_extraction_classification": "extracted_reference_only" + }, + { + "source_scope": "external", + "path": "/Users/wuyongnaren/文件仓库/印度占星文章/占星印度1/IMG_3224.JPG", + "suffix": ".jpg", + "byte_count": 4388817, + "sha256": "30b7f2ea6bcc962ccb3064f3656e7d298a5469e084d1fdf21322bc5ea3b21d90", + "extraction_status": "image_ocr_queued", + "classification": "external_book_or_document", + "priority": "priority_1", + "promotion_status": "external_reference_only", + "extraction_result": "ocr_blocked_missing_engine", + "extraction_method": "pytesseract", + "blocked_reason": "tesseract executable not found", + "extracted_character_count": 0, + "extracted_line_count": 0, + "text_sha256": null, + "post_extraction_classification": "extracted_reference_only" + }, + { + "source_scope": "external", + "path": "/Users/wuyongnaren/文件仓库/印度占星文章/占星印度1/IMG_3225.JPG", + "suffix": ".jpg", + "byte_count": 3539980, + "sha256": "4edcfa12004b48047dbff7f5512914aedd40768b37dc75ad45c467c05802ab25", + "extraction_status": "image_ocr_queued", + "classification": "external_book_or_document", + "priority": "priority_1", + "promotion_status": "external_reference_only", + "extraction_result": "ocr_blocked_missing_engine", + "extraction_method": "pytesseract", + "blocked_reason": "tesseract executable not found", + "extracted_character_count": 0, + "extracted_line_count": 0, + "text_sha256": null, + "post_extraction_classification": "extracted_reference_only" + }, + { + "source_scope": "external", + "path": "/Users/wuyongnaren/文件仓库/印度占星文章/占星印度1/IMG_3226.JPG", + "suffix": ".jpg", + "byte_count": 3118339, + "sha256": "820f1c29b11e09ed51681be292adf15919ca3d5157b23fb29d098023f4423c52", + "extraction_status": "image_ocr_queued", + "classification": "external_book_or_document", + "priority": "priority_1", + "promotion_status": "external_reference_only", + "extraction_result": "ocr_blocked_missing_engine", + "extraction_method": "pytesseract", + "blocked_reason": "tesseract executable not found", + "extracted_character_count": 0, + "extracted_line_count": 0, + "text_sha256": null, + "post_extraction_classification": "extracted_reference_only" + }, + { + "source_scope": "external", + "path": "/Users/wuyongnaren/文件仓库/印度占星文章/占星印度1/IMG_3227.JPG", + "suffix": ".jpg", + "byte_count": 6945195, + "sha256": "c6643554be26edc62274f8b4e0acd1cf305aaeff8c1720cb5b731e0842fada46", + "extraction_status": "image_ocr_queued", + "classification": "external_book_or_document", + "priority": "priority_1", + "promotion_status": "external_reference_only", + "extraction_result": "ocr_blocked_missing_engine", + "extraction_method": "pytesseract", + "blocked_reason": "tesseract executable not found", + "extracted_character_count": 0, + "extracted_line_count": 0, + "text_sha256": null, + "post_extraction_classification": "extracted_reference_only" + }, + { + "source_scope": "external", + "path": "/Users/wuyongnaren/文件仓库/印度占星文章/占星印度1/IMG_3228.JPG", + "suffix": ".jpg", + "byte_count": 2188130, + "sha256": "d118ce2ed91a3a3b3551833f20cca6604011d22ff921976d50e5cd21d08db3e7", + "extraction_status": "image_ocr_queued", + "classification": "external_book_or_document", + "priority": "priority_1", + "promotion_status": "external_reference_only", + "extraction_result": "ocr_blocked_missing_engine", + "extraction_method": "pytesseract", + "blocked_reason": "tesseract executable not found", + "extracted_character_count": 0, + "extracted_line_count": 0, + "text_sha256": null, + "post_extraction_classification": "extracted_reference_only" + }, + { + "source_scope": "external", + "path": "/Users/wuyongnaren/文件仓库/印度占星文章/占星印度1/IMG_3229.JPG", + "suffix": ".jpg", + "byte_count": 1390060, + "sha256": "630e6f8f91bfda5fcb3871c30758dec2db32108b89ec511d25aebea7313f0cfe", + "extraction_status": "image_ocr_queued", + "classification": "external_book_or_document", + "priority": "priority_1", + "promotion_status": "external_reference_only", + "extraction_result": "ocr_blocked_missing_engine", + "extraction_method": "pytesseract", + "blocked_reason": "tesseract executable not found", + "extracted_character_count": 0, + "extracted_line_count": 0, + "text_sha256": null, + "post_extraction_classification": "extracted_reference_only" + }, + { + "source_scope": "external", + "path": "/Users/wuyongnaren/文件仓库/印度占星文章/占星印度1/IMG_3230.JPG", + "suffix": ".jpg", + "byte_count": 2723452, + "sha256": "be3a1ddb38f42961273827537ce8a8c73dd2c5ad5e1effd90c49bcf623b196c2", + "extraction_status": "image_ocr_queued", + "classification": "external_book_or_document", + "priority": "priority_1", + "promotion_status": "external_reference_only", + "extraction_result": "ocr_blocked_missing_engine", + "extraction_method": "pytesseract", + "blocked_reason": "tesseract executable not found", + "extracted_character_count": 0, + "extracted_line_count": 0, + "text_sha256": null, + "post_extraction_classification": "extracted_reference_only" + }, + { + "source_scope": "external", + "path": "/Users/wuyongnaren/文件仓库/印度占星文章/占星印度1/IMG_3231.JPG", + "suffix": ".jpg", + "byte_count": 3460758, + "sha256": "279b99af4faa614eb21ef8d2a2bc67bf87a4cce112ba04627bca67f2f343297b", + "extraction_status": "image_ocr_queued", + "classification": "external_book_or_document", + "priority": "priority_1", + "promotion_status": "external_reference_only", + "extraction_result": "ocr_blocked_missing_engine", + "extraction_method": "pytesseract", + "blocked_reason": "tesseract executable not found", + "extracted_character_count": 0, + "extracted_line_count": 0, + "text_sha256": null, + "post_extraction_classification": "extracted_reference_only" + }, + { + "source_scope": "external", + "path": "/Users/wuyongnaren/文件仓库/印度占星文章/占星印度1/IMG_3232.JPG", + "suffix": ".jpg", + "byte_count": 3256088, + "sha256": "a46fb026076a3314ef9f263a7234659c7d2b75068aba20271d07d0f7a3b674b1", + "extraction_status": "image_ocr_queued", + "classification": "external_book_or_document", + "priority": "priority_1", + "promotion_status": "external_reference_only", + "extraction_result": "ocr_blocked_missing_engine", + "extraction_method": "pytesseract", + "blocked_reason": "tesseract executable not found", + "extracted_character_count": 0, + "extracted_line_count": 0, + "text_sha256": null, + "post_extraction_classification": "extracted_reference_only" + }, + { + "source_scope": "external", + "path": "/Users/wuyongnaren/文件仓库/印度占星文章/印度占星查悦/IMG_3233.JPG", + "suffix": ".jpg", + "byte_count": 5620475, + "sha256": "c3ed9e4d29163d9baa0f8b95669cfcbb52f20727ce23f105c5fc8c688cbd5fb6", + "extraction_status": "image_ocr_queued", + "classification": "external_book_or_document", + "priority": "priority_1", + "promotion_status": "external_reference_only", + "extraction_result": "ocr_blocked_missing_engine", + "extraction_method": "pytesseract", + "blocked_reason": "tesseract executable not found", + "extracted_character_count": 0, + "extracted_line_count": 0, + "text_sha256": null, + "post_extraction_classification": "extracted_reference_only" + }, + { + "source_scope": "external", + "path": "/Users/wuyongnaren/文件仓库/印度占星文章/印度占星查悦/IMG_3234.JPG", + "suffix": ".jpg", + "byte_count": 4739555, + "sha256": "1833b90c725ae183f3acf28bc7738858f7750e4dff67bd7157a70fb168c3301a", + "extraction_status": "image_ocr_queued", + "classification": "external_book_or_document", + "priority": "priority_1", + "promotion_status": "external_reference_only", + "extraction_result": "ocr_blocked_missing_engine", + "extraction_method": "pytesseract", + "blocked_reason": "tesseract executable not found", + "extracted_character_count": 0, + "extracted_line_count": 0, + "text_sha256": null, + "post_extraction_classification": "extracted_reference_only" + }, + { + "source_scope": "external", + "path": "/Users/wuyongnaren/文件仓库/印度占星文章/印度占星查悦/IMG_3235.JPG", + "suffix": ".jpg", + "byte_count": 5869585, + "sha256": "13a85b875309b89a47cfe13e52998cf85b1e5da09cc0905ac967877bb0f00091", + "extraction_status": "image_ocr_queued", + "classification": "external_book_or_document", + "priority": "priority_1", + "promotion_status": "external_reference_only", + "extraction_result": "ocr_blocked_missing_engine", + "extraction_method": "pytesseract", + "blocked_reason": "tesseract executable not found", + "extracted_character_count": 0, + "extracted_line_count": 0, + "text_sha256": null, + "post_extraction_classification": "extracted_reference_only" + }, + { + "source_scope": "external", + "path": "/Users/wuyongnaren/文件仓库/印度占星文章/印度占星查悦/IMG_3236.JPG", + "suffix": ".jpg", + "byte_count": 8733982, + "sha256": "6cd213236d66c235c8fe54722411375144e988029ef959a9e051f186399bbbc6", + "extraction_status": "image_ocr_queued", + "classification": "external_book_or_document", + "priority": "priority_1", + "promotion_status": "external_reference_only", + "extraction_result": "ocr_blocked_missing_engine", + "extraction_method": "pytesseract", + "blocked_reason": "tesseract executable not found", + "extracted_character_count": 0, + "extracted_line_count": 0, + "text_sha256": null, + "post_extraction_classification": "extracted_reference_only" + }, + { + "source_scope": "external", + "path": "/Users/wuyongnaren/文件仓库/印度占星文章/印度占星查悦/IMG_3237.JPG", + "suffix": ".jpg", + "byte_count": 5434137, + "sha256": "8a3eda7d1936530abb1ed5c93040b316bd013f02155d2b20eb9626bd84e7480e", + "extraction_status": "image_ocr_queued", + "classification": "external_book_or_document", + "priority": "priority_1", + "promotion_status": "external_reference_only", + "extraction_result": "ocr_blocked_missing_engine", + "extraction_method": "pytesseract", + "blocked_reason": "tesseract executable not found", + "extracted_character_count": 0, + "extracted_line_count": 0, + "text_sha256": null, + "post_extraction_classification": "extracted_reference_only" + }, + { + "source_scope": "external", + "path": "/Users/wuyongnaren/文件仓库/印度占星文章/印度占星查悦/IMG_3238.JPG", + "suffix": ".jpg", + "byte_count": 5918325, + "sha256": "c29063134357d4c7cb081d14c35c5558a47685913eff21be4a229703edd7256b", + "extraction_status": "image_ocr_queued", + "classification": "external_book_or_document", + "priority": "priority_1", + "promotion_status": "external_reference_only", + "extraction_result": "ocr_blocked_missing_engine", + "extraction_method": "pytesseract", + "blocked_reason": "tesseract executable not found", + "extracted_character_count": 0, + "extracted_line_count": 0, + "text_sha256": null, + "post_extraction_classification": "extracted_reference_only" + }, + { + "source_scope": "external", + "path": "/Users/wuyongnaren/文件仓库/印度占星文章/印度占星查悦/IMG_3239.JPG", + "suffix": ".jpg", + "byte_count": 5110208, + "sha256": "6633e0045710c1f6defda6624ec7c8ccf1c22dcb3bc34bf41bba7f48153a3255", + "extraction_status": "image_ocr_queued", + "classification": "external_book_or_document", + "priority": "priority_1", + "promotion_status": "external_reference_only", + "extraction_result": "ocr_blocked_missing_engine", + "extraction_method": "pytesseract", + "blocked_reason": "tesseract executable not found", + "extracted_character_count": 0, + "extracted_line_count": 0, + "text_sha256": null, + "post_extraction_classification": "extracted_reference_only" + }, + { + "source_scope": "external", + "path": "/Users/wuyongnaren/文件仓库/印度占星文章/印度占星查悦/IMG_3240.JPG", + "suffix": ".jpg", + "byte_count": 4155054, + "sha256": "5003bc196b649a9ee6f2cf1583ca55f13cc695030571184c5bf6db429775a5a6", + "extraction_status": "image_ocr_queued", + "classification": "external_book_or_document", + "priority": "priority_1", + "promotion_status": "external_reference_only", + "extraction_result": "ocr_blocked_missing_engine", + "extraction_method": "pytesseract", + "blocked_reason": "tesseract executable not found", + "extracted_character_count": 0, + "extracted_line_count": 0, + "text_sha256": null, + "post_extraction_classification": "extracted_reference_only" + }, + { + "source_scope": "external", + "path": "/Users/wuyongnaren/文件仓库/印度占星文章/印度占星查悦/IMG_3241.JPG", + "suffix": ".jpg", + "byte_count": 1262218, + "sha256": "4ffe9f3aadd4485ba99382a84d54abb02ae2520d8b0f57147fa7438408ce39d4", + "extraction_status": "image_ocr_queued", + "classification": "external_book_or_document", + "priority": "priority_1", + "promotion_status": "external_reference_only", + "extraction_result": "ocr_blocked_missing_engine", + "extraction_method": "pytesseract", + "blocked_reason": "tesseract executable not found", + "extracted_character_count": 0, + "extracted_line_count": 0, + "text_sha256": null, + "post_extraction_classification": "extracted_reference_only" + }, + { + "source_scope": "external", + "path": "/Users/wuyongnaren/文件仓库/印度占星文章/印度占星查悦/IMG_3242.JPG", + "suffix": ".jpg", + "byte_count": 1867271, + "sha256": "a15fadbbd4a250a30bac8e27915210b67fa6dc2ceb482b6a3792a0acba87bd77", + "extraction_status": "image_ocr_queued", + "classification": "external_book_or_document", + "priority": "priority_1", + "promotion_status": "external_reference_only", + "extraction_result": "ocr_blocked_missing_engine", + "extraction_method": "pytesseract", + "blocked_reason": "tesseract executable not found", + "extracted_character_count": 0, + "extracted_line_count": 0, + "text_sha256": null, + "post_extraction_classification": "extracted_reference_only" + }, + { + "source_scope": "external", + "path": "/Users/wuyongnaren/文件仓库/印度占星文章/印度占星查悦/IMG_3243.JPG", + "suffix": ".jpg", + "byte_count": 6305912, + "sha256": "64bd2a3a548a2c94372c1e3312e9f87bd291a276e73a3918fcc903e41f0fea9f", + "extraction_status": "image_ocr_queued", + "classification": "external_book_or_document", + "priority": "priority_1", + "promotion_status": "external_reference_only", + "extraction_result": "ocr_blocked_missing_engine", + "extraction_method": "pytesseract", + "blocked_reason": "tesseract executable not found", + "extracted_character_count": 0, + "extracted_line_count": 0, + "text_sha256": null, + "post_extraction_classification": "extracted_reference_only" + }, + { + "source_scope": "external", + "path": "/Users/wuyongnaren/文件仓库/印度占星文章/印度占星查悦/IMG_3244.JPG", + "suffix": ".jpg", + "byte_count": 7177473, + "sha256": "e7a486925218295da284ca6ca167ae92f2a37285e26ea5161094f531cd12ebd4", + "extraction_status": "image_ocr_queued", + "classification": "external_book_or_document", + "priority": "priority_1", + "promotion_status": "external_reference_only", + "extraction_result": "ocr_blocked_missing_engine", + "extraction_method": "pytesseract", + "blocked_reason": "tesseract executable not found", + "extracted_character_count": 0, + "extracted_line_count": 0, + "text_sha256": null, + "post_extraction_classification": "extracted_reference_only" + }, + { + "source_scope": "external", + "path": "/Users/wuyongnaren/文件仓库/印度占星文章/印度占星查悦/IMG_3245.JPG", + "suffix": ".jpg", + "byte_count": 6429277, + "sha256": "c5fd2b815ca6d295b8de5402084a9a7cdd3f9d2f08e53c50abd45b1352eb8b06", + "extraction_status": "image_ocr_queued", + "classification": "external_book_or_document", + "priority": "priority_1", + "promotion_status": "external_reference_only", + "extraction_result": "ocr_blocked_missing_engine", + "extraction_method": "pytesseract", + "blocked_reason": "tesseract executable not found", + "extracted_character_count": 0, + "extracted_line_count": 0, + "text_sha256": null, + "post_extraction_classification": "extracted_reference_only" + }, + { + "source_scope": "external", + "path": "/Users/wuyongnaren/文件仓库/印度占星文章/印度占星查悦/IMG_3246.JPG", + "suffix": ".jpg", + "byte_count": 92516, + "sha256": "355ae43a243fcdea344500b1b3f53a47683050cd73b01428fa9490844d04e222", + "extraction_status": "image_ocr_queued", + "classification": "external_book_or_document", + "priority": "priority_1", + "promotion_status": "external_reference_only", + "extraction_result": "ocr_blocked_missing_engine", + "extraction_method": "pytesseract", + "blocked_reason": "tesseract executable not found", + "extracted_character_count": 0, + "extracted_line_count": 0, + "text_sha256": null, + "post_extraction_classification": "extracted_reference_only" + }, + { + "source_scope": "external", + "path": "/Users/wuyongnaren/文件仓库/印度占星文章/印度占星查悦/IMG_3247.JPG", + "suffix": ".jpg", + "byte_count": 7406196, + "sha256": "0bc4a95e8d9ad41e6df47cd80a7cf84b2df24cb5400b9de56d63d3be66818e7f", + "extraction_status": "image_ocr_queued", + "classification": "external_book_or_document", + "priority": "priority_1", + "promotion_status": "external_reference_only", + "extraction_result": "ocr_blocked_missing_engine", + "extraction_method": "pytesseract", + "blocked_reason": "tesseract executable not found", + "extracted_character_count": 0, + "extracted_line_count": 0, + "text_sha256": null, + "post_extraction_classification": "extracted_reference_only" + }, + { + "source_scope": "external", + "path": "/Users/wuyongnaren/文件仓库/印度占星文章/印度占星查悦/IMG_3248.JPG", + "suffix": ".jpg", + "byte_count": 3862462, + "sha256": "a3b3f89232cece9d3475cd48a3fff7878a62233743927fa2492b2bb646dfefa3", + "extraction_status": "image_ocr_queued", + "classification": "external_book_or_document", + "priority": "priority_1", + "promotion_status": "external_reference_only", + "extraction_result": "ocr_blocked_missing_engine", + "extraction_method": "pytesseract", + "blocked_reason": "tesseract executable not found", + "extracted_character_count": 0, + "extracted_line_count": 0, + "text_sha256": null, + "post_extraction_classification": "extracted_reference_only" + }, + { + "source_scope": "external", + "path": "/Users/wuyongnaren/文件仓库/印度占星文章/印度占星查悦/IMG_3249.JPG", + "suffix": ".jpg", + "byte_count": 7780975, + "sha256": "8ae9bd3960a150e88feb78813d245c73aa2e6473ff16182a61632241f9f50014", + "extraction_status": "image_ocr_queued", + "classification": "external_book_or_document", + "priority": "priority_1", + "promotion_status": "external_reference_only", + "extraction_result": "ocr_blocked_missing_engine", + "extraction_method": "pytesseract", + "blocked_reason": "tesseract executable not found", + "extracted_character_count": 0, + "extracted_line_count": 0, + "text_sha256": null, + "post_extraction_classification": "extracted_reference_only" + }, + { + "source_scope": "external", + "path": "/Users/wuyongnaren/文件仓库/印度占星文章/印度占星查悦/IMG_3250.JPG", + "suffix": ".jpg", + "byte_count": 7389728, + "sha256": "6c895f9ddd16c2a1edf785858203cbec1a86c1abb3c6b24e03d24e74d1ea175d", + "extraction_status": "image_ocr_queued", + "classification": "external_book_or_document", + "priority": "priority_1", + "promotion_status": "external_reference_only", + "extraction_result": "ocr_blocked_missing_engine", + "extraction_method": "pytesseract", + "blocked_reason": "tesseract executable not found", + "extracted_character_count": 0, + "extracted_line_count": 0, + "text_sha256": null, + "post_extraction_classification": "extracted_reference_only" + }, + { + "source_scope": "external", + "path": "/Users/wuyongnaren/文件仓库/印度占星文章/受孕/IMG_3216.JPG", + "suffix": ".jpg", + "byte_count": 1441554, + "sha256": "3cdbdd47967592f2581b820b9df49aecd7117b377c45c71571b440cce3f5dddd", + "extraction_status": "image_ocr_queued", + "classification": "external_book_or_document", + "priority": "priority_1", + "promotion_status": "external_reference_only", + "extraction_result": "ocr_blocked_missing_engine", + "extraction_method": "pytesseract", + "blocked_reason": "tesseract executable not found", + "extracted_character_count": 0, + "extracted_line_count": 0, + "text_sha256": null, + "post_extraction_classification": "extracted_reference_only" + }, + { + "source_scope": "external", + "path": "/Users/wuyongnaren/文件仓库/印度占星文章/受孕/IMG_3218.JPG", + "suffix": ".jpg", + "byte_count": 1968582, + "sha256": "58d9de5cd5399e74e007d7d50f093dc50d7d0688df484a26646787a07a0c7e92", + "extraction_status": "image_ocr_queued", + "classification": "external_book_or_document", + "priority": "priority_1", + "promotion_status": "external_reference_only", + "extraction_result": "ocr_blocked_missing_engine", + "extraction_method": "pytesseract", + "blocked_reason": "tesseract executable not found", + "extracted_character_count": 0, + "extracted_line_count": 0, + "text_sha256": null, + "post_extraction_classification": "extracted_reference_only" + }, + { + "source_scope": "external", + "path": "/Users/wuyongnaren/文件仓库/印度占星文章/受孕/IMG_3219.JPG", + "suffix": ".jpg", + "byte_count": 2710815, + "sha256": "47bedfc7e2fdc225305afc31cc4ab74bd0021bd65e61b9d85e1b0909aa5950b6", + "extraction_status": "image_ocr_queued", + "classification": "external_book_or_document", + "priority": "priority_1", + "promotion_status": "external_reference_only", + "extraction_result": "ocr_blocked_missing_engine", + "extraction_method": "pytesseract", + "blocked_reason": "tesseract executable not found", + "extracted_character_count": 0, + "extracted_line_count": 0, + "text_sha256": null, + "post_extraction_classification": "extracted_reference_only" + }, + { + "source_scope": "external", + "path": "/Users/wuyongnaren/文件仓库/印度占星文章/受孕/IMG_3220.JPG", + "suffix": ".jpg", + "byte_count": 741635, + "sha256": "771256b16a47d9db785abbeab01b11388900e7e98d45220ff0defb52f24e7b1b", + "extraction_status": "image_ocr_queued", + "classification": "external_book_or_document", + "priority": "priority_1", + "promotion_status": "external_reference_only", + "extraction_result": "ocr_blocked_missing_engine", + "extraction_method": "pytesseract", + "blocked_reason": "tesseract executable not found", + "extracted_character_count": 0, + "extracted_line_count": 0, + "text_sha256": null, + "post_extraction_classification": "extracted_reference_only" + }, + { + "source_scope": "external", + "path": "/Users/wuyongnaren/文件仓库/印度占星文章/受孕/IMG_3221.JPG", + "suffix": ".jpg", + "byte_count": 1275215, + "sha256": "b219ca2e664ddff55ef95681aeaf5362c3a1589b2bef562129e39e8960e0202e", + "extraction_status": "image_ocr_queued", + "classification": "external_book_or_document", + "priority": "priority_1", + "promotion_status": "external_reference_only", + "extraction_result": "ocr_blocked_missing_engine", + "extraction_method": "pytesseract", + "blocked_reason": "tesseract executable not found", + "extracted_character_count": 0, + "extracted_line_count": 0, + "text_sha256": null, + "post_extraction_classification": "extracted_reference_only" + }, + { + "source_scope": "external", + "path": "/Users/wuyongnaren/文件仓库/印度占星文章/受孕/IMG_3222.JPG", + "suffix": ".jpg", + "byte_count": 1340781, + "sha256": "a7601e255c4d398d2480dc71fb99916aa67c56f978a722943970806f805bde26", + "extraction_status": "image_ocr_queued", + "classification": "external_book_or_document", + "priority": "priority_1", + "promotion_status": "external_reference_only", + "extraction_result": "ocr_blocked_missing_engine", + "extraction_method": "pytesseract", + "blocked_reason": "tesseract executable not found", + "extracted_character_count": 0, + "extracted_line_count": 0, + "text_sha256": null, + "post_extraction_classification": "extracted_reference_only" + }, + { + "source_scope": "project", + "path": "references/open_source_sources/VedicAstro/VedicAstroLogo.png", + "suffix": ".png", + "byte_count": 151345, + "sha256": "e64022e2dde10d7ce378a69f8b7f035b084d56517f37eb8f6ecc4bd47fe0fe2a", + "extraction_status": "image_ocr_queued", + "classification": "open_source_reference", + "priority": "priority_2", + "promotion_status": "reference_layer_candidate", + "extraction_result": "ocr_blocked_missing_engine", + "extraction_method": "pytesseract", + "blocked_reason": "tesseract executable not found", + "extracted_character_count": 0, + "extracted_line_count": 0, + "text_sha256": null, + "post_extraction_classification": "extracted_reference_only" + }, + { + "source_scope": "project", + "path": "references/open_source_sources/vedic-astro-skills/assets/alipay.jpg", + "suffix": ".jpg", + "byte_count": 164821, + "sha256": "f7d4dcf08239c738d5cd45d531401bdef92e4c1b7ea93965b7a7f51ab76dc8fc", + "extraction_status": "image_ocr_queued", + "classification": "open_source_reference", + "priority": "priority_1", + "promotion_status": "reference_layer_candidate", + "extraction_result": "ocr_blocked_missing_engine", + "extraction_method": "pytesseract", + "blocked_reason": "tesseract executable not found", + "extracted_character_count": 0, + "extracted_line_count": 0, + "text_sha256": null, + "post_extraction_classification": "extracted_reference_only" + }, + { + "source_scope": "project", + "path": "references/open_source_sources/vedic-astro-skills/assets/wechat.jpg", + "suffix": ".jpg", + "byte_count": 71804, + "sha256": "e94c027499059e7fb2170474fb03e3be875b4251dfbea5fc7f39b370d6242a62", + "extraction_status": "image_ocr_queued", + "classification": "open_source_reference", + "priority": "priority_1", + "promotion_status": "reference_layer_candidate", + "extraction_result": "ocr_blocked_missing_engine", + "extraction_method": "pytesseract", + "blocked_reason": "tesseract executable not found", + "extracted_character_count": 0, + "extracted_line_count": 0, + "text_sha256": null, + "post_extraction_classification": "extracted_reference_only" + }, + { + "source_scope": "external", + "path": "/Users/wuyongnaren/Downloads/印度占星.pdf", + "suffix": ".pdf", + "byte_count": 135905, + "sha256": "121507cf1d0d66711bc30c18f589f36f2d3cce797ecb13cdf4427625e6ec8894", + "extraction_status": "pdf_text_extraction_queued", + "classification": "external_book_or_document", + "priority": "priority_1", + "promotion_status": "external_reference_only", + "extraction_result": "text_extracted", + "extraction_method": "pdfplumber", + "blocked_reason": null, + "extracted_character_count": 31164, + "extracted_line_count": 605, + "text_sha256": "e63b112988500a71704511d007c52cffdc71c300e518c438eb7f0cb71d732ede", + "post_extraction_classification": "extracted_candidate_for_review" + }, + { + "source_scope": "external", + "path": "/Users/wuyongnaren/Downloads/印度占星1.pdf", + "suffix": ".pdf", + "byte_count": 132486, + "sha256": "92c9288c5d0011a869c545e3459f037ff09cd20f7508543bc0eb11b03079d930", + "extraction_status": "pdf_text_extraction_queued", + "classification": "external_book_or_document", + "priority": "priority_1", + "promotion_status": "external_reference_only", + "extraction_result": "text_extracted", + "extraction_method": "pdfplumber", + "blocked_reason": null, + "extracted_character_count": 31321, + "extracted_line_count": 645, + "text_sha256": "d93283239c33fab588747a9354a162049b263d18bd06463bbb7b02634704a1be", + "post_extraction_classification": "extracted_candidate_for_review" + } + ], + "artifacts": { + "json_report": "docs/research/character_level_extraction_results_latest.json", + "markdown_report": "docs/research/character_level_extraction_results_latest.md" + }, + "title": "Extraction Results Manifest" +} \ No newline at end of file diff --git a/docs/research/character_level_extraction_results_latest.md b/docs/research/character_level_extraction_results_latest.md new file mode 100644 index 00000000..2de6eddf --- /dev/null +++ b/docs/research/character_level_extraction_results_latest.md @@ -0,0 +1,33 @@ +# Extraction Results Manifest + +- status: pass +- scope: extraction-results +- generated_at: 2026-07-02T09:25:00.613875+00:00 +- total_files: 66 +- unhashed_files: 0 +- stored_text_payload_fields: 0 +- Heavy OCR: disabled + +## Result Counts + +- `extraction_failed`: 1 +- `ocr_blocked_missing_engine`: 53 +- `text_extracted`: 12 + +## Method Counts + +- `docx`: 11 +- `pdfplumber`: 2 +- `pytesseract`: 53 + +## Post-Extraction Classification Counts + +- `extracted_candidate_for_review`: 10 +- `extracted_private_reference_only`: 3 +- `extracted_reference_only`: 53 + +## Boundary + +Extraction results store text hashes and counts only. Extracted private text is not copied into the repo truth chain. + +No extracted text or OCR text is stored in this report; only hashes, counts, methods, and statuses are persisted. diff --git a/docs/research/character_level_inventory_manifest_latest.json b/docs/research/character_level_inventory_manifest_latest.json index 7cbe78ca..3c73b161 100644 --- a/docs/research/character_level_inventory_manifest_latest.json +++ b/docs/research/character_level_inventory_manifest_latest.json @@ -1,7 +1,7 @@ { "scope": "project", "status": "pass", - "generated_at": "2026-07-02T09:11:51.839696+00:00", + "generated_at": "2026-07-02T09:23:01.280161+00:00", "mode": { "heavy_ocr": false, "whole_machine_scan": false, @@ -17,7 +17,7 @@ "AGENTS.md" ], "summary": { - "total_files": 1073, + "total_files": 1075, "unhashed_files": 0, "unclassified_files": 0, "unknown_extraction_status": 0, @@ -28,12 +28,12 @@ "quarantined_draft": 93, "real_case_calibration": 5, "reference_candidate": 180, - "research_governance": 443 + "research_governance": 445 }, "extraction_status_counts": { "binary_indexed": 34, "image_ocr_queued": 3, - "text_indexed": 1036 + "text_indexed": 1038 } }, "root_summary": { @@ -46,8 +46,8 @@ "bytes": 43187 }, "docs/research": { - "files": 536, - "bytes": 2901473 + "files": 538, + "bytes": 2955810 }, "references": { "files": 236, @@ -5173,7 +5173,7 @@ "path": "docs/research/character_level_external_manifest_latest.json", "suffix": ".json", "byte_count": 666472, - "sha256": "244465beREDACTED_TIMEe81a2c8b3abac4f41e28bd55ce9f42f3f203d6574c52617dcfd9", + "sha256": "eb5243158ce7a2fbfbdedddf4cdaea2fb5ad867042b6492f5ed5449a65abb6ca", "extraction_status": "text_indexed", "character_count": 661666, "line_count": 12446, @@ -5187,7 +5187,7 @@ "path": "docs/research/character_level_external_manifest_latest.md", "suffix": ".md", "byte_count": 1280, - "sha256": "71cc5b027ea056c23ce1d5d1cda8921eeade065a8cb003910ea44d2a1165e642", + "sha256": "3a371858f58ddf1f040e161bb63fd764ae079a1a46d931baab9fbb4478ca64a3", "extraction_status": "text_indexed", "character_count": 1272, "line_count": 47, @@ -5201,7 +5201,7 @@ "path": "docs/research/character_level_extraction_queue_latest.json", "suffix": ".json", "byte_count": 31649, - "sha256": "cbfc03eee31d16cc3c796728cf34504c6eaa0722c5e42dd2f7d2ec1da966c5ef", + "sha256": "41fd28ba9ef0df29fbeb017830e2e81fbe7d86e6e2e53090c0d873cbab51d823", "extraction_status": "text_indexed", "character_count": 30151, "line_count": 758, @@ -5215,7 +5215,7 @@ "path": "docs/research/character_level_extraction_queue_latest.md", "suffix": ".md", "byte_count": 633, - "sha256": "6a45bb22f9f44d248c6e8ff71d74949180eb3eba537cb42080d15fef88395725", + "sha256": "21c0bf36f66edda5f1a7b941ea12c508d0851ebf79a24cd882332e71d73ae750", "extraction_status": "text_indexed", "character_count": 633, "line_count": 27, @@ -5225,11 +5225,39 @@ "promotion_status": "governance_or_history", "reason": "Research history or governance record; index separately from rule truth." }, + "docs/research/character_level_extraction_results_latest.json": { + "path": "docs/research/character_level_extraction_results_latest.json", + "suffix": ".json", + "byte_count": 53548, + "sha256": "bda3e585b7cb3e9ca0147b97e7186d56a8adf64ed4c46cc78d7a0d4b2b0f4acb", + "extraction_status": "text_indexed", + "character_count": 52050, + "line_count": 1227, + "decode_replacement_count": 0, + "classification": "research_governance", + "priority": "priority_3", + "promotion_status": "governance_or_history", + "reason": "Research history or governance record; index separately from rule truth." + }, + "docs/research/character_level_extraction_results_latest.md": { + "path": "docs/research/character_level_extraction_results_latest.md", + "suffix": ".md", + "byte_count": 789, + "sha256": "d0169690fb8b8d5f4438d1628b93b5cf86f76f2af97987eb3a4649370093d1c4", + "extraction_status": "text_indexed", + "character_count": 789, + "line_count": 34, + "decode_replacement_count": 0, + "classification": "research_governance", + "priority": "priority_3", + "promotion_status": "governance_or_history", + "reason": "Research history or governance record; index separately from rule truth." + }, "docs/research/character_level_inventory_manifest_latest.json": { "path": "docs/research/character_level_inventory_manifest_latest.json", "suffix": ".json", "byte_count": 721667, - "sha256": "aba3169d10fe86f02dfed264b150afb84473994225b2a62a36b720f485ad1a41", + "sha256": "de2aac78f33cb27575bac5e9f6f0a04e1655b8655b851fff397a8641ebc96c71", "extraction_status": "text_indexed", "character_count": 721117, "line_count": 15090, @@ -5243,7 +5271,7 @@ "path": "docs/research/character_level_inventory_manifest_latest.md", "suffix": ".md", "byte_count": 1090, - "sha256": "d088bb6312805a0f78506af37c2d32098e97af635eb3eed707a4943b75dae2ae", + "sha256": "e63d29e5ef20dab395ea86d4dddc4e41edab6e8e3019caef4b3fd31197e46a72", "extraction_status": "text_indexed", "character_count": 1090, "line_count": 44, diff --git a/docs/research/character_level_inventory_manifest_latest.md b/docs/research/character_level_inventory_manifest_latest.md index c58e9f69..f417ee63 100644 --- a/docs/research/character_level_inventory_manifest_latest.md +++ b/docs/research/character_level_inventory_manifest_latest.md @@ -2,8 +2,8 @@ - status: pass - scope: project -- generated_at: 2026-07-02T09:11:51.839696+00:00 -- total_files: 1073 +- generated_at: 2026-07-02T09:23:01.280161+00:00 +- total_files: 1075 - unhashed_files: 0 - unclassified_files: 0 - unknown_extraction_status: 0 @@ -16,7 +16,7 @@ | --- | ---: | ---: | | `AGENTS.md` | 1 | 3932 | | `SKILL.md` | 1 | 43187 | -| `docs/research` | 536 | 2901473 | +| `docs/research` | 538 | 2955810 | | `references` | 236 | 4008411 | | `references/open_source_sources` | 299 | 9365015 | @@ -24,7 +24,7 @@ - `binary_indexed`: 34 - `image_ocr_queued`: 3 -- `text_indexed`: 1036 +- `text_indexed`: 1038 ## Classification Counts @@ -34,7 +34,7 @@ - `quarantined_draft`: 93 - `real_case_calibration`: 5 - `reference_candidate`: 180 -- `research_governance`: 443 +- `research_governance`: 445 ## Boundary diff --git a/progress.md b/progress.md index 2bf48388..e97e0248 100644 --- a/progress.md +++ b/progress.md @@ -820,3 +820,12 @@ - 新增 `docs/research/character_level_extraction_queue_latest.json` 与 `.md`,当前 queued_files=`66`、`unhashed_files=0`。 - 队列构成:`image_ocr_queued=53`、`document_text_extraction_queued=11`、`pdf_text_extraction_queued=2`;来源为 `external=63`、`project=3`。 - 边界:本轮只做提取队列,不跑重 OCR,不把外部私人资料正文写进仓库,也不升格为 runtime truth。 + +## 2026-07-02T17:22:00+08:00 - PDF/DOCX 提取结果与 OCR blocked 分级 + +- 新增 `scripts/character_level_inventory_manifest.py --scope extraction-results`,对 extraction queue 做实际提取,但只保存文本 hash、字符数、行数、方法、状态和分级,不保存正文。 +- 新增 `docs/research/character_level_extraction_results_latest.json` 与 `.md`,当前 total_files=`66`、`unhashed_files=0`、`stored_text_payload_fields=0`。 +- 提取结果:`text_extracted=12`、`ocr_blocked_missing_engine=53`、`extraction_failed=1`。 +- 方法分布:`docx=11`、`pdfplumber=2`、`pytesseract=53`;系统当前没有 `tesseract` 可执行文件,因此图片 OCR 全部明确 blocked。 +- 失败项:`/Users/wuyongnaren/文件仓库/印度占星文章/4印度占星.docx`,`python-docx` 返回 `KeyError: "There is no item named 'NULL' in the archive"`;保留为 extraction_failed,不伪装为已提取。 +- 提取后分级:`extracted_candidate_for_review=10`、`extracted_private_reference_only=3`、`extracted_reference_only=53`;仍未进入 runtime truth chain。 diff --git a/scripts/character_level_inventory_manifest.py b/scripts/character_level_inventory_manifest.py index b3912da7..331728f6 100644 --- a/scripts/character_level_inventory_manifest.py +++ b/scripts/character_level_inventory_manifest.py @@ -11,6 +11,7 @@ from __future__ import annotations import argparse import hashlib import json +import shutil import sys from datetime import datetime, timezone from pathlib import Path @@ -24,6 +25,8 @@ EXTERNAL_REPORT_JSON = ROOT / "docs" / "research" / "character_level_external_ma EXTERNAL_REPORT_MD = ROOT / "docs" / "research" / "character_level_external_manifest_latest.md" EXTRACTION_QUEUE_JSON = ROOT / "docs" / "research" / "character_level_extraction_queue_latest.json" EXTRACTION_QUEUE_MD = ROOT / "docs" / "research" / "character_level_extraction_queue_latest.md" +EXTRACTION_RESULTS_JSON = ROOT / "docs" / "research" / "character_level_extraction_results_latest.json" +EXTRACTION_RESULTS_MD = ROOT / "docs" / "research" / "character_level_extraction_results_latest.md" PROJECT_SCAN_ROOTS = [ "references", @@ -425,6 +428,8 @@ def build_manifest(*, scope: str = "project", write: bool = True) -> dict[str, A } elif scope == "extraction-queue": return build_extraction_queue(write=write) + elif scope == "extraction-results": + return build_extraction_results(write=write) else: raise ValueError(f"Unsupported scope: {scope}") @@ -461,6 +466,162 @@ def build_manifest(*, scope: str = "project", write: bool = True) -> dict[str, A return report +def _hash_text(text: str) -> str: + return hashlib.sha256(text.encode("utf-8", errors="replace")).hexdigest() + + +def _extract_docx_text(path: Path) -> tuple[str, str | None]: + try: + from docx import Document + + document = Document(str(path)) + paragraphs = [paragraph.text for paragraph in document.paragraphs] + table_text: list[str] = [] + for table in document.tables: + for row in table.rows: + table_text.append("\t".join(cell.text for cell in row.cells)) + return "\n".join(paragraphs + table_text), None + except Exception as exc: # pragma: no cover - exercised by real files. + return "", f"{type(exc).__name__}: {exc}" + + +def _extract_pdf_text(path: Path) -> tuple[str, str, str | None]: + try: + import pdfplumber + + parts: list[str] = [] + with pdfplumber.open(str(path)) as pdf: + for page in pdf.pages: + parts.append(page.extract_text() or "") + text = "\n".join(parts) + if text.strip(): + return text, "pdfplumber", None + except Exception as exc: + pdfplumber_error = f"{type(exc).__name__}: {exc}" + else: + pdfplumber_error = None + try: + from pypdf import PdfReader + + reader = PdfReader(str(path)) + text = "\n".join(page.extract_text() or "" for page in reader.pages) + return text, "pypdf", None + except Exception as exc: # pragma: no cover - depends on local PDF shape. + errors = "; ".join(error for error in [pdfplumber_error, f"{type(exc).__name__}: {exc}"] if error) + return "", "pypdf", errors + + +def _extract_image_text(path: Path) -> tuple[str, str, str | None]: + if not shutil.which("tesseract"): + return "", "pytesseract", "tesseract executable not found" + try: + from PIL import Image + import pytesseract + + with Image.open(path) as image: + return pytesseract.image_to_string(image, lang="chi_sim+eng"), "pytesseract", None + except Exception as exc: # pragma: no cover - depends on local OCR install/languages. + return "", "pytesseract", f"{type(exc).__name__}: {exc}" + + +def _post_extraction_classification(item: dict[str, Any]) -> str: + path = str(item["path"]) + if "/Desktop/" in path or "/WorkBuddy/" in path: + return "extracted_private_reference_only" + if item["classification"] in {"external_book_or_document", "reference_candidate"}: + return "extracted_candidate_for_review" + return "extracted_reference_only" + + +def _extract_queued_item(item: dict[str, Any]) -> dict[str, Any]: + path = Path(item["path"]) + status = item["extraction_status"] + if status == "document_text_extraction_queued" and path.suffix.lower() == ".docx": + text, error = _extract_docx_text(path) + method = "docx" + elif status == "pdf_text_extraction_queued": + text, method, error = _extract_pdf_text(path) + elif status == "image_ocr_queued": + text, method, error = _extract_image_text(path) + if error and "tesseract executable not found" in error: + return { + **item, + "extraction_result": "ocr_blocked_missing_engine", + "extraction_method": method, + "blocked_reason": error, + "extracted_character_count": 0, + "extracted_line_count": 0, + "text_sha256": None, + "post_extraction_classification": "extracted_reference_only", + } + else: + text = "" + method = "unsupported" + error = "unsupported extraction target" + + normalized = text or "" + if error and not normalized.strip(): + result = "extraction_failed" + elif normalized.strip(): + result = "text_extracted" + else: + result = "text_empty" + return { + **item, + "extraction_result": result, + "extraction_method": method, + "blocked_reason": error, + "extracted_character_count": len(normalized), + "extracted_line_count": normalized.count("\n") + (1 if normalized else 0), + "text_sha256": _hash_text(normalized) if normalized else None, + "post_extraction_classification": _post_extraction_classification(item), + } + + +def build_extraction_results(*, write: bool = True) -> dict[str, Any]: + queue_report = build_extraction_queue(write=False) + results = [_extract_queued_item(item) for item in queue_report["queue"]] + result_counts: dict[str, int] = {} + method_counts: dict[str, int] = {} + classification_counts: dict[str, int] = {} + for item in results: + result_counts[item["extraction_result"]] = result_counts.get(item["extraction_result"], 0) + 1 + method_counts[item["extraction_method"]] = method_counts.get(item["extraction_method"], 0) + 1 + classification_counts[item["post_extraction_classification"]] = ( + classification_counts.get(item["post_extraction_classification"], 0) + 1 + ) + stored_text_payload_fields = sum(1 for item in results if "text" in item or "text_preview" in item) + report = { + "scope": "extraction-results", + "status": "pass", + "generated_at": datetime.now(timezone.utc).isoformat(), + "mode": { + "heavy_ocr": shutil.which("tesseract") is not None, + "whole_machine_scan": False, + "external_high_relevance_scan": True, + "semantic_promotion": False, + "boundary": "Extraction results store text hashes and counts only. Extracted private text is not copied into the repo truth chain.", + }, + "summary": { + "total_files": len(results), + "unhashed_files": sum(1 for item in results if not item.get("sha256")), + "stored_text_payload_fields": stored_text_payload_fields, + }, + "result_counts": dict(sorted(result_counts.items())), + "method_counts": dict(sorted(method_counts.items())), + "post_extraction_classification_counts": dict(sorted(classification_counts.items())), + "results": results, + "artifacts": { + "json_report": _relative(EXTRACTION_RESULTS_JSON), + "markdown_report": _relative(EXTRACTION_RESULTS_MD), + }, + "title": "Extraction Results Manifest", + } + if write: + _write_reports(report, json_report=EXTRACTION_RESULTS_JSON, markdown_report=EXTRACTION_RESULTS_MD) + return report + + def build_extraction_queue(*, write: bool = True) -> dict[str, Any]: project = build_manifest(scope="project", write=False) external = build_manifest(scope="external", write=False) @@ -527,6 +688,8 @@ def _render_markdown(report: dict[str, Any]) -> str: summary = report["summary"] if report["scope"] == "extraction-queue": return _render_extraction_queue_markdown(report) + if report["scope"] == "extraction-results": + return _render_extraction_results_markdown(report) lines = [ f"# {report.get('title', 'Character-Level Inventory Manifest')}", "", @@ -567,6 +730,43 @@ def _render_markdown(report: dict[str, Any]) -> str: return "\n".join(lines) +def _render_extraction_results_markdown(report: dict[str, Any]) -> str: + lines = [ + f"# {report.get('title', 'Extraction Results Manifest')}", + "", + f"- status: {report['status']}", + f"- scope: {report['scope']}", + f"- generated_at: {report['generated_at']}", + f"- total_files: {report['summary']['total_files']}", + f"- unhashed_files: {report['summary']['unhashed_files']}", + f"- stored_text_payload_fields: {report['summary']['stored_text_payload_fields']}", + f"- Heavy OCR: {'enabled' if report['mode']['heavy_ocr'] else 'disabled'}", + "", + "## Result Counts", + "", + ] + for name, count in report["result_counts"].items(): + lines.append(f"- `{name}`: {count}") + lines.extend(["", "## Method Counts", ""]) + for name, count in report["method_counts"].items(): + lines.append(f"- `{name}`: {count}") + lines.extend(["", "## Post-Extraction Classification Counts", ""]) + for name, count in report["post_extraction_classification_counts"].items(): + lines.append(f"- `{name}`: {count}") + lines.extend( + [ + "", + "## Boundary", + "", + report["mode"]["boundary"], + "", + "No extracted text or OCR text is stored in this report; only hashes, counts, methods, and statuses are persisted.", + "", + ] + ) + return "\n".join(lines) + + def _render_extraction_queue_markdown(report: dict[str, Any]) -> str: lines = [ f"# {report.get('title', 'Extraction Queue Manifest')}", @@ -611,7 +811,11 @@ def _summary_view(report: dict[str, Any]) -> dict[str, Any]: def main(argv: list[str] | None = None) -> int: parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument("--scope", default="project", choices=["project", "external", "extraction-queue"]) + parser.add_argument( + "--scope", + default="project", + choices=["project", "external", "extraction-queue", "extraction-results"], + ) parser.add_argument("--no-write", action="store_true", help="Print the manifest without writing report artifacts.") parser.add_argument("--summary-only", action="store_true", help="Print only summary fields; still writes full artifacts unless --no-write is set.") args = parser.parse_args(argv) diff --git a/tests/test_character_level_inventory_manifest.py b/tests/test_character_level_inventory_manifest.py index 6732f61f..62e64877 100644 --- a/tests/test_character_level_inventory_manifest.py +++ b/tests/test_character_level_inventory_manifest.py @@ -176,3 +176,42 @@ def test_extraction_queue_report_combines_project_and_external_binary_work() -> assert json_path.exists() assert md_path.exists() assert "Extraction Queue Manifest" in md_path.read_text(encoding="utf-8") + + +def test_extraction_results_extract_pdf_and_docx_without_storing_text() -> None: + report = _run_manifest("--scope", "extraction-results") + + assert report["scope"] == "extraction-results" + assert report["status"] == "pass" + assert report["summary"]["total_files"] >= 60 + assert report["summary"]["unhashed_files"] == 0 + assert report["summary"]["stored_text_payload_fields"] == 0 + assert report["result_counts"]["text_extracted"] >= 10 + assert report["method_counts"]["docx"] >= 10 + assert report["method_counts"]["pdfplumber"] + report["method_counts"].get("pypdf", 0) >= 2 + + for item in report["results"]: + assert item["sha256"] + assert item["source_scope"] in {"project", "external"} + assert item["extraction_result"] in { + "text_extracted", + "text_empty", + "ocr_blocked_missing_engine", + "extraction_failed", + } + assert "text" not in item + assert "text_preview" not in item + if item["extraction_result"] == "text_extracted": + assert item["extracted_character_count"] > 0 + assert item["text_sha256"] + assert item["post_extraction_classification"] in { + "extracted_reference_only", + "extracted_private_reference_only", + "extracted_candidate_for_review", + } + + json_path = ROOT / report["artifacts"]["json_report"] + md_path = ROOT / report["artifacts"]["markdown_report"] + assert json_path.exists() + assert md_path.exists() + assert "Extraction Results Manifest" in md_path.read_text(encoding="utf-8")