108 lines
4.7 KiB
Python
108 lines
4.7 KiB
Python
|
|
# -*- coding: utf-8 -*-
|
||
|
|
"""P3-MD: Markdown language inventory classifier (documentation-only, read-only).
|
||
|
|
|
||
|
|
Counts Indonesian vs English stopword/prose markers per .md file and classifies:
|
||
|
|
ENGLISH / PARTIALLY ENGLISH / NON-ENGLISH / CODE-ONLY
|
||
|
|
Writes inventory JSON (path, tree, size, language, score, status).
|
||
|
|
"""
|
||
|
|
import os
|
||
|
|
import json
|
||
|
|
import re
|
||
|
|
|
||
|
|
TREES = {
|
||
|
|
"FORGE_REPO": r"D:\TradingTerminal\HFM Metatrader 5\MQL5\Shared Projects\AlgoForge\publish\AlgoForge",
|
||
|
|
"WORKING_COPY": r"D:\TradingTerminal\HFM Metatrader 5\MQL5\Shared Projects\AlgoForge",
|
||
|
|
"LEGACY": r"D:\TradingTerminal\HFM Metatrader 5\MQL5\Shared Projects\SniperGold_ML",
|
||
|
|
}
|
||
|
|
|
||
|
|
ID = [
|
||
|
|
"yang", "dan", "untuk", "dengan", "pada", "dari", "tidak", "adalah", "ini",
|
||
|
|
"akan", "telah", "dapat", "harus", "bahwa", "atau", "sebagai", "setelah",
|
||
|
|
"sebelum", "karena", "namun", "tetapi", "antara", "terhadap", "dilakukan",
|
||
|
|
"menggunakan", "terdapat", "menjadi", "berdasarkan", "sesuai", "terkait",
|
||
|
|
"melalui", "tanpa", "sudah", "juga", "masih", "lebih", "sangat", "berikut",
|
||
|
|
"sekitar", "hingga", "sampai", "semua", "beberapa", "setiap", "saat",
|
||
|
|
"ketika", "jika", "misalnya", "contoh", "catatan", "kesimpulan", "temuan",
|
||
|
|
"hasil", "tujuan", "bukti", "perlu", "bila", "bukan", "seluruh", "dalam",
|
||
|
|
"kembali", "diubah", "diperbaiki", "terverifikasi", "diverifikasi",
|
||
|
|
"dokumentasi", "penelitian", "sesi", "tanggal", "status", "disimpulkan",
|
||
|
|
"karena", "wajib", "jangan", "silahkan", "lihat", "pakai", "memakai",
|
||
|
|
"sama", "berbeda", "dibuat", "dihitung", "dipakai", "utk", "thd", "dgn",
|
||
|
|
"pd", "utk", "sbg", "tdk", "krn", "sbb", "dst", "dll", "yaitu", "yakni",
|
||
|
|
"tersebut", "tersebut", "berikutnya", "sebelumnya", "kini", "saat ini",
|
||
|
|
"awal", "akhir", "langkah", "bagian", "bab", "subbab", "ringkasan",
|
||
|
|
"lampiran", "catatan", "terlampir", "pengujian", "pengujian", "uji",
|
||
|
|
"kasus", "sampel", "populasi", "rerata", "median", "persentase", "rata",
|
||
|
|
"grafik", "tabel", "gambar", "laporan", "handover", "checkpoint",
|
||
|
|
]
|
||
|
|
EN = [
|
||
|
|
"the", "and", "for", "with", "this", "that", "from", "not", "are", "will",
|
||
|
|
"have", "has", "can", "must", "should", "between", "against", "using",
|
||
|
|
"based", "according", "through", "without", "also", "still", "more",
|
||
|
|
"following", "around", "until", "all", "some", "every", "when", "if",
|
||
|
|
"example", "note", "conclusion", "finding", "result", "objective",
|
||
|
|
"evidence", "verified", "confirmed", "documentation", "research",
|
||
|
|
"session", "date", "status", "concluded", "summary", "appendix",
|
||
|
|
"testing", "test", "case", "sample", "population", "median", "table",
|
||
|
|
"figure", "report", "analysis", "audit", "specification", "conformance",
|
||
|
|
]
|
||
|
|
|
||
|
|
|
||
|
|
def classify(path):
|
||
|
|
with open(path, "r", encoding="utf-8", errors="replace") as f:
|
||
|
|
text = f.read()
|
||
|
|
# strip code fences
|
||
|
|
no_code = re.sub(r"```.*?```", " ", text, flags=re.S)
|
||
|
|
# strip inline code
|
||
|
|
no_code = re.sub(r"`[^`]*`", " ", no_code)
|
||
|
|
words = re.findall(r"[A-Za-z]{3,}", no_code.lower())
|
||
|
|
n_id = sum(1 for w in words if w in ID)
|
||
|
|
n_en = sum(1 for w in words if w in EN)
|
||
|
|
total = len(words)
|
||
|
|
score = (n_id - n_en) / max(1, total) * 1000.0 # per-mille
|
||
|
|
if total < 30:
|
||
|
|
lang = "CODE-ONLY" if score < 5 else "NON-ENGLISH"
|
||
|
|
elif score <= 2:
|
||
|
|
lang = "ENGLISH"
|
||
|
|
elif score <= 8:
|
||
|
|
lang = "PARTIALLY ENGLISH"
|
||
|
|
else:
|
||
|
|
lang = "NON-ENGLISH"
|
||
|
|
return lang, score, total, n_id, n_en
|
||
|
|
|
||
|
|
|
||
|
|
def main():
|
||
|
|
rows = []
|
||
|
|
for tree, root in TREES.items():
|
||
|
|
for dirpath, _dirs, files in os.walk(root):
|
||
|
|
if ".git" in dirpath:
|
||
|
|
continue
|
||
|
|
for fn in files:
|
||
|
|
if fn.lower().endswith(".md"):
|
||
|
|
p = os.path.join(dirpath, fn)
|
||
|
|
size = os.path.getsize(p)
|
||
|
|
lang, score, total, nid, nen = classify(p)
|
||
|
|
rows.append({
|
||
|
|
"tree": tree,
|
||
|
|
"path": os.path.relpath(p, root),
|
||
|
|
"size": size,
|
||
|
|
"language": lang,
|
||
|
|
"score_permille": round(score, 2),
|
||
|
|
"words": total,
|
||
|
|
"id_words": nid,
|
||
|
|
"en_words": nen,
|
||
|
|
})
|
||
|
|
rows.sort(key=lambda r: (r["tree"], r["path"]))
|
||
|
|
out = os.path.join(os.path.dirname(os.path.abspath(__file__)),
|
||
|
|
"..", "..", "output", "md_language_inventory.json")
|
||
|
|
os.makedirs(os.path.dirname(out), exist_ok=True)
|
||
|
|
with open(out, "w", encoding="utf-8") as f:
|
||
|
|
json.dump(rows, f, indent=2)
|
||
|
|
for r in rows:
|
||
|
|
print(f"{r['tree']:<14} {r['language']:<18} {r['score_permille']:>8} "
|
||
|
|
f"{r['path']}")
|
||
|
|
print(f"\nTOTAL {len(rows)} files -> {out}")
|
||
|
|
|
||
|
|
|
||
|
|
if __name__ == "__main__":
|
||
|
|
main()
|