Upload app.py
Browse files
app.py
CHANGED
|
@@ -48,6 +48,9 @@ sorted_by_name = []
|
|
| 48 |
sorted_by_size = []
|
| 49 |
repo_sorted_by_name = {}
|
| 50 |
repo_sorted_by_size = {}
|
|
|
|
|
|
|
|
|
|
| 51 |
RECORD_KEY_MAP = {
|
| 52 |
"r": "Repo",
|
| 53 |
"f": "File",
|
|
@@ -417,6 +420,7 @@ def load_data():
|
|
| 417 |
folder_browser_data = {}
|
| 418 |
print(f"📖 已加载 {len(records)} 条记录 ({time.time() - start:.2f}s)")
|
| 419 |
build_indexes()
|
|
|
|
| 420 |
|
| 421 |
def score_record(rec_idx, query_tokens, search_folders=True):
|
| 422 |
rec = records[rec_idx]
|
|
@@ -515,6 +519,53 @@ def build_response(results: list[dict], total: int, page: int, page_size: int) -
|
|
| 515 |
"page_size": page_size,
|
| 516 |
}
|
| 517 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 518 |
def apply_mixed_folder_filters(indices, self_folders=None, subtree_folders=None):
|
| 519 |
self_set = {str(path).strip("/") for path in (self_folders or []) if str(path).strip("/")}
|
| 520 |
subtree_set = {str(path).strip("/") for path in (subtree_folders or []) if str(path).strip("/")}
|
|
@@ -956,10 +1007,21 @@ def serve_sw():
|
|
| 956 |
if p.exists():
|
| 957 |
return PlainTextResponse(p.read_text(encoding="utf-8"), media_type="application/javascript")
|
| 958 |
return PlainTextResponse("", status_code=404)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 959 |
@app.get("/{rest_of_path:path}")
|
| 960 |
|
| 961 |
async def serve_spa(rest_of_path: str):
|
| 962 |
index_path = Path("static/index.html")
|
| 963 |
if index_path.exists():
|
| 964 |
-
|
|
|
|
|
|
|
|
|
|
| 965 |
return HTMLResponse("<h1>VoiceOfML Search</h1>", status_code=200)
|
|
|
|
| 48 |
sorted_by_size = []
|
| 49 |
repo_sorted_by_name = {}
|
| 50 |
repo_sorted_by_size = {}
|
| 51 |
+
initial_payload_global = None
|
| 52 |
+
initial_payload_by_repo = {}
|
| 53 |
+
INITIAL_PAGE_SIZE = 100
|
| 54 |
RECORD_KEY_MAP = {
|
| 55 |
"r": "Repo",
|
| 56 |
"f": "File",
|
|
|
|
| 420 |
folder_browser_data = {}
|
| 421 |
print(f"📖 已加载 {len(records)} 条记录 ({time.time() - start:.2f}s)")
|
| 422 |
build_indexes()
|
| 423 |
+
build_initial_payloads()
|
| 424 |
|
| 425 |
def score_record(rec_idx, query_tokens, search_folders=True):
|
| 426 |
rec = records[rec_idx]
|
|
|
|
| 519 |
"page_size": page_size,
|
| 520 |
}
|
| 521 |
|
| 522 |
+
def trim_initial_results(raw: list[dict]) -> list[dict]:
|
| 523 |
+
keys = ("Repo", "File", "Extension", "Folder", "Size", "HasTxt")
|
| 524 |
+
return [
|
| 525 |
+
{key: record.get(key, [] if key == "Folder" else "") for key in keys}
|
| 526 |
+
for record in raw
|
| 527 |
+
]
|
| 528 |
+
|
| 529 |
+
def build_initial_payload(repo: str | None = None) -> dict:
|
| 530 |
+
if repo:
|
| 531 |
+
indices = repo_records_map.get(repo, [])
|
| 532 |
+
result_records = [records[i] for i in indices[:INITIAL_PAGE_SIZE]]
|
| 533 |
+
mode = "repo"
|
| 534 |
+
total = len(indices)
|
| 535 |
+
else:
|
| 536 |
+
result_records = records[:INITIAL_PAGE_SIZE]
|
| 537 |
+
mode = "global"
|
| 538 |
+
total = len(records)
|
| 539 |
+
return {
|
| 540 |
+
"mode": mode,
|
| 541 |
+
"repo": repo,
|
| 542 |
+
"sort": "relevance",
|
| 543 |
+
"page": 1,
|
| 544 |
+
"page_size": INITIAL_PAGE_SIZE,
|
| 545 |
+
"total": total,
|
| 546 |
+
"results": trim_initial_results(result_records),
|
| 547 |
+
}
|
| 548 |
+
|
| 549 |
+
def build_initial_payloads():
|
| 550 |
+
global initial_payload_global, initial_payload_by_repo
|
| 551 |
+
initial_payload_global = build_initial_payload(None)
|
| 552 |
+
initial_payload_by_repo = {
|
| 553 |
+
repo: build_initial_payload(repo)
|
| 554 |
+
for repo in repo_records_map
|
| 555 |
+
}
|
| 556 |
+
|
| 557 |
+
def inject_initial_payload(html: str, repo_short: str | None = None) -> str:
|
| 558 |
+
repo = f"VoiceOfML/{repo_short}" if repo_short else None
|
| 559 |
+
payload = initial_payload_by_repo.get(repo) if repo else initial_payload_global
|
| 560 |
+
if not payload:
|
| 561 |
+
return html
|
| 562 |
+
script = (
|
| 563 |
+
'<script id="initial-search-data" type="application/json">'
|
| 564 |
+
+ json.dumps(payload, ensure_ascii=False, separators=(",", ":")).replace("</", "<\\/")
|
| 565 |
+
+ "</script>"
|
| 566 |
+
)
|
| 567 |
+
return html.replace("</body>", script + "\n</body>")
|
| 568 |
+
|
| 569 |
def apply_mixed_folder_filters(indices, self_folders=None, subtree_folders=None):
|
| 570 |
self_set = {str(path).strip("/") for path in (self_folders or []) if str(path).strip("/")}
|
| 571 |
subtree_set = {str(path).strip("/") for path in (subtree_folders or []) if str(path).strip("/")}
|
|
|
|
| 1007 |
if p.exists():
|
| 1008 |
return PlainTextResponse(p.read_text(encoding="utf-8"), media_type="application/javascript")
|
| 1009 |
return PlainTextResponse("", status_code=404)
|
| 1010 |
+
|
| 1011 |
+
@app.get("/")
|
| 1012 |
+
async def serve_root():
|
| 1013 |
+
index_path = Path("static/index.html")
|
| 1014 |
+
if index_path.exists():
|
| 1015 |
+
return HTMLResponse(inject_initial_payload(index_path.read_text(encoding="utf-8"), None))
|
| 1016 |
+
return HTMLResponse("<h1>VoiceOfML Search</h1>", status_code=200)
|
| 1017 |
+
|
| 1018 |
@app.get("/{rest_of_path:path}")
|
| 1019 |
|
| 1020 |
async def serve_spa(rest_of_path: str):
|
| 1021 |
index_path = Path("static/index.html")
|
| 1022 |
if index_path.exists():
|
| 1023 |
+
repo_short = rest_of_path.strip("/").split("/")[0] if rest_of_path.strip("/") else None
|
| 1024 |
+
if repo_short and f"VoiceOfML/{repo_short}" not in repo_counts:
|
| 1025 |
+
repo_short = None
|
| 1026 |
+
return HTMLResponse(inject_initial_payload(index_path.read_text(encoding="utf-8"), repo_short))
|
| 1027 |
return HTMLResponse("<h1>VoiceOfML Search</h1>", status_code=200)
|