如何运用DeepSeek R1构建一款全栈简历筛选应用

译文 精选
人工智能
在本文中,我们将学习如何在个人设备上本地运行开源模型,进而构建一款由React和NodeJS驱动的全栈应用程序。它能帮助大家快速分析简历内容,并做出明智的招聘决策。在构建之前,我们先聊聊开源大模型的优势所在。

译者 | 核子可乐

审校 | 重楼

在本文中,我们将共同了解如何使用DeepSeek R1大模型构建智能简历分析应用,节约运营成本。

DeepSeek开源大模型的发布已经在技术社区引发巨大轰动。如今,开发者们无需接入Claude、ChatGPT等在线AI模型,即可轻松实现本地应用程序构建。换言之,开源大模型准入门槛的持续降低,为企业应用程序与生成式AI的集成打通了机会之桥。

在本文中,我们将学习如何在个人设备上本地运行开源模型,进而构建一款由React和NodeJS驱动的全栈应用程序。它能帮助大家快速分析简历内容,并做出明智的招聘决策。在构建之前,我们先聊聊开源大模型的优势所在。

开源大语言模型的优势

与专有模型相比,开源大模型拥有以下几个关键优势:

经济高效且无需许可证

开源大模型极具成本效益,无需特殊许可证。截至本文撰稿时,OpenAI o1的每百万输出token成本为60美元,而开源DeepSeek R1的成本仅为2.19美元。

可定制、可微调

开源大模型可轻松进行微调以满足独特的业务需求,在更多特定领域支撑业务用例。

增强数据安全性与隐私性

宝贵的个人数据无需被上传至第三方服务器,而仅保留在本地设备或企业网络之内,因此应用程序更加安全。此外,开源模型还可进行微调以消除数据偏差。

社区驱动,摆脱供应商锁定

开源模型享有广泛的社区支持,受益于快速功能开发,也避免了专有模型受供应商锁定、且高度依赖供应商提供功能更新的弊端。

在了解上述背景信息后,下面直奔主题,了解如何使用DeepSeek R1开源模型、Node.js和React构建应用程序。

项目与架构概述

我们的目标是构建一款简历分析器应用,快速把握上传简历中的基本信息与申请者的优缺点。DeepSeek R1大模型负责分析上传的简历并提供反馈。大家可通过下图了解这款应用的基本架构:

架构示意图

用户界面由React开发,通过REST API与基于NodeJS的后端进行通信。之后,NodeJS后端将用户请求发送至由Ollama托管的DeepSeek R1。整个技术栈可在单一设备上运行,亦可跨多个容器托管以支持更复杂的用例。

前期准备

  • 要运行此项目,你需要一台具备一定性能的设备,最好搭载英伟达独立显卡。此项目已在配备英伟达4090RTX的Windows设备和M2 MacBook Pro上通过开发测试。
  • 你还需要在设备上安装NodeJS。本项目使用NodeJS 22.3.0版本,你可使用node -v 命令验证NodeJS的安装情况。
  • 你还需要选定一款编辑器以处理代码。本示例中使用Visual Studio Code,推荐你使用同款工具。

在本地设置并运行DeepSeek

要在本地运行DeepSeek R1,请遵循以下步骤:

  • 从官方网站处(https://ollama.com/)安装Ollama。
  • 安装完成后,即可使用设备终端上的 ollama run 命令运行模型。
  • 运行你选定的DeepSeek模型。本教程中使用DeepSeek R1 8B参数模型。你可使用 ollama run deepseek-r1:8b命令运行该模型。
  • 如果你的硬件规格低于前期准备部分的最低配置,亦可尝试运行7B及1.5B参数模型,但输出质量可能受到影响。
  • 模型首次运行可能须耗费一定时间,特别是下载过程。模型运行之后,你可直接在终端中向其提问并获取输出。你可参考下图查看DeepSeek R1 8B模型的实际运行情况。

Ollama DeepSeek R1

  • DeepSeek R1是一款推理模型,因此会先进行思考、而后开始生成答案。如上图所示,它在给出答案前会列出思考过程,具体细节请参阅 <think> </think>标签。

克隆并运行NodeJS后端

Ollama服务也可通过API访问。你可使用此API并构建基于NodeJS的后端层,由该层获取用户上传的PDF文件并从中提取文本内容。提取完成后,后端将通过Ollama API将文本导入DeepSeek R1模型以获取响应。最终响应结果将发送至客户端并展示给用户。

  • 使用此URL从GitHub克隆后端项目。这里推荐大家分叉该项目,而后克隆出自己的本地副本。
  • 克隆后,要运行此项目,请使用cd deepseek-ollama-backend转至项目根目录。
  • 在根目录内,使用npm install命令安装依赖项。安装完成后,即可使用npm start 命令运行本项目。项目核心为app.js文件,其代码内容如下所示:
const express = require('express');
const multer = require('multer');
const pdfParse = require('pdf-parse');
const axios = require('axios');
const fs = require('fs');
const cors = require('cors');

const app = express();
app.use(cors());
app.use(express.json());

const upload = multer({
    dest: 'uploads/',
    fileFilter: (req, file, cb) => {
        file.mimetype === 'application/pdf' ? cb(null, true) : cb(new Error('Only PDF files are allowed!'));
    }
}).single('pdfFile');

app.post('/analyze-pdf', (req, res) => {
    upload(req, res, async function(err) {
        if (err) {
            return res.status(400).json({ error: 'Upload error', details: err.message });
        }
        try {
            if (!req.file) {
                return res.status(400).json({ error: 'No PDF file uploaded' });
            }

            const dataBuffer = fs.readFileSync(req.file.path);
            const data = await pdfParse(dataBuffer);
            const pdfText = data.text;
            fs.unlinkSync(req.file.path);

            const response = await axios.post('http://127.0.0.1:11434/api/generate', {
                model: "deepseek-r1:8b",
                prompt: `Analyze this resume. Resume text is between two --- given ahead: ---${pdfText}---`,
                stream: false
            });

            res.json({ success: true, message: 'Successfully connected to Ollama', ollamaResponse: response.data });
        } catch (error) {
            if (req.file && fs.existsSync(req.file.path)) {
                fs.unlinkSync(req.file.path);
            }
            res.status(500).json({ error: 'Error processing PDF', details: error.message });
        }
    });
});

if (!fs.existsSync('uploads')) {
    fs.mkdirSync('uploads');
}

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
    console.log(`Server is running on port ${PORT}`);
});
  • 客户端通过调用/analyze-pdfAPI端点与后端交互,此端点为POST类型。客户端将用户上传的pdf文件作为有效载荷发送至该API。
  • 服务器将此文件临时存储在uploads目录中,并提取文件中的文本。
  • 服务器随后使用Oolama的hocalhost API端点向DeepSeek R1传递提示词。
  • DeepSeek R1分析简历内容并提供反馈,而后由服务器使用 res.json().将分析结果响应给客户端。

克隆并运行React用户界面

通过项目的用户界面上传简历,即可将内容发送至后端,而后向用户展示DeepSeek R1的分析结果。其中还将包含DeepSeek R1的思考过程,即内部思维链。

  • 首先,通过此GitHub URL分叉并克隆本项目。如果各位没有定制需求,也可直接克隆。
  • 克隆完成后,使用命令 cd deepseek-ollama-frontend转至项目根目录。
  • 在根目录下,使用npm install 命令安装必要依赖项。安装完成后,使用npm run dev命令启动本项目。
  • 示例React应用的main组件为ResumeAnalyzer,你可在选定的编辑器中打开并进行分析。
import './ResumeAnalyzer.css';
import React, { useState } from 'react';
import { Upload, Loader2 } from 'lucide-react';
import AnalysisSection from './AnalysisSection';

const ResumeAnalyzer = () => {
  const [file, setFile] = useState(null);
  const [loading, setLoading] = useState(false);
  const [feedback, setFeedback] = useState(null);
  const [error, setError] = useState(null);

  const handleFileChange = (event) => {
    const selectedFile = event.target.files?.[0];
    if (selectedFile && selectedFile.type === 'application/pdf') {
      setFile(selectedFile);
      setError(null);
    } else {
      setError('Please upload a PDF file');
      setFile(null);
    }
  };

  const analyzePDF = async () => {
    if (!file) return;

    setLoading(true);
    setError(null);

    try {
      const formData = new FormData();
      formData.append('pdfFile', file);

      const response = await fetch('http://localhost:3000/analyze-pdf', {
        method: 'POST',
        body: formData,
      });

      if (!response.ok) {
        const errorData = await response.json();
        throw new Error(errorData.details || 'Failed to analyze PDF');
      }

      const data = await response.json();
      setFeedback(data);
    } catch (err) {
      setError(err.message || 'An error occurred');
    } finally {
      setLoading(false);
    }
  };

  return (
    <div className="max-w-4xl mx-auto p-4">
      <div className="bg-gray-50 rounded-lg shadow-lg p-6">
        <h1 className="text-3xl font-bold mb-6 text-gray-800">Resume Analyzer</h1>

        <div className="bg-white rounded-lg shadow-sm p-8">
          <div className="border-2 border-dashed border-gray-300 rounded-lg p-8 text-center">
            <Upload className="w-12 h-12 text-gray-400 mx-auto mb-4" />
            <input
              type="file"
              accept=".pdf"
              onChange={handleFileChange}
              className="hidden"
              id="file-upload"
            />
            <label
              htmlFor="file-upload"
              className="cursor-pointer text-blue-600 hover:text-blue-800 font-medium"
            >
              Upload Resume (PDF)
            </label>
            {file && (
              <p className="mt-2 text-sm text-gray-600">
                Selected: {file.name}
              </p>
            )}
          </div>
        </div>

        {error && (
          <div className="mt-4 p-4 bg-red-50 text-red-700 rounded-lg border border-red-200">
            {error}
          </div>
        )}

        <button
          onClick={analyzePDF}
          disabled={!file || loading}
          className="mt-6 w-full bg-blue-600 text-white py-3 px-4 rounded-lg hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center font-medium transition-colors"
        >
          {loading ? (
            <>
              <Loader2 className="mr-2 h-5 w-5 animate-spin" />
              Analyzing Resume...
            </>
          ) : (
            'Analyze Resume'
          )}
        </button>

        {feedback && !loading && (
          <div className="mt-8">
            <h2 className="text-2xl font-bold mb-6 text-gray-800">Analysis Results</h2>
            {feedback.ollamaResponse && 
              <AnalysisSection ollamaResponse={feedback.ollamaResponse} />
            }
          </div>
        )}
      </div>
    </div>
  );
};

export default ResumeAnalyzer;
  • 此组件负责为用户提供输入字段以上传文件。
  • 使用API端点将上传的文件发送至服务器。
  • 服务器的响应结果分为两部分——模型的内部思维链与模型的实际响应内容。
  • 其中 AnalysisSection 组件用于显示DeepSeek R1的实际响应结果,ExpandableSection组件则用于显示模型的内部思维过程。

在浏览器中导航至URL以加载示例应用。之后即可上传任意简历并观察DeepSeek R1生成的分析结果。

Resume Analyzer截屏

总结

DeepSeek R1让我们拥有了以纯本地方式构建生成式AI驱动应用的能力,并可根据实际需求进行灵活自定义。

在本文中,我们使用DeepSeek R1、Node.js与React构建起一款具备实用价值的应用程序,可完全离线使用并依托AI实现简历分析。欢迎大家按照本文分享的流程探索更多用例和设计思路。

原文标题:Building a Full-Stack Resume Screening Application With AI,作者:Anujkumarsinh Donvir

责任编辑:姜华 来源: 51CTO内容精选
相关推荐

2025-01-27 12:30:07

2025-02-07 13:10:06

2022-02-12 00:00:00

架构

2025-01-16 14:11:55

开发框架LikeAdmin

2025-02-03 06:00:00

2018-10-15 10:22:51

2015-11-27 09:18:11

AngularJSWeb应用

2025-02-06 09:28:00

2012-04-28 10:57:27

Metro UI

2023-02-17 18:00:06

AI应用前端

2025-02-03 12:07:52

2025-02-03 00:00:55

DeepSeekRAG系统

2011-09-16 17:00:19

iOS应用Camera Geni

2017-03-06 11:02:59

产品软件Power Desig

2016-11-16 10:29:27

LinuxVR

2011-09-19 10:56:21

IOS应用Frenzapp Mu音乐

2014-12-16 10:11:22

2023-07-03 08:25:54

2021-04-11 07:33:03

开发Vue技术栈js

2011-09-16 15:05:26

IOS应用Trover定位发现
点赞
收藏

51CTO技术栈公众号