Add live search progress, session counter, and fix URLs
- Search candidates client-side with JS, showing "Checking X..." spinner instead of leaving user waiting on a blank page - Fix broken api_valid_hit endpoint (get_diff returns dict, not tuple) - Remove server-side get_best_hit; article_page now returns candidate list immediately and JS iterates via /api/1/valid_hit - URL now reflects current article via history.replaceState (?title=X), Skip navigates to ?after=X to advance past it - Track saves in session; show count as green badge in navbar - Add session counter incremented on each successful save Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
bc6265d4cd
commit
2c197f5c43
3 changed files with 114 additions and 71 deletions
76
web_view.py
76
web_view.py
|
|
@ -292,31 +292,6 @@ def match_type(q: str, snippet: str) -> str | None:
|
|||
return match
|
||||
|
||||
|
||||
class NoGoodHit(Exception):
|
||||
"""No good hit."""
|
||||
|
||||
|
||||
def get_best_hit(title: str, hits: list[Hit]) -> tuple[Hit, dict[str, typing.Any]]:
|
||||
"""Find the best hit within the search results."""
|
||||
for hit in hits:
|
||||
if hit["title"].lower() == title.lower():
|
||||
continue
|
||||
# if match_type(title, hit["snippet"]) != "exact":
|
||||
# continue
|
||||
|
||||
try:
|
||||
print(f'get diff: {hit["title"]}, {title}')
|
||||
found = get_diff(title, hit["title"], None)
|
||||
except NoMatch:
|
||||
print("no match")
|
||||
continue
|
||||
except api.MediawikiError as e:
|
||||
print(f"MediawikiError for {hit['title']!r}: {e}")
|
||||
continue
|
||||
|
||||
return (hit, found)
|
||||
|
||||
raise NoGoodHit
|
||||
|
||||
|
||||
def handle_post(url_title: str) -> Response:
|
||||
|
|
@ -329,6 +304,7 @@ def handle_post(url_title: str) -> Response:
|
|||
return flask.redirect(flask.url_for("start_oauth"))
|
||||
except mediawiki_api.APIError as e:
|
||||
return flask.make_response(f"Save failed: {e}", 502)
|
||||
flask.session["saves"] = flask.session.get("saves", 0) + 1
|
||||
return flask.redirect(
|
||||
flask.url_for("article_page", url_title=url_title, after=hit_title)
|
||||
)
|
||||
|
|
@ -341,47 +317,33 @@ def article_page(url_title: str) -> str | Response:
|
|||
return handle_post(url_title)
|
||||
|
||||
from_title = url_title.replace("_", " ").strip()
|
||||
article_title = flask.request.args.get("title")
|
||||
|
||||
total = search_count(from_title)
|
||||
with_link = search_count_with_link(from_title)
|
||||
_no_link_count, hits = search_no_link(from_title)
|
||||
|
||||
no_link_count, hits = search_no_link(from_title)
|
||||
# If a specific candidate was requested, move it to the front
|
||||
title_param = flask.request.args.get("title")
|
||||
if title_param:
|
||||
hits = [h for h in hits if h["title"] == title_param] + \
|
||||
[h for h in hits if h["title"] != title_param]
|
||||
|
||||
by_title = {hit["title"]: hit for hit in hits}
|
||||
# Skip past already-processed candidates
|
||||
after = flask.request.args.get("after")
|
||||
if after:
|
||||
hits_iter = itertools.dropwhile(lambda h: h["title"] != after, hits)
|
||||
next(hits_iter, None) # consume the "after" entry itself
|
||||
hits = list(hits_iter)
|
||||
|
||||
found = None
|
||||
if article_title in by_title:
|
||||
hit = by_title[article_title]
|
||||
try:
|
||||
found = get_diff(from_title, hit["title"], None)
|
||||
except NoMatch:
|
||||
pass
|
||||
|
||||
if not found:
|
||||
after = flask.request.args.get("after")
|
||||
if after:
|
||||
print(after)
|
||||
hits_iter = itertools.dropwhile(lambda hit: hit["title"] != after, hits)
|
||||
skip = next(hits_iter, None)
|
||||
if skip:
|
||||
hits = list(hits_iter)
|
||||
|
||||
try:
|
||||
hit, found = get_best_hit(from_title, hits)
|
||||
except NoGoodHit:
|
||||
return flask.render_template("all_done.html")
|
||||
if not hits:
|
||||
return flask.render_template("all_done.html")
|
||||
|
||||
return flask.render_template(
|
||||
"article.html",
|
||||
title=from_title,
|
||||
total=total,
|
||||
with_link=with_link,
|
||||
hit_title=hit["title"],
|
||||
hits=hits,
|
||||
replacement=found["replacement"],
|
||||
diff=found["diff"],
|
||||
found=found,
|
||||
url_title=url_title,
|
||||
)
|
||||
|
||||
|
|
@ -428,16 +390,16 @@ def api_hits() -> werkzeug.wrappers.response.Response:
|
|||
|
||||
@app.route("/api/1/valid_hit")
|
||||
def api_valid_hit() -> werkzeug.wrappers.response.Response:
|
||||
"""Return candidates for the given article title."""
|
||||
link_from = flask.request.args["link_from"]
|
||||
"""Check if a candidate article has a valid unlinked mention."""
|
||||
link_to = flask.request.args["link_to"]
|
||||
link_from = flask.request.args["link_from"]
|
||||
|
||||
try:
|
||||
diff, replacement = get_diff(link_to, link_from, None)
|
||||
found = get_diff(link_to, link_from, None)
|
||||
except NoMatch:
|
||||
return flask.jsonify(valid=False)
|
||||
|
||||
return flask.jsonify(valid=True, diff=diff, replacement=replacement)
|
||||
return flask.jsonify(valid=True, diff=found["diff"], replacement=found["replacement"])
|
||||
|
||||
|
||||
@app.route("/favicon.ico")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue