Spaces:
Running
Running
Upload app.py
Browse files
app.py
CHANGED
|
@@ -28,6 +28,7 @@ import time
|
|
| 28 |
import site_pages as SP
|
| 29 |
import report_flags as RF
|
| 30 |
import lt_grammar as LT
|
|
|
|
| 31 |
|
| 32 |
LT.warmup() # start LanguageTool in the background (free grammar check)
|
| 33 |
from humanizer import BRAND, RAINBOW, LOGO_SRC, FAVICON_SRC, FAVICON_PATH, MODES, OUT_DIR
|
|
@@ -45,17 +46,20 @@ def _stats_gauge(title, pct, caption, good_low=True):
|
|
| 45 |
return H._gauge(title, pct, caption, invert=not good_low)
|
| 46 |
|
| 47 |
|
| 48 |
-
def suite_panel(ai_before, ai_after, original, revised, labels=None):
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 53 |
return f"""
|
| 54 |
-
<div class="cs-scores">
|
| 55 |
-
{
|
| 56 |
-
{_stats_gauge(lb[2], ai_after, lb[3])}
|
| 57 |
-
{H._gauge("Similarity to source", sim, "Word n-gram overlap with your original")}
|
| 58 |
-
{H._gauge("Vocabulary changed", changed, "Share of new wording", fixed_color=BRAND["navy"])}
|
| 59 |
</div>
|
| 60 |
<div class="cs-disclaimer">
|
| 61 |
<b>Indicators only.</b> The AI score comes from an open-source detector and will differ from Turnitin,
|
|
@@ -297,12 +301,16 @@ def _smart_result(res, hi, mod, text_mode, rep=None, name=""):
|
|
| 297 |
gline = _grammar_line(res.get("note"))
|
| 298 |
rs = res.get("report")
|
| 299 |
table = ""
|
|
|
|
| 300 |
if rs: # report-guided run
|
| 301 |
what = "AI" if rs.get("kind") != "Similarity" else "Similarity"
|
| 302 |
if rs.get("score") is not None:
|
| 303 |
g_before, g_after = rs["score"], rs["est"]
|
| 304 |
-
labels = (f"{what} · {rs['tool']}", "
|
| 305 |
-
f"{what} · estimated
|
|
|
|
|
|
|
|
|
|
| 306 |
msg = (f"✅ **Done** — {rs['tool']} {what} score {rs['score']:g}% → estimated **{rs['est']:g}%** "
|
| 307 |
f"after rewriting. Re-check with {rs['tool']} for the actual score.")
|
| 308 |
else:
|
|
@@ -316,7 +324,10 @@ def _smart_result(res, hi, mod, text_mode, rep=None, name=""):
|
|
| 316 |
table = _report_table(rs)
|
| 317 |
msg += gline
|
| 318 |
preview = D.build_html(res["blocks"], a, hi, mod)
|
| 319 |
-
panel = suite_panel(g_before, g_after, res["orig"], res["new"], labels) + table
|
|
|
|
|
|
|
|
|
|
| 320 |
out = [H.status_done(msg), preview, panel, res["path"], H.download_button(res["path"])]
|
| 321 |
if text_mode:
|
| 322 |
out.insert(1, res["text"])
|
|
@@ -324,6 +335,23 @@ def _smart_result(res, hi, mod, text_mode, rep=None, name=""):
|
|
| 324 |
|
| 325 |
|
| 326 |
REPORT_KINDS = ["AI-writing report", "Similarity / plagiarism report"]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 327 |
|
| 328 |
|
| 329 |
def _use_report(report, kind=None, rep=None):
|
|
@@ -414,11 +442,27 @@ def smart_docx(path, target, passes, temp, mode, hi, mod, full_ai, vocab, report
|
|
| 414 |
|
| 415 |
|
| 416 |
# ---------------- Rigorous proofread (of a finished humanized document) ----------------
|
| 417 |
-
def
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 418 |
import proofread as PR
|
| 419 |
path = result if isinstance(result, str) else getattr(result, "name", None)
|
| 420 |
if not path or not str(path).lower().endswith(".docx"):
|
| 421 |
-
raise gr.Error("
|
|
|
|
|
|
|
| 422 |
try:
|
| 423 |
res = PR.proofread_docx(path, original if original and str(original).lower().endswith(".docx") else None,
|
| 424 |
rep, hi, mod)
|
|
@@ -428,17 +472,53 @@ def _proof_core(result, original, hi, mod, rep):
|
|
| 428 |
raise gr.Error(str(err))
|
| 429 |
rep.meta.update(name=os.path.basename(str(path)), words=res["before"]["all_words"],
|
| 430 |
before=res["before"]["pct"], after=res["after"]["pct"], output=res["path"])
|
| 431 |
-
|
| 432 |
-
|
| 433 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 434 |
|
| 435 |
|
| 436 |
def proofread_doc(result, original, hi, mod, user, request: gr.Request = None):
|
| 437 |
"""Free follow-up step on a document the user just humanized (does not use a document from the plan)."""
|
| 438 |
-
yield from _stream(_proof_core, (result, original, hi, mod),
|
| 439 |
tool="Proofread", quota=False)
|
| 440 |
|
| 441 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 442 |
# ---------------- Detector ----------------
|
| 443 |
def _det_core(file, text, hi, mod, rep):
|
| 444 |
if mod >= hi:
|
|
@@ -491,6 +571,7 @@ def _hum_docx_core(path, temp, min_words, mode, full_ai, vocab, rep):
|
|
| 491 |
rep.meta.update(name=os.path.basename(str(path)), words=len(orig.split()), before=b, after=a, output=out,
|
| 492 |
engine="CPU" if "CPU" in summary else "GPU")
|
| 493 |
panel = suite_panel(b, a, orig, new)
|
|
|
|
| 494 |
print(f"[humanizer] {summary}", flush=True)
|
| 495 |
return out, dl, H.status_done(summary.split("\n\n")[0] + _grammar_line(summary)), panel, preview
|
| 496 |
|
|
@@ -1451,10 +1532,47 @@ with gr.Blocks(title=f"{APP_NAME} · CS Software Solutions", theme=theme, css=CS
|
|
| 1451 |
sd_pr_status = gr.HTML()
|
| 1452 |
sd_pr_file = gr.File(label="Download proofread .docx", interactive=False)
|
| 1453 |
sd_pr_dl = gr.HTML()
|
|
|
|
| 1454 |
sd_scores = gr.HTML(EMPTY)
|
| 1455 |
with gr.Accordion("Final AI highlight view", open=False):
|
| 1456 |
sd_prev = gr.HTML()
|
| 1457 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1458 |
# ============================ DETECTOR ============================
|
| 1459 |
with gr.Tab("🔍 AI Detector", id="detect"):
|
| 1460 |
gr.HTML('<div class="cs-intro"><b>AI Writing Report.</b> Sentence-level highlighting '
|
|
@@ -1558,6 +1676,7 @@ with gr.Blocks(title=f"{APP_NAME} · CS Software Solutions", theme=theme, css=CS
|
|
| 1558 |
hd_pr_status = gr.HTML()
|
| 1559 |
hd_pr_file = gr.File(label="Download proofread .docx", interactive=False)
|
| 1560 |
hd_pr_dl = gr.HTML()
|
|
|
|
| 1561 |
hd_scores = gr.HTML(EMPTY)
|
| 1562 |
with gr.Accordion("Preview of changes (first 10)", open=False):
|
| 1563 |
hd_prev = gr.Markdown()
|
|
@@ -1906,11 +2025,17 @@ with gr.Blocks(title=f"{APP_NAME} · CS Software Solutions", theme=theme, css=CS
|
|
| 1906 |
|
| 1907 |
# rigorous proofread of the humanized file
|
| 1908 |
sd_pr_btn.click(lambda: WAIT, None, sd_pr_status, queue=False, **HID).then(
|
| 1909 |
-
proofread_doc, [sd_file, sd_in, s_hi, s_mod, user_state], [sd_pr_status, sd_pr_file, sd_pr_dl],
|
| 1910 |
**JOB(sd_pr_status))
|
| 1911 |
hd_pr_btn.click(lambda: WAIT, None, hd_pr_status, queue=False, **HID).then(
|
| 1912 |
-
proofread_doc, [hd_file, hd_in, s_hi, s_mod, user_state], [hd_pr_status, hd_pr_file, hd_pr_dl],
|
| 1913 |
**JOB(hd_pr_status))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1914 |
|
| 1915 |
# detector
|
| 1916 |
dp_run = dp_btn.click(lambda: WAIT, None, dp_status, queue=False, **HID).then(detect_text, [dp_in, d_hi, d_mod, user_state], [dp_status, dp_html, dp_pdf, dp_dl], **JOB(dp_status))
|
|
|
|
| 28 |
import site_pages as SP
|
| 29 |
import report_flags as RF
|
| 30 |
import lt_grammar as LT
|
| 31 |
+
import textparse as TP
|
| 32 |
|
| 33 |
LT.warmup() # start LanguageTool in the background (free grammar check)
|
| 34 |
from humanizer import BRAND, RAINBOW, LOGO_SRC, FAVICON_SRC, FAVICON_PATH, MODES, OUT_DIR
|
|
|
|
| 46 |
return H._gauge(title, pct, caption, invert=not good_low)
|
| 47 |
|
| 48 |
|
| 49 |
+
def suite_panel(ai_before, ai_after, original, revised, labels=None, extra=None, sim_vocab=True):
|
| 50 |
+
lb = labels or ("AI · our detector, before", "Open-source detector on your original",
|
| 51 |
+
"AI · our detector, after", "Same detector on the rewritten text")
|
| 52 |
+
gauges = [_stats_gauge(lb[0], ai_before, lb[1]), _stats_gauge(lb[2], ai_after, lb[3])]
|
| 53 |
+
gauges += [_stats_gauge(t, v, c) for t, v, c in (extra or [])]
|
| 54 |
+
if sim_vocab:
|
| 55 |
+
sim = H.similarity_to_source(original, revised)
|
| 56 |
+
changed = H.words_changed(original, revised)
|
| 57 |
+
gauges += [H._gauge("Similarity to source", sim, "Word n-gram overlap with your original"),
|
| 58 |
+
H._gauge("Vocabulary changed", changed, "Share of new wording", fixed_color=BRAND["navy"])]
|
| 59 |
+
cols = min(4, max(2, len(gauges)))
|
| 60 |
return f"""
|
| 61 |
+
<div class="cs-scores" style="grid-template-columns:repeat({cols},1fr)">
|
| 62 |
+
{"".join(gauges)}
|
|
|
|
|
|
|
|
|
|
| 63 |
</div>
|
| 64 |
<div class="cs-disclaimer">
|
| 65 |
<b>Indicators only.</b> The AI score comes from an open-source detector and will differ from Turnitin,
|
|
|
|
| 301 |
gline = _grammar_line(res.get("note"))
|
| 302 |
rs = res.get("report")
|
| 303 |
table = ""
|
| 304 |
+
extra = None
|
| 305 |
if rs: # report-guided run
|
| 306 |
what = "AI" if rs.get("kind") != "Similarity" else "Similarity"
|
| 307 |
if rs.get("score") is not None:
|
| 308 |
g_before, g_after = rs["score"], rs["est"]
|
| 309 |
+
labels = (f"{what} · {rs['tool']} report", "Read from the report you uploaded",
|
| 310 |
+
f"{what} · {rs['tool']}, estimated now", f"Our estimate for {rs['tool']}; re-check there to confirm")
|
| 311 |
+
if what == "AI": # our own detector, clearly labelled as a different scale
|
| 312 |
+
extra = [("AI · our detector, now", a["pct"],
|
| 313 |
+
f"Open-source detector (was {b['pct']}%); a different scale from {rs['tool']}")]
|
| 314 |
msg = (f"✅ **Done** — {rs['tool']} {what} score {rs['score']:g}% → estimated **{rs['est']:g}%** "
|
| 315 |
f"after rewriting. Re-check with {rs['tool']} for the actual score.")
|
| 316 |
else:
|
|
|
|
| 324 |
table = _report_table(rs)
|
| 325 |
msg += gline
|
| 326 |
preview = D.build_html(res["blocks"], a, hi, mod)
|
| 327 |
+
panel = suite_panel(g_before, g_after, res["orig"], res["new"], labels, extra) + table
|
| 328 |
+
_remember(res["path"], ours=a["pct"], ours_before=b["pct"],
|
| 329 |
+
tool=(rs or {}).get("tool"), kind=(rs or {}).get("kind"),
|
| 330 |
+
rep_score=(rs or {}).get("score"), rep_est=(rs or {}).get("est"))
|
| 331 |
out = [H.status_done(msg), preview, panel, res["path"], H.download_button(res["path"])]
|
| 332 |
if text_mode:
|
| 333 |
out.insert(1, res["text"])
|
|
|
|
| 335 |
|
| 336 |
|
| 337 |
REPORT_KINDS = ["AI-writing report", "Similarity / plagiarism report"]
|
| 338 |
+
RESULT_CTX = {} # sha1 of an output file -> its scores (so a later proofread can show matching indicators)
|
| 339 |
+
|
| 340 |
+
|
| 341 |
+
def _file_key(path):
|
| 342 |
+
try:
|
| 343 |
+
with open(path, "rb") as fh:
|
| 344 |
+
return hashlib.sha1(fh.read()).hexdigest()
|
| 345 |
+
except Exception:
|
| 346 |
+
return None
|
| 347 |
+
|
| 348 |
+
|
| 349 |
+
def _remember(path, **ctx):
|
| 350 |
+
k = _file_key(path)
|
| 351 |
+
if k:
|
| 352 |
+
if len(RESULT_CTX) > 2000:
|
| 353 |
+
RESULT_CTX.clear()
|
| 354 |
+
RESULT_CTX[k] = ctx
|
| 355 |
|
| 356 |
|
| 357 |
def _use_report(report, kind=None, rep=None):
|
|
|
|
| 442 |
|
| 443 |
|
| 444 |
# ---------------- Rigorous proofread (of a finished humanized document) ----------------
|
| 445 |
+
def _proof_panel(res, ctx):
|
| 446 |
+
"""Indicators after a proofread, on the same scales as the result it was run on."""
|
| 447 |
+
b, a = res["before"]["pct"], res["after"]["pct"]
|
| 448 |
+
labels = ("AI · our detector, before proofread", "Open-source detector on the file you proofread",
|
| 449 |
+
"AI · our detector, after proofread", "Same detector on the proofread file")
|
| 450 |
+
extra = [("Sentences corrected", round(100 * res["n"] / max(1, res["total"])),
|
| 451 |
+
f"{res['n']} of {res['total']} sentences")]
|
| 452 |
+
if ctx and ctx.get("rep_est") is not None and ctx.get("kind") != "Similarity":
|
| 453 |
+
est = max(0, min(100, round(ctx["rep_est"] + (a - b))))
|
| 454 |
+
extra.insert(0, (f"AI · {ctx['tool']}, estimated after proofread", est,
|
| 455 |
+
f"Was {ctx['rep_est']:g}% estimated after humanizing; re-check with {ctx['tool']}"))
|
| 456 |
+
return suite_panel(b, a, "", "", labels, extra, sim_vocab=False)
|
| 457 |
+
|
| 458 |
+
|
| 459 |
+
def _proof_core(result, original, hi, mod, rep, standalone=False):
|
| 460 |
import proofread as PR
|
| 461 |
path = result if isinstance(result, str) else getattr(result, "name", None)
|
| 462 |
if not path or not str(path).lower().endswith(".docx"):
|
| 463 |
+
raise gr.Error("Upload a Word (.docx) file to proofread." if standalone else
|
| 464 |
+
"Humanize a Word document first; the proofread works on the humanized file.")
|
| 465 |
+
ctx = RESULT_CTX.get(_file_key(path))
|
| 466 |
try:
|
| 467 |
res = PR.proofread_docx(path, original if original and str(original).lower().endswith(".docx") else None,
|
| 468 |
rep, hi, mod)
|
|
|
|
| 472 |
raise gr.Error(str(err))
|
| 473 |
rep.meta.update(name=os.path.basename(str(path)), words=res["before"]["all_words"],
|
| 474 |
before=res["before"]["pct"], after=res["after"]["pct"], output=res["path"])
|
| 475 |
+
_remember(res["path"], ours=res["after"]["pct"], ours_before=res["before"]["pct"],
|
| 476 |
+
**{k: (ctx or {}).get(k) for k in ("tool", "kind", "rep_score")},
|
| 477 |
+
rep_est=(None if not ctx or ctx.get("rep_est") is None else
|
| 478 |
+
max(0, min(100, round(ctx["rep_est"] + res["after"]["pct"] - res["before"]["pct"])))))
|
| 479 |
+
head = f"✅ **Proofread done** — {res['n']} of {res['total']} sentences corrected."
|
| 480 |
+
return (H.status_done(head + "\n\n" + res["note"]), res["path"], H.download_button(res["path"]),
|
| 481 |
+
_proof_panel(res, ctx))
|
| 482 |
|
| 483 |
|
| 484 |
def proofread_doc(result, original, hi, mod, user, request: gr.Request = None):
|
| 485 |
"""Free follow-up step on a document the user just humanized (does not use a document from the plan)."""
|
| 486 |
+
yield from _stream(_proof_core, (result, original, hi, mod), 4, 0, user, True, request,
|
| 487 |
tool="Proofread", quota=False)
|
| 488 |
|
| 489 |
|
| 490 |
+
PROOF_STANDALONE_FREE = os.getenv("PROOF_STANDALONE_FREE", "0") == "1"
|
| 491 |
+
|
| 492 |
+
|
| 493 |
+
def _proof_new_core(file, original, hi, mod, rep):
|
| 494 |
+
return _proof_core(file, original, hi, mod, rep, standalone=True)
|
| 495 |
+
|
| 496 |
+
|
| 497 |
+
def proofread_new(file, original, hi, mod, user, request: gr.Request = None):
|
| 498 |
+
"""Proofread any Word document (a new article): uses one document from the plan unless PROOF_STANDALONE_FREE=1."""
|
| 499 |
+
yield from _stream(_proof_new_core, (file, original, hi, mod), 4, 0, user, True, request,
|
| 500 |
+
tool="Proofread", words=P.doc_words(file) if file else None, quota=not PROOF_STANDALONE_FREE)
|
| 501 |
+
|
| 502 |
+
|
| 503 |
+
def _proof_text_core(text, hi, mod, rep):
|
| 504 |
+
from docx import Document
|
| 505 |
+
d = Document()
|
| 506 |
+
for p in [p for p, _ in TP.parse_paste(text)]:
|
| 507 |
+
d.add_paragraph(p)
|
| 508 |
+
tmp = OUT_DIR / f"paste_{secrets.token_hex(6)}.docx"
|
| 509 |
+
d.save(tmp)
|
| 510 |
+
st, path, dl, panel = _proof_core(str(tmp), None, hi, mod, rep, standalone=True)
|
| 511 |
+
out_text = "\n\n".join(p.text for p in Document(path).paragraphs if p.text.strip())
|
| 512 |
+
return st, out_text, path, dl, panel
|
| 513 |
+
|
| 514 |
+
|
| 515 |
+
def proofread_text(text, hi, mod, user, request: gr.Request = None):
|
| 516 |
+
if not (text or "").strip():
|
| 517 |
+
raise gr.Error("Please paste some text to proofread.")
|
| 518 |
+
yield from _stream(_proof_text_core, (text, hi, mod), 5, 0, user, False, request, tool="Proofread",
|
| 519 |
+
paste=text)
|
| 520 |
+
|
| 521 |
+
|
| 522 |
# ---------------- Detector ----------------
|
| 523 |
def _det_core(file, text, hi, mod, rep):
|
| 524 |
if mod >= hi:
|
|
|
|
| 571 |
rep.meta.update(name=os.path.basename(str(path)), words=len(orig.split()), before=b, after=a, output=out,
|
| 572 |
engine="CPU" if "CPU" in summary else "GPU")
|
| 573 |
panel = suite_panel(b, a, orig, new)
|
| 574 |
+
_remember(out, ours=a, ours_before=b)
|
| 575 |
print(f"[humanizer] {summary}", flush=True)
|
| 576 |
return out, dl, H.status_done(summary.split("\n\n")[0] + _grammar_line(summary)), panel, preview
|
| 577 |
|
|
|
|
| 1532 |
sd_pr_status = gr.HTML()
|
| 1533 |
sd_pr_file = gr.File(label="Download proofread .docx", interactive=False)
|
| 1534 |
sd_pr_dl = gr.HTML()
|
| 1535 |
+
sd_pr_panel = gr.HTML()
|
| 1536 |
sd_scores = gr.HTML(EMPTY)
|
| 1537 |
with gr.Accordion("Final AI highlight view", open=False):
|
| 1538 |
sd_prev = gr.HTML()
|
| 1539 |
|
| 1540 |
+
with gr.Tab("🔍 Proofread only"):
|
| 1541 |
+
gr.Markdown("Proofread **any** article or chapter, no humanizing needed: grammar first (every "
|
| 1542 |
+
"error fixed and verified), then clarity, academic wording and flow, doubled terms "
|
| 1543 |
+
"and AI leftovers removed, while keeping the AI score where it was.")
|
| 1544 |
+
with gr.Tabs(elem_classes="sub-tabs"):
|
| 1545 |
+
with gr.Tab("📄 Word document 🔒"):
|
| 1546 |
+
_, pn_open, pn_lockbtn = lock_gate("Word documents")
|
| 1547 |
+
GOTO_ACCOUNT.append(pn_lockbtn)
|
| 1548 |
+
with pn_open:
|
| 1549 |
+
with gr.Row(equal_height=False):
|
| 1550 |
+
with gr.Column(elem_classes="cs-card"):
|
| 1551 |
+
pn_in = gr.File(label="Document to proofread (.docx)", file_types=[".docx"],
|
| 1552 |
+
type="filepath")
|
| 1553 |
+
pn_orig = gr.File(label="Optional: the author's original version (.docx), "
|
| 1554 |
+
"used to repair unclear sentences",
|
| 1555 |
+
file_types=[".docx"], type="filepath")
|
| 1556 |
+
pn_btn = gr.Button("🔍 Proofread document", variant="primary", size="lg")
|
| 1557 |
+
with gr.Column(elem_classes="cs-card"):
|
| 1558 |
+
pn_status = gr.HTML(H.status_idle("Upload a .docx and press **Proofread "
|
| 1559 |
+
"document**."))
|
| 1560 |
+
pn_file = gr.File(label="Download proofread .docx", interactive=False)
|
| 1561 |
+
pn_dl = gr.HTML()
|
| 1562 |
+
pn_panel = gr.HTML(EMPTY)
|
| 1563 |
+
with gr.Tab("✍️ Paste text"):
|
| 1564 |
+
with gr.Row(equal_height=False):
|
| 1565 |
+
with gr.Column(elem_classes="cs-card"):
|
| 1566 |
+
pt_in = gr.Textbox(label="Text to proofread", lines=12,
|
| 1567 |
+
placeholder="Paste a paragraph, abstract or section…")
|
| 1568 |
+
pt_btn = gr.Button("🔍 Proofread text", variant="primary", size="lg")
|
| 1569 |
+
with gr.Column(elem_classes="cs-card"):
|
| 1570 |
+
pt_status = gr.HTML(H.status_idle("Paste text and press **Proofread text**."))
|
| 1571 |
+
pt_out = gr.Textbox(label="Proofread text", lines=12, interactive=False)
|
| 1572 |
+
pt_file = gr.File(label="Download as .docx", interactive=False)
|
| 1573 |
+
pt_dl = gr.HTML()
|
| 1574 |
+
pt_panel = gr.HTML(EMPTY)
|
| 1575 |
+
|
| 1576 |
# ============================ DETECTOR ============================
|
| 1577 |
with gr.Tab("🔍 AI Detector", id="detect"):
|
| 1578 |
gr.HTML('<div class="cs-intro"><b>AI Writing Report.</b> Sentence-level highlighting '
|
|
|
|
| 1676 |
hd_pr_status = gr.HTML()
|
| 1677 |
hd_pr_file = gr.File(label="Download proofread .docx", interactive=False)
|
| 1678 |
hd_pr_dl = gr.HTML()
|
| 1679 |
+
hd_pr_panel = gr.HTML()
|
| 1680 |
hd_scores = gr.HTML(EMPTY)
|
| 1681 |
with gr.Accordion("Preview of changes (first 10)", open=False):
|
| 1682 |
hd_prev = gr.Markdown()
|
|
|
|
| 2025 |
|
| 2026 |
# rigorous proofread of the humanized file
|
| 2027 |
sd_pr_btn.click(lambda: WAIT, None, sd_pr_status, queue=False, **HID).then(
|
| 2028 |
+
proofread_doc, [sd_file, sd_in, s_hi, s_mod, user_state], [sd_pr_status, sd_pr_file, sd_pr_dl, sd_pr_panel],
|
| 2029 |
**JOB(sd_pr_status))
|
| 2030 |
hd_pr_btn.click(lambda: WAIT, None, hd_pr_status, queue=False, **HID).then(
|
| 2031 |
+
proofread_doc, [hd_file, hd_in, s_hi, s_mod, user_state], [hd_pr_status, hd_pr_file, hd_pr_dl, hd_pr_panel],
|
| 2032 |
**JOB(hd_pr_status))
|
| 2033 |
+
pn_btn.click(lambda: WAIT, None, pn_status, queue=False, **HID).then(
|
| 2034 |
+
proofread_new, [pn_in, pn_orig, s_hi, s_mod, user_state], [pn_status, pn_file, pn_dl, pn_panel],
|
| 2035 |
+
**JOB(pn_status))
|
| 2036 |
+
pt_btn.click(lambda: WAIT, None, pt_status, queue=False, **HID).then(
|
| 2037 |
+
proofread_text, [pt_in, s_hi, s_mod, user_state], [pt_status, pt_out, pt_file, pt_dl, pt_panel],
|
| 2038 |
+
**JOB(pt_status))
|
| 2039 |
|
| 2040 |
# detector
|
| 2041 |
dp_run = dp_btn.click(lambda: WAIT, None, dp_status, queue=False, **HID).then(detect_text, [dp_in, d_hi, d_mod, user_state], [dp_status, dp_html, dp_pdf, dp_dl], **JOB(dp_status))
|