最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

接入DeepSeek大模型?全流程一次给你讲的明明白白

网站源码admin2浏览0评论

接入DeepSeek大模型?全流程一次给你讲的明明白白

第三方接口

去哪找大模型接口,这个这里不谈。

但你可以去硅基流动,有免费额度。

你注册了,我也有点免费额度。

你好,我好,大家好。

注册地址:

免费额度够用一段时间。

下面进入正题。

整体流程

从前端到后端流程如下:

  1. 前端使用Vue 3+Element Plus+Element Plus X;
  2. 中间使用Nginx进行反向代理(这个地方略有小坑);
  3. 后端使用Java调用大模型接口.

下面倒着来,从后端到前端.

Java后端调用DeepSeek接口

前置条件,先去申请一个大模型的KEY(此处以硅基流动为例)。

AIChatMessage(接收消息,就一个属性):

代码语言:javascript代码运行次数:0运行复制
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
 * AI消息
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class AIChatMessage {
  private String content;
}

AIChatController(处理并返回请求):

此处请求返回时,会区分thinking和result。

thinking是思考过程,result是结果。

后面前端例子的时候会讲到。

代码语言:javascript代码运行次数:0运行复制
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.URI;
import java.http.HttpClient;
import java.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
/**
 * AI接口.
 *
 */
@RestController
@RequestMapping("/ai-chat")
@Slf4j
public class AIChatController {
  // 接口调用地址: / (硅基流动)
  @Value("${ai.base-url}")
  private String baseUrl;
  // 接口调用key(用你自己申请的)
  @Value("${ai.key}")
  private String key;
  /**
   * AI分析
   *
   * @return 结果
   */
  @PostMapping(value = "/chat-flux", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
  public SseEmitter aiAnalysisStream(@RequestBody AIChatMessage aiChatMessage) {
    if (aiChatMessage == null || !StringUtils.hasText(aiChatMessage.getContent())) {
      return null;
    }
    SseEmitter emitter = new SseEmitter(600_000L);
    HttpClient client = HttpClient.newHttpClient();
    Map<String, Object> data = new HashMap<>();
    data.put("model", "deepseek-ai/DeepSeek-R1");
    data.put("max_tokens", 15000);
    data.put("temperature", 0.7);
    data.put("stream", true);
    List<Map<String, String>> messages = new ArrayList<>();
    Map<String, String> userMessage = new HashMap<>();
    userMessage.put("role", "user");
    userMessage.put("content", aiChatMessage.getContent());
    messages.add(userMessage);
    data.put("messages", messages);
    java.http.HttpRequest request =
            java.http.HttpRequest.newBuilder()
                    .uri(URI.create(baseUrl + "v1/chat/completions"))
                    .header("Authorization", "Bearer " + key)
                    .header("Content-Type", "application/json")
                    .timeout(Duration.ofMinutes(10))
                    .POST(java.http.HttpRequest.BodyPublishers.ofString(JSONUtil.toJsonStr(data)))
                    .build();
    CompletableFuture.runAsync(() -> {
      try {
        client.sendAsync(request, HttpResponse.BodyHandlers.ofInputStream())
                .thenAccept(response -> {
                  try (InputStream bodyStream = response.body()) {
                    BufferedReader reader = new BufferedReader(
                            new InputStreamReader(bodyStream, StandardCharsets.UTF_8));
                    String line;
                    while ((line = reader.readLine()) != null) {
                      if (line.startsWith("data: ")) {
                        String jsonStr = line.substring(5).trim().replaceAll("\n", "");
                        if ("[DONE]".equalsIgnoreCase(jsonStr)) {
                          emitterplete();
                          return;
                        }
                        JSONObject json = JSONUtil.parseObj(jsonStr);
                        String reasoning = json.getByPath("choices[0].delta.reasoning_content", String.class);
                        if (StringUtils.hasText(reasoning)) {
                          emitter.send(SseEmitter.event()
                                  .name("thinking")
                                  .data(reasoning)
                                  .id(UUID.randomUUID().toString()));
                        }
                        String content = json.getByPath("choices[0].delta.content", String.class);
                        if (StringUtils.hasText(content)) {
                          emitter.send(SseEmitter.event()
                                  .name("result")
                                  .data(content)
                                  .id(UUID.randomUUID().toString()));
                        }
                      }
                    }
                  } catch (Exception e) {
                    emitterpleteWithError(e);
                  }
                });
      } catch (Exception ex) {
        emitterpleteWithError(ex);
      }
    });
    return emitter;
  }
}

Nginx反向代理配置

按照下面这个配置,后台接口可以正常返回推理过程。

代码语言:javascript代码运行次数:0运行复制
location /ai-service/ai-chat/ {
    add_header X-XSS-Protection "1;mode=block";
    add_header X-Frame-Options DENY;
    add_header X-Content-Type-Options nosniff;
    proxy_buffering off;           
    proxy_cache off;              
    proxy_set_header Connection ''; 
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $host;
    proxy_set_header X-Scheme $scheme;
    proxy_ssl_session_reuse on;
    proxy_redirect off;
    proxy_http_version 1.1;
    proxy_ignore_client_abort on;
    proxy_connect_timeout 86400s;
    proxy_read_timeout 86400s;
    proxy_send_timeout 86400s;
    proxy_pass http://127.0.0.1:8089/ai-chat/;
}

前端配置

先安装好Element Plus,然后再继续下面的步骤。

安装:

代码语言:javascript代码运行次数:0运行复制
npm install vue-element-plus-x
npm install @microsoft/fetch-event-source

在main.js或者main.ts中配置:

代码语言:javascript代码运行次数:0运行复制
// 导入
import ElementPlusX from 'vue-element-plus-x'
// 引用
app.use(ElementPlusX)

在页面中使用,假设页面名称是AIChat.vue:

代码语言:javascript代码运行次数:0运行复制
<template>
  <div class="content">
<div>
	  <Thinking v-model="state.thinkOpenStatus" :content="state.aiAnalysisThinkContent"
	            :status="state.thinkStatus"
	            auto-collapse
	            button-width="250px"
	            max-width="100%"
	  />
</div>
<div>
	  <Typewriter :content="state.aiAnalysisContent" :is-markdown="true" typing/>
</div>
   </div>
</template>
<script lang="ts" setup>
import {fetchEventSource} from "@microsoft/fetch-event-source";
const state = reactive({
  aiAnalysisContent: '',
  thinkOpenStatus: true,
  thinkStatus: 'start',
  aiAnalysisThinkContent: '',
 })	
const aiAnalysis = async()=>{
await fetchEventSource(
		  // 换成你自己的接口地址.
          `http://localhost:8081/ai-service/ai-chat/chat-flux`,
          {
            method: 'POST',
            headers: {
              'Content-Type': 'application/json',
            },
            body: JSON.stringify({content: "你是谁?"}),
            openWhenHidden: true,
            onmessage: function (response) {
              try {
                const data = response.data;
                console.log(data)
                if (response.event === "thinking") {
                  if (state.thinkStatus != 'thinking') {
                    state.thinkStatus = 'thinking';
                  }
                  state.aiAnalysisThinkContent += data;
                }
                if (response.event === "result") {
                  if (state.thinkStatus != 'end') {
                    state.thinkStatus = 'end';
                  }
                  state.aiAnalysisContent += data;
                }
              } catch (e) {
                if (state.thinkStatus != 'error') {
                  state.thinkStatus = 'error';
                }
                let chunk = response.data;
                if (chunk.includes('<tool_response>')) {
                  thinkFlag = false;
                }
                if (!(chunk.includes('<tool_response>') || chunk.includes('</think>'))) {
                  if (!thinkFlag) {
                    state.aiAnalysisContent += chunk;
                  } else {
                    state.aiAnalysisThinkContent += chunk;
                  }
                }
              }
            },
            onerror: (err) => {
              console.error('SSE连接异常:', err);
            }
          }
      )
}
</script>

搞定,效果看着还行。

写代码累了,玩会游戏

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。原始发表:2025-04-28,如有侵权请联系 cloudcommunity@tencent 删除配置前端DeepSeek接口模型
发布评论

评论列表(0)

  1. 暂无评论