🎁 功能完全免费 · 无广告 · 无需登录 · 本地记录

粘贴简历和目标岗位 JD,30 秒生成一份 AI 诊断报告

1 简历诊断 → 2 按 JD 改写 → 3 记录投递 → 4 模拟面试 → 5 Offer 核验

建议先隐藏手机号、住址等敏感信息

0 / 8000

应聘目标

0 / 8000

🔒 无需登录。简历只用于本次 AI 分析;投递记录保存在当前设备,不会上传简历原文。

诊断后,你还能继续做什么

围绕当前公司和岗位持续推进

🎤

模拟面试

基于简历和 JD 生成问题、考察点与回答思路。

🗂

记录投递

保存公司、岗位、状态和下一步提醒,集中查看进度。

✓

Offer 核验

在签约前核对薪资、试用期、社保和入职条件。

你会得到什么
一次诊断,拿到一份能直接照着改的"简历体检报告"——每张卡片都能点,直接开始用
🎯

综合匹配度打分

0–100 分,一眼判断这份简历现在能不能投,不用再自己瞎猜。

点这里开始诊断 →
🩺

五个维度体检

岗位匹配、量化程度、表达质量、结构、关键词覆盖,逐项打分给评语。

点这里开始诊断 →
✍️

逐条改写示范 升级

原文 vs 改写后对照着看,每条改写都能一键复制,拿走就能用。

点这里开始诊断 →
📄

多模板一键导出 新增

挑一套排版模板(共 8 套),一页纸 / 不限页数直接导出 PDF。

点这里直接改写 →
🎤

模拟面试提问 新增

根据你的简历和目标 JD 出 6–8 道面试题,附考察点和回答思路,面试前先自测。

点这里生成面试题 →
AI 改写长这样
不虚构、只基于你的真实经历,把"平淡罗列"改成"有结果的表达"
改写前 负责公众号的日常内容运营,提升了粉丝数量和阅读量。
✎ 改写后 独立运营公众号 3 个月,产出推文 25 篇;通过选题复盘将平均阅读量从 800 提升至 2100(+163%),粉丝净增 1500+。
五个维度,像体检一样
哪块"生病"了、该先治哪里,报告里说得清清楚楚
简历模板展示
先看风格,再选择版式。每套模板都支持一页纸和不限页数导出。
🎯
岗位匹配度

简历和目标 JD 的核心要求对不对得上。

📊
量化程度

有没有用数字说话,而不是只写"负责""参与"。

✒️
表达质量

动作动词是否精准有力,有没有反复啰嗦。

🧱
结构完整度

模块是否齐全、顺序是否合理。

🔑
关键词覆盖

能不能过机器初筛(ATS)的关键词匹配。

适合谁用
只要你正在投简历,它就能帮你把命中率提上来
🎓
应届毕业生

没经验不知道怎么写,先体检再照着改写模板补。

🔄
转行求职者

看清简历和新岗位差在哪,把可迁移能力写出来。

🚀
海投没回音的人

先搞清是不是简历的锅,别再无效海投浪费机会。

常见问题
会保存我的简历吗?

不会。简历只用于本次分析,服务器不存储任何简历内容,用完即弃。

要花钱吗?

完全免费,不需要注册或登录。浏览器只保存随机匿名标识,用于聚合统计。

诊断准不准?

由 AI 模型基于简历与 JD 生成,作为优化参考很实用;最终投递前建议自己再核对一遍。

支持哪些格式?

可直接粘贴文本,也能上传 PDF 或图片(截图/拍照)自动识别文字。

AI 医生正在阅读你的简历……约需 20–30 秒

综合匹配度
-- / 100

五维评分

JD 中出现但简历未覆盖的关键词

机器初筛(ATS)按关键词匹配,如果你确实具备这些技能,务必写进简历。

问题清单

改写示范

挑选了最值得优化的几条经历,对照学习后可举一反三修改全文。每条改写后可一键复制。

🎤 模拟面试题

根据你的简历 + 目标 JD 生成,面试前先自测一遍。每题都标了考察点和一条回答思路,右上角可单条复制。

`); w.document.close(); } $('pdf-one-btn').addEventListener('click', () => exportPdf(true)); $('pdf-btn').addEventListener('click', () => exportPdf(false)); $('download-btn').addEventListener('click', () => { const blob = new Blob([$('rewrite-content').textContent], { type: 'text/markdown;charset=utf-8' }); const a = document.createElement('a'); a.href = URL.createObjectURL(blob); a.download = '修改版简历.md'; a.click(); URL.revokeObjectURL(a.href); }); /* ================= 诊断海报(Canvas 生成,含二维码) ================= */ const QR_B64 = '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'; function rrect(ctx, x, y, w, h, r) { ctx.beginPath(); ctx.moveTo(x + r, y); ctx.arcTo(x + w, y, x + w, y + h, r); ctx.arcTo(x + w, y + h, x, y + h, r); ctx.arcTo(x, y + h, x, y, r); ctx.arcTo(x, y, x + w, y, r); ctx.closePath(); } function wrapText(ctx, text, maxWidth, maxLines) { const lines = []; let cur = ''; for (const ch of text) { if (ctx.measureText(cur + ch).width > maxWidth) { lines.push(cur); cur = ch; if (lines.length === maxLines) break; } else cur += ch; } if (lines.length < maxLines && cur) lines.push(cur); else if (lines.length === maxLines && cur) lines[maxLines - 1] = lines[maxLines - 1].slice(0, -1) + '…'; return lines; } async function buildPoster() { const d = lastReport; if (!d) return null; const S = 2, W = 750 * S, H = 1250 * S; const cv = document.createElement('canvas'); cv.width = W; cv.height = H; const ctx = cv.getContext('2d'); const FONT = 'system-ui, "PingFang SC", "Microsoft YaHei", sans-serif'; const NAVY = '#0b2545', ACCENT = '#2a78d6', GRAY = '#52514e', LIGHT = '#898781'; // 背景 const bg = ctx.createLinearGradient(0, 0, 0, H); bg.addColorStop(0, '#eef4fd'); bg.addColorStop(1, '#dce8f8'); ctx.fillStyle = bg; ctx.fillRect(0, 0, W, H); ctx.fillStyle = 'rgba(42,120,214,0.08)'; ctx.beginPath(); ctx.arc(W - 60 * S, 90 * S, 140 * S, 0, 7); ctx.fill(); ctx.beginPath(); ctx.arc(40 * S, H - 120 * S, 110 * S, 0, 7); ctx.fill(); // 标题 ctx.textAlign = 'center'; ctx.fillStyle = NAVY; ctx.font = `800 ${44 * S}px ${FONT}`; ctx.fillText('简历医生 +', W / 2, 86 * S); ctx.fillStyle = GRAY; ctx.font = `${22 * S}px ${FONT}`; const today = new Date(); ctx.fillText(`我的 AI 简历诊断报告 · ${today.getMonth() + 1} 月 ${today.getDate()} 日`, W / 2, 124 * S); // 主卡片 ctx.save(); ctx.shadowColor = 'rgba(42,120,214,0.28)'; ctx.shadowBlur = 30 * S; ctx.shadowOffsetY = 10 * S; ctx.fillStyle = '#ffffff'; rrect(ctx, 40 * S, 156 * S, 670 * S, 682 * S, 26 * S); ctx.fill(); ctx.restore(); // 分数 ctx.fillStyle = GRAY; ctx.font = `${24 * S}px ${FONT}`; ctx.fillText('综合匹配度', W / 2, 226 * S); ctx.fillStyle = NAVY; ctx.font = `800 ${128 * S}px ${FONT}`; ctx.fillText(String(d.score), W / 2 - 30 * S, 356 * S); ctx.fillStyle = LIGHT; ctx.font = `${28 * S}px ${FONT}`; ctx.textAlign = 'left'; ctx.fillText('/100', W / 2 + 40 * S, 356 * S); ctx.textAlign = 'center'; // 评级胶囊 const bandInfo = d.score >= 80 ? ['✓ 可直接投递', '#0ca30c', 'rgba(12,163,12,0.12)'] : d.score >= 65 ? ['△ 小幅打磨后投递', '#8a6200', 'rgba(250,178,25,0.18)'] : d.score >= 45 ? ['⚠ 建议优化后再投', '#c05621', 'rgba(236,131,90,0.18)'] : ['✕ 需要大幅修改', '#d03b3b', 'rgba(208,59,59,0.12)']; ctx.font = `700 ${26 * S}px ${FONT}`; const bw = ctx.measureText(bandInfo[0]).width + 56 * S; ctx.fillStyle = bandInfo[2]; rrect(ctx, (W - bw) / 2, 388 * S, bw, 52 * S, 26 * S); ctx.fill(); ctx.fillStyle = bandInfo[1]; ctx.fillText(bandInfo[0], W / 2, 424 * S); // 五维评分条 const dims = d.dimensions || []; let dy = 484 * S; ctx.textAlign = 'left'; for (const dim of dims) { ctx.fillStyle = GRAY; ctx.font = `${22 * S}px ${FONT}`; ctx.fillText(dim.name, 84 * S, dy + 8 * S); const bx = 236 * S, bwidth = 330 * S; ctx.fillStyle = '#dce8f8'; rrect(ctx, bx, dy - 10 * S, bwidth, 20 * S, 10 * S); ctx.fill(); ctx.fillStyle = ACCENT; const fw = Math.max(0.04, Math.min(1, dim.score / 100)) * bwidth; rrect(ctx, bx, dy - 10 * S, fw, 20 * S, 10 * S); ctx.fill(); ctx.fillStyle = NAVY; ctx.font = `700 ${24 * S}px ${FONT}`; ctx.fillText(String(dim.score), bx + bwidth + 24 * S, dy + 9 * S); dy += 50 * S; } // 总评(截断 3 行) ctx.fillStyle = GRAY; ctx.font = `${20 * S}px ${FONT}`; const vlines = wrapText(ctx, d.verdict || '', 600 * S, 3); let vy = dy + 24 * S; for (const line of vlines) { ctx.fillText(line, 78 * S, vy); vy += 32 * S; } // 底部二维码卡片 ctx.save(); ctx.shadowColor = 'rgba(42,120,214,0.25)'; ctx.shadowBlur = 26 * S; ctx.shadowOffsetY = 8 * S; ctx.fillStyle = '#ffffff'; rrect(ctx, 40 * S, 852 * S, 670 * S, 300 * S, 26 * S); ctx.fill(); ctx.restore(); const qr = new Image(); await new Promise((res, rej) => { qr.onload = res; qr.onerror = rej; qr.src = 'data:image/png;base64,' + QR_B64; }); ctx.drawImage(qr, 76 * S, 884 * S, 236 * S, 236 * S); ctx.textAlign = 'left'; ctx.fillStyle = NAVY; ctx.font = `800 ${34 * S}px ${FONT}`; ctx.fillText('扫码免费诊断你的简历', 344 * S, 948 * S); ctx.fillStyle = GRAY; ctx.font = `${22 * S}px ${FONT}`; ctx.fillText('30 秒生成报告 · 一键改简历', 344 * S, 994 * S); ctx.fillText('无广告 · 不存储简历内容', 344 * S, 1030 * S); ctx.fillStyle = ACCENT; ctx.font = `700 ${24 * S}px ${FONT}`; ctx.fillText('520resume-doctor.online', 344 * S, 1080 * S); // 页脚 ctx.textAlign = 'center'; ctx.fillStyle = LIGHT; ctx.font = `${20 * S}px ${FONT}`; ctx.fillText('AI 帮你找出简历的"病",别再无效海投了', W / 2, 1204 * S); return cv.toDataURL('image/png'); } $('poster-btn').addEventListener('click', async () => { const btn = $('poster-btn'); btn.disabled = true; const orig = btn.textContent; btn.textContent = '生成中…'; try { const url = await buildPoster(); if (!url) throw new Error('请先完成一次诊断'); $('poster-img').src = url; $('poster-modal').style.display = 'block'; } catch (e) { alert(e.message || '海报生成失败,请重试。'); } finally { btn.disabled = false; btn.textContent = orig; } }); $('poster-close').addEventListener('click', () => { $('poster-modal').style.display = 'none'; }); $('poster-modal').addEventListener('click', (e) => { if (e.target === $('poster-modal')) $('poster-modal').style.display = 'none'; }); $('poster-download').addEventListener('click', () => { const a = document.createElement('a'); a.href = $('poster-img').src; a.download = '我的简历诊断海报.png'; a.click(); }); /* Anonymous visitor identifier */ const VISITOR_ID_KEY = 'rd_visitor_id'; const VISITOR_ID_PATTERN = /^rd_[a-f0-9]{32}$/; function makeVisitorId() { if (window.crypto && typeof window.crypto.randomUUID === 'function') return 'rd_' + window.crypto.randomUUID().replace(/-/g, ''); const b = new Uint8Array(16); if (window.crypto && typeof window.crypto.getRandomValues === 'function') { window.crypto.getRandomValues(b); return 'rd_' + Array.from(b, n => n.toString(16).padStart(2, '0')).join(''); } return 'rd_' + Array.from({ length: 32 }, () => Math.floor(Math.random() * 16).toString(16)).join(''); } function getVisitorId() { try { const v = localStorage.getItem(VISITOR_ID_KEY) || ''; if (VISITOR_ID_PATTERN.test(v)) return v; const created = makeVisitorId(); localStorage.setItem(VISITOR_ID_KEY, created); return created; } catch { return makeVisitorId(); } } const visitorId = getVisitorId(); function apiHeaders() { return { 'Content-Type': 'application/json', 'X-Visitor-Id': visitorId }; } /* ================= 公开统计 ================= */ fetch('/api/stats').then(r => r.json()).then(s => { if (s && s.analyses > 0) { $('stats-line').textContent = `已有 ${s.visitors || 0} 位求职者在这里完成了 ${s.analyses} 次诊断`; } }).catch(() => {}); /* ================= 诊断 ================= */ async function runAnalysis() { $('input-panel').style.display = 'none'; $('loading').style.display = 'block'; try { const resp = await fetch('/api/analyze', { method: 'POST', headers: apiHeaders(), body: JSON.stringify(lastInput) }); const data = await resp.json().catch(() => ({})); if (!resp.ok) throw new Error(data.error || `分析服务暂时不可用 (HTTP ${resp.status}),请稍后重试。`); renderReport(data); } catch (err) { showError(err.message === 'Failed to fetch' ? '无法连接分析服务。如果你在本地直接打开了 HTML 文件,请先部署或启动本地服务;也可以点击"查看演示报告"体验效果。' : err.message); } } /* 读取并校验主页输入,写入 lastInput;返回 {resume, jd} 或 null */ function readHomeInputs() { const resume = $('resume').value.trim(); const jd = $('jd').value.trim(); const { company, jobTitle } = currentTarget(); $('error').style.display = 'none'; if (resume.length > MAX_LEN || jd.length > MAX_LEN) { showError('内容超过 8000 字上限,请精简后重试。'); return null; } lastInput = { resume, jd, company, jobTitle }; return lastInput; } $('analyze-btn').addEventListener('click', () => { const resume = $('resume').value.trim(); const jd = $('jd').value.trim(); const { company, jobTitle } = currentTarget(); $('error').style.display = 'none'; if (resume.length < 50) return showError('简历内容太短了(至少 50 字),请粘贴完整的简历文本;想先看看效果可以点"查看演示"。'); if (resume.length > MAX_LEN || jd.length > MAX_LEN) return showError('内容超过 8000 字上限,请精简后重试。'); lastInput = { resume, jd, company, jobTitle }; runAnalysis(); }); /* 主页入口·直接改写 + 选模板(留空则进演示) */ $('rewrite-direct-btn').addEventListener('click', () => { const v = readHomeInputs(); if (!v) return; doRewrite(); }); /* 主页入口·模拟面试题(留空则进演示) */ $('interview-btn').addEventListener('click', () => { const v = readHomeInputs(); if (!v) return; doInterview(); }); /* 首页功能卡点击 = 触发对应入口按钮 */ document.querySelectorAll('.feat-card[data-act]').forEach(card => { card.addEventListener('click', () => { window.scrollTo({ top: 0, behavior: 'smooth' }); const btn = $(card.dataset.act); if (btn) setTimeout(() => btn.click(), 350); }); }); renderAuthStatus(); /* ================= 事件 ================= */ $('demo-btn').addEventListener('click', () => { prevScore = null; lastInput = { resume: '', jd: '' }; renderReport(DEMO_DATA); }); /* 首页营销区底部 CTA:回到顶部并聚焦简历输入框 */ $('cta-top-btn').addEventListener('click', () => { window.scrollTo({ top: 0, behavior: 'smooth' }); setTimeout(() => $('resume').focus(), 400); }); $('back-btn').addEventListener('click', () => { /* 新增·功能1:离开报告去"再测一次"前,记住本次分数,下次出报告时对比 */ prevScore = lastReport ? lastReport.score : null; $('report').style.display = 'none'; $('rewrite-view').style.display = 'none'; $('input-panel').style.display = 'block'; window.scrollTo({ top: 0 }); });