Rishit Pant commited on
Commit
f19b66b
·
1 Parent(s): a28f6db

Add noise pattern (#2)

Browse files

* Update dependencies

* Update requirements

* ChromaDB initialised

* Lock dependencies

* Ingest and store in chromaDB

* Update db

* Update noise patterns

* Removed db

Files changed (2) hide show
  1. .gitignore +1 -0
  2. src/ingest.py +38 -13
.gitignore CHANGED
@@ -10,3 +10,4 @@ wheels/
10
  .venv
11
 
12
  .env
 
 
10
  .venv
11
 
12
  .env
13
+ db
src/ingest.py CHANGED
@@ -47,20 +47,46 @@ def html_tables_to_markdown(text: str) -> str:
47
 
48
 
49
  def clean_markdown(raw_text: str) -> str:
50
- """Strip Google Docs scrape noise and normalize whitespace."""
51
  noise_patterns = [
52
  r'\d{1,2}/\d{1,2}/\d{2,4},\s+\d{1,2}:\d{2}\s+[AP]M[^\n]*',
53
- r'Google Docs(?: icon| logo)? Published using Google Docs[^\n]*',
54
- r'Report abuse\s+Learn more[^\n]*',
55
- r'Updated automatically every \d+ minutes[^\n]*',
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
56
  r'https://docs\.google\.com/\S+',
 
 
 
57
  ]
58
  text = raw_text
59
  for pattern in noise_patterns:
60
  text = re.sub(pattern, '', text, flags=re.IGNORECASE)
61
 
62
  text = html_tables_to_markdown(text)
63
- text = re.sub(r'\n{3,}', '\n\n', text).strip()
 
 
64
  return text
65
 
66
 
@@ -70,8 +96,8 @@ def load_and_split(md_path: Path) -> list[Document]:
70
 
71
  header_splitter = MarkdownHeaderTextSplitter(
72
  headers_to_split_on=HEADERS_TO_SPLIT,
73
- strip_headers=False,
74
- return_each_line=False
75
  )
76
  header_docs = header_splitter.split_text(cleaned)
77
 
@@ -80,13 +106,12 @@ def load_and_split(md_path: Path) -> list[Document]:
80
  chunk_overlap=CHUNK_OVERLAP,
81
  separators=["\n\n", "\n", " ", ""],
82
  )
83
-
84
  final_docs = char_splitter.split_documents(header_docs)
85
-
86
  for doc in final_docs:
87
  doc.metadata["source"] = md_path.name
88
-
89
- print(f"{md_path.name}: {len(final_docs)} chunks")
90
  return final_docs
91
 
92
 
@@ -98,7 +123,7 @@ def build_index():
98
  )
99
 
100
  all_docs: list[Document] = []
101
- for md_path in sorted(DATA_DIR.glob("*md")):
102
  print(f"\nProcessing: {md_path.name}")
103
  all_docs.extend(load_and_split(md_path))
104
 
@@ -112,7 +137,7 @@ def build_index():
112
  documents=all_docs,
113
  embedding=embeddings,
114
  persist_directory=DB_DIR,
115
- collection_name=COLLECTION_NAME
116
  )
117
 
118
  print(f"\n✅ Ingestion complete! {vectorstore._collection.count()} chunks stored.")
 
47
 
48
 
49
  def clean_markdown(raw_text: str) -> str:
 
50
  noise_patterns = [
51
  r'\d{1,2}/\d{1,2}/\d{2,4},\s+\d{1,2}:\d{2}\s+[AP]M[^\n]*',
52
+
53
+ # Full footer form: "Google Docs Published using Google Docs"
54
+ r'Google Docs(?:\s+icon|\s+logo)?\s+Published using Google Docs[^\n]*',
55
+
56
+ # Fragment form that appears mid-chunk after splitting:
57
+ # " 10/66 info icon Published using Google Docs IITM BS Degree ..."
58
+ r'\d+/\d+\s+info\s+icon\s+Published\s+using\s+Google\s+Docs[^\n]*',
59
+
60
+ # Standalone "Published using Google Docs" anywhere
61
+ r'Published\s+using\s+Google\s+Docs[^\n]*',
62
+
63
+ # "info icon" artifact on its own or leading a sentence
64
+ r'\binfo\s+icon\b[^\n]*',
65
+
66
+ # Document title trailers: "IITM BS Degree Programme - Student Handb..."
67
+ # These appear as orphaned suffixes after the noise strip above
68
+ r'IITM\s+BS\s+Degree\s+Programme\s*[-–]\s*Student\s+Hand\w*[^\n]*',
69
+
70
+ # Report abuse / learn more footer
71
+ r'Report\s+abuse\s+Learn\s+more[^\n]*',
72
+
73
+ # Auto-update notice
74
+ r'Updated\s+automatically\s+every\s+\d+\s+minutes[^\n]*',
75
+
76
+ # Google Docs URLs
77
  r'https://docs\.google\.com/\S+',
78
+
79
+ # Bare page-number artifacts: " 38/66 " or "10/66" on their own
80
+ r'(?<!\d)\d{1,3}/\d{2,3}(?!\d)(?=\s|$)',
81
  ]
82
  text = raw_text
83
  for pattern in noise_patterns:
84
  text = re.sub(pattern, '', text, flags=re.IGNORECASE)
85
 
86
  text = html_tables_to_markdown(text)
87
+ # Collapse runs of whitespace left behind by removals
88
+ text = re.sub(r'[ \t]{2,}', ' ', text) # multiple spaces → single
89
+ text = re.sub(r'\n{3,}', '\n\n', text).strip() # blank line runs → one
90
  return text
91
 
92
 
 
96
 
97
  header_splitter = MarkdownHeaderTextSplitter(
98
  headers_to_split_on=HEADERS_TO_SPLIT,
99
+ strip_headers=False,
100
+ return_each_line=False,
101
  )
102
  header_docs = header_splitter.split_text(cleaned)
103
 
 
106
  chunk_overlap=CHUNK_OVERLAP,
107
  separators=["\n\n", "\n", " ", ""],
108
  )
 
109
  final_docs = char_splitter.split_documents(header_docs)
110
+
111
  for doc in final_docs:
112
  doc.metadata["source"] = md_path.name
113
+
114
+ print(f" {md_path.name}: {len(final_docs)} chunks")
115
  return final_docs
116
 
117
 
 
123
  )
124
 
125
  all_docs: list[Document] = []
126
+ for md_path in sorted(DATA_DIR.glob("*.md")):
127
  print(f"\nProcessing: {md_path.name}")
128
  all_docs.extend(load_and_split(md_path))
129
 
 
137
  documents=all_docs,
138
  embedding=embeddings,
139
  persist_directory=DB_DIR,
140
+ collection_name=COLLECTION_NAME,
141
  )
142
 
143
  print(f"\n✅ Ingestion complete! {vectorstore._collection.count()} chunks stored.")