SeaWolf-AI commited on
Commit
3658b75
·
verified ·
1 Parent(s): 774e6c9

feat: free tab now renders full professional report (locks gauge, meta cards, 3-axis sections, priorities) + upsell; deep tab keeps full-site differentiation

Browse files
Files changed (1) hide show
  1. app.py +39 -5
app.py CHANGED
@@ -110,6 +110,39 @@ def _scorebar(label, g):
110
  label, s, col, col, col, L, s)
111
 
112
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
113
  def _cards(items, empty, lang):
114
  if not items:
115
  return '<div style="color:#067647;font-weight:700;padding:8px 0">%s</div>' % empty
@@ -220,7 +253,7 @@ def build_teaser(d, lang="ko"):
220
  '<div style="text-align:center;color:#9ca3af;font-size:11px;margin-top:12px">' + _L("서비스: 퀀트ID(QuantID) · 엔진: 치토스(CHITOS)", "Service: QuantID · Engine: CHITOS", lang) + '</div></div>')
221
 
222
 
223
- def build_report(d, deep=False, verified_email=None, lang="ko"):
224
  if d.get("error"):
225
  return _note("⚠ " + html.escape(_P(d["error"], lang)), "hi")
226
  if d.get("blocked"):
@@ -305,13 +338,14 @@ def build_report(d, deep=False, verified_email=None, lang="ko"):
305
  + '<div style="flex:1;border:1px solid #e4e9ef;border-radius:10px;padding:10px"><b style="color:#b54708;font-size:22px">%d</b><div style="font-size:11px;color:#6b7280">%s</div></div>' % (nmid, _L("보완", "Advisory", lang))
306
  + '<div style="flex:1;border:1px solid #e4e9ef;border-radius:10px;padding:10px"><b style="color:#8a6d00;font-size:22px">%d</b><div style="font-size:11px;color:#6b7280">%s</div></div>' % (nlow, _L("낮음", "Low", lang))
307
  + '</div>'
308
- + _h2("🛡 " + _L("보안 점검", "Security checks", lang)) + _cards(sec, _L("✓ 외부에서 보이는 보안 위생 문제 없음", "✓ No externally visible security-hygiene issues", lang), lang)
309
- + _h2("📈 " + _L("SEO 토대 (검색 노출)", "SEO foundation (search visibility)", lang)) + _cards(seo, _L("✓ SEO 기본 요소 양호", "✓ SEO fundamentals are healthy", lang), lang)
310
  + _h2("🤖 " + _L("AI 로봇 접근 (AI 가시성)", "AI crawler access (AI visibility)", lang))
311
  + '<div style="font-size:12.5px;color:#4b5563;margin:4px 0 8px">' + _L("생성형 AI가 당신을 인용하려면 로봇이 먼저 들어와야 합니다.", "For generative AI to cite you, its crawlers must get in first.", lang) + '</div>'
312
  + _traffic(d.get('matrix', {}), lang) + _cards(geo, _L("✓ 기계 판독 신호 양호", "✓ Machine-readability signals are healthy", lang), lang)
313
  + '<div style="font-size:12px;color:#6b7280;margin-top:6px">' + _L("제목", "Title", lang) + ': ' + title80 + ' · H1 ' + str(meta.get('h1', 0)) + ' · ' + _L("구조화", "Schema", lang) + ' ' + str(meta.get('jsonld', 0)) + ' · ' + _L("홈", "Home", lang) + ' ' + str(meta.get('size_kb', 0)) + 'KB · alt ' + str(meta.get('alt_cov', 0)) + '%</div>'
314
  + deep_html
 
315
  + _h2("✓ " + _L("잘 되어 있는 점", "What's done well", lang)) + '<div>' + good + '</div>'
316
  + _h2("📌 " + _L("조치 우선순위", "Action priorities", lang)) + _priority(allf, lang)
317
  + '<div style="background:#f4f0ff;border:1px dashed #b89cff;border-radius:12px;padding:14px 16px;margin-top:16px"><b style="color:#6d28d9">' + _L("정밀 진단 안내", "About in-depth diagnosis", lang) + '</b><br><span style="font-size:13px;color:#374151">' + _L(
@@ -352,7 +386,7 @@ def free_scan(url, lang):
352
  if not (url or "").strip():
353
  return _note(_L("진단할 주소를 입력하세요. 예: example.com", "Enter a URL to scan. e.g. example.com", lang), "mid"), None
354
  d = _api("/scan", {"url": url})
355
- return build_teaser(d, lang), d
356
 
357
 
358
  def deep_scan(url, lang, profile: gr.OAuthProfile | None = None, oauth_token: gr.OAuthToken | None = None):
@@ -593,7 +627,7 @@ def footer_html(lang):
593
 
594
  def relang(label, last_scan, last_deep):
595
  lang = "en" if str(label).startswith("Eng") else "ko"
596
- o1u = gr.update(value=build_teaser(last_scan, lang)) if last_scan else gr.update()
597
  o2u = gr.update(value=build_report(last_deep["d"], deep=True, verified_email=last_deep.get("email"), lang=lang)) if last_deep else gr.update()
598
  return (lang, gr.update(value=label), header_html(lang), desc1(lang), desc2(lang), desc3(lang),
599
  area_help(lang), guideline_html(lang), footer_html(lang), o1u, o2u)
 
110
  label, s, col, col, col, L, s)
111
 
112
 
113
+ def _locks(n, lang):
114
+ cells = ""
115
+ for i in range(6):
116
+ on = i < n
117
+ cells += ('<div style="flex:1;text-align:center;border:1px solid #e4e9ef;border-radius:8px;padding:7px 2px;background:%s">'
118
+ '<div style="font-size:18px">%s</div></div>') % ("#ecfdf3" if on else "#fef3f2", "🔒" if on else "🔓")
119
+ cap = _L("보안 응답 헤더 6종 중 <b>%d개</b> 적용", "<b>%d of 6</b> security response headers applied", lang) % n
120
+ return ('<div style="font-size:12px;color:#4b5563;margin:10px 0 4px">🔐 ' + cap + '</div>'
121
+ '<div style="display:flex;gap:5px">' + cells + '</div>')
122
+
123
+
124
+ def _metacards(meta, lang):
125
+ tl = len(html.unescape(str(meta.get("title") or "")))
126
+ data = [(_L("제목 길이", "Title len", lang), "%d%s" % (tl, _L("자", "ch", lang))),
127
+ ("H1", str(meta.get("h1", 0))),
128
+ (_L("구조화", "Schema", lang), str(meta.get("jsonld", 0))),
129
+ (_L("홈 용량", "Home", lang), "%dKB" % meta.get("size_kb", 0)),
130
+ ("alt", "%d%%" % meta.get("alt_cov", 0))]
131
+ cells = "".join('<div style="flex:1;text-align:center;border:1px solid #e4e9ef;border-radius:10px;padding:8px 4px">'
132
+ '<div style="font-size:17px;font-weight:800;color:#2e1065">%s</div>'
133
+ '<div style="font-size:10.5px;color:#6b7280;margin-top:2px">%s</div></div>' % (v, k) for k, v in data)
134
+ return '<div style="display:flex;gap:6px;margin:8px 0">' + cells + '</div>'
135
+
136
+
137
+ def _upsell(lang):
138
+ return ('<div style="background:linear-gradient(135deg,#6d28d9,#8b5cf6);border-radius:14px;padding:16px 18px;margin:16px 0">'
139
+ '<div style="font-weight:800;font-size:15px;color:#fff">🔓 ' + _L("전사이트 정밀 리포트 — ② 도메인 인증 탭", "Full-site report — ② Domain Verification tab", lang) + '</div>'
140
+ '<div style="font-size:13px;color:#f3e8ff;margin-top:6px">' + _L(
141
+ "이 리포트는 <b>홈 1페이지</b> 기준입니다. 회사/조직 도메인 메일로 가입한 Hugging Face 계정으로 로그인하면 — <b>전사이트 페이지별 이슈 · 구조화데이터 커버리지 · 이메일 위조방지(SPF/DMARC) · 자기모순(주소·전화) 탐지 · 다운로드 리포트</b>까지 받습니다.",
142
+ "This report is based on the <b>home page</b>. Sign in with a Hugging Face account on your company/org domain email to unlock — <b>per-page issues across the whole site · structured-data coverage · email anti-spoofing (SPF/DMARC) · self-contradiction (address/phone) detection · downloadable report</b>.", lang)
143
+ + '</div></div>')
144
+
145
+
146
  def _cards(items, empty, lang):
147
  if not items:
148
  return '<div style="color:#067647;font-weight:700;padding:8px 0">%s</div>' % empty
 
253
  '<div style="text-align:center;color:#9ca3af;font-size:11px;margin-top:12px">' + _L("서비스: 퀀트ID(QuantID) · 엔진: 치토스(CHITOS)", "Service: QuantID · Engine: CHITOS", lang) + '</div></div>')
254
 
255
 
256
+ def build_report(d, deep=False, verified_email=None, lang="ko", show_upsell=False):
257
  if d.get("error"):
258
  return _note("⚠ " + html.escape(_P(d["error"], lang)), "hi")
259
  if d.get("blocked"):
 
338
  + '<div style="flex:1;border:1px solid #e4e9ef;border-radius:10px;padding:10px"><b style="color:#b54708;font-size:22px">%d</b><div style="font-size:11px;color:#6b7280">%s</div></div>' % (nmid, _L("보완", "Advisory", lang))
339
  + '<div style="flex:1;border:1px solid #e4e9ef;border-radius:10px;padding:10px"><b style="color:#8a6d00;font-size:22px">%d</b><div style="font-size:11px;color:#6b7280">%s</div></div>' % (nlow, _L("낮음", "Low", lang))
340
  + '</div>'
341
+ + _h2("🛡 " + _L("보안 점검", "Security checks", lang)) + _locks(d.get('locks_on', 0), lang) + _cards(sec, _L("✓ 외부에서 보이는 보안 위생 문제 없음", "✓ No externally visible security-hygiene issues", lang), lang)
342
+ + _h2("📈 " + _L("SEO 토대 (검색 노출)", "SEO foundation (search visibility)", lang)) + _metacards(meta, lang) + _cards(seo, _L("✓ SEO 기본 요소 양호", "✓ SEO fundamentals are healthy", lang), lang)
343
  + _h2("🤖 " + _L("AI 로봇 접근 (AI 가시성)", "AI crawler access (AI visibility)", lang))
344
  + '<div style="font-size:12.5px;color:#4b5563;margin:4px 0 8px">' + _L("생성형 AI가 당신을 인용하려면 로봇이 먼저 들어와야 합니다.", "For generative AI to cite you, its crawlers must get in first.", lang) + '</div>'
345
  + _traffic(d.get('matrix', {}), lang) + _cards(geo, _L("✓ 기계 판독 신호 양호", "✓ Machine-readability signals are healthy", lang), lang)
346
  + '<div style="font-size:12px;color:#6b7280;margin-top:6px">' + _L("제목", "Title", lang) + ': ' + title80 + ' · H1 ' + str(meta.get('h1', 0)) + ' · ' + _L("구조화", "Schema", lang) + ' ' + str(meta.get('jsonld', 0)) + ' · ' + _L("홈", "Home", lang) + ' ' + str(meta.get('size_kb', 0)) + 'KB · alt ' + str(meta.get('alt_cov', 0)) + '%</div>'
347
  + deep_html
348
+ + (_upsell(lang) if show_upsell else "")
349
  + _h2("✓ " + _L("잘 되어 있는 점", "What's done well", lang)) + '<div>' + good + '</div>'
350
  + _h2("📌 " + _L("조치 우선순위", "Action priorities", lang)) + _priority(allf, lang)
351
  + '<div style="background:#f4f0ff;border:1px dashed #b89cff;border-radius:12px;padding:14px 16px;margin-top:16px"><b style="color:#6d28d9">' + _L("정밀 진단 안내", "About in-depth diagnosis", lang) + '</b><br><span style="font-size:13px;color:#374151">' + _L(
 
386
  if not (url or "").strip():
387
  return _note(_L("진단할 주소를 입력하세요. 예: example.com", "Enter a URL to scan. e.g. example.com", lang), "mid"), None
388
  d = _api("/scan", {"url": url})
389
+ return build_report(d, deep=False, lang=lang, show_upsell=True), d
390
 
391
 
392
  def deep_scan(url, lang, profile: gr.OAuthProfile | None = None, oauth_token: gr.OAuthToken | None = None):
 
627
 
628
  def relang(label, last_scan, last_deep):
629
  lang = "en" if str(label).startswith("Eng") else "ko"
630
+ o1u = gr.update(value=build_report(last_scan, deep=False, lang=lang, show_upsell=True)) if last_scan else gr.update()
631
  o2u = gr.update(value=build_report(last_deep["d"], deep=True, verified_email=last_deep.get("email"), lang=lang)) if last_deep else gr.update()
632
  return (lang, gr.update(value=label), header_html(lang), desc1(lang), desc2(lang), desc3(lang),
633
  area_help(lang), guideline_html(lang), footer_html(lang), o1u, o2u)