news 2026/9/11 4:33:00

Resume-Matcher 前端 API 客户端层全解析:从 API Base 到 LLM 配置与看板追踪

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Resume-Matcher 前端 API 客户端层全解析:从 API Base 到 LLM 配置与看板追踪

Resume-Matcher 前端 API 客户端层全解析:从 API Base 到 LLM 配置与看板追踪

【免费下载链接】Resume-MatcherThe #1 AI Harness for Building Resumes, PDFs, Cover Letters & more, locally with 100+ LLMs support.项目地址: https://gitcode.com/GitHub_Trending/re/Resume-Matcher

本文基于 docs/agent/apis/front-end-apis.md 撰写,围绕 Resume-Matcher 前端lib/api/*客户端层展开。Resume-Matcher 是一套本地运行的 AI 简历构建工具(支持简历上传、PDF 生成、求职信与 100+ LLM 接入),本文通过阅读 apps/frontend/lib/api/ 下client.tsresume.tsresume-wizard.tstracker.tsconfig.ts的实际源码,并结合 apps/backend/app/routers/ 中resumes.pyresume_wizard.pyapplications.pyconfig.py的后端实现,完整拆解前端 API 层的模块划分、请求封装、超时策略、错误处理与调用约定。读完本文,你将能熟练定位任何前端功能对应的 API 函数、理解其请求路径与后端行为,并掌握自定义调用(如直接请求 PDF、批量更新看板卡片)的正确姿势。

一、客户端层整体架构:单一入口,统一导出

前端 API 层集中在 apps/frontend/lib/api/ 目录,按业务域拆分为五个模块,并通过 apps/frontend/lib/api/index.ts 统一导出:

模块文件业务域核心导出
client.ts基础客户端API_URLAPI_BASEapiFetchapiPostapiPatchapiPutapiDeletegetUploadUrlDEFAULT_TIMEOUT_MS
resume.ts简历操作uploadJobDescriptionsimproveResumepreviewImproveResumeconfirmImproveResumefetchResumefetchResumeListupdateResumedeleteResumedownloadResumePdfdownloadCoverLetterPdf及各类生成函数
resume-wizard.ts简历向导postResumeWizardTurnfinalizeResumeWizardcreateInitialResumeWizardState及状态类型
tracker.ts求职追踪看板listApplicationscreateApplicationgetApplicationDetailupdateApplicationbulkUpdateStatusdeleteApplicationbulkDeleteApplications
config.ts配置中心fetchLlmConfigupdateLlmConfigtestLlmConnectionfetchSystemStatus、API Keys 管理、Feature Flags、语言与 Prompt 配置、PROVIDER_INFO

index.ts的导出清单可以看到,它还额外导出了previewImproveResumeconfirmImproveResume(改进预览与确认)、fetchPromptConfigupdatePromptConfig等原文档未展开的函数,这些会在后文结合源码逐一说明。index.ts同时导出了全部 TypeScript 类型(如ResumeListItemLLMConfigSystemStatusResumeWizardState),组件层只需import { fetchResume, API_BASE, PROVIDER_INFO } from '@/lib/api'一条语句即可按需取用。

二、Base Client:请求基座的三个关键设计

2.1 API 地址解析:默认同源代理,支持外部后端

apps/frontend/lib/api/client.ts 定义了 API 地址的完整解析链路:

const DEFAULT_PUBLIC_API_URL = '/'; const INTERNAL_API_ORIGIN = 'http://127.0.0.1:8000'; export const API_URL = normalizeApiUrl(process.env.NEXT_PUBLIC_API_URL ?? DEFAULT_PUBLIC_API_URL); export const API_BASE = resolveRuntimeApiBase(toApiBase(API_URL));

解析规则可以归纳为三层:

  1. 默认值NEXT_PUBLIC_API_URL未设置时回退为/(同源部署,由 Next.js 反向代理到后端);
  2. 规范化normalizeApiUrl会去掉末尾斜杠,空串或/保持原样,避免拼接出//api/v1这类脏路径;
  3. 运行时修正resolveRuntimeApiBase服务端渲染(SSR)场景下(typeof window === 'undefined'且路径以/开头)自动补全为http://127.0.0.1:8000,保证服务端组件同样能访问后端;浏览器端则直接使用相对路径。

最终API_BASE形如/api/v1(同源)或http://localhost:8000/api/v1(显式配置外部后端),所有业务请求都拼在API_BASE之后。

2.2 三层超时联动机制:一个环境变量驱动全局

client.ts中有一段非常值得注意的超时设计(apps/frontend/lib/api/client.ts):

const rawTimeoutMs = process.env.NEXT_PUBLIC_REQUEST_TIMEOUT_MS; const parsedTimeoutMs = rawTimeoutMs ? Number(rawTimeoutMs) : NaN; export const DEFAULT_TIMEOUT_MS = Number.isFinite(parsedTimeoutMs) ? Math.min(1_800_000, Math.max(30_000, parsedTimeoutMs)) : 240_000;

代码注释明确说明:DEFAULT_TIMEOUT_MS必须与后端REQUEST_TIMEOUT_SECONDS(见 apps/backend/app/config.py)以及 Next.js 的proxyTimeout(见 apps/frontend/next.config.ts)保持一致——三层中先到时的层会先中止请求,所以三者的取值统一由同一个NEXT_PUBLIC_REQUEST_TIMEOUT_MS驱动。默认值 240 秒(4 分钟),并通过Math.min(1_800_000, Math.max(30_000, ...))夹在 30 秒到 30 分钟之间。注释特别提醒:本地 LLM(如 Ollama)生成简历通常很慢,240 秒默认值常常不够,需要调大该变量并同步后端REQUEST_TIMEOUT_SECONDS

2.3 标准 fetch 封装与超时中止

apiFetch(apps/frontend/lib/api/client.ts)是唯一真正发请求的函数:

  • 端点路径以/开头时自动与API_BASE拼接;传入绝对 URL(http(s)://)或/api/开头的路径时则直接使用原值(后一种情况再次经过resolveRuntimeApiBase,保证 SSR 下仍能命中127.0.0.1:8000);
  • 使用AbortController实现超时中止,超时后抛出带诊断提示的错误:"如果运行本地 LLM,请增大NEXT_PUBLIC_REQUEST_TIMEOUT_MS(并同步后端REQUEST_TIMEOUT_SECONDS)";
  • apiPost<T>apiPatch<T>apiPut<T>apiDelete是基于apiFetch的语义化薄封装,自动设置Content-Type: application/json并序列化 body(apiPost额外支持透传timeoutMs,供长耗时调用覆盖默认超时);
  • getUploadUrl()返回${API_BASE}/resumes/upload,供文件上传(multipart/form-data)使用。

需要指出的是,apiFetch采用返回Response而非解析后的 JSON的约定,各业务模块(如postImprove)在拿到Response后自行判断res.ok、读取错误体并抛出自定义错误,这也是错误信息能携带后端detail文本的原因。

三、Resume Operations:简历全生命周期 API

apps/frontend/lib/api/resume.ts 是最大的一块,覆盖 JD 上传、定制化改进、CRUD、PDF 下载与按需内容生成。

3.1 JD 上传与改进管线(upload → improve)

  • uploadJobDescriptions(descriptions: string[], resumeId)POST /api/v1/jobs/upload,body 为{ job_descriptions, resume_id },从响应中取data.job_id[0]返回单个job_id
  • improveResume(resumeId, jobId, promptId?)POST /resumes/improve,body 为{ resume_id, job_id, prompt_id },返回完整的ImprovedResult(含改进后的简历数据、逐条 diff 说明等);
  • previewImproveResume(resumeId, jobId, promptId?)POST /resumes/improve/preview——预览模式不落库,返回resume_id: null,供用户确认前对比;
  • confirmImproveResume(payload)POST /resumes/improve/confirm,提交{ resume_id, job_id, improved_data, improvements },把用户确认后的改进结果正式保存为定制版简历。

三个函数都经由私有postImprove走统一错误路径(apps/frontend/lib/api/resume.ts):显式传入DEFAULT_TIMEOUT_MS(改进调用可能很慢)、失败时打印响应体、成功时JSON.parse结果。源码注释表明这条路径对应 issue #776——让NEXT_PUBLIC_REQUEST_TIMEOUT_MS真正作用于耗时的 improve/preview/confirm 调用。

后端对应实现位于 apps/backend/app/routers/resumes.py:improve/preview使用asyncio.wait_for包裹整个改进流程,超时返回 504 并给出同样指向REQUEST_TIMEOUT_SECONDS的提示(resumes.py)。从后端流程可以看到,preview内部执行的是基于 diff 的改进:先generate_skill_target_plan生成技能目标计划并校验,再generate_resume_diffs产出逐条改动、apply_diffs应用并verify_diff_result验证;随后还有一组防御性的安全网——_preserve_personal_info(个人联系方式强制保留原值)、_restore_original_dates(恢复 LLM 可能截断的月份日期)、_preserve_original_skills(技能/证书/语言/奖项绝不允许丢失)、_protect_custom_sections(防自定义段落幻觉)。这些机制解释了为什么预览/确认流程需要完整的improvements列表回传——后端在confirm时会对personalInfo做逐字段一致性校验(_validate_confirm_payload),确保 LLM 不会篡改联系方式。

3.2 简历 CRUD

  • fetchResume(resumeId)GET /resumes?resume_id=...,返回ResumeResponse['data'],同时携带raw_resume(原始 markdown)与processed_resume(结构化 JSON,若 LLM 解析成功);源码注释提醒:viewer/builder 应优先使用 processed 数据;
  • fetchResumeList(includeMaster = false)GET /resumes/list?include_master=...,默认不包含主简历(master resume),返回按updated_at倒序的ResumeListItem[]
  • updateResume(resumeId, resumeData)PATCH /resumes/{id},把 builder 编辑后的ProcessedResume写回;
  • deleteResume(resumeId)DELETE /resumes/{id}
  • 另外源码还提供了文档未列出的renameResume(resumeId, title)PATCH /resumes/{id}/title)与retryProcessing(resumeId)POST /resumes/{id}/retry-processing,用于重试失败的 LLM 解析)。

3.3 PDF 下载:模板参数如何传递

downloadResumePdf/getResumePdfUrl是最容易用错的函数,因为它把整套模板排版设置序列化成了 URL 查询参数(apps/frontend/lib/api/resume.ts)。getResumePdfUrl(resumeId, settings?, locale?)生成的 URL 形如:

{API_BASE}/resumes/{resume_id}/pdf?template=swiss-single&pageSize=A4&marginTop=...&sectionSpacing=...&lineHeight=...&fontSize=...&accentColor=...&lang=...

关键点:

  • settings时,模板、纸张(pageSize)、四边距(marginTop/Bottom/Left/Right)、段落间距(sectionSpacing)、行距(lineHeight)、字号与页眉缩放(fontSize)、页眉/正文字体、紧凑模式(compactMode)、联系图标开关(showContactIcons)、强调色(accentColor)都会被序列化为参数;
  • 不传settings只发送template=swiss-single&pageSize=A4两个默认参数——也就是说默认模板是swiss-single、默认纸张是 A4;
  • 可选locale追加lang参数,控制 PDF 中的日期/文案本地化。

downloadCoverLetterPdf(resumeId, pageSize = 'A4', locale?){API_BASE}/resumes/{id}/cover-letter/pdfpageSize仅接受'A4' | 'LETTER'。此外源码还提供generateCoverLetterPOST /resumes/{id}/generate-cover-letter)与generateOutreachMessagePOST /resumes/{id}/generate-outreach),它们不返回 Blob 而是返回data.content文本。

3.4 按需生成内容

  • generateInterviewPrep(resumeId)POST /resumes/{id}/generate-interview-prep,响应体为{ interview_prep: InterviewPrepData },函数内已解包,直接返回InterviewPrepData
  • fetchJobDescription(resumeId)GET /resumes/{id}/job-description,返回{ job_id, content },用于在定制简历详情页回显当初使用的 JD。

后端配套的interview_prep在数据库中以 JSON 字符串存储,读取时由_parse_interview_prep反序列化并容错(解析失败返回 null 而不报错,见 resumes.py)。

四、Resume Wizard:AI 引导式问答建简历

resume-wizard.ts封装了一个与上传解析相互独立的简历构建流程:不依赖任何 JD,由 LLM 一次一个问题引导用户填出一份通用主简历。

4.1 状态模型

核心类型(apps/frontend/lib/api/resume-wizard.ts):

  • ResumeWizardSectionintro | contact | summary | workExperience | internships | education | personalProjects | skills | review九个阶段;
  • ResumeWizardStepintro | question | review | complete四步 UI 状态;
  • ResumeWizardActionstart | answer | skip | back | review五种动作;
  • ResumeWizardState:包含stepresume_data(累积的简历草稿)、current_questionhistory(含每次回答前的resume_data_before快照,供回退使用)、asked_countinferred_skills(LLM 推断出的技能)、is_completeprogress{current, total},初始 8 题)、warnings

createInitialResumeWizardState()在本地直接构造初始状态,第一个问题是固定常量INTRO_QUESTION"Hi — I'll help you build your master resume. What's your name, and what kind of role are you going for?"progress.total为 8。

4.2 两个后端端点

  • postResumeWizardTurn(payload)POST /api/v1/resume-wizard/turn,请求体为{ state, action, answer? },响应{ state }——完整状态在请求与响应之间往返。后端行为(apps/backend/app/routers/resume_wizard.py):
    • start直接返回build_initial_wizard_state()
    • back/review走确定性逻辑(apply_back/apply_review),不消耗 LLM 调用
    • answer/skip调用run_ai_turn执行一次 AI 生成,更新resume_data,返回下一个current_questioninferred_skillsis_complete标志;
    • 成本护栏:一旦asked_count >= RESUME_WIZARD_MAX_QUESTIONS(后端常量),answer/skip不再发 LLM 请求,直接转为apply_review
  • finalizeResumeWizard(state)POST /api/v1/resume-wizard/finalize,把草稿落库为主简历。后端用normalize_resume_data规范化数据后,通过create_resume_atomic_master原子创建主简历(标题自动生成为"{姓名} Master Resume");若已存在processing_status == "ready"的主简历则返回409finalize的响应类型ResumeWizardFinalizeResponse承诺processing_status: 'ready'is_master: true

原文档特别强调:向导的问题与内容文本使用配置的 content language 生成,而静态 UI 文案走resumeWizard.*i18n 键(对应 apps/frontend/messages/ 下各语言 JSON)。该流程不依赖 JD、也不取代上传解析器——两种方式最终都汇入主简历体系。

五、Application Tracker:七列看板的 API 约定

apps/frontend/lib/api/tracker.ts 实现求职追踪看板,七个状态列是稳定键(不随 i18n 标签变化):saved | applied | no_response | response | interview | accepted | rejected,顺序常量APPLICATION_STATUS_ORDER与后端APPLICATION_STATUS_ORDER(见 apps/backend/app/routers/applications.py)一一对应。

5.1 单卡片与看板

  • listApplications()GET /applications(注意带credentials: 'include'),返回{ columns: Record<status, Application[]> },后端_group_by_status保证七个键始终存在,未知状态的行被跳过而非让整个看板 500;
  • createApplication(payload)POST /applications,从粘贴的 JD 手动建卡。后端会先create_job,公司/职位缺失时用extract_job_keywords做 best-effort 提取,创建失败时清理孤儿 job(见 applications.py);
  • getApplicationDetail(id)GET /applications/{id},一次往返同时取回内嵌 JD(job_content)与所用简历(resume);简历被删除时返回resume: null而非 500(后端get_application_detail对详情加载全程 try/except);
  • updateApplication(id, payload)PATCH /applications/{id},可更新status/position/notes/company/role/applied_at,后端用model_dump(exclude_unset=True)只更新出现的字段。

5.2 批量操作

  • bulkUpdateStatus(applicationIds, status)PATCH /applications/bulk,body{ application_ids, status },一次移动多张卡到同一列,返回{ message, affected }
  • bulkDeleteApplications(applicationIds)POST /applications/bulk-delete,body{ application_ids }
  • deleteApplication(id)DELETE /applications/{id}

5.3 值得借鉴的错误处理

tracker.ts中的extractDetail(apps/frontend/lib/api/tracker.ts)是一个处理 FastAPI 错误体的通用工具:FastAPI 的HTTPException返回字符串detail,而校验错误返回[{ msg, loc, ... }]数组,extractDetail将两者统一转为可读字符串,并兜底把 dict 形式的detailJSON.stringify——保证错误信息永远不会渲染成 "[object Object]"asJson<T>封装在此基础上统一抛错,可作为前端调用其他 FastAPI 服务的参考模板。

六、Config Operations:配置中心与密钥管理

apps/frontend/lib/api/config.ts 覆盖 LLM 配置、健康检查、API Key 加密存储、功能开关、语言与 Prompt 配置。

6.1 LLM 配置与连接测试

  • fetchLlmConfig()GET /config/llm-api-key(带credentials: 'include'),返回LLMConfig
  • updateLlmConfig(config)PUT /config/llm-api-key
  • testLlmConnection(config?)POST /config/llm-test——可选传入待测试配置(用于保存前预检),不传则测当前存储配置;返回LLMHealthCheck,含healthyerror/error_codewarning/warning_codetest_promptmodel_outputreasoning_content等诊断字段。

6.2 API Key 的加密存储设计(重要变更)

原文档明确标记了一条行为变更updateLlmApiKeyPUT /config/llm-api-key已不再持久化密钥,密钥改为通过加密的按 provider 维度/config/api-keys端点管理。源码印证(config.ts 注释):旧设计把单个api_key槽位写入配置,正是导致不同 provider 互相覆盖、遮蔽 per-provider 密钥表的根因;现在request.api_key仅保留在 schema 中用于响应掩码与向后兼容。

新的密钥 API 一族:

  • fetchApiKeyStatus()GET /config/api-keys,返回{ providers: [{ provider, configured, masked_key }] }masked_key形如sk-a******xxxx(后端_mask_api_key:保留前 4 后 4,中间星号,长度 ≤8 时全星号);
  • updateApiKeys(keys)POST /config/api-keys,可同时更新多个 provider 的密钥,返回{ message, updated_providers }
  • deleteApiKey(provider)DELETE /config/api-keys/{provider}
  • clearAllApiKeys()DELETE /config/api-keys?confirm=CLEAR_ALL_KEYS——清空全部密钥需要显式 confirm 参数,防止误操作;
  • 配套的resetDatabase()POST /config/reset,同样需要{ confirm: 'RESET_ALL_DATA' }

注意两个 provider 命名轴的区别:LLMProvider(活跃 provider)与ApiKeyProvider(密钥存储名)。llmProviderToKeyProvider实现了映射——gemini 的密钥存在google名下gemini → google),其余 provider 直通,与后端_PROVIDER_KEY_MAP保持一致。

6.3 Feature Flags、语言与 Prompt 配置

  • fetchFeatureConfig()/updateFeatureConfig()GET/PUT /config/features,三个布尔开关enable_cover_letterenable_outreach_messageenable_interview_prep,控制定制简历后是否自动生成求职信、外联消息与面试准备内容;
  • fetchLanguageConfig()/updateLanguageConfig()GET/PUT /config/languageSupportedLanguage'en' | 'es' | 'zh' | 'ja' | 'pt' | 'fr'LanguageConfig区分ui_language(界面语言)与content_language(AI 生成内容语言);
  • fetchPromptConfig()/updatePromptConfig()GET/PUT /config/prompts,切换简历改进默认 Prompt(default_prompt_id+ 可用选项列表);
  • fetchFeaturePrompts()/updateFeaturePrompts()GET/PUT /config/feature-prompts,自定义求职信与外联消息 Prompt。这个函数的错误处理最为细致:422 且detail.code === 'missing_placeholders'时抛出专属FeaturePromptsError(携带缺失占位符列表missing: string[],UI 可精确定位缺了哪些 token);其余情况把字符串/dict/缺失三种 detail 形态分别归一为可读消息;成功路径则不吞 JSON 解析错误,避免静默返回字段缺失的对象。

七、Provider Info:受支持 LLM 提供方清单

config.ts中的PROVIDER_INFO是前端渲染 provider 选择器的数据源(apps/frontend/lib/api/config.ts),当前实际源码比原文档多出一个groqopenai_compatible条目:

provider显示名defaultModelrequiresKey
openaiOpenAIgpt-5-nano-2025-08-07true
openai_compatibleOpenAI-Compatible (Local)custom-modelfalse
anthropicAnthropicclaude-haiku-4-5-20251001true
openrouterOpenRouterdeepseek/deepseek-chattrue
geminiGoogle Geminigemini-3-flash-previewtrue
deepseekDeepSeekdeepseek-chattrue
groqGroqllama-3.3-70b-versatiletrue
ollamaOllama (Local)gemma3:4bfalse

几个实现细节:

  • openai_compatible是本地模型接入的关键入口:注释明确它面向 llama.cpp、vLLM、LM Studio 等暴露 OpenAI Chat Completions API 的服务器,密钥可选(后端在空白时发送哨兵值),默认模型名占位custom-model,需配合api_base指向本地端点;
  • requiresKey: false的只有openai_compatibleollama(本地服务无需鉴权);
  • 默认模型均为硬编码常量,实际生效模型以配置为准(后端get_llm_config_endpoint优先读 config 文件,再回退settings.llm_model)。

LLMConfig还包含reasoning_effort字段('minimal' | 'low' | 'medium' | 'high' | null),null表示不发送该参数(最大兼容性);updateLlmConfig中传空串''表示清除,null则被服务器忽略。后端同时做了api_base的空值规范化(config.py):空白字符串被归一为None,避免空端点泄漏给 LiteLLM。

八、Usage:最小调用示例与实战建议

原文档给出的调用方式(docs/agent/apis/front-end-apis.md):

import { fetchResume, API_BASE, PROVIDER_INFO } from '@/lib/api';

基于以上源码分析,可以补充几个实战调用模式:

// 1. 拉取简历列表(排除主简历)并取回详情 const items = await fetchResumeList(); const detail = await fetchResume(items[0].resume_id); const { processed_resume, cover_letter } = detail; // 2. 定制化:上传 JD → 预览改进 → 确认落库 const jobId = await uploadJobDescriptions([jdText], resumeId); const preview = await improveResume(resumeId, jobId); // 或 previewImproveResume 先预览 await confirmImproveResume({ resume_id: resumeId, job_id: jobId, improved_data: preview.resume_data, improvements: preview.improvements }); // 3. 生成 PDF(注意 settings 序列化为查询参数) const blob = await downloadResumePdf(resumeId, templateSettings, 'zh'); const url = URL.createObjectURL(blob); // 4. 看板批量移动 await bulkUpdateStatus([id1, id2], 'interview'); // 5. 本地模型接入:openai_compatible + 自定义 base await updateLlmConfig({ provider: 'openai_compatible', model: 'qwen2.5:7b', api_base: 'http://localhost:1234/v1' }); await updateApiKeys({ openai_compatible: 'sk-local' }); // 本地服务器要求鉴权时

实际使用中的注意事项:

  1. 超时参数三处同步:任何修改NEXT_PUBLIC_REQUEST_TIMEOUT_MS的部署,都必须同步后端REQUEST_TIMEOUT_SECONDS与 apps/frontend/next.config.ts 的proxyTimeout,否则最短的一层会先中止;
  2. SSR 场景API_BASE在服务端自动解析为http://127.0.0.1:8000,因此后端必须监听 8000 端口或调整INTERNAL_API_ORIGIN;若后端部署在其他地址,需通过NEXT_PUBLIC_API_URL显式配置并保持前后端同源/跨域配置一致;
  3. 密钥管理走新端点:新代码一律使用updateApiKeys/fetchApiKeyStatus,不要再依赖updateLlmApiKey持久化密钥;
  4. Provider 命名轴:更新密钥前用llmProviderToKeyProvider(provider)换算存储名(gemini → google);
  5. 看板错误处理:批量操作与卡片更新建议复用extractDetail语义,展示后端detail而非笼统状态码。

九、与前端组件的对应关系

API 层的调用方分布在 apps/frontend/components/ 与 apps/frontend/hooks/:

  • resume.ts服务于 dashboard 的简历列表/上传(apps/frontend/components/dashboard/resume-upload-dialog.tsx)、tailor 定制页(apps/frontend/app/(default)/tailor/page.tsx/tailor/page.tsx))与 PDF 预览(apps/frontend/components/preview/paginated-preview.tsx);
  • resume-wizard.ts被 apps/frontend/hooks/use-enrichment-wizard.ts 及 apps/frontend/components/resume-wizard/resume-wizard-page.tsx 使用,配合live-preview.tsx实现边答边预览;
  • tracker.ts支撑 apps/frontend/components/tracker/kanban-board.tsx 与 apps/frontend/components/tracker/manual-add-application-dialog.tsx;
  • config.ts驱动 apps/frontend/app/(default)/settings/page.tsx/settings/page.tsx) 中的 LLM 配置、密钥管理与语言设置面板。

前端测试对 API 层有完整覆盖(如 apps/frontend/tests/api-client.test.ts、apps/frontend/tests/api-resume.test.ts、apps/frontend/tests/api-tracker.test.ts、apps/frontend/tests/resume-wizard-api.test.ts),后端集成测试则位于 apps/backend/tests/integration/(如test_resume_api.pytest_resume_wizard_api.pytest_tracker_autocreate.pytest_config_api.py),阅读这些测试可以进一步确认各端点的精确请求/响应形状与边界行为(如 409 冲突、404 兜底)。

十、小结

Resume-Matcher 前端 API 层的设计可以总结为四个要点:单一基座client.ts集中管理地址解析、超时与错误)、业务域分模块(resume / resume-wizard / tracker / config 各自封装领域类型与端点)、后端契约驱动(类型定义与 apps/backend/app/schemas/ 的 Pydantic 模型对齐,如ResumeDataApplicationStatus)、安全与可观测并重(密钥加密存储、masked 返回、三层超时联动、结构化错误透传)。无论是接入本地 LLM、扩展看板行为,还是为定制简历增加新的生成内容,lib/api/*都是前端与后端之间的唯一事实入口——理解它,就等于掌握了整个应用的数据流主干。

【免费下载链接】Resume-MatcherThe #1 AI Harness for Building Resumes, PDFs, Cover Letters & more, locally with 100+ LLMs support.项目地址: https://gitcode.com/GitHub_Trending/re/Resume-Matcher

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/11 4:25:26

飞行汽车技术发展现状与未来趋势

1. 飞行汽车技术发展现状与核心挑战飞行汽车作为融合地面行驶与空中飞行能力的下一代交通工具&#xff0c;正在从科幻概念走向工程现实。根据中国汽车工程学会最新研究&#xff0c;全球已有超过200家企业投入飞行汽车研发&#xff0c;其中既包含传统航空巨头波音、空客&#xf…

作者头像 李华
网站建设 2026/9/11 4:25:16

毕业论文写作全流程指南:从选题到答辩

1. 毕业论文写作全景指南刚拿到导师给的选题通知时&#xff0c;我和大多数同学一样两眼发懵。图书馆里那些砖头般的学术专著&#xff0c;知网上密密麻麻的文献&#xff0c;还有导师口中"要有创新性"的要求&#xff0c;都让人头皮发麻。直到经历了开题被毙、中期检查被…

作者头像 李华
网站建设 2026/9/11 4:24:23

Matlab在分布式光伏储能系统优化配置中的应用

1. 分布式光伏储能系统优化配置的核心挑战 在新能源发电领域&#xff0c;光伏系统的规模化应用面临一个关键瓶颈&#xff1a;如何解决发电间歇性与负荷需求持续性的矛盾。我参与过多个光伏电站的设计&#xff0c;发现单纯增加光伏板数量并不能提升系统可靠性&#xff0c;反而可…

作者头像 李华
网站建设 2026/9/11 4:22:00

AI全栈开发实战:从需求到SLA交付的四层能力流水线

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华