Spaces:
Running
Running
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
- .gitignore +1 -0
- 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 |
-
|
| 54 |
-
|
| 55 |
-
r'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
-
|
|
|
|
|
|
|
| 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.")
|