效果
先来看一下最后实现的效果
(1)未点击前的功能页面
(2)点击后的页面
(3)生成的结果
(4)导出为pdf文件
接入步骤
一、注册千帆大模型 点此跳转到千帆大模型首页
记得需要实名认证一下
二、点击立即体验(直接上图)
三、进入了 千帆ModelBuilder页面,找到 应用接入
四、我们点击 切换至旧版
五、切换后我们创建应用
六、记录下应用的API Key 和 Secret Key
七、引入依赖
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.12.0</version>
</dependency>
八、可以选择自己喜欢的模型并找到测试代码进行调试
九、我的测试代码(在文章末尾有,此处不粘贴,只介绍)
十、测试结果
项目接入
配置类:WenXinYiYan
import com.sun.media.jfxmedia.logging.Logger;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
@Slf4j
public class WenXinYiYan {
public static final String API_KEY = "你个人的API_KEY";
public static final String SECRET_KEY = "你个人的SECRET_KEY ";
// OkHttpClient配置,设置连接超时和读取超时
static final OkHttpClient HTTP_CLIENT = new OkHttpClient.Builder()
.connectTimeout(60, TimeUnit.SECONDS) // 设置连接超时时间为60秒
.readTimeout(60, TimeUnit.SECONDS) // 设置读取超时时间为60秒
.build();
public static String getResult(String askContent){
try {
JSONObject requestBody = new JSONObject();
JSONArray messages = new JSONArray();
JSONObject message = new JSONObject();
message.put("role", "user");
message.put("content", askContent);
messages.put(message);
requestBody.put("messages", messages);
requestBody.put("temperature",0.95);
requestBody.put("top_p",0.8);
requestBody.put("penalty_score",1);
requestBody.put("enable_system_memory",false);
requestBody.put("disable_search",false);
requestBody.put("model","qwen-max-v1.5-turbo");
// 打印请求体,确保格式正确
// System.out.println("Request Body: " + requestBody.toString());
// 定义请求的媒体类型
MediaType mediaType = MediaType.parse("application/json;charset=utf-8");
// 构建请求体,消息内容包含了用户请求
RequestBody body = RequestBody.create(mediaType, requestBody.toString());
// 构建http请求
Request request = new Request.Builder()
.url("https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/completions_pro?access_token=" + getAccessToken())
.method("POST", body)
.addHeader("Content-Type", "application/json;charset=utf-8")
.build();
// 发送请求并获取响应
Response response = HTTP_CLIENT.newCall(request).execute();
if(!response.isSuccessful()){
throw new IOException("Unexpected code " + response);
}
// 获取相应体
ResponseBody responseBody = response.body();
if(responseBody == null){
throw new IOException("Response body is null");
}
String responseBodyString = responseBody.string();
// 解析json数据
JSONObject jsonResponse = new JSONObject(responseBodyString);
// 提取”result“字段
if (jsonResponse.has("result")) {
Object result = jsonResponse.get("result");
return result.toString();
} else {
return "Response does not contain 'result' field.";
}
} catch (IOException e) {
// 捕获 IO 异常(如网络错误、超时等),并打印异常信息
return "Error: " + e.getMessage();
}
}
/**
* 从用户的AK,SK生成鉴权签名(Access Token)
*
* @return 鉴权签名(Access Token)
* @throws IOException IO异常
*/
static String getAccessToken() throws IOException, JSONException {
// 设置请求体的媒体类型为 x-www-form-urlencoded
MediaType mediaType = MediaType.parse("application/x-www-form-urlencoded");
// 创建请求体,包含 API 的 client_id 和 client_secret
RequestBody body = RequestBody.create(mediaType, "grant_type=client_credentials&client_id=" + API_KEY
+ "&client_secret=" + SECRET_KEY);
// 构建请求,使用 POST 方法获取 Access Token
Request request = new Request.Builder()
.url("https://aip.baidubce.com/oauth/2.0/token")
.method("POST", body)
.addHeader("Content-Type", "application/x-www-form-urlencoded")
.build();
try(Response response = HTTP_CLIENT.newCall(request).execute();) {
// 从响应中解析出Access Token
return new JSONObject(response.body().string()).getString("access_token");
}
}
}
前端
vue代码
(style设置的代码就不粘贴了,主要是展示功能调用)
<template>
<div class="container">
<!-- 消息输入区域 -->
<div class="input-button-container">
<button @click="fetchStudentSummary">一键优化我的简历</button>
</div>
<!-- 消息显示区域 -->
<div class="message-area">
<div class="message-section" style="width: 90%;">
<!-- 正式回答文字在内容框的上方,居左显示 -->
<div class="section-title">正式回答:</div>
<div class="message-container messages pdf-preview" ref="pdfContent" :style="containerStyle">
<!-- 默认内容 -->
<div v-if="messages.length === 0 && !isLoading" class="default-content">
(1)点击按钮可以一键优化简历哦<br>
(2)优化后的简历,在这里查看
</div>
<!-- 加载动画 -->
<div v-if="isLoading" class="loading-container">
<div class="loader"></div>
<div>简历生成中...</div>
</div>
<!-- 返回的内容 -->
<div v-else v-html="formattedContent" class="markdown-content"></div>
</div>
</div>
<div v-if="messages.length > 0" class="export-button-container">
<button @click="exportToPDF" class="export-button">导出为PDF</button>
</div>
</div>
</div>
</template>
<script setup>
import { ref, reactive, onMounted, computed } from 'vue';
import axios from 'axios';
import Cookies from 'js-cookie';
import { enhanceResume } from '@/api/recommend/recommend.js';
import { marked } from 'marked';
import html2pdf from 'html2pdf.js';
import DOMPurify from 'dompurify';
const messages = ref([]);
const isLoading = ref(false);
const pdfContent = ref(null);
// 动态设置内容框的高度
const containerStyle = computed(() => {
return {
height: messages.value.length > 0 ? '600px' : '100px',
overflowY: 'auto'
};
});
// 添加markdown转换方法
const formattedContent = computed(() => {
if (messages.value.length === 0) return '';
const rawMarkdown = messages.value.join('\n');
const cleanHtml = DOMPurify.sanitize(marked(rawMarkdown));
return cleanHtml;
});
// 导出PDF方法
const exportToPDF = () => {
const element = pdfContent.value;
const opt = {
margin: 10,
filename: '优化简历.pdf',
image: { type: 'jpeg', quality: 0.98 },
html2canvas: { scale: 2 },
jsPDF: { unit: 'mm', format: 'a4', orientation: 'portrait' },
};
html2pdf().from(element).set(opt).save();
};
// 获取当前登录账号的username
const getCurrentUsername = () => {
return Cookies.get('username');
};
// 根据username请求学生信息
const fetchStudentSummary = async () => {
try {
isLoading.value = true;
const username = getCurrentUsername();
console.log('当前登录账号的用户名:', username);
const response = await enhanceResume(username);
console.log('获取到的学生信息:', response.data);
messages.value = [response.data]; // 将获取到的内容展示在正式回答区域
} catch (error) {
console.error('请求失败:', error);
alert('请求失败,请稍后再试');
} finally {
isLoading.value = false;
}
};
</script>
js代码
// 简历优化接口
export function enhanceResume(username) {
return request({
url: `/system/studentSum/enhance/${username}`,
method: 'get',
})
}
后端
mapper层
@Mapper
public interface StudentSumMapper
{
/**
* 查询用户信息及简历关联
*
* @param userName 用户名
* @return 用户信息及简历关联
*/
public StudentSum selectStudentSumByUserName(String userName);
}
service层
-
接口
public interface IStudentSumService { /** * 获取简历增强结果 * @param username * @return */ public String enhanceResume(String username); }
-
实现类
@Service public class StudentSumServiceImpl implements IStudentSumService { @Autowired private StudentSumMapper studentSumMapper; @Override @Transactional public String enhanceResume(String username) { // 获取简历信息 StudentSum studentSum = studentSumMapper.selectStudentSumByUserName(username); // 根据username获取简历信息,然后拼接在一起 if (studentSum == null) { return "未找到用户信息"; } String askContent = "我叫"+studentSum.getNickName()+",性别"+studentSum.getSex()+ "毕业于"+studentSum.getEducation()+ ",电话号码为"+studentSum.getPhonenumber()+ ",邮箱为"+studentSum.getEmail()+ ",求职意向为:"+studentSum.getTitle()+ ",当前状态为:"+studentSum.getSearchStatus()+ ",个人简介为:"+studentSum.getSummary()+ ",个人技能为:"+studentSum.getSkills()+ ",证书及获奖情况为:"+studentSum.getCertifications()+ ",工作经历为:"+studentSum.getExperience()+ ",项目经历为:"+studentSum.getContent()+",/n请帮我写一份优化后的简历,需要对项目经历、个人技能、工作经历进行润色,其他的内容不需要润色,数据需要保留。返回内容按照个人信息、专业技能、教育经历、就业经历、项目经历展示,只展示简历的内容,不要写任何多余的文字,不要写任何多余的文字,不要写任何多余的文字"; return WenXinYiYan.getResult(askContent); } }
-
注意需要在发送的时候补充内容:
请帮我写一份优化后的简历,需要对项目经历、个人技能、工作经历进行润色,其他的内容不需要润色,数据需要保留。返回内容按照个人信息、专业技能、教育经历、就业经历、项目经历展示,只展示简历的内容,不要写任何多余的文字,不要写任何多余的文字,不要写任何多余的文字
controller层
@RestController
@RequestMapping("/system/studentSum")
public class StudentSumController extends BaseController
{
@Autowired
private IStudentSumService studentSumService;
@GetMapping(value = "/enhance/{username}")
@Transactional
public AjaxResult enhanceResume( @PathVariable String username)
{
return AjaxResult.success("上传成功", studentSumService.enhanceResume(username));
}
}
测试代码
package com.example.springbootdemo2024;
import okhttp3.*;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
public class WenXinYiYan {
// 你的apiKey
public static final String API_KEY = "------";
// 你的SECRET_KEY
public static final String SECRET_KEY = "--------";
// OkHttpClient配置,设置连接超时和读取超时
static final OkHttpClient HTTP_CLIENT = new OkHttpClient.Builder()
.connectTimeout(60, TimeUnit.SECONDS) // 设置连接超时时间为60秒
.readTimeout(60, TimeUnit.SECONDS) // 设置读取超时时间为60秒
.build();
public static String getResult(String askContent){
try {
JSONObject requestBody = new JSONObject();
JSONArray messages = new JSONArray();
JSONObject message = new JSONObject();
message.put("role", "user");
message.put("content", askContent);
messages.put(message);
requestBody.put("messages", messages);
requestBody.put("temperature",0.95);
requestBody.put("top_p",0.8);
requestBody.put("penalty_score",1);
requestBody.put("enable_system_memory",false);
requestBody.put("disable_search",false);
requestBody.put("model","qwen-max-v1.5-turbo");
// 打印请求体,确保格式正确
// System.out.println("Request Body: " + requestBody.toString());
// 定义请求的媒体类型
MediaType mediaType = MediaType.parse("application/json;charset=utf-8");
// 构建请求体,消息内容包含了用户请求
RequestBody body = RequestBody.create(mediaType, requestBody.toString());
// 构建http请求
Request request = new Request.Builder()
.url("https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/completions_pro?access_token=" + getAccessToken())
.method("POST", body)
.addHeader("Content-Type", "application/json")
.build();
// 发送请求并获取响应
Response response = HTTP_CLIENT.newCall(request).execute();
if(!response.isSuccessful()){
throw new IOException("Unexpected code " + response);
}
// 获取相应体
ResponseBody responseBody = response.body();
if(responseBody == null){
throw new IOException("Response body is null");
}
String responseBodyString = responseBody.string();
// 解析json数据
JSONObject jsonResponse = new JSONObject(responseBodyString);
System.out.println(jsonResponse);
// 提取”result“字段
if (jsonResponse.has("result")) {
Object result = jsonResponse.get("result");
// 打印 "result" 字段
return result.toString();
} else {
return "Response does not contain 'result' field.";
}
} catch (IOException e) {
// 捕获 IO 异常(如网络错误、超时等),并打印异常信息
return "Error: " + e.getMessage();
} catch (JSONException e) {
throw new RuntimeException(e);
}
}
/**
* 从用户的AK,SK生成鉴权签名(Access Token)
*
* @return 鉴权签名(Access Token)
* @throws IOException IO异常
*/
static String getAccessToken() throws IOException, JSONException {
// 设置请求体的媒体类型为 x-www-form-urlencoded
MediaType mediaType = MediaType.parse("application/x-www-form-urlencoded");
// 创建请求体,包含 API 的 client_id 和 client_secret
RequestBody body = RequestBody.create(mediaType, "grant_type=client_credentials&client_id=" + API_KEY
+ "&client_secret=" + SECRET_KEY);
// 构建请求,使用 POST 方法获取 Access Token
Request request = new Request.Builder()
.url("https://aip.baidubce.com/oauth/2.0/token")
.method("POST", body)
.addHeader("Content-Type", "application/x-www-form-urlencoded")
.build();
try(Response response = HTTP_CLIENT.newCall(request).execute();) {
// 从响应中解析出Access Token
return new JSONObject(response.body().string()).getString("access_token");
}
}
public static void main(String[] args) {
String askContent = "我叫张三丰,性别1毕业于2019.9 – 2023.6 XX 大学 |,电话号码为16134864653,邮箱为jpsd@yahoo.com,求职意向为:Java 后端开发AAA,当前状态为:在看机会,个人简介为:毕业于 XX 大学。熟悉各类软件系统的研发流程和技术,主要擅长 java 技术体系的后端技术,个人技能为:• 熟悉互联网项目整体开发流程’技术,架构,项目和人员管理。包括后端设计、开发、测试上线等\n" +
"• 具备技术团队管理经验,能够推进技术人员交流和成长,为业务发展提供良好的技术保障\n" +
"• 熟悉服务端相关技术或工具,如 linux、tomact、redis、git、maven、Mysql\n" +
"• 熟练使用 postman\\charles\\jmeter 等测试工具,了解并使用 shell、libimobidevice 对 app 进行测试\n" +
"• 了解并使用 selenium 进行过 web 端自动化测试\n" +
"• 了解前端和移动端,如 html/css/js/jQuery/Android/iOS 等;\n" +
"• 了解设计模式:工厂模式、单例模式,证书及获奖情况为:PMP 高级项目工程师\n" +
"Java 二级,工作经历为:2024.1-2024.12 CCCCCCCC 科技有限公司 java 后端开发\n" +
"2022.5-2023.11 AAAAAA(北京)科技有限公司 java 后端开发\n" +
"2020.5-2022.5 BBBBBBBB 技术有限公司 java 后端开发,项目经历为:CCCCCCCC 科技有限公司【2024.1-2024.12】\n" +
"工作内容:负责风电机预警项目、就业风向标项目、教师大赛等后端技术开发、数据库设计和管理。\n" +
"AAAAAA(北京)科技有限公司【2020.5-2023.11】\n" +
" BBBBBBBB 技术有限公司【2019.2-2020.】\n" +
"负责公司 wap 端和 PC 端的业务软件测试。主要项目有房贷计算器、直播活动、问答日报等\n" +
"教育经历\n" +
"2019.9 – 2023.6 XX 大学 |,/n请帮我写一份优化后的简历,不要写任何多余的文字,不要写任何多余的文字,不要写任何多余的文字";
System.out.println(getResult("优化后的内容:"+askContent));
}
}