Coding-With-Bashir commited on
Commit
0ed341a
·
verified ·
1 Parent(s): e111a5f

Upload .\src\data_collection\wikimedia_collector.py with huggingface_hub

Browse files
.//src//data_collection//wikimedia_collector.py ADDED
@@ -0,0 +1,257 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Wikimedia projects collector for Wikisource and Wiktionary."""
2
+
3
+ import json
4
+ import logging
5
+ import time
6
+ from pathlib import Path
7
+ from typing import Any
8
+
9
+ import requests
10
+ from bs4 import BeautifulSoup
11
+
12
+ logger = logging.getLogger(__name__)
13
+
14
+
15
+ class WikisourceCollector:
16
+ """Collects texts from Kinyarwanda Wikisource."""
17
+
18
+ def __init__(self, output_dir: str, config: dict[str, Any]):
19
+ self.output_dir = Path(output_dir)
20
+ self.output_dir.mkdir(parents=True, exist_ok=True)
21
+ self.config = config
22
+ self.session = requests.Session()
23
+ self.session.headers.update({
24
+ "User-Agent": "BwengeAi/0.1 (Kinyarwanda AI Research)"
25
+ })
26
+
27
+ ws_config = config.get("wikisource", {})
28
+ self.api_url = ws_config.get("api_url", "https://rw.wikisource.org/w/api.php")
29
+ self.base_url = ws_config.get("base_url", "https://rw.wikisource.org")
30
+
31
+ def fetch_page_list(self, namespace: int = 0, limit: int = 500) -> list[str]:
32
+ """Fetch list of page titles."""
33
+ pages = []
34
+ params = {
35
+ "action": "query",
36
+ "list": "allpages",
37
+ "apnamespace": namespace,
38
+ "aplimit": str(min(limit, 500)),
39
+ "format": "json",
40
+ }
41
+
42
+ while True:
43
+ try:
44
+ time.sleep(0.5)
45
+ response = self.session.get(self.api_url, params=params, timeout=30)
46
+ response.raise_for_status()
47
+ data = response.json()
48
+
49
+ allpages = data.get("query", {}).get("allpages", [])
50
+ pages.extend(p["title"] for p in allpages)
51
+
52
+ if "continue" in data and len(pages) < limit:
53
+ params["apcontinue"] = data["continue"]["apcontinue"]
54
+ else:
55
+ break
56
+
57
+ except Exception as e:
58
+ logger.error(f"Failed to fetch page list: {e}")
59
+ break
60
+
61
+ return pages[:limit]
62
+
63
+ def fetch_page_content(self, title: str) -> dict[str, Any] | None:
64
+ """Fetch content for a single page."""
65
+ params = {
66
+ "action": "parse",
67
+ "page": title,
68
+ "prop": "text",
69
+ "format": "json",
70
+ }
71
+
72
+ try:
73
+ time.sleep(0.5)
74
+ response = self.session.get(self.api_url, params=params, timeout=30)
75
+ response.raise_for_status()
76
+ data = response.json()
77
+
78
+ parse = data.get("parse", {})
79
+ html = parse.get("text", {}).get("*", "")
80
+
81
+ text = self._clean_html(html)
82
+
83
+ if text and len(text) > 100:
84
+ return {
85
+ "title": title,
86
+ "text": text,
87
+ "source": "wikisource",
88
+ "length": len(text),
89
+ }
90
+
91
+ except Exception as e:
92
+ logger.warning(f"Failed to fetch page '{title}': {e}")
93
+
94
+ return None
95
+
96
+ def _clean_html(self, html: str) -> str:
97
+ """Clean HTML to plain text."""
98
+ soup = BeautifulSoup(html, "lxml")
99
+
100
+ for tag in soup(["script", "style", "sup", "sub", "table"]):
101
+ tag.decompose()
102
+
103
+ text = soup.get_text(separator=" ", strip=True)
104
+
105
+ lines = text.split()
106
+ clean_lines = [line.strip() for line in lines if line.strip() and len(line) > 2]
107
+ return " ".join(clean_lines)
108
+
109
+ def collect_all(self) -> list[dict[str, Any]]:
110
+ """Collect all texts from Kinyarwanda Wikisource."""
111
+ logger.info("Starting Kinyarwanda Wikisource collection...")
112
+
113
+ pages = self.fetch_page_list(namespace=0, limit=500)
114
+ logger.info(f"Found {len(pages)} pages")
115
+
116
+ results = []
117
+ for title in pages:
118
+ content = self.fetch_page_content(title)
119
+ if content:
120
+ results.append(content)
121
+
122
+ output_path = self.output_dir / "wikisource_articles.jsonl"
123
+ with open(output_path, "w", encoding="utf-8") as f:
124
+ for article in results:
125
+ f.write(json.dumps(article, ensure_ascii=False) + "\n")
126
+
127
+ summary = {
128
+ "source": "wikisource",
129
+ "total_pages": len(pages),
130
+ "collected": len(results),
131
+ "output_path": str(output_path),
132
+ "total_characters": sum(r["length"] for r in results),
133
+ }
134
+
135
+ summary_path = self.output_dir / "wikisource_summary.json"
136
+ with open(summary_path, "w", encoding="utf-8") as f:
137
+ json.dump(summary, f, indent=2, ensure_ascii=False)
138
+
139
+ logger.info(f"Collected {len(results)} texts from Wikisource")
140
+ return results
141
+
142
+
143
+ class WiktionaryCollector:
144
+ """Collects dictionary entries from Kinyarwanda Wiktionary."""
145
+
146
+ def __init__(self, output_dir: str, config: dict[str, Any]):
147
+ self.output_dir = Path(output_dir)
148
+ self.output_dir.mkdir(parents=True, exist_ok=True)
149
+ self.config = config
150
+ self.session = requests.Session()
151
+ self.session.headers.update({
152
+ "User-Agent": "BwengeAi/0.1 (Kinyarwanda AI Research)"
153
+ })
154
+
155
+ wt_config = config.get("wiktionary", {})
156
+ self.api_url = wt_config.get("api_url", "https://rw.wiktionary.org/w/api.php")
157
+
158
+ def fetch_all_words(self, limit: int = 2000) -> list[str]:
159
+ """Fetch all word entries."""
160
+ words = []
161
+ params = {
162
+ "action": "query",
163
+ "list": "allpages",
164
+ "apnamespace": 0,
165
+ "aplimit": "500",
166
+ "format": "json",
167
+ }
168
+
169
+ while len(words) < limit:
170
+ try:
171
+ time.sleep(0.5)
172
+ response = self.session.get(self.api_url, params=params, timeout=30)
173
+ response.raise_for_status()
174
+ data = response.json()
175
+
176
+ allpages = data.get("query", {}).get("allpages", [])
177
+ words.extend(p["title"] for p in allpages)
178
+
179
+ if "continue" in data:
180
+ params["apcontinue"] = data["continue"]["apcontinue"]
181
+ else:
182
+ break
183
+
184
+ except Exception as e:
185
+ logger.error(f"Failed to fetch words: {e}")
186
+ break
187
+
188
+ return words[:limit]
189
+
190
+ def fetch_word_entry(self, word: str) -> dict[str, Any] | None:
191
+ """Fetch a single word entry."""
192
+ params = {
193
+ "action": "parse",
194
+ "page": word,
195
+ "prop": "text",
196
+ "format": "json",
197
+ }
198
+
199
+ try:
200
+ time.sleep(0.3)
201
+ response = self.session.get(self.api_url, params=params, timeout=30)
202
+ response.raise_for_status()
203
+ data = response.json()
204
+
205
+ html = data.get("parse", {}).get("text", {}).get("*", "")
206
+
207
+ soup = BeautifulSoup(html, "lxml")
208
+ for tag in soup(["script", "style"]):
209
+ tag.decompose()
210
+
211
+ text = soup.get_text(separator=" ", strip=True)
212
+
213
+ if text and len(text) > 10:
214
+ return {
215
+ "word": word,
216
+ "text": text,
217
+ "source": "wiktionary",
218
+ "length": len(text),
219
+ }
220
+
221
+ except Exception as e:
222
+ logger.warning(f"Failed to fetch word '{word}': {e}")
223
+
224
+ return None
225
+
226
+ def collect_all(self) -> list[dict[str, Any]]:
227
+ """Collect all dictionary entries."""
228
+ logger.info("Starting Kinyarwanda Wiktionary collection...")
229
+
230
+ words = self.fetch_all_words(limit=2000)
231
+ logger.info(f"Found {len(words)} words")
232
+
233
+ results = []
234
+ for word in words:
235
+ entry = self.fetch_word_entry(word)
236
+ if entry:
237
+ results.append(entry)
238
+
239
+ output_path = self.output_dir / "wiktionary_entries.jsonl"
240
+ with open(output_path, "w", encoding="utf-8") as f:
241
+ for entry in results:
242
+ f.write(json.dumps(entry, ensure_ascii=False) + "\n")
243
+
244
+ summary = {
245
+ "source": "wiktionary",
246
+ "total_words": len(words),
247
+ "collected": len(results),
248
+ "output_path": str(output_path),
249
+ "total_characters": sum(r["length"] for r in results),
250
+ }
251
+
252
+ summary_path = self.output_dir / "wiktionary_summary.json"
253
+ with open(summary_path, "w", encoding="utf-8") as f:
254
+ json.dump(summary, f, indent=2, ensure_ascii=False)
255
+
256
+ logger.info(f"Collected {len(results)} entries from Wiktionary")
257
+ return results