Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
张文彪
/
employmentBusinessPc
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Settings
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
14c56833
authored
Dec 05, 2025
by
zwb
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
新增岗位智推
parent
01791790
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
41 changed files
with
1598 additions
and
53 deletions
employmentBusiness-pc-common/employmentBusiness-pc-common-core/pom.xml
employmentBusiness-pc-common/employmentBusiness-pc-common-core/src/main/java/org/dromara/common/core/config/LlmEmbeddingConfig.java
employmentBusiness-pc-common/employmentBusiness-pc-common-core/src/main/java/org/dromara/common/core/config/QwenClientSingleton.java
employmentBusiness-pc-common/employmentBusiness-pc-common-core/src/main/java/org/dromara/common/core/constant/CacheConstants.java
employmentBusiness-pc-common/employmentBusiness-pc-common-core/src/main/java/org/dromara/common/core/constant/Constants.java
employmentBusiness-pc-modules/employmentBusiness-pc-system/pom.xml
employmentBusiness-pc-modules/employmentBusiness-pc-system/src/main/java/com/bkty/system/config/RedisConfig.java
employmentBusiness-pc-modules/employmentBusiness-pc-system/src/main/java/com/bkty/system/controller/JobRecommendController.java
employmentBusiness-pc-modules/employmentBusiness-pc-system/src/main/java/com/bkty/system/controller/NewEditionResumeController.java
employmentBusiness-pc-modules/employmentBusiness-pc-system/src/main/java/com/bkty/system/domain/entity/AiPositionRecommendRecord.java
employmentBusiness-pc-modules/employmentBusiness-pc-system/src/main/java/com/bkty/system/domain/entity/FunctionPositionPortraitV2.java
employmentBusiness-pc-modules/employmentBusiness-pc-system/src/main/java/com/bkty/system/domain/entity/JobEvaluation.java
employmentBusiness-pc-modules/employmentBusiness-pc-system/src/main/java/com/bkty/system/domain/entity/MatchResult.java
employmentBusiness-pc-modules/employmentBusiness-pc-system/src/main/java/com/bkty/system/domain/entity/ProcessItem.java
employmentBusiness-pc-modules/employmentBusiness-pc-system/src/main/java/com/bkty/system/domain/vo/AiPositionRecommendRecordVo.java
employmentBusiness-pc-modules/employmentBusiness-pc-system/src/main/java/com/bkty/system/domain/vo/AiRecommendVo.java
employmentBusiness-pc-modules/employmentBusiness-pc-system/src/main/java/com/bkty/system/domain/vo/FunctionPositionPortraitVo.java
employmentBusiness-pc-modules/employmentBusiness-pc-system/src/main/java/com/bkty/system/domain/vo/RecommendItem.java
employmentBusiness-pc-modules/employmentBusiness-pc-system/src/main/java/com/bkty/system/domain/vo/RerankVo.java
employmentBusiness-pc-modules/employmentBusiness-pc-system/src/main/java/com/bkty/system/employmentBusinessPCSystemApplication.java
employmentBusiness-pc-modules/employmentBusiness-pc-system/src/main/java/com/bkty/system/init/CategoryCacheManager.java
employmentBusiness-pc-modules/employmentBusiness-pc-system/src/main/java/com/bkty/system/llm/JdWriter.java
employmentBusiness-pc-modules/employmentBusiness-pc-system/src/main/java/com/bkty/system/mapper/AiAnalysisMapper.java
employmentBusiness-pc-modules/employmentBusiness-pc-system/src/main/java/com/bkty/system/mapper/CityDataMapper.java
employmentBusiness-pc-modules/employmentBusiness-pc-system/src/main/java/com/bkty/system/mapper/PositionRecommendMapper.java
employmentBusiness-pc-modules/employmentBusiness-pc-system/src/main/java/com/bkty/system/service/coze/CozeApiService.java
employmentBusiness-pc-modules/employmentBusiness-pc-system/src/main/java/com/bkty/system/service/coze/impl/CozeApiServiceImpl.java
employmentBusiness-pc-modules/employmentBusiness-pc-system/src/main/java/com/bkty/system/service/jobRecommend/AiAnalysisService.java
employmentBusiness-pc-modules/employmentBusiness-pc-system/src/main/java/com/bkty/system/service/jobRecommend/JobRecommendService.java
employmentBusiness-pc-modules/employmentBusiness-pc-system/src/main/java/com/bkty/system/service/jobRecommend/PositionRecommendRedisService.java
employmentBusiness-pc-modules/employmentBusiness-pc-system/src/main/java/com/bkty/system/service/jobRecommend/RecommendPositionService.java
employmentBusiness-pc-modules/employmentBusiness-pc-system/src/main/java/com/bkty/system/service/jobRecommend/impl/AiAnalysisServiceImpl.java
employmentBusiness-pc-modules/employmentBusiness-pc-system/src/main/java/com/bkty/system/service/jobRecommend/impl/JobRecommendServiceImpl.java
employmentBusiness-pc-modules/employmentBusiness-pc-system/src/main/java/com/bkty/system/service/jobRecommend/impl/PositionRecommendRedisServiceImpl.java
employmentBusiness-pc-modules/employmentBusiness-pc-system/src/main/java/com/bkty/system/service/jobRecommend/impl/RecommendPositionServiceImpl.java
employmentBusiness-pc-modules/employmentBusiness-pc-system/src/main/java/com/bkty/system/service/resume/NewEditionResumeService.java
employmentBusiness-pc-modules/employmentBusiness-pc-system/src/main/java/com/bkty/system/service/resume/ResumeMakeService.java
employmentBusiness-pc-modules/employmentBusiness-pc-system/src/main/java/com/bkty/system/service/resume/impl/ResumeMakeServiceImpl.java
employmentBusiness-pc-modules/employmentBusiness-pc-system/src/main/java/com/bkty/system/utils/MariaDbAdtUtil.java
employmentBusiness-pc-modules/employmentBusiness-pc-system/src/main/resources/mapper/system/AiAnalysisMapper.xml
employmentBusiness-pc-modules/employmentBusiness-pc-system/src/main/resources/mapper/system/PositionRecommendMapper.xml
employmentBusiness-pc-common/employmentBusiness-pc-common-core/pom.xml
View file @
14c56833
...
@@ -138,6 +138,20 @@
...
@@ -138,6 +138,20 @@
<artifactId>
fastjson2
</artifactId>
<artifactId>
fastjson2
</artifactId>
<version>
2.0.43
</version>
<version>
2.0.43
</version>
</dependency>
</dependency>
<dependency>
<groupId>
dev.langchain4j
</groupId>
<artifactId>
langchain4j
</artifactId>
<version>
0.29.1
</version>
</dependency>
<dependency>
<groupId>
dev.langchain4j
</groupId>
<artifactId>
langchain4j-open-ai
</artifactId>
<version>
0.29.1
</version>
</dependency>
</dependencies>
</dependencies>
</project>
</project>
employmentBusiness-pc-common/employmentBusiness-pc-common-core/src/main/java/org/dromara/common/core/config/LlmEmbeddingConfig.java
0 → 100644
View file @
14c56833
package
org
.
dromara
.
common
.
core
.
config
;
import
dev.langchain4j.model.embedding.EmbeddingModel
;
import
dev.langchain4j.model.openai.OpenAiEmbeddingModel
;
/**
* @author jiangxiaoge
* @description
* @data 2025/2/13
**/
public
class
LlmEmbeddingConfig
{
// 使用 volatile 保证在多线程环境下的正确性
private
static
volatile
EmbeddingModel
instance
;
// 私有构造方法,防止外部实例化
private
LlmEmbeddingConfig
()
{
}
public
static
EmbeddingModel
getEmbeddingModel
()
{
// 双重检查锁定实现单例
if
(
instance
==
null
)
{
synchronized
(
LlmEmbeddingConfig
.
class
)
{
if
(
instance
==
null
)
{
try
{
// 初始化 ChatLanguageModel 实例
instance
=
OpenAiEmbeddingModel
.
builder
()
//.baseUrl("https://api.openai.com/v1")
.
baseUrl
(
"http://47.253.179.191:6666/v1"
)
.
modelName
(
"text-embedding-3-small"
)
.
apiKey
(
"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"
)
.
build
();
}
catch
(
Exception
e
)
{
// 错误处理
e
.
printStackTrace
();
return
null
;
}
}
}
}
return
instance
;
}
}
employmentBusiness-pc-common/employmentBusiness-pc-common-core/src/main/java/org/dromara/common/core/config/QwenClientSingleton.java
0 → 100644
View file @
14c56833
This diff is collapsed.
Click to expand it.
employmentBusiness-pc-common/employmentBusiness-pc-common-core/src/main/java/org/dromara/common/core/constant/CacheConstants.java
View file @
14c56833
...
@@ -85,4 +85,7 @@ public interface CacheConstants {
...
@@ -85,4 +85,7 @@ public interface CacheConstants {
* 下载使用简历对应模版缓存pdf
* 下载使用简历对应模版缓存pdf
*/
*/
String
RESUME_TEMPLATE_PDF_ID
=
"template:resume:pdf:download:%s"
;
String
RESUME_TEMPLATE_PDF_ID
=
"template:resume:pdf:download:%s"
;
/**分析职业期望数据*/
String
REDIS_USER_ANALYSIS_KEY
=
"user:analysis:%s"
;
}
}
employmentBusiness-pc-common/employmentBusiness-pc-common-core/src/main/java/org/dromara/common/core/constant/Constants.java
View file @
14c56833
...
@@ -82,8 +82,5 @@ public interface Constants {
...
@@ -82,8 +82,5 @@ public interface Constants {
/** 全字段时间格式化字符串模式:yyyy-MM-dd HH:mm:ss */
/** 全字段时间格式化字符串模式:yyyy-MM-dd HH:mm:ss */
public
static
final
String
DATE_FULL_FORMAT
=
"yyyy-MM-dd HH:mm:ss"
;
public
static
final
String
DATE_FULL_FORMAT
=
"yyyy-MM-dd HH:mm:ss"
;
/**分析职业期望数据*/
String
REDIS_USER_ANALYSIS_KEY
=
"user:analysis:%s"
;
}
}
employmentBusiness-pc-modules/employmentBusiness-pc-system/pom.xml
View file @
14c56833
...
@@ -151,6 +151,19 @@
...
@@ -151,6 +151,19 @@
<artifactId>
fastjson2
</artifactId>
<artifactId>
fastjson2
</artifactId>
<version>
2.0.43
</version>
<version>
2.0.43
</version>
</dependency>
</dependency>
<dependency>
<groupId>
dev.langchain4j
</groupId>
<artifactId>
langchain4j
</artifactId>
<version>
0.29.1
</version>
</dependency>
<dependency>
<groupId>
dev.langchain4j
</groupId>
<artifactId>
langchain4j-open-ai
</artifactId>
<version>
0.29.1
</version>
</dependency>
</dependencies>
</dependencies>
<build>
<build>
...
...
employmentBusiness-pc-modules/employmentBusiness-pc-system/src/main/java/com/bkty/system/config/RedisConfig.java
0 → 100644
View file @
14c56833
package
com
.
bkty
.
system
.
config
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.data.redis.connection.RedisConnectionFactory
;
import
org.springframework.data.redis.core.RedisTemplate
;
import
org.springframework.data.redis.serializer.StringRedisSerializer
;
@Configuration
public
class
RedisConfig
{
@Bean
public
RedisTemplate
<
String
,
Object
>
redisTemplate
(
RedisConnectionFactory
factory
)
{
RedisTemplate
<
String
,
Object
>
template
=
new
RedisTemplate
<>();
template
.
setConnectionFactory
(
factory
);
// 使用 StringRedisSerializer 处理 Key 和 Value
StringRedisSerializer
stringRedisSerializer
=
new
StringRedisSerializer
();
template
.
setKeySerializer
(
stringRedisSerializer
);
template
.
setValueSerializer
(
stringRedisSerializer
);
template
.
setHashKeySerializer
(
stringRedisSerializer
);
template
.
setHashValueSerializer
(
stringRedisSerializer
);
template
.
afterPropertiesSet
();
return
template
;
}
}
\ No newline at end of file
employmentBusiness-pc-modules/employmentBusiness-pc-system/src/main/java/com/bkty/system/controller/JobRecommendController.java
View file @
14c56833
...
@@ -12,7 +12,11 @@ import lombok.RequiredArgsConstructor;
...
@@ -12,7 +12,11 @@ import lombok.RequiredArgsConstructor;
import
lombok.extern.slf4j.Slf4j
;
import
lombok.extern.slf4j.Slf4j
;
import
org.dromara.common.core.domain.R
;
import
org.dromara.common.core.domain.R
;
import
org.dromara.common.core.exception.JxgException
;
import
org.dromara.common.core.exception.JxgException
;
import
org.dromara.common.core.exception.WarnException
;
import
org.dromara.common.core.utils.DateTimeWrapper
;
import
org.dromara.common.core.utils.SecurityUtils
;
import
org.dromara.common.core.utils.StringUtils
;
import
org.dromara.common.core.utils.StringUtils
;
import
org.dromara.common.satoken.utils.LoginHelper
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.web.bind.annotation.*
;
import
org.springframework.web.bind.annotation.*
;
...
@@ -79,4 +83,20 @@ public class JobRecommendController {
...
@@ -79,4 +83,20 @@ public class JobRecommendController {
public
R
<
List
<
Level1City
>>
getAllCitys
()
{
public
R
<
List
<
Level1City
>>
getAllCitys
()
{
return
new
R
<>(
categoryCacheManager
.
getCityCache
());
return
new
R
<>(
categoryCacheManager
.
getCityCache
());
}
}
@Operation
(
summary
=
"岗位智推"
)
@GetMapping
(
"/position"
)
public
R
<
Void
>
recommendPosition
(
@RequestParam
(
value
=
"analysisId"
)
Long
analysisId
,
@RequestParam
(
"resumeId"
)
Long
resumeId
)
{
if
(
analysisId
==
null
||
resumeId
==
null
){
throw
new
WarnException
(
"分析数据不能为空"
);
}
if
(
resumeId
==
null
){
throw
new
WarnException
(
"简历id不能为空"
);
}
Long
userId
=
LoginHelper
.
getLoginUser
().
getUserId
();
jobRecommendService
.
recommendPosition
(
analysisId
,
userId
,
resumeId
);
return
R
.
ok
();
}
}
}
employmentBusiness-pc-modules/employmentBusiness-pc-system/src/main/java/com/bkty/system/controller/NewEditionResumeController.java
View file @
14c56833
...
@@ -5,12 +5,14 @@ import cn.hutool.core.collection.CollectionUtil;
...
@@ -5,12 +5,14 @@ import cn.hutool.core.collection.CollectionUtil;
import
com.bkty.system.api.model.LoginUser
;
import
com.bkty.system.api.model.LoginUser
;
import
com.bkty.system.domain.dto.*
;
import
com.bkty.system.domain.dto.*
;
import
com.bkty.system.domain.entity.FunctionResumeBaseTag
;
import
com.bkty.system.domain.entity.FunctionResumeBaseTag
;
import
com.bkty.system.domain.entity.FunctionResumeSketch
;
import
com.bkty.system.domain.vo.ResumeBase
;
import
com.bkty.system.domain.vo.ResumeBase
;
import
com.bkty.system.domain.vo.ResumeByPdfVo
;
import
com.bkty.system.domain.vo.ResumeByPdfVo
;
import
com.bkty.system.domain.vo.ResumeModelVo
;
import
com.bkty.system.domain.vo.ResumeModelVo
;
import
com.bkty.system.domain.vo.ResumeVo
;
import
com.bkty.system.domain.vo.ResumeVo
;
import
com.bkty.system.service.resume.NewEditionResumeService
;
import
com.bkty.system.service.resume.NewEditionResumeService
;
import
com.bkty.system.service.resume.ResumeCacheService
;
import
com.bkty.system.service.resume.ResumeCacheService
;
import
com.bkty.system.service.resume.ResumeMakeService
;
import
io.swagger.v3.oas.annotations.Operation
;
import
io.swagger.v3.oas.annotations.Operation
;
import
io.swagger.v3.oas.annotations.tags.Tag
;
import
io.swagger.v3.oas.annotations.tags.Tag
;
import
lombok.RequiredArgsConstructor
;
import
lombok.RequiredArgsConstructor
;
...
@@ -44,6 +46,8 @@ public class NewEditionResumeController {
...
@@ -44,6 +46,8 @@ public class NewEditionResumeController {
private
final
ResumeCacheService
resumeCacheService
;
private
final
ResumeCacheService
resumeCacheService
;
private
final
ResumeMakeService
resumeMakeService
;
/**
/**
* 新版导入简历
* 新版导入简历
* @param file 文件
* @param file 文件
...
@@ -256,4 +260,15 @@ public class NewEditionResumeController {
...
@@ -256,4 +260,15 @@ public class NewEditionResumeController {
this
.
newEditionResumeService
.
reversalExperience
(
dto
);
this
.
newEditionResumeService
.
reversalExperience
(
dto
);
return
R
.
ok
();
return
R
.
ok
();
}
}
/**
* 查询简历分析详情
* @param resumeId
* @return
*/
@GetMapping
(
"/query-resume-sketch"
)
public
R
<
FunctionResumeSketch
>
queryResumeSketch
(
@RequestParam
(
"resumeId"
)
Long
resumeId
){
FunctionResumeSketch
vo
=
this
.
resumeMakeService
.
queryResumeSketch
(
resumeId
);
return
new
R
<>(
vo
);
}
}
}
employmentBusiness-pc-modules/employmentBusiness-pc-system/src/main/java/com/bkty/system/domain/entity/AiPositionRecommendRecord.java
0 → 100644
View file @
14c56833
package
com
.
bkty
.
system
.
domain
.
entity
;
import
com.baomidou.mybatisplus.annotation.IdType
;
import
com.baomidou.mybatisplus.annotation.TableId
;
import
com.baomidou.mybatisplus.annotation.TableName
;
import
lombok.Data
;
import
org.dromara.common.mybatis.core.domain.BaseEntity
;
import
java.util.Date
;
/**
* @author jiangxiaoge
* @description 岗位推荐记录
* @data 2025/2/18
**/
@Data
@TableName
(
"ai_position_recommend_record"
)
public
class
AiPositionRecommendRecord
extends
BaseEntity
{
/**
* 主键ID
*/
@TableId
(
value
=
"id"
,
type
=
IdType
.
ASSIGN_ID
)
private
Long
id
;
private
Long
userId
;
private
Long
positionId
;
/**
* 是否收藏 0.否 1.是 2.不喜欢
*/
private
Integer
treasuresType
;
/**
* 是否已读 0.否 1.是
*/
private
Integer
alreadyType
;
private
Integer
deliverType
;
private
Integer
operationType
;
private
Integer
rScore
;
private
String
rDetails
;
private
Date
recommendTime
;
private
Long
resumeId
;
private
String
cityCode
;
private
String
analyzeJson
;
private
String
evaluationJson
;
private
String
jobTitle
;
private
String
jobProfession
;
private
String
standardPosition
;
private
Integer
companySize
;
private
Integer
companyNature
;
private
String
expDemand
;
private
String
eduDemand
;
private
String
publicPlatform
;
private
Integer
maxPay
;
private
String
companyName
;
private
Integer
positionScore
;
private
String
jdMd
;
/**
* 首次评分
*/
private
Integer
firstScore
;
//岗位优势分析
private
String
advantageAnalysis
;
//岗位匹配度
private
String
matchRate
;
//投递准备
private
String
deliverPrepare
;
//自我介绍
private
String
selfIntroduction
;
//公司规模
private
String
companyScale
;
//公司行业
private
String
companyIndustry
;
// 分析id
private
Long
analysisId
;
}
\ No newline at end of file
employmentBusiness-pc-modules/employmentBusiness-pc-system/src/main/java/com/bkty/system/domain/entity/FunctionPositionPortraitV2.java
0 → 100644
View file @
14c56833
package
com
.
bkty
.
system
.
domain
.
entity
;
import
lombok.Data
;
import
org.springframework.data.annotation.Id
;
import
org.springframework.data.elasticsearch.annotations.Document
;
import
org.springframework.data.elasticsearch.annotations.Field
;
import
org.springframework.data.elasticsearch.annotations.FieldType
;
import
java.util.Date
;
import
java.util.List
;
/**
* @author jiangxiaoge
* @description 岗位画像实体类
* @data 2025/2/7
**/
@Data
//@Document(indexName = "function_position_portrait_test") // 使用前缀
@Document
(
indexName
=
"#{@environment.getProperty('elasticsearch.index-name-prefix')}"
)
// 使用前缀
public
class
FunctionPositionPortraitV2
{
@Id
private
Long
positionDataId
;
//岗位名称
@Field
(
type
=
FieldType
.
Keyword
)
private
String
jobTitle
;
//公司行业
@Field
(
type
=
FieldType
.
Text
,
analyzer
=
"ik_max_word"
)
private
String
industry
;
//标准职位
@Field
(
type
=
FieldType
.
Text
,
analyzer
=
"ik_max_word"
)
private
String
standardPosition
;
//城市信息
@Field
(
type
=
FieldType
.
Keyword
)
private
List
<
String
>
workPlace
;
//全职、实习、灵活工作
@Field
(
type
=
FieldType
.
Text
,
analyzer
=
"ik_max_word"
)
private
String
natureOfPost
;
//薪资范围
@Field
(
type
=
FieldType
.
Text
,
analyzer
=
"ik_max_word"
)
private
String
salaryRange
;
//薪资(查询用)
@Field
(
type
=
FieldType
.
Integer
)
private
Integer
pay
;
//公司名称
@Field
(
type
=
FieldType
.
Text
,
analyzer
=
"ik_max_word"
)
private
String
companyName
;
//公司性质
@Field
(
type
=
FieldType
.
Integer
)
private
Integer
companyNature
;
//公司规模
@Field
(
type
=
FieldType
.
Integer
)
private
Integer
companySize
;
//经验要求
@Field
(
type
=
FieldType
.
Text
,
analyzer
=
"ik_max_word"
)
private
String
expDemand
;
//学历要求
@Field
(
type
=
FieldType
.
Text
,
analyzer
=
"ik_max_word"
)
private
String
eduDemand
;
//发布渠道
@Field
(
type
=
FieldType
.
Text
,
analyzer
=
"ik_max_word"
)
private
String
publicPlatform
;
//发布链接
@Field
(
type
=
FieldType
.
Text
,
analyzer
=
"ik_max_word"
)
private
String
platformUrl
;
//JD信息
@Field
(
type
=
FieldType
.
Text
,
analyzer
=
"ik_max_word"
)
private
String
jdHtml
;
//专业技能
@Field
(
type
=
FieldType
.
Keyword
)
private
List
<
String
>
skill
;
//福利
@Field
(
type
=
FieldType
.
Keyword
)
private
List
<
String
>
welfare
;
//晋升路径
@Field
(
type
=
FieldType
.
Text
,
analyzer
=
"ik_max_word"
)
private
String
promote
;
//软技能
@Field
(
type
=
FieldType
.
Text
,
analyzer
=
"ik_max_word"
)
private
String
mild
;
@Field
(
type
=
FieldType
.
Text
,
analyzer
=
"ik_max_word"
)
private
String
graduate
;
@Field
(
type
=
FieldType
.
Text
,
analyzer
=
"ik_max_word"
)
private
String
graduateContent
;
@Field
(
type
=
FieldType
.
Text
,
analyzer
=
"ik_max_word"
)
private
String
graduatePercentage
;
@Field
(
type
=
FieldType
.
Dense_Vector
,
dims
=
1536
,
similarity
=
"cosine"
)
private
List
<
Float
>
featureVector
;
@Field
(
type
=
FieldType
.
Text
,
analyzer
=
"ik_max_word"
)
private
String
sketch
;
@Field
(
type
=
FieldType
.
Text
,
analyzer
=
"ik_max_word"
)
private
String
experienceType
;
@Field
(
type
=
FieldType
.
Text
,
analyzer
=
"ik_max_word"
)
private
String
publicTime
;
@Field
(
type
=
FieldType
.
Date
)
private
Date
queryDate
;
private
String
standardJobDesc
;
//是否实习
@Field
(
type
=
FieldType
.
Text
)
private
String
isIntern
;
}
\ No newline at end of file
employmentBusiness-pc-modules/employmentBusiness-pc-system/src/main/java/com/bkty/system/domain/entity/JobEvaluation.java
0 → 100644
View file @
14c56833
package
com
.
bkty
.
system
.
domain
.
entity
;
import
com.alibaba.fastjson.annotation.JSONField
;
import
lombok.Data
;
import
java.util.List
;
@Data
public
class
JobEvaluation
{
@JSONField
(
name
=
"competitiveness"
)
private
Competitiveness
competitiveness
;
@JSONField
(
name
=
"jobFit"
)
private
JobFit
jobFit
;
@JSONField
(
name
=
"resumeTips"
)
private
ResumeTips
resumeTips
;
@JSONField
(
name
=
"prepGrowth"
)
private
PrepGrowth
prepGrowth
;
@Data
public
static
class
Competitiveness
{
private
List
<
String
>
advantages
;
private
List
<
String
>
weaknesses
;
private
List
<
String
>
suggestions
;
}
@Data
public
static
class
JobFit
{
private
List
<
String
>
requirements
;
private
MatchDetails
matchDetails
;
}
@Data
public
static
class
MatchDetails
{
private
List
<
MatchedSkill
>
matched
;
private
List
<
MissingSkill
>
missing
;
}
@Data
public
static
class
ResumeTips
{
private
List
<
String
>
improvements
;
}
@Data
public
static
class
MatchedSkill
{
private
String
skill
;
private
String
status
;
private
String
analysis
;
}
@Data
public
static
class
MissingSkill
{
private
String
skill
;
private
String
importance
;
private
String
suggestion
;
}
@Data
public
static
class
PrepGrowth
{
private
List
<
String
>
shortTerm
;
private
List
<
String
>
longTerm
;
}
}
\ No newline at end of file
employmentBusiness-pc-modules/employmentBusiness-pc-system/src/main/java/com/bkty/system/domain/entity/MatchResult.java
0 → 100644
View file @
14c56833
package
com
.
bkty
.
system
.
domain
.
entity
;
import
com.alibaba.fastjson.annotation.JSONField
;
import
lombok.Data
;
import
java.util.List
;
@Data
public
class
MatchResult
{
@JSONField
(
name
=
"comprehensiveMatchScore"
)
private
Object
comprehensiveMatchScore
;
// 处理数字和字符串两种情况
private
String
comprehensiveMatchRecommendation
;
private
List
<
String
>
jobSeekingAdvice
;
private
MatchDimensionAnalysis
matchDimensionAnalysis
;
public
int
getComprehensiveMatchScoreAsInt
()
{
if
(
comprehensiveMatchScore
instanceof
Number
)
{
return
((
Number
)
comprehensiveMatchScore
).
intValue
();
}
else
if
(
comprehensiveMatchScore
instanceof
String
)
{
try
{
return
Integer
.
parseInt
((
String
)
comprehensiveMatchScore
);
}
catch
(
NumberFormatException
e
)
{
return
0
;
// 处理异常情况
}
}
return
0
;
}
@Data
public
static
class
MatchDimensionAnalysis
{
private
MatchDetail
education
;
private
MatchDetail
professionalSkills
;
private
MatchDetail
salaryExpectation
;
private
MatchDetail
workLocation
;
private
MatchDetail
practicalExperience
;
private
MatchDetail
softSkills
;
}
@Data
public
static
class
MatchDetail
{
private
String
matchDegree
;
private
String
detailedAnalysis
;
private
String
matchPoint
;
private
String
improvementSuggestion
;
}
}
\ No newline at end of file
employmentBusiness-pc-modules/employmentBusiness-pc-system/src/main/java/com/bkty/system/domain/entity/ProcessItem.java
0 → 100644
View file @
14c56833
package
com
.
bkty
.
system
.
domain
.
entity
;
import
lombok.AllArgsConstructor
;
import
lombok.Data
;
import
lombok.NoArgsConstructor
;
/**
* @author jiangxiaoge
* @description 推送消息状态封装
* @data 2025/6/17
**/
@AllArgsConstructor
@NoArgsConstructor
@Data
public
class
ProcessItem
{
private
String
status
;
private
String
text
;
private
double
percent
;
private
String
time
;
}
\ No newline at end of file
employmentBusiness-pc-modules/employmentBusiness-pc-system/src/main/java/com/bkty/system/domain/vo/AiPositionRecommendRecordVo.java
0 → 100644
View file @
14c56833
package
com
.
bkty
.
system
.
domain
.
vo
;
import
com.bkty.system.domain.entity.AiPositionRecommendRecord
;
import
com.bkty.system.domain.entity.FunctionPositionPortraitV2
;
import
lombok.Data
;
import
java.util.List
;
import
java.util.Map
;
/**
* @author jiangxiaoge
* @description
* @data 2025/2/18
**/
@Data
public
class
AiPositionRecommendRecordVo
extends
AiPositionRecommendRecord
{
private
String
resumeName
;
private
FunctionPositionPortraitV2
portraitV2
;
private
List
<
String
>
kitIds
;
private
Map
<
String
,
String
>
levelMap
;
}
employmentBusiness-pc-modules/employmentBusiness-pc-system/src/main/java/com/bkty/system/domain/vo/AiRecommendVo.java
0 → 100644
View file @
14c56833
package
com
.
bkty
.
system
.
domain
.
vo
;
import
lombok.Data
;
import
java.util.List
;
import
java.util.Map
;
/**
* @author Zhang Wenbiao
* @description 职业需求分析数据vo
* @datetime 2025/12/4 12:08
*/
@Data
public
class
AiRecommendVo
{
private
String
id
;
/**期望职业*/
private
List
<
String
>
career
;
/**单位性质*/
private
List
<
String
>
companyNature
;
/**目标城市*/
private
List
<
String
>
targetCity
;
/**期望薪资*/
private
String
pay
;
private
String
mbti
;
private
Long
resumeCount
;
private
List
<
Integer
>
companySize
;
private
Integer
workTime
;
private
Integer
internTime
;
/**求职性质:1-实习,2-全职*/
private
String
jobType
;
/**自动推荐状态 0.已经自动推荐*/
private
Integer
authRecommend
;
/**推荐状态 0.未推荐 1.推荐中 2.推荐完成*/
private
Integer
recommendStatus
;
/**发送给智能体的岗位列表*/
private
List
<
Map
<
String
,
String
>>
jobList
;
}
employmentBusiness-pc-modules/employmentBusiness-pc-system/src/main/java/com/bkty/system/domain/vo/FunctionPositionPortraitVo.java
0 → 100644
View file @
14c56833
package
com
.
bkty
.
system
.
domain
.
vo
;
import
com.bkty.system.domain.entity.JobEvaluation
;
import
com.bkty.system.domain.entity.MatchResult
;
import
com.bkty.system.domain.entity.FunctionPositionPortraitV2
;
import
lombok.Data
;
/**
* @author jiangxiaoge
* @description
* @data 2025/2/18
**/
@Data
public
class
FunctionPositionPortraitVo
extends
FunctionPositionPortraitV2
{
private
String
score
;
private
String
details
;
private
String
resumeId
;
private
String
cityCode
;
private
String
whetherItMatches
;
private
String
resumeSketch
;
private
Float
scoreFloat
;
private
MatchResult
matchResult
;
private
JobEvaluation
jobEvaluation
;
private
String
jdMd
;
private
Float
rerankScore
;
private
String
cozeResult
;
}
\ No newline at end of file
employmentBusiness-pc-modules/employmentBusiness-pc-system/src/main/java/com/bkty/system/domain/vo/RecommendItem.java
0 → 100644
View file @
14c56833
package
com
.
bkty
.
system
.
domain
.
vo
;
import
lombok.Data
;
import
java.util.List
;
/**
* @author jiangxiaoge
* @description 岗位推荐列表item
* @data 2025/3/28
**/
@Data
public
class
RecommendItem
{
private
Long
id
;
private
String
jobTitle
;
private
String
standardPosition
;
private
List
<
String
>
welfare
;
private
String
salaryRange
;
private
Integer
maxPay
;
private
String
rDetails
;
private
String
companyName
;
private
Integer
companyNature
;
private
String
city
;
private
String
createTime
;
private
String
resumeName
;
private
Integer
positionScore
;
private
String
jdMd
;
}
\ No newline at end of file
employmentBusiness-pc-modules/employmentBusiness-pc-system/src/main/java/com/bkty/system/domain/vo/RerankVo.java
0 → 100644
View file @
14c56833
package
com
.
bkty
.
system
.
domain
.
vo
;
import
lombok.AllArgsConstructor
;
import
lombok.Data
;
/**
* @author jiangxiaoge
* @description 重排序vo
* @data 2025/7/1
**/
@Data
@AllArgsConstructor
public
class
RerankVo
{
private
FunctionPositionPortraitVo
positionData
;
private
Float
score
;
}
\ No newline at end of file
employmentBusiness-pc-modules/employmentBusiness-pc-system/src/main/java/com/bkty/system/employmentBusinessPCSystemApplication.java
View file @
14c56833
...
@@ -4,6 +4,8 @@ import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
...
@@ -4,6 +4,8 @@ import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
import
org.springframework.boot.SpringApplication
;
import
org.springframework.boot.SpringApplication
;
import
org.springframework.boot.autoconfigure.SpringBootApplication
;
import
org.springframework.boot.autoconfigure.SpringBootApplication
;
import
org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup
;
import
org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup
;
import
org.springframework.cache.annotation.EnableCaching
;
import
org.springframework.context.annotation.ComponentScan
;
import
org.springframework.scheduling.annotation.EnableScheduling
;
import
org.springframework.scheduling.annotation.EnableScheduling
;
/**
/**
...
@@ -13,6 +15,7 @@ import org.springframework.scheduling.annotation.EnableScheduling;
...
@@ -13,6 +15,7 @@ import org.springframework.scheduling.annotation.EnableScheduling;
*/
*/
@EnableDubbo
@EnableDubbo
@EnableScheduling
@EnableScheduling
@EnableCaching
@SpringBootApplication
@SpringBootApplication
public
class
employmentBusinessPCSystemApplication
{
public
class
employmentBusinessPCSystemApplication
{
public
static
void
main
(
String
[]
args
)
{
public
static
void
main
(
String
[]
args
)
{
...
...
employmentBusiness-pc-modules/employmentBusiness-pc-system/src/main/java/com/bkty/system/init/CategoryCacheManager.java
View file @
14c56833
...
@@ -64,7 +64,43 @@ public class CategoryCacheManager {
...
@@ -64,7 +64,43 @@ public class CategoryCacheManager {
public
Level1Group
getPositionDataByName
(
String
level1Name
)
{
public
Level1Group
getPositionDataByName
(
String
level1Name
)
{
return
positionNameMap
.
get
(
level1Name
);
return
positionNameMap
.
get
(
level1Name
);
}
}
/**
* 根据三级分类名称获取二级分类下所有三级分类名称 (更新后的方法)
*/
public
List
<
String
>
getLevel2NameByLevel3Name
(
String
level3Name
){
for
(
Level1Group
level1Group
:
positionCache
)
{
for
(
Level2Group
level2Group
:
level1Group
.
getLevel2Groups
())
{
for
(
Level3Group
level3Group
:
level2Group
.
getLevel3Groups
())
{
if
(
level3Group
.
getName
().
equals
(
level3Name
))
{
return
level2Group
.
getLevel3Groups
().
stream
().
map
(
Level3Group:
:
getName
).
toList
();
}
}
}
}
return
null
;
}
/**
* 根据三级分类名称获取每一级分类的名称Map
*/
public
Map
<
String
,
String
>
getLevelNameMapByLevel3Name
(
String
level3Name
)
{
Map
<
String
,
String
>
levelNameMap
=
new
ConcurrentHashMap
<>();
for
(
Level1Group
level1Group
:
positionCache
)
{
for
(
Level2Group
level2Group
:
level1Group
.
getLevel2Groups
())
{
for
(
Level3Group
level3Group
:
level2Group
.
getLevel3Groups
())
{
if
(
level3Group
.
getName
().
equals
(
level3Name
))
{
levelNameMap
.
put
(
"level1"
,
level1Group
.
getName
());
levelNameMap
.
put
(
"level2"
,
level2Group
.
getName
());
levelNameMap
.
put
(
"level3"
,
level3Group
.
getName
());
return
levelNameMap
;
}
}
}
}
return
null
;
}
/**
/**
* 根据一级分类获取数据
* 根据一级分类获取数据
*/
*/
...
...
employmentBusiness-pc-modules/employmentBusiness-pc-system/src/main/java/com/bkty/system/llm/JdWriter.java
0 → 100644
View file @
14c56833
This diff is collapsed.
Click to expand it.
employmentBusiness-pc-modules/employmentBusiness-pc-system/src/main/java/com/bkty/system/mapper/AiAnalysisMapper.java
0 → 100644
View file @
14c56833
package
com
.
bkty
.
system
.
mapper
;
import
com.baomidou.mybatisplus.core.mapper.BaseMapper
;
import
com.bkty.system.domain.entity.AiRecommendBase
;
import
org.apache.ibatis.annotations.Mapper
;
import
org.apache.ibatis.annotations.Param
;
@Mapper
public
interface
AiAnalysisMapper
extends
BaseMapper
<
AiRecommendBase
>
{
void
updateAnalysis
(
@Param
(
"analysisId"
)
Long
analysisId
,
@Param
(
"rType"
)
Integer
rType
,
@Param
(
"userId"
)
Long
userId
,
@Param
(
"authRecommend"
)
Integer
authRecommend
);
}
employmentBusiness-pc-modules/employmentBusiness-pc-system/src/main/java/com/bkty/system/mapper/CityDataMapper.java
View file @
14c56833
...
@@ -3,7 +3,14 @@ package com.bkty.system.mapper;
...
@@ -3,7 +3,14 @@ package com.bkty.system.mapper;
import
com.baomidou.mybatisplus.core.mapper.BaseMapper
;
import
com.baomidou.mybatisplus.core.mapper.BaseMapper
;
import
com.bkty.system.domain.entity.CityData
;
import
com.bkty.system.domain.entity.CityData
;
import
org.apache.ibatis.annotations.Mapper
;
import
org.apache.ibatis.annotations.Mapper
;
import
org.apache.ibatis.annotations.Param
;
import
org.apache.ibatis.annotations.Select
;
@Mapper
@Mapper
public
interface
CityDataMapper
extends
BaseMapper
<
CityData
>
{
public
interface
CityDataMapper
extends
BaseMapper
<
CityData
>
{
@Select
(
"""
select city_code from city_data
where city_name = #{city}
"""
)
String
getCityCodeByName
(
@Param
(
"city"
)
String
city
);
}
}
employmentBusiness-pc-modules/employmentBusiness-pc-system/src/main/java/com/bkty/system/mapper/PositionRecommendMapper.java
0 → 100644
View file @
14c56833
package
com
.
bkty
.
system
.
mapper
;
import
com.baomidou.mybatisplus.core.mapper.BaseMapper
;
import
com.bkty.system.domain.entity.AiPositionRecommendRecord
;
import
com.bkty.system.domain.vo.AiPositionRecommendRecordVo
;
import
org.apache.ibatis.annotations.Mapper
;
import
org.apache.ibatis.annotations.Param
;
import
org.apache.ibatis.annotations.Select
;
import
java.util.List
;
/**
* @author jiangxiaoge
* @description 岗位推荐mapper
* @data 2025/2/18
**/
@Mapper
public
interface
PositionRecommendMapper
extends
BaseMapper
<
AiPositionRecommendRecord
>
{
@Select
(
"""
SELECT position_id from ai_position_recommend_record where is_deleted = 0 and analysis_id = #{analysisId}
"""
)
List
<
Long
>
selectPositionIdList
(
@Param
(
"analysisId"
)
Long
analysisId
);
List
<
AiPositionRecommendRecordVo
>
selectPositionList
(
@Param
(
"analysisId"
)
Long
analysisId
,
@Param
(
"queryType"
)
Integer
queryType
,
@Param
(
"recommendTime"
)
String
recommendTime
,
@Param
(
"pId"
)
Long
pId
,
@Param
(
"start"
)
Long
start
,
@Param
(
"size"
)
Long
size
,
@Param
(
"sortField"
)
String
sortField
,
@Param
(
"sortType"
)
String
sortType
,
@Param
(
"deliverType"
)
Integer
deliverType
);
}
employmentBusiness-pc-modules/employmentBusiness-pc-system/src/main/java/com/bkty/system/service/coze/CozeApiService.java
View file @
14c56833
...
@@ -13,4 +13,12 @@ public interface CozeApiService {
...
@@ -13,4 +13,12 @@ public interface CozeApiService {
* @return
* @return
*/
*/
String
getCozeTokenCn
(
String
cozeSource
)
throws
Exception
;
String
getCozeTokenCn
(
String
cozeSource
)
throws
Exception
;
/**
* 获取cozeToken
* @return
*/
String
getCozeToken
()
throws
Exception
;
String
getCozeDomainUri
();
}
}
employmentBusiness-pc-modules/employmentBusiness-pc-system/src/main/java/com/bkty/system/service/coze/impl/CozeApiServiceImpl.java
View file @
14c56833
...
@@ -14,11 +14,9 @@ import org.apache.commons.collections4.MapUtils;
...
@@ -14,11 +14,9 @@ import org.apache.commons.collections4.MapUtils;
import
org.dromara.common.core.constant.CacheConstants
;
import
org.dromara.common.core.constant.CacheConstants
;
import
org.dromara.common.core.constant.Constants
;
import
org.dromara.common.core.constant.Constants
;
import
org.dromara.common.core.constant.CozeConstsnts
;
import
org.dromara.common.core.constant.CozeConstsnts
;
import
org.dromara.common.core.exception.JxgException
;
import
org.dromara.common.core.exception.WarnException
;
import
org.dromara.common.core.exception.WarnException
;
import
org.dromara.common.core.utils.AESUtil
;
import
org.dromara.common.core.utils.*
;
import
org.dromara.common.core.utils.JWTGenerator
;
import
org.dromara.common.core.utils.StringUtils
;
import
org.dromara.common.core.utils.TimeTool
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.beans.factory.annotation.Qualifier
;
import
org.springframework.beans.factory.annotation.Qualifier
;
import
org.springframework.core.ParameterizedTypeReference
;
import
org.springframework.core.ParameterizedTypeReference
;
...
@@ -107,4 +105,91 @@ public class CozeApiServiceImpl implements CozeApiService {
...
@@ -107,4 +105,91 @@ public class CozeApiServiceImpl implements CozeApiService {
}
}
throw
new
WarnException
(
"获取coze令牌失败"
);
throw
new
WarnException
(
"获取coze令牌失败"
);
}
}
@Override
public
String
getCozeToken
()
throws
Exception
{
HttpServletRequest
request
=
WebUtils
.
getRequest
();
String
redisKey
=
CacheConstants
.
REDIS_CN_COZE_TOKEN_KEY
;
String
publicKey
=
CozeConstsnts
.
COZE_CN_OAUTH_PUBLIC_KEY_STR
;
String
oauthId
=
CozeConstsnts
.
COZE_CN_OAUTH_ID
;
String
apiDomainName
=
CozeConstsnts
.
COZE_CN_API_DOMAIN_NAME
;
String
privateKey
=
CozeConstsnts
.
COZE_CN_OAUTH_PRIVATE_KEY_STR
;
if
(
request
!=
null
){
/*log.info("request不为空");
Enumeration<String> headerNames = request.getHeaderNames();
while (headerNames.hasMoreElements()) {
String headerName = headerNames.nextElement();
String headerValue = request.getHeader(headerName);
log.info("{}:{}", headerName, headerValue);
}*/
String
cozeSource
=
request
.
getHeader
(
CozeConstsnts
.
COZE_HEADER_TOKEN_NAME
);
//log.info("cozeSource:{}", cozeSource);
if
(
StringUtils
.
isNotBlank
(
cozeSource
)
&&
cozeSource
.
equals
(
CozeConstsnts
.
COZE_SOURCE_NAME
)){
//log.info("进入国内访问");
redisKey
=
CacheConstants
.
REDIS_COZE_TOKEN_KEY
;
publicKey
=
CozeConstsnts
.
COZE_OAUTH_PUBLIC_KEY_STR
;
oauthId
=
CozeConstsnts
.
COZE_OAUTH_ID
;
apiDomainName
=
CozeConstsnts
.
COZE_API_DOMAIN_NAME
;
privateKey
=
CozeConstsnts
.
COZE_OAUTH_PRIVATE_KEY_STR
;
}
}
try
{
if
(
Boolean
.
TRUE
.
equals
(
redisTemplate
.
hasKey
(
redisKey
))){
return
redisTemplate
.
opsForValue
().
get
(
redisKey
);
}
}
catch
(
Exception
e
)
{
log
.
warn
(
"Redis操作超时或异常,将直接获取新token: {}"
,
e
.
getMessage
());
// 继续执行后续代码获取新token
}
Map
<
String
,
Object
>
headerMap
=
Map
.
of
(
"alg"
,
"RS256"
,
"typ"
,
"JWT"
,
"kid"
,
publicKey
);
//String headerString = Base64.getEncoder().encodeToString(JSON.toJSONString(headerMap).getBytes());
long
iat
=
TimeTool
.
nowMilli
();
long
expiredTime
=
TimeTool
.
nowMilli
()
+
TimeUnit
.
MINUTES
.
toMillis
(
10
);
Map
<
String
,
Object
>
payloadMap
=
Map
.
of
(
"iss"
,
oauthId
,
"aud"
,
apiDomainName
,
"iat"
,
iat
,
"exp"
,
expiredTime
,
"jti"
,
UUID
.
randomUUID
());
String
payloadString
=
JSON
.
toJSONString
(
payloadMap
);
String
jwtString
=
JWTGenerator
.
generatorJwtString
(
headerMap
,
payloadString
,
privateKey
);
HttpHeaders
headers
=
new
HttpHeaders
();
headers
.
setContentType
(
MediaType
.
APPLICATION_JSON
);
headers
.
set
(
HttpHeaders
.
AUTHORIZATION
,
CozeConstsnts
.
COZE_TOKEN_BEARER
+
jwtString
);
// 创建请求体(示例 JSON 数据)
Map
<
String
,
Object
>
requestBody
=
new
HashMap
<>();
requestBody
.
put
(
"duration_seconds"
,
86399
);
requestBody
.
put
(
"grant_type"
,
"urn:ietf:params:oauth:grant-type:jwt-bearer"
);
HttpEntity
<
Map
<
String
,
Object
>>
requestEntity
=
new
HttpEntity
<>(
requestBody
,
headers
);
// 发送 POST 请求并获取响应
ResponseEntity
<
String
>
response
=
restTemplate
.
exchange
(
getCozeDomainUri
()
+
"/api/permission/oauth2/token"
,
HttpMethod
.
POST
,
requestEntity
,
String
.
class
);
com
.
alibaba
.
fastjson
.
JSONObject
jsonObject
=
JSON
.
parseObject
(
response
.
getBody
());
String
accessToken
;
if
(
jsonObject
!=
null
)
{
accessToken
=
jsonObject
.
getString
(
"access_token"
);
redisTemplate
.
opsForValue
().
set
(
redisKey
,
accessToken
,
86399
-
60
,
TimeUnit
.
SECONDS
);
return
accessToken
;
}
throw
new
JxgException
(
"获取coze令牌失败"
);
}
@Override
public
String
getCozeDomainUri
(){
HttpServletRequest
request
=
WebUtils
.
getRequest
();
if
(
request
!=
null
){
String
header
=
request
.
getHeader
(
CozeConstsnts
.
COZE_HEADER_TOKEN_NAME
);
if
(
StringUtils
.
isNotBlank
(
header
)
&&
CozeConstsnts
.
COZE_SOURCE_NAME
.
equals
(
header
)){
return
Constants
.
HTTPS
+
CozeConstsnts
.
COZE_API_DOMAIN_NAME
;
}
}
return
Constants
.
HTTPS
+
CozeConstsnts
.
COZE_CN_API_DOMAIN_NAME
;
}
}
}
employmentBusiness-pc-modules/employmentBusiness-pc-system/src/main/java/com/bkty/system/service/jobRecommend/AiAnalysisService.java
View file @
14c56833
...
@@ -3,6 +3,7 @@ package com.bkty.system.service.jobRecommend;
...
@@ -3,6 +3,7 @@ package com.bkty.system.service.jobRecommend;
import
com.baomidou.mybatisplus.extension.service.IService
;
import
com.baomidou.mybatisplus.extension.service.IService
;
import
com.bkty.system.domain.dto.AnalysisCareerDto
;
import
com.bkty.system.domain.dto.AnalysisCareerDto
;
import
com.bkty.system.domain.entity.AiRecommendBase
;
import
com.bkty.system.domain.entity.AiRecommendBase
;
import
com.bkty.system.domain.vo.AiRecommendVo
;
public
interface
AiAnalysisService
extends
IService
<
AiRecommendBase
>
{
public
interface
AiAnalysisService
extends
IService
<
AiRecommendBase
>
{
...
@@ -11,4 +12,9 @@ public interface AiAnalysisService extends IService<AiRecommendBase> {
...
@@ -11,4 +12,9 @@ public interface AiAnalysisService extends IService<AiRecommendBase> {
* @param dto
* @param dto
*/
*/
String
saveAnalysisData
(
AnalysisCareerDto
dto
);
String
saveAnalysisData
(
AnalysisCareerDto
dto
);
/**
* 查询个人分析推荐数据
*/
AiRecommendVo
queryAnalysisData
(
Long
analysisId
);
}
}
employmentBusiness-pc-modules/employmentBusiness-pc-system/src/main/java/com/bkty/system/service/jobRecommend/JobRecommendService.java
View file @
14c56833
...
@@ -14,4 +14,12 @@ public interface JobRecommendService {
...
@@ -14,4 +14,12 @@ public interface JobRecommendService {
* @return
* @return
*/
*/
List
<
Level1Group
>
getLevel1Groups
(
String
level1
);
List
<
Level1Group
>
getLevel1Groups
(
String
level1
);
/**
* 岗位智推
* @param analysisId
* @param userId
* @param resumeId
*/
void
recommendPosition
(
Long
analysisId
,
Long
userId
,
Long
resumeId
);
}
}
employmentBusiness-pc-modules/employmentBusiness-pc-system/src/main/java/com/bkty/system/service/jobRecommend/PositionRecommendRedisService.java
0 → 100644
View file @
14c56833
package
com
.
bkty
.
system
.
service
.
jobRecommend
;
import
com.bkty.system.domain.entity.FunctionPositionPortraitV2
;
import
com.bkty.system.domain.vo.AiPositionRecommendRecordVo
;
import
java.util.Map
;
/**
* @author jiangxiaoge
* @description 岗位推荐查询redisService
* @data 2025/3/28
**/
public
interface
PositionRecommendRedisService
{
/**
* 初始化redis数据
*/
public
boolean
initRedisData
(
Long
analysisId
);
/**
* 保存岗位到redis
* @param portraitV2
* @param position
*/
void
savePositionToRedis
(
FunctionPositionPortraitV2
portraitV2
,
AiPositionRecommendRecordVo
position
,
Long
userId
);
}
\ No newline at end of file
employmentBusiness-pc-modules/employmentBusiness-pc-system/src/main/java/com/bkty/system/service/jobRecommend/RecommendPositionService.java
0 → 100644
View file @
14c56833
package
com
.
bkty
.
system
.
service
.
jobRecommend
;
import
com.bkty.system.domain.entity.FunctionPositionPortraitV2
;
import
java.util.Collection
;
import
java.util.List
;
/**
* 岗位推荐service
*/
public
interface
RecommendPositionService
{
/**
* 根据求职意向岗位推荐
* @param analysisId
*/
void
recommendPosition
(
Long
analysisId
,
Long
userId
,
Long
resumeId
);
List
<
FunctionPositionPortraitV2
>
queryPositionList
(
String
cityCode
,
List
<
Long
>
positionIdList
);
}
employmentBusiness-pc-modules/employmentBusiness-pc-system/src/main/java/com/bkty/system/service/jobRecommend/impl/AiAnalysisServiceImpl.java
View file @
14c56833
...
@@ -6,8 +6,10 @@ import com.alibaba.nacos.common.utils.StringUtils;
...
@@ -6,8 +6,10 @@ import com.alibaba.nacos.common.utils.StringUtils;
import
com.baomidou.mybatisplus.core.conditions.query.QueryWrapper
;
import
com.baomidou.mybatisplus.core.conditions.query.QueryWrapper
;
import
com.baomidou.mybatisplus.extension.service.impl.ServiceImpl
;
import
com.baomidou.mybatisplus.extension.service.impl.ServiceImpl
;
import
com.bkty.system.domain.dto.AnalysisCareerDto
;
import
com.bkty.system.domain.dto.AnalysisCareerDto
;
import
com.bkty.system.domain.dto.ResumeMakeDto
;
import
com.bkty.system.domain.entity.AiRecommendBase
;
import
com.bkty.system.domain.entity.AiRecommendBase
;
import
com.bkty.system.domain.entity.FunctionResumeBase
;
import
org.dromara.common.core.constant.CacheConstants
;
import
com.bkty.system.domain.vo.AiRecommendVo
;
import
com.bkty.system.mapper.AiRecommendBaseMapper
;
import
com.bkty.system.mapper.AiRecommendBaseMapper
;
import
com.bkty.system.mapper.FunctionResumeBaseMapper
;
import
com.bkty.system.mapper.FunctionResumeBaseMapper
;
import
com.bkty.system.service.coze.CozeApiService
;
import
com.bkty.system.service.coze.CozeApiService
;
...
@@ -48,63 +50,54 @@ public class AiAnalysisServiceImpl extends ServiceImpl<AiRecommendBaseMapper, Ai
...
@@ -48,63 +50,54 @@ public class AiAnalysisServiceImpl extends ServiceImpl<AiRecommendBaseMapper, Ai
@Override
@Override
public
String
saveAnalysisData
(
AnalysisCareerDto
dto
)
{
public
String
saveAnalysisData
(
AnalysisCareerDto
dto
)
{
AiRecommendBase
aiRecommendBase
=
new
AiRecommendBase
();
AiRecommendBase
aiRecommendBase
=
new
AiRecommendBase
();
// if (StringUtils.isNotBlank(dto.getAnalysisId())){
aiRecommendBase
.
setResumeId
(
Long
.
valueOf
(
dto
.
getResumeId
()));
//简历id
// //String json = redisTemplate.opsForValue().get(CacheConstants.REDIS_USER_ANALYSIS_KEY.formatted(user.getId()));
aiRecommendBase
.
setPay
(
dto
.
getPay
());
//期望薪资
// aiRecommendBase = this.baseMapper.selectById(dto.getAnalysisId());
aiRecommendBase
.
setCareer
(
JSON
.
toJSONString
(
dto
.
getCareer
()));
//目标岗位
// }
aiRecommendBase
.
setTargetCity
(
JSON
.
toJSONString
(
dto
.
getTargetCity
()));
//目标城市
aiRecommendBase
.
setAuthRecommend
(
0
);
//自动推荐
/* if (CollectionUtil.isNotEmpty(dto.getCareer())){
aiRecommendBase
.
setRecommendStatus
(
0
);
//未推荐
aiRecommendBase.setCareer(JSON.toJSONString(dto.getCareer()));
aiRecommendBase
.
setUserId
(
Objects
.
requireNonNull
(
LoginHelper
.
getLoginUser
()).
getUserId
());
}
this
.
baseMapper
.
insert
(
aiRecommendBase
);
redisTemplate
.
opsForValue
().
set
(
CacheConstants
.
REDIS_USER_ANALYSIS_KEY
.
formatted
(
aiRecommendBase
.
getId
()),
JSON
.
toJSONString
(
aiRecommendBase
));
if (CollectionUtil.isNotEmpty(dto.getTargetCity())){
return
String
.
valueOf
(
aiRecommendBase
.
getId
());
aiRecommendBase.setTargetCity(JSON.toJSONString(dto.getTargetCity()));
}
}
if (StringUtils.isNotBlank(dto.getPay())){
@Override
aiRecommendBase.setPay(dto.getPay());
public
AiRecommendVo
queryAnalysisData
(
Long
analysisId
)
{
}
if (CollectionUtil.isNotEmpty(dto.getCompanyNature())){
AiRecommendVo
vo
=
new
AiRecommendVo
();
aiRecommendBase.setCompanyNature(JSON.toJSONString(dto.getCompanyNature()));
AiRecommendBase
recommendBase
=
null
;
String
recommendJson
=
redisTemplate
.
opsForValue
().
get
(
CacheConstants
.
REDIS_USER_ANALYSIS_KEY
.
formatted
(
analysisId
));
if
(
StringUtils
.
isBlank
(
recommendJson
)){
recommendBase
=
this
.
baseMapper
.
selectById
(
analysisId
);
}
else
{
recommendBase
=
JSON
.
parseObject
(
recommendJson
,
AiRecommendBase
.
class
);
}
}
if
(
StringUtils
.
isNotBlank
(
recommendBase
.
getCareer
())){
if (StringUtils.isNotBlank(dto.getMbti())){
List
<
String
>
list
=
JSON
.
parseObject
(
recommendBase
.
getCareer
(),
List
.
class
);
aiRecommendBase.setMbti(dto.getMbti()
);
vo
.
setCareer
(
list
);
}
}
if (null != dto.getWorkTime()){
if
(
StringUtils
.
isNotBlank
(
recommendBase
.
getTargetCity
())){
aiRecommendBase.setWorkTime(dto.getWorkTime());
List
<
String
>
list
=
JSON
.
parseObject
(
recommendBase
.
getTargetCity
(),
List
.
class
);
vo
.
setTargetCity
(
list
);
}
}
if (
null != dto.getInternTime(
)){
if
(
StringUtils
.
isNotBlank
(
recommendBase
.
getPay
()
)){
aiRecommendBase.setInternTime(dto.getInternTime
());
vo
.
setPay
(
recommendBase
.
getPay
());
}
}
if (
CollectionUtil.isNotEmpty(dto.getCompanySize()
)){
if
(
null
!=
recommendBase
.
getAuthRecommend
(
)){
aiRecommendBase.setCompanySize(JSON.toJSONString(dto.getCompanySize()
));
vo
.
setAuthRecommend
(
recommendBase
.
getAuthRecommend
(
));
}
}
if (null !=
dto.getJobType
()){
if
(
null
!=
recommendBase
.
getRecommendStatus
()){
aiRecommendBase.setJobType(dto.getJobType
());
vo
.
setRecommendStatus
(
recommendBase
.
getRecommendStatus
());
}
}
if (null != dto.getAuthRecommend()){
vo
.
setId
(
String
.
valueOf
(
recommendBase
.
getId
()));
aiRecommendBase.setAuthRecommend(dto.getAuthRecommend());
}
if (null != dto.getRecommendStatus()){
return
vo
;
aiRecommendBase.setRecommendStatus(dto.getRecommendStatus());
}*/
aiRecommendBase
.
setResumeId
(
Long
.
valueOf
(
dto
.
getResumeId
()));
//简历id
aiRecommendBase
.
setPay
(
dto
.
getPay
());
//期望薪资
aiRecommendBase
.
setCareer
(
JSON
.
toJSONString
(
dto
.
getCareer
()));
//目标岗位
aiRecommendBase
.
setTargetCity
(
JSON
.
toJSONString
(
dto
.
getTargetCity
()));
//目标城市
aiRecommendBase
.
setAuthRecommend
(
0
);
//自动推荐
aiRecommendBase
.
setRecommendStatus
(
0
);
//未推荐
aiRecommendBase
.
setUserId
(
Objects
.
requireNonNull
(
LoginHelper
.
getLoginUser
()).
getUserId
());
this
.
baseMapper
.
insert
(
aiRecommendBase
);
redisTemplate
.
opsForValue
().
set
(
Constants
.
REDIS_USER_ANALYSIS_KEY
.
formatted
(
aiRecommendBase
.
getId
()),
JSON
.
toJSONString
(
aiRecommendBase
));
return
String
.
valueOf
(
aiRecommendBase
.
getId
());
}
}
}
}
employmentBusiness-pc-modules/employmentBusiness-pc-system/src/main/java/com/bkty/system/service/jobRecommend/impl/JobRecommendServiceImpl.java
View file @
14c56833
package
com
.
bkty
.
system
.
service
.
jobRecommend
.
impl
;
package
com
.
bkty
.
system
.
service
.
jobRecommend
.
impl
;
import
com.bkty.system.domain.entity.AiRecommendBase
;
import
com.bkty.system.init.CategoryCacheManager
;
import
com.bkty.system.init.CategoryCacheManager
;
import
com.bkty.system.init.Level1Group
;
import
com.bkty.system.init.Level1Group
;
import
com.bkty.system.init.Level2Group
;
import
com.bkty.system.init.Level2Group
;
import
com.bkty.system.init.Level3Group
;
import
com.bkty.system.init.Level3Group
;
import
com.bkty.system.mapper.AiAnalysisMapper
;
import
com.bkty.system.service.jobRecommend.AiAnalysisService
;
import
com.bkty.system.service.jobRecommend.JobRecommendService
;
import
com.bkty.system.service.jobRecommend.JobRecommendService
;
import
com.bkty.system.service.jobRecommend.RecommendPositionService
;
import
lombok.RequiredArgsConstructor
;
import
lombok.RequiredArgsConstructor
;
import
lombok.extern.slf4j.Slf4j
;
import
lombok.extern.slf4j.Slf4j
;
import
org.apache.commons.collections4.CollectionUtils
;
import
org.apache.commons.collections4.CollectionUtils
;
import
org.dromara.common.core.domain.R
;
import
org.dromara.common.core.utils.DateTimeWrapper
;
import
org.dromara.common.core.utils.SecurityUtils
;
import
org.dromara.common.satoken.utils.LoginHelper
;
import
org.jetbrains.annotations.NotNull
;
import
org.jetbrains.annotations.NotNull
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.stereotype.Service
;
import
org.springframework.stereotype.Service
;
...
@@ -28,6 +36,11 @@ public class JobRecommendServiceImpl implements JobRecommendService {
...
@@ -28,6 +36,11 @@ public class JobRecommendServiceImpl implements JobRecommendService {
@Autowired
@Autowired
private
CategoryCacheManager
categoryCacheManager
;
private
CategoryCacheManager
categoryCacheManager
;
@Autowired
private
AiAnalysisMapper
aiAnalysisMapper
;
private
final
RecommendPositionService
recommendPositionService
;
@Override
@Override
public
List
<
Level1Group
>
getLevel1Groups
(
String
level1
)
{
public
List
<
Level1Group
>
getLevel1Groups
(
String
level1
)
{
...
@@ -60,4 +73,40 @@ public class JobRecommendServiceImpl implements JobRecommendService {
...
@@ -60,4 +73,40 @@ public class JobRecommendServiceImpl implements JobRecommendService {
}
}
return
result
;
return
result
;
}
}
@Override
public
void
recommendPosition
(
Long
analysisId
,
Long
userId
,
Long
resumeId
)
{
log
.
info
(
"开始推荐岗位"
);
if
(
userId
==
null
)
{
userId
=
LoginHelper
.
getLoginUser
().
getUserId
();
}
final
Long
thisUserId
=
userId
;
AiRecommendBase
aiRecommendBase
=
aiAnalysisMapper
.
selectById
(
analysisId
);
if
(
aiRecommendBase
.
getRecommendStatus
()
!=
null
&&
aiRecommendBase
.
getRecommendStatus
()
==
1
)
{
log
.
info
(
"用户数据推送中"
);
return
;
}
Integer
orlStatus
=
aiRecommendBase
.
getRecommendStatus
();
log
.
info
(
"修改岗位意向数据为推送中"
);
aiAnalysisMapper
.
updateAnalysis
(
analysisId
,
1
,
thisUserId
,
1
);
//开启一个异步线程调用方法
new
Thread
(
new
Runnable
()
{
@Override
public
void
run
()
{
//异步调用推荐岗位
log
.
info
(
"开始推荐岗位"
);
log
.
info
(
"推荐岗位参数:analysisId:{},userId:{}"
,
analysisId
,
thisUserId
);
try
{
recommendPositionService
.
recommendPosition
(
analysisId
,
thisUserId
,
resumeId
);
}
catch
(
Exception
e
)
{
log
.
info
(
"恢复岗位意向数据,错误信息:{}"
,
e
.
toString
());
aiAnalysisMapper
.
updateAnalysis
(
analysisId
,
orlStatus
,
thisUserId
,
1
);
}
}
}).
start
();
}
}
}
employmentBusiness-pc-modules/employmentBusiness-pc-system/src/main/java/com/bkty/system/service/jobRecommend/impl/PositionRecommendRedisServiceImpl.java
0 → 100644
View file @
14c56833
package
com
.
bkty
.
system
.
service
.
jobRecommend
.
impl
;
import
cn.hutool.core.collection.CollectionUtil
;
import
com.alibaba.fastjson2.JSON
;
import
com.alibaba.nacos.common.utils.StringUtils
;
import
com.baomidou.mybatisplus.core.conditions.query.QueryWrapper
;
import
com.baomidou.mybatisplus.core.toolkit.Wrappers
;
import
com.bkty.system.domain.entity.AiPositionRecommendRecord
;
import
com.bkty.system.domain.entity.FunctionPositionPortraitV2
;
import
com.bkty.system.domain.vo.AiPositionRecommendRecordVo
;
import
com.bkty.system.domain.vo.RecommendItem
;
import
com.bkty.system.mapper.PositionRecommendMapper
;
import
com.bkty.system.service.jobRecommend.PositionRecommendRedisService
;
import
com.bkty.system.service.jobRecommend.RecommendPositionService
;
import
lombok.AllArgsConstructor
;
import
lombok.extern.slf4j.Slf4j
;
import
org.dromara.common.core.constant.Constants
;
import
org.dromara.common.core.utils.DateTimeWrapper
;
import
org.springframework.data.redis.core.RedisTemplate
;
import
org.springframework.stereotype.Service
;
import
java.util.*
;
import
java.util.concurrent.TimeUnit
;
import
java.util.stream.Collectors
;
/**
* @author jiangxiaoge
* @description 岗位推荐Redis实现类
* @data 2025/3/28
**/
@Slf4j
@Service
@AllArgsConstructor
public
class
PositionRecommendRedisServiceImpl
implements
PositionRecommendRedisService
{
private
final
PositionRecommendMapper
positionRecommendMapper
;
private
final
RedisTemplate
<
String
,
Object
>
redisTemplate
;
private
final
RecommendPositionService
recommendPositionService
;
private
static
final
String
ALL_KEY
=
"recommend:%d:all"
;
private
static
final
String
NOT_READ_KEY
=
"recommend:%d:not_read"
;
private
static
final
String
FAVORITE_KEY
=
"recommend:%d:favorite"
;
private
static
final
String
NOT_SUITABLE_KEY
=
"recommend:%d:not_suitable"
;
private
static
final
String
DELIVERED_KEY
=
"recommend:%d:delivered"
;
private
static
final
String
RECOMMEND_ITEM_KEY
=
"recommend:%d:item:%d"
;
private
static
final
String
RECOMMEND_COUNT_KEY
=
"recommend:count:%d"
;
//推荐次数
@Override
public
boolean
initRedisData
(
Long
analysisId
)
{
// 1. 查询所有岗位推荐数据
QueryWrapper
<
AiPositionRecommendRecord
>
queryWrapper
=
Wrappers
.
query
();
queryWrapper
.
select
(
"id"
,
"resume_id"
,
"operation_type"
,
"treasures_type"
,
"deliver_type"
,
"city_code"
,
"r_details"
,
"position_score"
,
"jd_md"
);
queryWrapper
.
eq
(
"analysis_id"
,
analysisId
).
eq
(
"is_deleted"
,
false
);
List
<
AiPositionRecommendRecordVo
>
positions
=
positionRecommendMapper
.
selectPositionList
(
analysisId
,
null
,
null
,
null
,
null
,
null
,
null
,
null
,
null
);
if
(
CollectionUtil
.
isEmpty
(
positions
)){
//无岗位推荐数据
return
false
;
}
Map
<
String
,
List
<
AiPositionRecommendRecordVo
>>
queryGroup
=
positions
.
stream
().
collect
(
Collectors
.
groupingBy
(
AiPositionRecommendRecordVo:
:
getCityCode
));
List
<
FunctionPositionPortraitV2
>
portraitV2s
=
new
ArrayList
<>();
for
(
Map
.
Entry
<
String
,
List
<
AiPositionRecommendRecordVo
>>
entry
:
queryGroup
.
entrySet
())
{
String
cityCode
=
entry
.
getKey
();
portraitV2s
.
addAll
(
recommendPositionService
.
queryPositionList
(
cityCode
,
entry
.
getValue
().
stream
().
map
(
AiPositionRecommendRecordVo:
:
getPositionId
).
toList
()));
}
Map
<
Long
,
FunctionPositionPortraitV2
>
collect
=
portraitV2s
.
stream
().
collect
(
Collectors
.
toMap
(
FunctionPositionPortraitV2:
:
getPositionDataId
,
p
->
p
));
// 构造 Redis Key
String
allKey
=
String
.
format
(
ALL_KEY
,
analysisId
);
String
notReadKey
=
String
.
format
(
NOT_READ_KEY
,
analysisId
);
String
favoriteKey
=
String
.
format
(
FAVORITE_KEY
,
analysisId
);
String
notSuitableKey
=
String
.
format
(
NOT_SUITABLE_KEY
,
analysisId
);
String
deliveredKey
=
String
.
format
(
DELIVERED_KEY
,
analysisId
);
delRedisKey
(
allKey
,
notReadKey
,
favoriteKey
,
notSuitableKey
,
deliveredKey
);
// 2. 遍历数据,将其存入 Redis
for
(
AiPositionRecommendRecordVo
position
:
positions
)
{
savePositionToRedis
(
collect
.
get
(
position
.
getPositionId
()),
position
,
analysisId
);
}
return
true
;
}
private
void
delRedisKey
(
String
...
keys
){
redisTemplate
.
delete
(
List
.
of
(
keys
));
}
@Override
public
void
savePositionToRedis
(
FunctionPositionPortraitV2
portraitV2
,
AiPositionRecommendRecordVo
position
,
Long
analysisId
)
{
// 构造 Redis Key
//String allKey = String.format(ALL_KEY, userId);
String
notReadKey
=
String
.
format
(
NOT_READ_KEY
,
analysisId
);
String
favoriteKey
=
String
.
format
(
FAVORITE_KEY
,
analysisId
);
String
notSuitableKey
=
String
.
format
(
NOT_SUITABLE_KEY
,
analysisId
);
String
deliveredKey
=
String
.
format
(
DELIVERED_KEY
,
analysisId
);
Long
resumeId
=
position
.
getResumeId
();
Long
positionId
=
position
.
getId
();
RecommendItem
item
=
new
RecommendItem
();
item
.
setId
(
position
.
getId
());
item
.
setCity
(
position
.
getCityCode
());
item
.
setStandardPosition
(
portraitV2
.
getStandardPosition
());
item
.
setWelfare
(
portraitV2
.
getWelfare
());
item
.
setSalaryRange
(
portraitV2
.
getSalaryRange
());
item
.
setCompanyName
(
portraitV2
.
getCompanyName
());
item
.
setCompanyNature
(
portraitV2
.
getCompanyNature
());
item
.
setCreateTime
(
DateTimeWrapper
.
parseFromDate
(
position
.
getRecommendTime
(),
null
).
toString
(
Constants
.
DATE_FULL_FORMAT
));
item
.
setRDetails
(
position
.
getRDetails
());
item
.
setPositionScore
(
position
.
getPositionScore
());
//R<String> stringR = remoteResumeService.queryResumeName(resumeId);
item
.
setResumeName
(
position
.
getResumeName
());
item
.
setJobTitle
(
position
.
getJobTitle
());
item
.
setJdMd
(
position
.
getJdMd
());
try
{
item
.
setMaxPay
(
Integer
.
valueOf
(
portraitV2
.
getSalaryRange
().
split
(
"-"
)[
1
]));
}
catch
(
Exception
e
){
item
.
setMaxPay
(
0
);
}
if
(
resumeId
==
null
||
positionId
==
null
)
{
return
;
}
// 2.1 存入 "全部" 集合
long
createTimeTimestamp
=
position
.
getCreateTime
().
getTime
();
//redisTemplate.opsForZSet().add(allKey, position.getId(), createTimeTimestamp);
// 2.2 根据岗位状态存入对应的 Redis 集合
if
(
position
.
getPositionScore
()
==
null
||
position
.
getPositionScore
()
==
0
)
{
redisTemplate
.
opsForZSet
().
add
(
notReadKey
,
position
.
getId
(),
createTimeTimestamp
);
}
if
(
position
.
getPositionScore
()
!=
null
&&
position
.
getPositionScore
()
>
4
)
{
redisTemplate
.
opsForZSet
().
add
(
favoriteKey
,
position
.
getId
(),
createTimeTimestamp
);
}
if
(
position
.
getPositionScore
()
!=
null
&&
position
.
getPositionScore
()
<
5
)
{
redisTemplate
.
opsForZSet
().
add
(
notSuitableKey
,
position
.
getId
(),
createTimeTimestamp
);
}
if
(
position
.
getDeliverType
()
!=
null
&&
position
.
getDeliverType
()
==
1
)
{
redisTemplate
.
opsForZSet
().
add
(
deliveredKey
,
position
.
getId
(),
createTimeTimestamp
);
}
// 2.3 将 RecommendItem 对象转换为 JSON 字符串并存储到 Redis 中
try
{
String
jsonString
=
JSON
.
toJSONString
(
item
);
redisTemplate
.
opsForValue
().
set
(
String
.
format
(
RECOMMEND_ITEM_KEY
,
analysisId
,
positionId
),
jsonString
);
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
}
}
}
\ No newline at end of file
employmentBusiness-pc-modules/employmentBusiness-pc-system/src/main/java/com/bkty/system/service/jobRecommend/impl/RecommendPositionServiceImpl.java
0 → 100644
View file @
14c56833
This diff is collapsed.
Click to expand it.
employmentBusiness-pc-modules/employmentBusiness-pc-system/src/main/java/com/bkty/system/service/resume/NewEditionResumeService.java
View file @
14c56833
package
com
.
bkty
.
system
.
service
.
resume
;
package
com
.
bkty
.
system
.
service
.
resume
;
import
com.bkty.system.domain.dto.*
;
import
com.bkty.system.domain.dto.*
;
import
com.bkty.system.domain.entity.FunctionResumeSketch
;
import
com.bkty.system.domain.vo.ResumeByPdfVo
;
import
com.bkty.system.domain.vo.ResumeByPdfVo
;
import
com.bkty.system.domain.vo.ResumeModelVo
;
import
com.bkty.system.domain.vo.ResumeModelVo
;
import
com.bkty.system.domain.vo.ResumeVo
;
import
com.bkty.system.domain.vo.ResumeVo
;
...
@@ -120,4 +121,5 @@ public interface NewEditionResumeService {
...
@@ -120,4 +121,5 @@ public interface NewEditionResumeService {
*/
*/
void
reversalExperience
(
ResumeExpChangeDto
dto
)
throws
Exception
;
void
reversalExperience
(
ResumeExpChangeDto
dto
)
throws
Exception
;
}
}
employmentBusiness-pc-modules/employmentBusiness-pc-system/src/main/java/com/bkty/system/service/resume/ResumeMakeService.java
0 → 100644
View file @
14c56833
package
com
.
bkty
.
system
.
service
.
resume
;
import
com.baomidou.mybatisplus.extension.service.IService
;
import
com.bkty.system.domain.entity.FunctionResumeBase
;
import
com.bkty.system.domain.entity.FunctionResumeSketch
;
/**
* @author jiangxiaoge
* @description 简历制作Service
* @data 2024/12/16
**/
public
interface
ResumeMakeService
extends
IService
<
FunctionResumeBase
>
{
/**
* 查询简历分析详情
* @param resumeId
* @return
*/
FunctionResumeSketch
queryResumeSketch
(
Long
resumeId
);
}
employmentBusiness-pc-modules/employmentBusiness-pc-system/src/main/java/com/bkty/system/service/resume/impl/ResumeMakeServiceImpl.java
0 → 100644
View file @
14c56833
package
com
.
bkty
.
system
.
service
.
resume
.
impl
;
import
com.baomidou.mybatisplus.core.conditions.query.QueryWrapper
;
import
com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper
;
import
com.baomidou.mybatisplus.extension.service.impl.ServiceImpl
;
import
com.bkty.system.domain.entity.FunctionResumeBase
;
import
com.bkty.system.domain.entity.FunctionResumeSketch
;
import
com.bkty.system.domain.vo.ResumeVo
;
import
com.bkty.system.mapper.FunctionResumeBaseMapper
;
import
com.bkty.system.mapper.FunctionResumeSketchMapper
;
import
com.bkty.system.service.coze.CozeApiService
;
import
com.bkty.system.service.resume.NewEditionResumeService
;
import
com.bkty.system.service.resume.ResumeMakeService
;
import
lombok.AllArgsConstructor
;
import
lombok.extern.slf4j.Slf4j
;
import
dev.langchain4j.model.embedding.EmbeddingModel
;
import
org.dromara.common.core.config.LlmEmbeddingConfig
;
import
org.dromara.common.core.constant.CozeConstsnts
;
import
org.springframework.http.HttpHeaders
;
import
org.springframework.stereotype.Service
;
import
java.util.*
;
/**
* @author Zhang Wenbiao
* @description 简历制作service
* @datetime 2025/12/4 16:25
*/
@Slf4j
@AllArgsConstructor
@Service
public
class
ResumeMakeServiceImpl
extends
ServiceImpl
<
FunctionResumeBaseMapper
,
FunctionResumeBase
>
implements
ResumeMakeService
{
private
final
NewEditionResumeService
newEditionResumeService
;
private
final
CozeApiService
cozeApiService
;
private
final
FunctionResumeSketchMapper
resumeSketchMapper
;
@Override
public
FunctionResumeSketch
queryResumeSketch
(
Long
resumeId
)
{
try
{
ResumeVo
join
=
newEditionResumeService
.
queryNewEditionResumeId
(
String
.
valueOf
(
resumeId
)).
join
();
String
resumeDescByCoze
=
getResumeDescByCoze
(
com
.
alibaba
.
fastjson2
.
JSON
.
toJSONString
(
join
),
"7506433655737630720"
);
EmbeddingModel
embeddingModel
=
LlmEmbeddingConfig
.
getEmbeddingModel
();
List
<
Float
>
dutyVector
=
embeddingModel
.
embed
(
resumeDescByCoze
).
content
().
vectorAsList
();
QueryWrapper
<
FunctionResumeSketch
>
queryWrapper
=
new
QueryWrapper
<>();
queryWrapper
.
eq
(
"resume_id"
,
resumeId
).
eq
(
"is_deleted"
,
false
);
FunctionResumeSketch
resumeSketch
=
new
FunctionResumeSketch
();
resumeSketch
.
setResumeId
(
resumeId
);
resumeSketch
.
setSketch
(
resumeDescByCoze
);
resumeSketch
.
setVectorQuantity
(
com
.
alibaba
.
fastjson2
.
JSON
.
toJSONString
(
dutyVector
));
if
(
resumeSketchMapper
.
exists
(
queryWrapper
))
{
UpdateWrapper
<
FunctionResumeSketch
>
updateWrapper
=
new
UpdateWrapper
<>();
updateWrapper
.
eq
(
"resume_id"
,
resumeId
).
eq
(
"is_deleted"
,
false
)
.
set
(
"sketch"
,
resumeDescByCoze
).
set
(
"vector_quantity"
,
com
.
alibaba
.
fastjson2
.
JSON
.
toJSONString
(
dutyVector
));
resumeSketchMapper
.
update
(
null
,
updateWrapper
);
}
else
{
resumeSketchMapper
.
insert
(
resumeSketch
);
}
return
resumeSketch
;
}
catch
(
Exception
e
)
{
throw
new
RuntimeException
(
e
);
}
}
private
String
getResumeDescByCoze
(
String
sendData
,
String
botId
)
throws
Exception
{
String
cozeToken
=
cozeApiService
.
getCozeToken
();
// 构建请求头
Map
<
String
,
String
>
headers
=
new
HashMap
<>();
headers
.
put
(
"Content-Type"
,
"application/json"
);
headers
.
put
(
HttpHeaders
.
AUTHORIZATION
,
CozeConstsnts
.
COZE_TOKEN_BEARER
+
cozeToken
);
List
<
Map
<
String
,
Object
>>
additionalMessages
=
new
ArrayList
<>();
Map
<
String
,
Object
>
content
=
Map
.
of
(
"content_type"
,
"text"
,
"content"
,
sendData
,
"role"
,
"user"
);
additionalMessages
.
add
(
content
);
Map
<
String
,
Object
>
body
=
Map
.
of
(
"bot_id"
,
botId
,
"user_id"
,
"9527"
,
"stream"
,
false
,
"additional_messages"
,
additionalMessages
);
String
uri
=
cozeApiService
.
getCozeDomainUri
()
+
"/v3/chat"
;
// 使用 Hutool 发送 POST 请求
try
{
String
jsonBody
=
com
.
alibaba
.
fastjson2
.
JSON
.
toJSONString
(
body
);
cn
.
hutool
.
http
.
HttpRequest
request
=
cn
.
hutool
.
http
.
HttpRequest
.
post
(
uri
)
.
addHeaders
(
headers
)
.
body
(
jsonBody
)
.
timeout
(
30000
);
// 设置超时时间 30 秒
cn
.
hutool
.
http
.
HttpResponse
response
=
request
.
execute
();
String
responseBody
=
response
.
body
();
Map
<
String
,
Object
>
map
=
com
.
alibaba
.
fastjson2
.
JSON
.
parseObject
(
responseBody
,
Map
.
class
);
String
code
=
Objects
.
toString
(
map
.
get
(
"code"
),
""
);
if
(
code
.
equals
(
"0"
))
{
Map
<
String
,
Object
>
data
=
(
Map
<
String
,
Object
>)
map
.
get
(
"data"
);
String
status
=
Objects
.
toString
(
data
.
get
(
"status"
),
""
);
boolean
inProgress
=
status
.
equals
(
"in_progress"
);
while
(
inProgress
)
{
String
retrieveUri
=
cozeApiService
.
getCozeDomainUri
()
+
"/v3/chat/retrieve?chat_id=%s&conversation_id=%s"
.
formatted
(
data
.
get
(
"id"
).
toString
(),
data
.
get
(
"conversation_id"
).
toString
());
// 使用 Hutool 发送 GET 请求
cn
.
hutool
.
http
.
HttpRequest
retrieveRequest
=
cn
.
hutool
.
http
.
HttpRequest
.
get
(
retrieveUri
)
.
addHeaders
(
headers
)
.
timeout
(
30000
);
cn
.
hutool
.
http
.
HttpResponse
retrieveResponse
=
retrieveRequest
.
execute
();
String
retrieveResponseBody
=
retrieveResponse
.
body
();
System
.
out
.
println
(
retrieveResponseBody
);
Map
<
String
,
Object
>
mapData
=
com
.
alibaba
.
fastjson2
.
JSON
.
parseObject
(
retrieveResponseBody
,
Map
.
class
);
if
(!
"0"
.
equals
(
mapData
.
get
(
"code"
).
toString
()))
{
break
;
}
Map
<
String
,
Object
>
rData
=
(
Map
<
String
,
Object
>)
mapData
.
get
(
"data"
);
String
status1
=
rData
.
get
(
"status"
).
toString
();
inProgress
=
status1
.
equals
(
"in_progress"
);
if
(
status1
.
equals
(
"completed"
))
{
String
messageListUri
=
cozeApiService
.
getCozeDomainUri
()
+
"/v3/chat/message/list?chat_id=%s&conversation_id=%s"
.
formatted
(
data
.
get
(
"id"
).
toString
(),
data
.
get
(
"conversation_id"
).
toString
());
// 使用 Hutool 发送 GET 请求
cn
.
hutool
.
http
.
HttpRequest
messageListRequest
=
cn
.
hutool
.
http
.
HttpRequest
.
get
(
messageListUri
)
.
addHeaders
(
headers
)
.
timeout
(
30000
);
cn
.
hutool
.
http
.
HttpResponse
messageListResponse
=
messageListRequest
.
execute
();
String
messageListResponseBody
=
messageListResponse
.
body
();
com
.
alibaba
.
fastjson2
.
JSONObject
jsonObject
=
com
.
alibaba
.
fastjson2
.
JSON
.
parseObject
(
messageListResponseBody
);
if
(
jsonObject
!=
null
)
{
if
(
jsonObject
.
getInteger
(
"code"
)
==
0
)
{
com
.
alibaba
.
fastjson2
.
JSONArray
jsonArray
=
jsonObject
.
getJSONArray
(
"data"
);
for
(
int
i
=
0
;
i
<
jsonArray
.
size
();
i
++)
{
com
.
alibaba
.
fastjson2
.
JSONObject
thisJsonObject
=
jsonArray
.
getJSONObject
(
i
);
if
(
thisJsonObject
.
getString
(
"type"
).
equals
(
"answer"
))
{
String
contentString
=
thisJsonObject
.
getString
(
"content"
);
contentString
=
contentString
.
replace
(
"```json"
,
""
);
contentString
=
contentString
.
replace
(
"```"
,
""
);
log
.
info
(
"执行成功,简历信息:{}\n描述信息:{}"
,
data
,
contentString
);
return
contentString
;
}
}
}
}
}
Thread
.
sleep
(
1000
);
}
}
}
catch
(
Exception
e
)
{
log
.
error
(
"发送HTTP请求时发生异常: "
,
e
);
throw
new
Exception
(
"请求发送失败: "
+
e
.
getMessage
(),
e
);
}
return
null
;
}
}
employmentBusiness-pc-modules/employmentBusiness-pc-system/src/main/java/com/bkty/system/utils/MariaDbAdtUtil.java
0 → 100644
View file @
14c56833
package
com
.
bkty
.
system
.
utils
;
import
java.sql.*
;
import
java.util.Iterator
;
import
java.util.Map
;
import
java.util.NoSuchElementException
;
import
java.util.HashMap
;
public
class
MariaDbAdtUtil
{
// 数据库连接配置
//private static final String JDBC_URL = "jdbc:mariadb://127.0.0.1:33066/gov_datacenter";
private
static
final
String
JDBC_URL
=
"jdbc:mariadb://192.168.1.218:3306/gov_datacenter"
;
private
static
final
String
JDBC_USERNAME
=
"wangwenjiang"
;
private
static
final
String
JDBC_PASSWORD
=
"Q8$l63I6-iijE3^9"
;
/**
* 获取 MariaDB 数据库连接
*/
private
static
Connection
getConnection
()
throws
SQLException
{
return
DriverManager
.
getConnection
(
JDBC_URL
,
JDBC_USERNAME
,
JDBC_PASSWORD
);
}
/**
* 根据ID查询recruit_qqxb表,返回单条记录的Map表示
*
* @param id 要查询的记录ID
* @return 包含记录字段的Map,如果未找到记录则返回null
*/
public
static
Map
<
String
,
Object
>
queryRecruitQqxbById
(
long
id
)
{
String
query
=
"SELECT * FROM recruit_qqxb WHERE id = ?"
;
int
maxRetries
=
3
;
for
(
int
attempt
=
0
;
attempt
<
maxRetries
;
attempt
++)
{
try
(
Connection
connection
=
getConnection
();
PreparedStatement
statement
=
connection
.
prepareStatement
(
query
))
{
statement
.
setLong
(
1
,
id
);
statement
.
setQueryTimeout
(
10
);
// 设置查询超时为10秒
try
(
ResultSet
resultSet
=
statement
.
executeQuery
())
{
if
(
resultSet
.
next
())
{
return
resultSetToMap
(
resultSet
);
}
return
null
;
}
}
catch
(
SQLException
e
)
{
if
(
attempt
==
maxRetries
-
1
)
{
throw
new
RuntimeException
(
"查询recruit_qqxb表 id:"
+
id
+
"失败: "
+
e
.
getMessage
(),
e
);
}
try
{
Thread
.
sleep
(
1000
);
// 等待1秒后重试
}
catch
(
InterruptedException
ie
)
{
Thread
.
currentThread
().
interrupt
();
throw
new
RuntimeException
(
"查询被中断"
,
ie
);
}
}
}
return
null
;
}
/**
* 将ResultSet当前行转换为Map<String, Object>
*
* @param resultSet 查询结果集
* @return 包含当前行数据的Map
* @throws SQLException SQL异常
*/
private
static
Map
<
String
,
Object
>
resultSetToMap
(
ResultSet
resultSet
)
throws
SQLException
{
Map
<
String
,
Object
>
resultMap
=
new
HashMap
<>();
ResultSetMetaData
metaData
=
resultSet
.
getMetaData
();
int
columnCount
=
metaData
.
getColumnCount
();
for
(
int
i
=
1
;
i
<=
columnCount
;
i
++)
{
String
columnName
=
metaData
.
getColumnLabel
(
i
);
Object
value
=
resultSet
.
getObject
(
i
);
resultMap
.
put
(
columnName
,
value
);
}
return
resultMap
;
}
/**
* 查询并返回游标迭代器
*/
public
static
Iterable
<
Map
.
Entry
<
Integer
,
String
>>
queryWithCursor
(
String
query
)
{
return
()
->
new
Iterator
<>()
{
private
Connection
connection
;
private
PreparedStatement
statement
;
private
ResultSet
resultSet
;
private
boolean
isNextAvailable
;
{
try
{
// 初始化数据库连接和查询
connection
=
getConnection
();
statement
=
connection
.
prepareStatement
(
query
,
ResultSet
.
TYPE_FORWARD_ONLY
,
ResultSet
.
CONCUR_READ_ONLY
);
statement
.
setFetchSize
(
Integer
.
MIN_VALUE
);
// 启用游标模式
resultSet
=
statement
.
executeQuery
();
isNextAvailable
=
resultSet
.
next
();
// 移动到第一条记录
}
catch
(
SQLException
e
)
{
close
();
// 出现异常时清理资源
throw
new
RuntimeException
(
"查询执行失败: "
+
e
.
getMessage
(),
e
);
}
}
@Override
public
boolean
hasNext
()
{
return
isNextAvailable
;
}
@Override
public
Map
.
Entry
<
Integer
,
String
>
next
()
{
if
(!
isNextAvailable
)
{
throw
new
NoSuchElementException
(
"没有更多数据"
);
}
try
{
// 读取 position_id 和 position_portrayal 字段
int
positionId
=
resultSet
.
getInt
(
"position_id"
);
String
positionPortrayal
=
resultSet
.
getString
(
"position_portrayal"
);
isNextAvailable
=
resultSet
.
next
();
// 移动到下一条记录
return
new
HashMap
.
SimpleEntry
<>(
positionId
,
positionPortrayal
);
}
catch
(
SQLException
e
)
{
throw
new
RuntimeException
(
"获取下一条数据失败: "
+
e
.
getMessage
(),
e
);
}
}
/**
* 关闭资源
*/
private
void
close
()
{
try
{
if
(
resultSet
!=
null
)
resultSet
.
close
();
if
(
statement
!=
null
)
statement
.
close
();
if
(
connection
!=
null
)
connection
.
close
();
}
catch
(
SQLException
e
)
{
e
.
printStackTrace
();
}
}
@Override
protected
void
finalize
()
throws
Throwable
{
close
();
super
.
finalize
();
}
};
}
public
static
void
main
(
String
[]
args
)
{
/*String query = "SELECT position_id, position_portrayal FROM function_position_portrayal WHERE is_deleted = false";
for (Map.Entry<Integer, String> entry : queryWithCursor(query)) {
System.out.println("Position ID: " + entry.getKey() + ", Position Portrayal: " + entry.getValue());
// 在这里处理每条数据
}*/
// 新增功能测试
long
idToQuery
=
38243537L
;
Map
<
String
,
Object
>
result
=
queryRecruitQqxbById
(
idToQuery
);
if
(
result
!=
null
)
{
System
.
out
.
println
(
"查询结果:"
);
result
.
forEach
((
key
,
value
)
->
System
.
out
.
println
(
key
+
": "
+
value
));
}
else
{
System
.
out
.
println
(
"未找到ID为 "
+
idToQuery
+
" 的记录"
);
}
}
}
employmentBusiness-pc-modules/employmentBusiness-pc-system/src/main/resources/mapper/system/AiAnalysisMapper.xml
0 → 100644
View file @
14c56833
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper
namespace=
"com.bkty.system.mapper.AiAnalysisMapper"
>
<update
id=
"updateAnalysis"
>
update ai_recommend_base set
recommend_status = #{rType}
<if
test=
"authRecommend != null"
>
, auth_recommend = #{authRecommend}
</if>
where id = #{analysisId}
</update>
</mapper>
\ No newline at end of file
employmentBusiness-pc-modules/employmentBusiness-pc-system/src/main/resources/mapper/system/PositionRecommendMapper.xml
0 → 100644
View file @
14c56833
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper
namespace=
"com.bkty.system.mapper.PositionRecommendMapper"
>
<select
id=
"selectPositionList"
resultType=
"com.bkty.system.domain.vo.AiPositionRecommendRecordVo"
>
SELECT
t1.*, t2.resume_name as resumeName
FROM
ai_position_recommend_record t1, function_resume_base t2
WHERE
t1.is_deleted = 0 and
t1.analysis_id = #{analysisId} and
t1.resume_id = t2.id
<if
test=
"queryType == 1 and recommendTime == null"
>
AND t1.recommend_time = (SELECT MAX(recommend_time) FROM ai_position_recommend_record WHERE analysis_id = #{analysisId} AND is_deleted = 0)
ORDER BY t1.r_score DESC
</if>
<if
test=
"queryType == 1 and recommendTime != null"
>
AND t1.recommend_time = #{recommendTime}
ORDER BY t1.r_score DESC
</if>
<if
test=
"queryType == 0"
>
AND t1.operation_type = 1
<if
test=
"deliverType != null"
>
AND t1.treasures_type != 2
</if>
<choose>
<when
test=
"sortField != null and sortField != ''"
>
ORDER BY t1.${sortField} ${sortType}
</when>
<otherwise>
ORDER BY t1.update_time DESC
</otherwise>
</choose>
</if>
<if
test=
"queryType == 2"
>
AND t1.treasures_type = 1
order by t1.create_time desc
</if>
<if
test=
"queryType == 3"
>
AND t1.treasures_type = 2
order by t1.create_time desc
</if>
<if
test=
"queryType == 4"
>
AND t1.deliver_type = 1
order by t1.create_time desc
</if>
<if
test=
"pId != null"
>
AND t1.id = #{pId}
</if>
<if
test=
"start != null"
>
limit #{start}, #{size}
</if>
</select>
</mapper>
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment