希望大家一起能参与我的新开源项目nbmade-boot: 宁波智能制造低代码实训平台
下面简单介绍调用最近大红的AI :deepseek的api过程与显示,包括前后端代码与效果图
一、后端代码
1、几个基础的java类
DeepSeekRequest .java
package com.nbcio.demo.domain;
import java.util.List;
import lombok.Data;
@Data
public class DeepSeekRequest {
private String model;
private List<Message> messages;
@Data
public static class Message {
private String role;
private String content;
}
}
DeepSeekResponse.java
package com.nbcio.demo.domain;
import java.util.List;
import com.nbcio.demo.domain.DeepSeekRequest.Message;
import lombok.Data;
@Data
public class DeepSeekResponse {
private List<Choice> choices;
@Data
public static class Choice {
private Message message;
}
}
HttpClientSingleton.java
package com.nbcio.demo.utils;
import java.util.concurrent.TimeUnit;
import okhttp3.OkHttpClient;
public class HttpClientSingleton {
private static OkHttpClient client;
public static OkHttpClient getClient() {
if (client == null) {
client = new OkHttpClient.Builder()
.connectTimeout(300, TimeUnit.SECONDS)
.writeTimeout(300, TimeUnit.SECONDS)
.readTimeout(300, TimeUnit.SECONDS)
.build();
}
return client;
}
}
2、DeepSeekController.java接口类
package com.nbcio.demo.controller;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.nbcio.common.core.domain.R;
import com.nbcio.demo.domain.DeepSeekRequest;
import com.nbcio.demo.service.IDeepSeekService;
/**
* deepseek api 演示案例
*
* @author nbacheng
*/
@RequiredArgsConstructor
@RestController
@RequestMapping("/demo/deepseek")
public class DeepSeekController {
private final IDeepSeekService deepSeekService;
@PostMapping("/chat")
public R<?> chat(@RequestBody DeepSeekRequest request) {
try {
String response = deepSeekService.callDeepSeekAPI(request);
return R.ok(response);
} catch (Exception e) {
return R.fail("API调用失败: " + e.getMessage());
}
}
}
3、DeepSeekServiceImpl.java实现类
package com.nbcio.demo.service.impl;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import com.google.gson.Gson;
import com.nbcio.demo.domain.DeepSeekRequest;
import com.nbcio.demo.service.IDeepSeekService;
import com.nbcio.demo.utils.HttpClientSingleton;
import lombok.RequiredArgsConstructor;
import okhttp3.*;
import java.io.IOException;
@Service
@RequiredArgsConstructor
public class DeepSeekServiceImpl implements IDeepSeekService {
@Value("${deepseek.api.key}")
private String apiKey;
@Value("${deepseek.api.url}")
private String apiUrl;
public String callDeepSeekAPI(DeepSeekRequest request) throws IOException {
OkHttpClient client = HttpClientSingleton.getClient();
MediaType mediaType = MediaType.parse("application/json;charset=utf-8");
RequestBody body = RequestBody.create(mediaType, new Gson().toJson(request));
Request httpRequest = new Request.Builder()
.url(apiUrl)
.method("POST", body)
.addHeader("Content-Type", "application/json")
.addHeader("Accept", "application/json")
.addHeader("Authorization", "Bearer " + apiKey)
.build();
try (Response response = client.newCall(httpRequest).execute()) {
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
return response.body().string();
}
}
}
二、前端代码如下:
<!-- views/ai/DeepSeekChat.vue -->
<template>
<div class="chat-container">
<div class="chat-history">
<div v-for="(msg, index) in messages" :key="index" :class="['message', msg.role]">
<div class="message-content" v-html="msg.htmlContent"></div>
</div>
</div>
<div class="input-area">
<el-input
v-model="inputMessage"
type="textarea"
:rows="4"
placeholder="输入您的问题..."
@keydown.enter.exact.prevent="sendMessage"
/>
<el-button
type="primary"
:loading="loading"
@click="sendMessage"
class="send-button"
>
发送
</el-button>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { deepSeekChat } from '@/api/demo/deepseek'
import MarkdownIt from 'markdown-it'
import hljs from 'highlight.js'
import 'highlight.js/styles/github-dark.css'
const md = new MarkdownIt({
html: true,
linkify: true,
highlight: (str, lang) => {
if (lang && hljs.getLanguage(lang)) {
try {
return `<pre class="hljs"><code>${hljs.highlight(str, {
language: lang,
ignoreIllegals: true
}).value}</code></pre>`
} catch (__) {}
}
return `<pre class="hljs"><code>${md.utils.escapeHtml(str)}</code></pre>`
}
})
const messages = ref([])
const inputMessage = ref('')
const loading = ref(false)
const formatContent = (content) => {
return md.render(content)
}
const sendMessage = async () => {
if (!inputMessage.value.trim()) return
const userMessage = {
role: 'user',
content: inputMessage.value,
htmlContent: formatContent(inputMessage.value)
}
messages.value.push(userMessage)
loading.value = true
try {
const response = await deepSeekChat({
model: 'deepseek-chat',
messages: [...messages.value.map(m => ({ role: m.role, content: m.content }))]
})
const content = JSON.parse(response.msg)
const aiMessage = {
role: 'assistant',
content: content.choices[0].message.content,
htmlContent: formatContent(content.choices[0].message.content)
}
messages.value.push(aiMessage)
} catch (error) {
ElMessage.error('请求失败:' + error.message)
} finally {
inputMessage.value = ''
loading.value = false
}
}
</script>
<style scoped>
.chat-container {
max-width: 800px;
margin: 20px auto;
height: 70vh;
display: flex;
flex-direction: column;
}
.chat-history {
flex: 1;
overflow-y: auto;
padding: 20px;
border: 1px solid #ebeef5;
border-radius: 4px;
margin-bottom: 20px;
background: #f9fafb;
}
.message {
margin: 10px 0;
padding: 15px 20px;
border-radius: 8px;
line-height: 1.6;
}
.message.user {
background-color: #fff;
margin-left: 20%;
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
}
.message.assistant {
background-color: #ffffff;
margin-right: 20%;
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
border: 1px solid #e5e7eb;
}
.input-area {
position: relative;
}
.send-button {
margin-top: 10px;
float: right;
}
/* Markdown内容样式 */
.message-content ::v-deep() {
h1, h2, h3 {
margin: 1em 0 0.5em;
font-weight: 600;
}
p {
margin: 0.8em 0;
}
pre {
background: #1f2937;
color: #fff;
padding: 1em;
border-radius: 6px;
overflow-x: auto;
margin: 1em 0;
}
code {
font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
background: #f3f4f6;
padding: 0.2em 0.4em;
border-radius: 4px;
font-size: 0.9em;
}
blockquote {
border-left: 4px solid #e5e7eb;
padding: 0 1em;
color: #6b7280;
margin: 1em 0;
}
ul, ol {
padding-left: 2em;
margin: 1em 0;
}
li {
margin: 0.3em 0;
}
}
</style>
三、效果图
在发送提问里输入:测试deepseek的api返回显示样式调整
显示返回效果如下: