Pointf5ive commited on
Commit
74365bc
·
1 Parent(s): d149161

fix: support DOCX manuscript uploads in dashboard and codex extractor

Browse files
Files changed (2) hide show
  1. app.py +5 -5
  2. src/codex_extractor.py +24 -4
app.py CHANGED
@@ -2597,7 +2597,7 @@ def run_codex_extraction(
2597
  """
2598
  if file_obj is None:
2599
  return (
2600
- "No file uploaded. Please upload a .txt or .pdf file.",
2601
  "",
2602
  "ERROR: No file uploaded.",
2603
  )
@@ -2814,7 +2814,7 @@ def analyze_manuscript_for_dashboard(file_obj, active_path: str):
2814
  """
2815
  file_path = _extract_uploaded_path(file_obj)
2816
  if not file_path:
2817
- raise gr.Error("Upload a manuscript (.txt or .pdf) first.")
2818
 
2819
  stem = Path(file_path).stem.strip() or "Unknown Author"
2820
  author_name = stem.replace("_", " ")[:120]
@@ -2922,8 +2922,8 @@ with gr.Blocks(title="TOTEM Studio") as demo:
2922
  "Upload manuscript here to run extraction and refresh workbook scoring context."
2923
  )
2924
  dashboard_manuscript_file = gr.File(
2925
- label="Manuscript (.txt or .pdf)",
2926
- file_types=[".txt", ".pdf"],
2927
  type="filepath",
2928
  )
2929
  dashboard_manuscript_analyze = gr.Button(
@@ -3015,7 +3015,7 @@ with gr.Blocks(title="TOTEM Studio") as demo:
3015
  )
3016
  codex_file = gr.File(
3017
  label="Upload Text or PDF",
3018
- file_types=[".txt", ".pdf"],
3019
  type="filepath",
3020
  )
3021
  with gr.Row():
 
2597
  """
2598
  if file_obj is None:
2599
  return (
2600
+ "No file uploaded. Please upload a .txt, .docx, or .pdf file.",
2601
  "",
2602
  "ERROR: No file uploaded.",
2603
  )
 
2814
  """
2815
  file_path = _extract_uploaded_path(file_obj)
2816
  if not file_path:
2817
+ raise gr.Error("Upload a manuscript (.txt, .docx, or .pdf) first.")
2818
 
2819
  stem = Path(file_path).stem.strip() or "Unknown Author"
2820
  author_name = stem.replace("_", " ")[:120]
 
2922
  "Upload manuscript here to run extraction and refresh workbook scoring context."
2923
  )
2924
  dashboard_manuscript_file = gr.File(
2925
+ label="Manuscript (.txt, .docx, or .pdf)",
2926
+ file_types=[".txt", ".docx", ".pdf"],
2927
  type="filepath",
2928
  )
2929
  dashboard_manuscript_analyze = gr.Button(
 
3015
  )
3016
  codex_file = gr.File(
3017
  label="Upload Text or PDF",
3018
+ file_types=[".txt", ".docx", ".pdf"],
3019
  type="filepath",
3020
  )
3021
  with gr.Row():
src/codex_extractor.py CHANGED
@@ -87,6 +87,7 @@ import math
87
  import os
88
  import re
89
  import string
 
90
  from collections import Counter
91
  from pathlib import Path
92
  from shutil import which
@@ -473,14 +474,33 @@ def extract_text_from_file(
473
  end_page: int | None = None,
474
  ) -> tuple[str, str, list[dict]]:
475
  """
476
- Extract text from PDF or plain text file.
477
 
478
  Returns (story_text, raw_text, page_trace).
479
  For plain text files page_trace contains a single synthetic entry.
480
  """
481
  path = Path(file_path)
482
- if path.suffix.lower() == ".pdf":
 
483
  return extract_text_from_pdf(path, start_page=start_page, end_page=end_page)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
484
  else:
485
  content = path.read_text(encoding="utf-8", errors="replace")
486
  wc = _word_count(content)
@@ -1805,7 +1825,7 @@ def process_upload(
1805
  Entry point for Gradio interface.
1806
 
1807
  Args:
1808
- file_path: Path to uploaded PDF or text file.
1809
  author_name: Author's full name.
1810
  author_id: Codex author ID.
1811
  works_sampled: Title of the uploaded work (user-supplied only;
@@ -1913,4 +1933,4 @@ if __name__ == "__main__":
1913
  debug_output_dir="/tmp/codex_debug",
1914
  )
1915
  print(format_fingerprint_report(fp))
1916
- print("\nDebug artefacts written to:", fp.get("Debug_Artefacts", {}))
 
87
  import os
88
  import re
89
  import string
90
+ import zipfile
91
  from collections import Counter
92
  from pathlib import Path
93
  from shutil import which
 
474
  end_page: int | None = None,
475
  ) -> tuple[str, str, list[dict]]:
476
  """
477
+ Extract text from PDF, DOCX, or plain text file.
478
 
479
  Returns (story_text, raw_text, page_trace).
480
  For plain text files page_trace contains a single synthetic entry.
481
  """
482
  path = Path(file_path)
483
+ suffix = path.suffix.lower()
484
+ if suffix == ".pdf":
485
  return extract_text_from_pdf(path, start_page=start_page, end_page=end_page)
486
+ if suffix == ".docx":
487
+ with zipfile.ZipFile(path) as zf:
488
+ xml = zf.read("word/document.xml").decode("utf-8", errors="replace")
489
+ xml = re.sub(r"<w:tab\\s*/>", "\t", xml)
490
+ xml = re.sub(r"</w:p>", "\n", xml)
491
+ content = re.sub(r"<[^>]+>", "", xml)
492
+ content = content.replace("&amp;", "&").replace("&lt;", "<").replace("&gt;", ">")
493
+ content = re.sub(r"\n{3,}", "\n\n", content).strip()
494
+ wc = _word_count(content)
495
+ page_trace = [{
496
+ "page_number": 1,
497
+ "raw_word_count": wc,
498
+ "cleaned_word_count": wc,
499
+ "classification": "story",
500
+ "included": True,
501
+ "skip_reason": "",
502
+ }]
503
+ return content, content, page_trace
504
  else:
505
  content = path.read_text(encoding="utf-8", errors="replace")
506
  wc = _word_count(content)
 
1825
  Entry point for Gradio interface.
1826
 
1827
  Args:
1828
+ file_path: Path to uploaded PDF, DOCX, or text file.
1829
  author_name: Author's full name.
1830
  author_id: Codex author ID.
1831
  works_sampled: Title of the uploaded work (user-supplied only;
 
1933
  debug_output_dir="/tmp/codex_debug",
1934
  )
1935
  print(format_fingerprint_report(fp))
1936
+ print("\nDebug artefacts written to:", fp.get("Debug_Artefacts", {}))