Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
E
elleai
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
ai-tech
E
ellehuis-group
backend
elleai
Commits
c02dd4e7
Commit
c02dd4e7
authored
Oct 21, 2024
by
陈立彬
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
1.pinyin4j 2.AI问答切回dify
parent
261128ef
Changes
29
Hide whitespace changes
Inline
Side-by-side
Showing
29 changed files
with
407 additions
and
55 deletions
+407
-55
pom.xml
pom.xml
+6
-0
AiChatComplateResultDto.java
...elleai/application/dto/inner/AiChatComplateResultDto.java
+19
-0
ExamineQaRequestDto.java
...e/elleai/application/dto/request/ExamineQaRequestDto.java
+8
-0
ExamineRecordRequestDto.java
...leai/application/dto/request/ExamineRecordRequestDto.java
+4
-0
ExamineRequestDto.java
...eze/elleai/application/dto/request/ExamineRequestDto.java
+16
-0
ExamineSceneCategoryRequestDto.java
...plication/dto/request/ExamineSceneCategoryRequestDto.java
+3
-0
ExamineSceneRequestDto.java
...lleai/application/dto/request/ExamineSceneRequestDto.java
+3
-0
ProperNounRequestDto.java
.../elleai/application/dto/request/ProperNounRequestDto.java
+3
-0
QaAssistantRequestDto.java
...elleai/application/dto/request/QaAssistantRequestDto.java
+6
-1
UserQaRequestDto.java
...eeze/elleai/application/dto/request/UserQaRequestDto.java
+13
-0
WikiRequestDto.java
...breeze/elleai/application/dto/request/WikiRequestDto.java
+9
-2
AppChatCompletionService.java
.../elleai/application/service/AppChatCompletionService.java
+72
-21
AppCommonService.java
...n/breeze/elleai/application/service/AppCommonService.java
+16
-3
AppExamineService.java
.../breeze/elleai/application/service/AppExamineService.java
+9
-0
ExamineQaController.java
...n/breeze/elleai/controller/admin/ExamineQaController.java
+12
-0
ChatCompletionMobileController.java
...leai/controller/front/ChatCompletionMobileController.java
+1
-2
ExamineQaRequestModel.java
.../domain/sparring/model/request/ExamineQaRequestModel.java
+3
-1
ExamineRecordRequestModel.java
...ain/sparring/model/request/ExamineRecordRequestModel.java
+2
-0
ExamineRequestModel.java
...ai/domain/sparring/model/request/ExamineRequestModel.java
+8
-3
ProperNounRequestModel.java
...domain/sparring/model/request/ProperNounRequestModel.java
+2
-1
QaAssistantRequestModel.java
...omain/sparring/model/request/QaAssistantRequestModel.java
+2
-1
UserQaRequestModel.java
...eai/domain/sparring/model/request/UserQaRequestModel.java
+11
-0
WikiRequestModel.java
...lleai/domain/sparring/model/request/WikiRequestModel.java
+7
-1
ChatCompletionServiceImpl.java
...ai/domain/sparring/service/ChatCompletionServiceImpl.java
+19
-4
CommonServiceImpl.java
...eze/elleai/domain/sparring/service/CommonServiceImpl.java
+3
-0
ExamineService.java
...breeze/elleai/domain/sparring/service/ExamineService.java
+2
-0
ExamineServiceImpl.java
...ze/elleai/domain/sparring/service/ExamineServiceImpl.java
+48
-15
ChineseCharacterUtil.java
...main/java/cn/breeze/elleai/util/ChineseCharacterUtil.java
+98
-0
application.yml
src/main/resources/application.yml
+2
-0
No files found.
pom.xml
View file @
c02dd4e7
...
...
@@ -143,6 +143,12 @@
<version>
2.3.2
</version>
</dependency>
<dependency>
<groupId>
com.belerweb
</groupId>
<artifactId>
pinyin4j
</artifactId>
<version>
2.5.1
</version>
</dependency>
</dependencies>
<build>
...
...
src/main/java/cn/breeze/elleai/application/dto/inner/AiChatComplateResultDto.java
0 → 100644
View file @
c02dd4e7
package
cn
.
breeze
.
elleai
.
application
.
dto
.
inner
;
import
io.swagger.v3.oas.annotations.media.Schema
;
import
lombok.Data
;
import
java.io.Serializable
;
/**
* AI问答结果
*/
@Data
public
class
AiChatComplateResultDto
implements
Serializable
{
@Schema
(
description
=
"ai回复结果"
)
private
String
content
;
@Schema
(
description
=
"DIFY会话ID"
)
private
String
difySessionId
;;
}
src/main/java/cn/breeze/elleai/application/dto/request/ExamineQaRequestDto.java
View file @
c02dd4e7
...
...
@@ -19,4 +19,12 @@ public class ExamineQaRequestDto implements Serializable {
@Schema
(
description
=
"题目名称"
)
private
String
name
;
@Schema
(
description
=
"对练分类ID"
)
@JsonProperty
(
"category_id"
)
private
Integer
categoryId
;
@Schema
(
description
=
"状态(0禁用 1启用)"
)
private
Integer
status
;
}
src/main/java/cn/breeze/elleai/application/dto/request/ExamineRecordRequestDto.java
View file @
c02dd4e7
...
...
@@ -22,6 +22,10 @@ public class ExamineRecordRequestDto implements Serializable {
@JsonProperty
(
"user_id"
)
private
String
userId
;
@Schema
(
description
=
"用户名称"
)
@JsonProperty
(
"user_name"
)
private
String
userName
;
@Schema
(
description
=
"考试ID"
)
@JsonProperty
(
"examine_id"
)
private
Integer
examineId
;
...
...
src/main/java/cn/breeze/elleai/application/dto/request/ExamineRequestDto.java
View file @
c02dd4e7
...
...
@@ -5,6 +5,7 @@ import io.swagger.v3.oas.annotations.media.Schema;
import
lombok.Data
;
import
java.io.Serializable
;
import
java.util.Date
;
@Data
public
class
ExamineRequestDto
implements
Serializable
{
...
...
@@ -20,7 +21,22 @@ public class ExamineRequestDto implements Serializable {
@Schema
(
description
=
"对练名称"
)
private
String
name
;
@Schema
(
description
=
"场景ID"
)
@JsonProperty
(
"scene_id"
)
private
Integer
sceneId
;
@Schema
(
description
=
"场景分类ID"
)
@JsonProperty
(
"category_id"
)
private
Integer
categoryId
;
@Schema
(
description
=
"状态(0禁用 1启用)"
)
private
Integer
status
;
@Schema
(
description
=
"开始时间"
)
@JsonProperty
(
"start_time"
)
private
Date
startTime
;
@Schema
(
description
=
"结束时间"
)
@JsonProperty
(
"end_time"
)
private
Date
endTime
;
}
src/main/java/cn/breeze/elleai/application/dto/request/ExamineSceneCategoryRequestDto.java
View file @
c02dd4e7
...
...
@@ -24,4 +24,7 @@ public class ExamineSceneCategoryRequestDto implements Serializable {
@Schema
(
description
=
"场景ID"
)
@JsonProperty
(
"scene_id"
)
private
Integer
sceneId
;
@Schema
(
description
=
"状态(0禁用 1启用)"
)
private
Integer
status
;
}
src/main/java/cn/breeze/elleai/application/dto/request/ExamineSceneRequestDto.java
View file @
c02dd4e7
...
...
@@ -20,4 +20,7 @@ public class ExamineSceneRequestDto implements Serializable {
@Schema
(
description
=
"场景名称"
)
private
String
name
;
@Schema
(
description
=
"状态(0禁用 1启用)"
)
private
Integer
status
;
}
src/main/java/cn/breeze/elleai/application/dto/request/ProperNounRequestDto.java
View file @
c02dd4e7
...
...
@@ -20,4 +20,7 @@ public class ProperNounRequestDto implements Serializable {
@Schema
(
description
=
"专有名词名称"
)
private
String
name
;
@Schema
(
description
=
"状态(0禁用 1启用)"
)
private
Integer
status
;
}
src/main/java/cn/breeze/elleai/application/dto/request/QaAssistantRequestDto.java
View file @
c02dd4e7
...
...
@@ -16,5 +16,10 @@ public class QaAssistantRequestDto implements Serializable {
@Schema
(
description
=
"分页数量"
)
@JsonProperty
(
"page_size"
)
private
Integer
pageSize
=
10
;
@Schema
(
description
=
"助手名称"
)
private
String
name
;
@Schema
(
description
=
"状态(0禁用 1启用)"
)
private
Integer
status
;
}
src/main/java/cn/breeze/elleai/application/dto/request/UserQaRequestDto.java
View file @
c02dd4e7
...
...
@@ -5,6 +5,7 @@ import io.swagger.v3.oas.annotations.media.Schema;
import
lombok.Data
;
import
java.io.Serializable
;
import
java.util.Date
;
@Data
public
class
UserQaRequestDto
implements
Serializable
{
...
...
@@ -20,4 +21,16 @@ public class UserQaRequestDto implements Serializable {
@Schema
(
description
=
"用户ID"
)
@JsonProperty
(
"user_id"
)
private
String
userId
;
@Schema
(
description
=
"用户名称"
)
@JsonProperty
(
"user_name"
)
private
String
userName
;
@Schema
(
description
=
"开始时间"
)
@JsonProperty
(
"start_time"
)
private
Date
startTime
;
@Schema
(
description
=
"结束时间"
)
@JsonProperty
(
"end_time"
)
private
Date
endTime
;
}
src/main/java/cn/breeze/elleai/application/dto/request/WikiRequestDto.java
View file @
c02dd4e7
...
...
@@ -21,6 +21,13 @@ public class WikiRequestDto implements Serializable {
private
String
name
;
@Schema
(
description
=
"知识库分类ID"
)
@JsonProperty
(
"category_id"
)
private
Integer
categoryId
;
@JsonProperty
(
"wiki_category_id"
)
private
Integer
wikiCategoryId
;
@Schema
(
description
=
"场景分类ID"
)
@JsonProperty
(
"scene_category_id"
)
private
Integer
sceneCategoryId
;
@Schema
(
description
=
"状态(0禁用 1启用)"
)
private
Integer
status
;
}
src/main/java/cn/breeze/elleai/application/service/AppChatCompletionService.java
View file @
c02dd4e7
package
cn
.
breeze
.
elleai
.
application
.
service
;
import
cn.breeze.elleai.application.dto.PageResult
;
import
cn.breeze.elleai.application.dto.inner.AiChatComplateResultDto
;
import
cn.breeze.elleai.application.dto.inner.AiSingleEvaluateResultDto
;
import
cn.breeze.elleai.application.dto.request.*
;
import
cn.breeze.elleai.application.dto.response.*
;
import
cn.breeze.elleai.domain.sparring.model.request.QaAssistantRequestModel
;
...
...
@@ -20,15 +22,15 @@ import com.alibaba.fastjson.JSONObject;
import
com.mybatisflex.core.paginate.Page
;
import
lombok.RequiredArgsConstructor
;
import
lombok.extern.slf4j.Slf4j
;
import
org.apache.commons.lang3.StringUtils
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.http.HttpEntity
;
import
org.springframework.http.HttpHeaders
;
import
org.springframework.http.MediaType
;
import
org.springframework.http.ResponseEntity
;
import
org.springframework.data.redis.core.StringRedisTemplate
;
import
org.springframework.http.*
;
import
org.springframework.stereotype.Component
;
import
org.springframework.web.client.RestTemplate
;
import
java.util.*
;
import
java.util.concurrent.TimeUnit
;
import
java.util.stream.Collectors
;
...
...
@@ -40,10 +42,10 @@ import java.util.stream.Collectors;
@RequiredArgsConstructor
public
class
AppChatCompletionService
{
@Value
(
"${dify.
api_base:https://ai-api.tech.breezeai.cn/v1
}"
)
@Value
(
"${dify.
chat_api_base
}"
)
private
String
difyBase
;
@Value
(
"${dify.
api_key:app-ilgoEphXjLw0I7x7fGeCyKYk
}"
)
@Value
(
"${dify.
chat_api_key
}"
)
private
String
apiKey
;
private
final
RestTemplate
restTemplate
=
new
RestTemplate
();
...
...
@@ -299,6 +301,17 @@ public class AppChatCompletionService {
public
UserAskResultMobileDto
userAsk
(
UserPrincipal
userPrincipal
,
UserQaMobileRequestDto
request
)
{
UserAskResultMobileDto
result
=
new
UserAskResultMobileDto
();
// 获取会话详情
UserQaRequestModel
requestModel
=
new
UserQaRequestModel
();
requestModel
.
setChatCompletionId
(
request
.
getChatCompletionId
());
requestModel
.
setUserId
(
userPrincipal
.
getUserId
());
UserChatCompletionResponseModel
ccModel
=
chatCompletionService
.
userQaDetail
(
requestModel
);
String
sessionId
=
""
;
if
(
Objects
.
nonNull
(
ccModel
)
&&
StrUtil
.
isNotEmpty
(
ccModel
.
getSessionId
()))
{
sessionId
=
ccModel
.
getSessionId
();
}
// 更新会话信息
UserChatCompletionSaveModel
saveModel
=
new
UserChatCompletionSaveModel
();
saveModel
.
setUserId
(
userPrincipal
.
getUserId
());
...
...
@@ -308,10 +321,9 @@ public class AppChatCompletionService {
saveModel
.
setShopId
(
userPrincipal
.
getShopId
());
saveModel
.
setShopName
(
userPrincipal
.
getShopName
());
// 首次提问
if
(
Objects
.
isNull
(
request
.
getChatCompletionId
()))
{
if
(
Objects
.
isNull
(
request
.
getChatCompletionId
())
||
(
Objects
.
nonNull
(
ccModel
)
&&
StrUtil
.
isEmpty
(
ccModel
.
getFirstQuestion
()))
)
{
saveModel
.
setCreateTime
(
new
Date
());
saveModel
.
setFirstQuestion
(
request
.
getContent
());
saveModel
.
setSessionId
(
UUID
.
randomUUID
().
toString
());
}
Integer
recordId
=
chatCompletionService
.
saveUserQaSession
(
saveModel
);
...
...
@@ -319,28 +331,57 @@ public class AppChatCompletionService {
chatCompletionService
.
saveUserQaRecord
(
recordId
,
0
,
request
.
getContent
());
// 问一下AI
String
replyContent
=
ask4Knowledge
(
saveModel
.
getSessionId
(),
saveModel
.
getUserId
(),
request
.
getContent
());
AiChatComplateResultDto
complateResultDto
=
ask4Knowledge
(
sessionId
,
userPrincipal
.
getUserId
(),
request
.
getContent
());
if
(
Objects
.
nonNull
(
complateResultDto
))
{
String
replyContent
=
complateResultDto
.
getContent
();
// 更新DIFY会话ID
if
(
StrUtil
.
isEmpty
(
sessionId
))
{
UserChatCompletionSaveModel
updateModel
=
new
UserChatCompletionSaveModel
();
updateModel
.
setId
(
recordId
);
updateModel
.
setSessionId
(
sessionId
);
chatCompletionService
.
saveUserQaSession
(
updateModel
);
}
// 保存AI问答详情
chatCompletionService
.
saveUserQaRecord
(
recordId
,
1
,
replyContent
);
result
.
setChatCompletionId
(
recordId
);
result
.
setReplyContent
(
replyContent
);
}
return
result
;
}
/**
* 新会话
* @return
*/
public
NewCompletionResultMobileDto
newChatCompletion
(
UserPrincipal
userPrincipal
)
{
NewCompletionResultMobileDto
result
=
new
NewCompletionResultMobileDto
();
// 保存AI问答详情
chatCompletionService
.
saveUserQaRecord
(
recordId
,
1
,
replyContent
);
// 新会话信息
UserChatCompletionSaveModel
saveModel
=
new
UserChatCompletionSaveModel
();
saveModel
.
setUserId
(
userPrincipal
.
getUserId
());
saveModel
.
setUserName
(
userPrincipal
.
getUserName
());
saveModel
.
setShopId
(
userPrincipal
.
getShopId
());
saveModel
.
setShopName
(
userPrincipal
.
getShopName
());
saveModel
.
setCreateTime
(
new
Date
());
Integer
recordId
=
chatCompletionService
.
saveUserQaSession
(
saveModel
);
result
.
setChatCompletionId
(
recordId
);
result
.
setReplyContent
(
replyContent
);
return
result
;
}
public
String
ask4Knowledge
(
String
sessionId
,
String
userId
,
String
question
)
{
if
(
true
)
{
return
"moke ai reply."
;
}
public
AiChatComplateResultDto
ask4Knowledge
(
String
sessionId
,
String
userId
,
String
question
)
{
Map
<
String
,
String
>
inputs
=
new
HashMap
<>();
inputs
.
put
(
"
question
"
,
question
);
inputs
.
put
(
"
context
"
,
question
);
JSONObject
param
=
new
JSONObject
();
param
.
put
(
"inputs"
,
inputs
);
param
.
put
(
"query"
,
question
);
param
.
put
(
"response_mode"
,
"blocking"
);
param
.
put
(
"conversation_id"
,
""
);
param
.
put
(
"conversation_id"
,
sessionId
);
param
.
put
(
"user"
,
userId
);
HttpHeaders
headers
=
new
HttpHeaders
();
headers
.
setContentType
(
MediaType
.
APPLICATION_JSON
);
...
...
@@ -351,7 +392,17 @@ public class AppChatCompletionService {
HttpEntity
<
String
>
postEntity
=
new
HttpEntity
<>(
param
.
toJSONString
(),
headers
);
ResponseEntity
<
String
>
response
=
restTemplate
.
postForEntity
(
difyBase
+
"/chat-messages"
,
postEntity
,
String
.
class
);
String
body
=
response
.
getBody
();
log
.
info
(
"执行结果:"
,
JSONObject
.
parseObject
(
body
));
return
body
;
log
.
info
(
"AI问答执行结果:{}"
,
body
);
if
(
Objects
.
equals
(
response
.
getStatusCode
(),
HttpStatus
.
OK
))
{
JSONObject
bodyObject
=
JSONObject
.
parseObject
(
body
);
String
conversationId
=
bodyObject
.
getString
(
"conversation_id"
);
String
answer
=
bodyObject
.
getString
(
"answer"
);
AiChatComplateResultDto
result
=
new
AiChatComplateResultDto
();
result
.
setContent
(
answer
);
result
.
setDifySessionId
(
conversationId
);
return
result
;
}
return
null
;
}
}
src/main/java/cn/breeze/elleai/application/service/AppCommonService.java
View file @
c02dd4e7
...
...
@@ -11,6 +11,7 @@ import cn.breeze.elleai.domain.sparring.model.request.ProperNounSaveModel;
import
cn.breeze.elleai.domain.sparring.model.response.DataDicResponseModel
;
import
cn.breeze.elleai.domain.sparring.model.response.ProperNounResponseModel
;
import
cn.breeze.elleai.domain.sparring.service.CommonService
;
import
cn.breeze.elleai.util.ChineseCharacterUtil
;
import
cn.breeze.elleai.util.Codes
;
import
cn.hutool.core.bean.BeanUtil
;
import
cn.hutool.core.collection.CollectionUtil
;
...
...
@@ -76,9 +77,21 @@ public class AppCommonService {
*/
public
void
saveproperNoun
(
ProperNounSaveDto
dto
)
{
ProperNounSaveModel
model
=
BeanUtil
.
copyProperties
(
dto
,
ProperNounSaveModel
.
class
);
model
.
setSimilarWords
(
JSON
.
toJSONString
(
dto
.
getSimilarWordList
()));
commonService
.
saveProperNoun
(
model
);
if
(
Objects
.
nonNull
(
dto
))
{
String
upperCase
=
ChineseCharacterUtil
.
getUpperCase
(
dto
.
getName
(),
false
);
String
upperCase2
=
ChineseCharacterUtil
.
getUpperCase
(
dto
.
getName
(),
true
);
if
(
CollectionUtil
.
isNotEmpty
(
dto
.
getSimilarWordList
()))
{
dto
.
getSimilarWordList
().
forEach
(
v
->
{
System
.
out
.
println
(
v
+
"=="
+
ChineseCharacterUtil
.
getUpperCase
(
dto
.
getName
(),
true
));
});
}
}
else
{
ProperNounSaveModel
model
=
BeanUtil
.
copyProperties
(
dto
,
ProperNounSaveModel
.
class
);
model
.
setSimilarWords
(
JSON
.
toJSONString
(
dto
.
getSimilarWordList
()));
commonService
.
saveProperNoun
(
model
);
}
}
...
...
src/main/java/cn/breeze/elleai/application/service/AppExamineService.java
View file @
c02dd4e7
...
...
@@ -321,6 +321,15 @@ public class AppExamineService {
examineService
.
updateExamineQaStatus
(
id
,
status
);
}
/**
* 更新QA
* @param idList
* @param status
*/
public
void
batchUpdateQaStatus
(
List
<
Integer
>
idList
,
Integer
status
)
{
examineService
.
batchUpdateExamineQaStatus
(
idList
,
status
);
}
/**
* 删除QA
* @param id
...
...
src/main/java/cn/breeze/elleai/controller/admin/ExamineQaController.java
View file @
c02dd4e7
...
...
@@ -14,6 +14,8 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import
lombok.RequiredArgsConstructor
;
import
org.springframework.web.bind.annotation.*
;
import
java.util.List
;
/**
* 对练QA
*/
...
...
@@ -61,4 +63,14 @@ public class ExamineQaController {
PageResult
<
ExamineQaDto
>
pageResult
=
examineService
.
examineQaPaginQuery
(
request
);
return
ApiResponse
.
ok
(
pageResult
);
}
@Operation
(
summary
=
"批量启用/禁用对练题目"
)
@PostMapping
(
"/batch_update_status"
)
public
ApiResponse
<
String
>
batchUpdateStatus
(
@Schema
(
description
=
"题目ID"
)
@RequestParam
(
"id_list"
)
List
<
Integer
>
idList
,
@Schema
(
description
=
"状态(0禁用 1启用)"
)
@RequestParam
(
"status"
)
Integer
status
)
{
examineService
.
batchUpdateQaStatus
(
idList
,
status
);
return
ApiResponse
.
ok
(
"ok"
);
}
}
src/main/java/cn/breeze/elleai/controller/front/ChatCompletionMobileController.java
View file @
c02dd4e7
...
...
@@ -69,8 +69,7 @@ public class ChatCompletionMobileController {
@Operation
(
summary
=
"开启新会话,返回新会话ID"
)
@PostMapping
(
"/new_completion"
)
public
ApiResponse
<
NewCompletionResultMobileDto
>
newChatCompletion
(
@Parameter
(
hidden
=
true
)
UserPrincipal
userPrincipal
)
{
NewCompletionResultMobileDto
result
=
new
NewCompletionResultMobileDto
();
result
.
setChatCompletionId
(
1
);
NewCompletionResultMobileDto
result
=
chatCompletionService
.
newChatCompletion
(
userPrincipal
);
return
ApiResponse
.
ok
(
result
);
}
...
...
src/main/java/cn/breeze/elleai/domain/sparring/model/request/ExamineQaRequestModel.java
View file @
c02dd4e7
...
...
@@ -13,5 +13,7 @@ public class ExamineQaRequestModel implements Serializable {
private
String
name
;
private
Integer
categoryId
;
private
Integer
status
;
}
src/main/java/cn/breeze/elleai/domain/sparring/model/request/ExamineRecordRequestModel.java
View file @
c02dd4e7
...
...
@@ -19,6 +19,8 @@ public class ExamineRecordRequestModel implements Serializable {
*/
private
String
userId
;
private
String
userName
;
/**
* 对练ID
*/
...
...
src/main/java/cn/breeze/elleai/domain/sparring/model/request/ExamineRequestModel.java
View file @
c02dd4e7
...
...
@@ -5,6 +5,7 @@ import io.swagger.v3.oas.annotations.media.Schema;
import
lombok.Data
;
import
java.io.Serializable
;
import
java.util.Date
;
@Data
public
class
ExamineRequestModel
implements
Serializable
{
...
...
@@ -15,10 +16,14 @@ public class ExamineRequestModel implements Serializable {
private
String
name
;
private
Integer
s
tatus
;
private
Integer
s
ceneId
;
@Schema
(
description
=
"场景分类ID"
)
@JsonProperty
(
"category_id"
)
private
Integer
categoryId
;
private
Integer
status
;
private
Date
startTime
;
private
Date
endTime
;
}
src/main/java/cn/breeze/elleai/domain/sparring/model/request/ProperNounRequestModel.java
View file @
c02dd4e7
package
cn
.
breeze
.
elleai
.
domain
.
sparring
.
model
.
request
;
import
io.swagger.v3.oas.annotations.media.Schema
;
import
lombok.Data
;
import
java.io.Serializable
;
...
...
@@ -13,5 +14,5 @@ public class ProperNounRequestModel implements Serializable {
private
String
name
;
private
Integer
status
;
}
src/main/java/cn/breeze/elleai/domain/sparring/model/request/QaAssistantRequestModel.java
View file @
c02dd4e7
package
cn
.
breeze
.
elleai
.
domain
.
sparring
.
model
.
request
;
import
io.swagger.v3.oas.annotations.media.Schema
;
import
lombok.Data
;
import
java.io.Serializable
;
...
...
@@ -13,5 +14,5 @@ public class QaAssistantRequestModel implements Serializable {
private
String
name
;
private
Integer
status
;
}
src/main/java/cn/breeze/elleai/domain/sparring/model/request/UserQaRequestModel.java
View file @
c02dd4e7
package
cn
.
breeze
.
elleai
.
domain
.
sparring
.
model
.
request
;
import
com.fasterxml.jackson.annotation.JsonProperty
;
import
io.swagger.v3.oas.annotations.media.Schema
;
import
lombok.Data
;
import
java.io.Serializable
;
import
java.util.Date
;
@Data
public
class
UserQaRequestModel
implements
Serializable
{
...
...
@@ -13,5 +16,13 @@ public class UserQaRequestModel implements Serializable {
private
String
userId
;
private
String
userName
;
private
String
sessionId
;
private
Date
startTime
;
private
Date
endTime
;
private
Integer
chatCompletionId
;
}
src/main/java/cn/breeze/elleai/domain/sparring/model/request/WikiRequestModel.java
View file @
c02dd4e7
package
cn
.
breeze
.
elleai
.
domain
.
sparring
.
model
.
request
;
import
com.fasterxml.jackson.annotation.JsonProperty
;
import
io.swagger.v3.oas.annotations.media.Schema
;
import
lombok.Data
;
import
java.io.Serializable
;
...
...
@@ -13,5 +15,9 @@ public class WikiRequestModel implements Serializable {
private
String
name
;
private
Integer
categoryId
;
private
Integer
wikiCategoryId
;
private
Integer
sceneCategoryId
;
private
Integer
status
;
}
src/main/java/cn/breeze/elleai/domain/sparring/service/ChatCompletionServiceImpl.java
View file @
c02dd4e7
...
...
@@ -4,7 +4,6 @@ import cn.breeze.elleai.domain.sparring.model.request.*;
import
cn.breeze.elleai.domain.sparring.model.response.QaAssistantResponseModel
;
import
cn.breeze.elleai.domain.sparring.model.response.UserChatCompletionHistoryResponseModel
;
import
cn.breeze.elleai.domain.sparring.model.response.UserChatCompletionResponseModel
;
import
cn.breeze.elleai.infra.entity.ExamineEntity
;
import
cn.breeze.elleai.infra.entity.QaAssistantEntity
;
import
cn.breeze.elleai.infra.entity.UserChatCompletionEntity
;
import
cn.breeze.elleai.infra.entity.UserChatCompletionHistoryEntity
;
...
...
@@ -49,6 +48,15 @@ public class ChatCompletionServiceImpl implements ChatCompletionService{
if
(
StrUtil
.
isNotEmpty
(
request
.
getUserId
()))
{
queryWrapper
.
where
(
USER_CHAT_COMPLETION_ENTITY
.
USER_ID
.
eq
(
request
.
getUserId
()));
}
if
(
StrUtil
.
isNotEmpty
(
request
.
getUserId
()))
{
queryWrapper
.
where
(
USER_CHAT_COMPLETION_ENTITY
.
USER_NAME
.
like
(
"%"
+
request
.
getUserName
()+
"%"
));
}
if
(
Objects
.
nonNull
(
request
.
getStartTime
()))
{
queryWrapper
.
where
(
USER_CHAT_COMPLETION_ENTITY
.
CREATE_TIME
.
ge
(
request
.
getStartTime
()));
}
if
(
Objects
.
nonNull
(
request
.
getEndTime
()))
{
queryWrapper
.
where
(
USER_CHAT_COMPLETION_ENTITY
.
CREATE_TIME
.
le
(
request
.
getEndTime
()));
}
queryWrapper
.
orderBy
(
USER_CHAT_COMPLETION_ENTITY
.
CREATE_TIME
,
false
);
Page
<
UserChatCompletionResponseModel
>
page
=
chatCompletionMapper
.
paginateAs
(
pageNo
,
pageSize
,
queryWrapper
,
UserChatCompletionResponseModel
.
class
);
...
...
@@ -111,8 +119,12 @@ public class ChatCompletionServiceImpl implements ChatCompletionService{
@Override
public
UserChatCompletionResponseModel
userQaDetail
(
UserQaRequestModel
request
)
{
QueryWrapper
queryWrapper
=
QueryWrapper
.
create
();
queryWrapper
.
where
(
USER_CHAT_COMPLETION_ENTITY
.
USER_ID
.
eq
(
request
.
getUserId
()));
queryWrapper
.
where
(
USER_CHAT_COMPLETION_ENTITY
.
SESSION_ID
.
eq
(
request
.
getSessionId
()));
if
(
Objects
.
nonNull
(
request
.
getUserId
()))
{
queryWrapper
.
where
(
USER_CHAT_COMPLETION_ENTITY
.
USER_ID
.
eq
(
request
.
getUserId
()));
}
if
(
Objects
.
nonNull
(
request
.
getChatCompletionId
()))
{
queryWrapper
.
where
(
USER_CHAT_COMPLETION_ENTITY
.
ID
.
eq
(
request
.
getChatCompletionId
()));
}
queryWrapper
.
orderBy
(
USER_CHAT_COMPLETION_ENTITY
.
CREATE_TIME
,
false
);
return
chatCompletionMapper
.
selectOneByQueryAs
(
queryWrapper
,
UserChatCompletionResponseModel
.
class
);
}
...
...
@@ -145,7 +157,10 @@ public class ChatCompletionServiceImpl implements ChatCompletionService{
QueryWrapper
queryWrapper
=
QueryWrapper
.
create
()
.
where
(
QA_ASSISTANT_ENTITY
.
DELETED
.
eq
(
0
));
if
(
StrUtil
.
isNotEmpty
(
request
.
getName
()))
{
queryWrapper
.
where
(
QA_ASSISTANT_ENTITY
.
NAME
.
like
(
"%"
+
request
.
getName
()+
"%"
));
queryWrapper
.
and
(
QA_ASSISTANT_ENTITY
.
NAME
.
like
(
"%"
+
request
.
getName
()+
"%"
));
}
if
(
Objects
.
nonNull
(
request
.
getStatus
()))
{
queryWrapper
.
and
(
QA_ASSISTANT_ENTITY
.
STATUS
.
eq
(
request
.
getStatus
()));
}
queryWrapper
.
orderBy
(
QA_ASSISTANT_ENTITY
.
CREATE_TIME
,
false
);
...
...
src/main/java/cn/breeze/elleai/domain/sparring/service/CommonServiceImpl.java
View file @
c02dd4e7
...
...
@@ -49,6 +49,9 @@ public class CommonServiceImpl implements CommonService{
if
(
StrUtil
.
isNotEmpty
(
request
.
getName
()))
{
queryWrapper
.
where
(
PROPER_NOUN_ENTITY
.
NAME
.
like
(
"%"
+
request
.
getName
()+
"%"
));
}
if
(
Objects
.
nonNull
(
request
.
getStatus
()))
{
queryWrapper
.
where
(
PROPER_NOUN_ENTITY
.
STATUS
.
eq
(
request
.
getStatus
()));
}
queryWrapper
.
orderBy
(
PROPER_NOUN_ENTITY
.
CREATE_TIME
,
false
);
Page
<
ProperNounResponseModel
>
page
=
properNounMapper
.
paginateAs
(
pageNo
,
pageSize
,
queryWrapper
,
ProperNounResponseModel
.
class
);
...
...
src/main/java/cn/breeze/elleai/domain/sparring/service/ExamineService.java
View file @
c02dd4e7
...
...
@@ -57,6 +57,8 @@ public interface ExamineService {
void
updateExamineQaStatus
(
Integer
qaId
,
Integer
status
);
void
batchUpdateExamineQaStatus
(
List
<
Integer
>
qaIdList
,
Integer
status
);
void
deleteExamineQa
(
Integer
qaId
);
void
saveExamineQa
(
ExamineQaSaveModel
dto
);
...
...
src/main/java/cn/breeze/elleai/domain/sparring/service/ExamineServiceImpl.java
View file @
c02dd4e7
...
...
@@ -72,10 +72,10 @@ public class ExamineServiceImpl implements ExamineService {
queryWrapper
.
from
(
EXAMINE_SCENE_ENTITY
.
getTableName
());
queryWrapper
.
where
(
EXAMINE_SCENE_ENTITY
.
DELETED
.
eq
(
0
));
if
(
StrUtil
.
isNotEmpty
(
request
.
getName
()))
{
queryWrapper
.
where
(
EXAMINE_SCENE_ENTITY
.
NAME
.
like
(
"%"
+
request
.
getName
()+
"%"
));
queryWrapper
.
and
(
EXAMINE_SCENE_ENTITY
.
NAME
.
like
(
"%"
+
request
.
getName
()+
"%"
));
}
if
(
Objects
.
nonNull
(
request
.
getStatus
()))
{
queryWrapper
.
where
(
EXAMINE_SCENE_ENTITY
.
STATUS
.
eq
(
request
.
getStatus
()));
queryWrapper
.
and
(
EXAMINE_SCENE_ENTITY
.
STATUS
.
eq
(
request
.
getStatus
()));
}
Page
<
ExamineSceneResponseModel
>
page
=
sceneMapper
.
paginateAs
(
pageNo
,
pageSize
,
queryWrapper
,
ExamineSceneResponseModel
.
class
);
...
...
@@ -93,13 +93,13 @@ public class ExamineServiceImpl implements ExamineService {
queryWrapper
.
from
(
EXAMINE_SCENE_CATEGORY_ENTITY
.
getTableName
());
queryWrapper
.
where
(
EXAMINE_SCENE_CATEGORY_ENTITY
.
DELETED
.
eq
(
0
));
if
(
StringUtils
.
isNotEmpty
(
request
.
getName
()))
{
queryWrapper
.
where
(
EXAMINE_SCENE_CATEGORY_ENTITY
.
NAME
.
like
(
"%"
+
request
.
getName
()+
"%"
));
queryWrapper
.
and
(
EXAMINE_SCENE_CATEGORY_ENTITY
.
NAME
.
like
(
"%"
+
request
.
getName
()+
"%"
));
}
if
(
Objects
.
nonNull
(
request
.
getStatus
()))
{
queryWrapper
.
where
(
EXAMINE_SCENE_CATEGORY_ENTITY
.
STATUS
.
eq
(
request
.
getStatus
()));
queryWrapper
.
and
(
EXAMINE_SCENE_CATEGORY_ENTITY
.
STATUS
.
eq
(
request
.
getStatus
()));
}
if
(
Objects
.
nonNull
(
request
.
getSceneId
()))
{
queryWrapper
.
where
(
EXAMINE_SCENE_CATEGORY_ENTITY
.
SCENE_ID
.
eq
(
request
.
getSceneId
()));
queryWrapper
.
and
(
EXAMINE_SCENE_CATEGORY_ENTITY
.
SCENE_ID
.
eq
(
request
.
getSceneId
()));
}
Page
<
ExamineSceneCategoryResponseModel
>
page
=
sceneCategoryMapper
.
paginateAs
(
pageNo
,
pageSize
,
queryWrapper
,
ExamineSceneCategoryResponseModel
.
class
);
...
...
@@ -204,7 +204,13 @@ public class ExamineServiceImpl implements ExamineService {
QueryWrapper
queryWrapper
=
QueryWrapper
.
create
()
.
where
(
EXAMINE_QA_ENTITY
.
DELETED
.
eq
(
0
));
if
(
StrUtil
.
isNotEmpty
(
request
.
getName
()))
{
queryWrapper
.
where
(
EXAMINE_QA_ENTITY
.
QUESTION
.
like
(
"%"
+
request
.
getName
()+
"%"
));
queryWrapper
.
and
(
EXAMINE_QA_ENTITY
.
QUESTION
.
like
(
"%"
+
request
.
getName
()+
"%"
));
}
if
(
Objects
.
nonNull
(
request
.
getStatus
()))
{
queryWrapper
.
and
(
EXAMINE_QA_ENTITY
.
STATUS
.
eq
(
request
.
getStatus
()));
}
if
(
Objects
.
nonNull
(
request
.
getCategoryId
()))
{
queryWrapper
.
and
(
EXAMINE_QA_ENTITY
.
CATEGORY_ID
.
eq
(
request
.
getCategoryId
()));
}
Page
<
ExamineQaResponseModel
>
page
=
qaMapper
.
paginateAs
(
pageNo
,
pageSize
,
queryWrapper
,
ExamineQaResponseModel
.
class
);
...
...
@@ -255,6 +261,15 @@ public class ExamineServiceImpl implements ExamineService {
.
update
();
}
@Override
public
void
batchUpdateExamineQaStatus
(
List
<
Integer
>
qaIdList
,
Integer
status
)
{
UpdateChain
.
of
(
ExamineQaEntity
.
class
)
.
set
(
EXAMINE_QA_ENTITY
.
STATUS
,
status
)
.
set
(
EXAMINE_QA_ENTITY
.
UPDATE_TIME
,
new
Date
())
.
where
(
EXAMINE_QA_ENTITY
.
ID
.
in
(
qaIdList
))
.
update
();
}
@Override
public
void
deleteExamineQa
(
Integer
qaId
)
{
UpdateChain
.
of
(
ExamineQaEntity
.
class
)
...
...
@@ -292,6 +307,15 @@ public class ExamineServiceImpl implements ExamineService {
if
(
Objects
.
nonNull
(
request
.
getCategoryId
()))
{
queryWrapper
.
where
(
EXAMINE_ENTITY
.
CATEGORY_ID
.
eq
(
request
.
getCategoryId
()));
}
if
(
Objects
.
nonNull
(
request
.
getSceneId
()))
{
queryWrapper
.
where
(
EXAMINE_ENTITY
.
SCENE_ID
.
eq
(
request
.
getSceneId
()));
}
if
(
Objects
.
nonNull
(
request
.
getStartTime
()))
{
queryWrapper
.
where
(
EXAMINE_ENTITY
.
START_TIME
.
ge
(
request
.
getStartTime
()));
}
if
(
Objects
.
nonNull
(
request
.
getEndTime
()))
{
queryWrapper
.
where
(
EXAMINE_ENTITY
.
END_TIME
.
le
(
request
.
getEndTime
()));
}
Page
<
ExamineResponseModel
>
page
=
examineMapper
.
paginateAs
(
pageNo
,
pageSize
,
queryWrapper
,
ExamineResponseModel
.
class
);
...
...
@@ -383,22 +407,25 @@ public class ExamineServiceImpl implements ExamineService {
Integer
pageSize
=
ObjectUtil
.
defaultIfNull
(
request
.
getPageSize
(),
10
);
QueryWrapper
queryWrapper
=
QueryWrapper
.
create
();
queryWrapper
.
where
(
USER_EXAMINE_RECORD_ENTITY
.
DELETED
.
eq
(
0
));
if
(
StrUtil
.
isNotEmpty
(
request
.
getUserId
()))
{
queryWrapper
.
where
(
USER_EXAMINE_RECORD_ENTITY
.
USER_ID
.
eq
(
request
.
getUserId
()));
queryWrapper
.
and
(
USER_EXAMINE_RECORD_ENTITY
.
USER_ID
.
eq
(
request
.
getUserId
()));
}
if
(
StrUtil
.
isNotEmpty
(
request
.
getUserName
()))
{
queryWrapper
.
and
(
USER_EXAMINE_RECORD_ENTITY
.
USER_NAME
.
like
(
"%"
+
request
.
getUserName
()+
"%"
));
}
if
(
Objects
.
nonNull
(
request
.
getExamineMode
()))
{
queryWrapper
.
where
(
USER_EXAMINE_RECORD_ENTITY
.
EXAMINE_MODE
.
eq
(
request
.
getExamineMode
()));
queryWrapper
.
and
(
USER_EXAMINE_RECORD_ENTITY
.
EXAMINE_MODE
.
eq
(
request
.
getExamineMode
()));
}
if
(
Objects
.
nonNull
(
request
.
getExamineId
()))
{
queryWrapper
.
where
(
USER_EXAMINE_RECORD_ENTITY
.
EXAMINE_ID
.
eq
(
request
.
getExamineId
()));
queryWrapper
.
and
(
USER_EXAMINE_RECORD_ENTITY
.
EXAMINE_ID
.
eq
(
request
.
getExamineId
()));
}
if
(
Objects
.
nonNull
(
request
.
getStartTime
()))
{
queryWrapper
.
where
(
USER_EXAMINE_RECORD_ENTITY
.
CREATE_TIME
.
ge
(
request
.
getStartTime
()));
queryWrapper
.
and
(
USER_EXAMINE_RECORD_ENTITY
.
CREATE_TIME
.
ge
(
request
.
getStartTime
()));
}
if
(
Objects
.
nonNull
(
request
.
getEndTime
()))
{
queryWrapper
.
where
(
USER_EXAMINE_RECORD_ENTITY
.
CREATE_TIME
.
le
(
request
.
getEndTime
()));
queryWrapper
.
and
(
USER_EXAMINE_RECORD_ENTITY
.
CREATE_TIME
.
le
(
request
.
getEndTime
()));
}
queryWrapper
.
where
(
USER_EXAMINE_RECORD_ENTITY
.
DELETED
.
eq
(
0
));
queryWrapper
.
orderBy
(
USER_EXAMINE_RECORD_ENTITY
.
CREATE_TIME
,
false
);
Page
<
ExamineRecordResponseModel
>
page
=
userExamineRecordMapper
.
paginateAs
(
pageNo
,
pageSize
,
queryWrapper
,
ExamineRecordResponseModel
.
class
);
...
...
@@ -575,10 +602,16 @@ public class ExamineServiceImpl implements ExamineService {
QueryWrapper
queryWrapper
=
QueryWrapper
.
create
()
.
where
(
WIKI_ENTITY
.
DELETED
.
eq
(
0
));
if
(
StrUtil
.
isNotEmpty
(
request
.
getName
()))
{
queryWrapper
.
where
(
WIKI_ENTITY
.
NAME
.
like
(
"%"
+
request
.
getName
()+
"%"
));
queryWrapper
.
and
(
WIKI_ENTITY
.
NAME
.
like
(
"%"
+
request
.
getName
()+
"%"
));
}
if
(
Objects
.
nonNull
(
request
.
getCategoryId
()))
{
queryWrapper
.
where
(
WIKI_ENTITY
.
WIKI_CATEGORY_ID
.
eq
(
request
.
getCategoryId
()));
if
(
Objects
.
nonNull
(
request
.
getWikiCategoryId
()))
{
queryWrapper
.
and
(
WIKI_ENTITY
.
WIKI_CATEGORY_ID
.
eq
(
request
.
getWikiCategoryId
()));
}
if
(
Objects
.
nonNull
(
request
.
getSceneCategoryId
()))
{
queryWrapper
.
and
(
WIKI_ENTITY
.
SCENE_CATEGORY_ID
.
eq
(
request
.
getSceneCategoryId
()));
}
if
(
Objects
.
nonNull
(
request
.
getStatus
()))
{
queryWrapper
.
and
(
WIKI_ENTITY
.
STATUS
.
eq
(
request
.
getStatus
()));
}
Page
<
WikiResponseModel
>
page
=
wikiMapper
.
paginateAs
(
pageNo
,
pageSize
,
queryWrapper
,
WikiResponseModel
.
class
);
...
...
src/main/java/cn/breeze/elleai/util/ChineseCharacterUtil.java
0 → 100644
View file @
c02dd4e7
package
cn
.
breeze
.
elleai
.
util
;
import
net.sourceforge.pinyin4j.PinyinHelper
;
import
net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat
;
import
net.sourceforge.pinyin4j.format.HanyuPinyinToneType
;
import
java.util.regex.Matcher
;
import
java.util.regex.Pattern
;
public
class
ChineseCharacterUtil
{
/**
* @description 获取汉字首字母或全拼大写字母
* @param chinese 汉字
* @param isFull 是否全拼 true:表示全拼 false表示:首字母
* @return String 全拼或者首字母大写字符窜
*/
public
static
String
getUpperCase
(
String
chinese
,
boolean
isFull
){
return
convertHanzi2Pinyin
(
chinese
,
isFull
).
toUpperCase
();
}
/**
* @description 获取汉字首字母或全拼小写字母
* @param chinese 汉字
* @param isFull 是否全拼 true:表示全拼 false表示:首字母
* @return String 全拼或者首字母小写字符窜
*/
public
static
String
getLowerCase
(
String
chinese
,
boolean
isFull
){
return
convertHanzi2Pinyin
(
chinese
,
isFull
).
toLowerCase
();
}
/**
* @description 将汉字转成拼音,取首字母或全拼
* @param hanzi 汉字字符串
* @param isFull 是否全拼 true:表示全拼 false表示:首字母
* @return String 拼音
*/
private
static
String
convertHanzi2Pinyin
(
String
hanzi
,
boolean
isFull
){
/***
* ^[\u2E80-\u9FFF]+$ 匹配所有东亚区的语言
* ^[\u4E00-\u9FFF]+$ 匹配简体和繁体
* ^[\u4E00-\u9FA5]+$ 匹配简体
*/
String
regExp
=
"^[\u4E00-\u9FFF]+$"
;
StringBuffer
sb
=
new
StringBuffer
();
if
(
hanzi
==
null
||
""
.
equals
(
hanzi
.
trim
())){
return
""
;
}
String
pinyin
=
""
;
for
(
int
i
=
0
;
i
<
hanzi
.
length
();
i
++){
char
unit
=
hanzi
.
charAt
(
i
);
//是汉字,则转拼音
if
(
match
(
String
.
valueOf
(
unit
),
regExp
)){
pinyin
=
convertSingleHanzi2Pinyin
(
unit
);
if
(
isFull
){
sb
.
append
(
pinyin
);
}
else
{
sb
.
append
(
pinyin
.
charAt
(
0
));
}
}
else
{
sb
.
append
(
unit
);
}
}
return
sb
.
toString
();
}
/**
* @description 单个汉字转成拼音
* @param hanzi 汉字字符
* @return String 拼音
*/
private
static
String
convertSingleHanzi2Pinyin
(
char
hanzi
){
HanyuPinyinOutputFormat
outputFormat
=
new
HanyuPinyinOutputFormat
();
outputFormat
.
setToneType
(
HanyuPinyinToneType
.
WITHOUT_TONE
);
String
[]
res
;
StringBuffer
sb
=
new
StringBuffer
();
try
{
res
=
PinyinHelper
.
toHanyuPinyinStringArray
(
hanzi
,
outputFormat
);
sb
.
append
(
res
[
0
]);
//对于多音字,只用第一个拼音
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
return
""
;
}
return
sb
.
toString
();
}
/***
* @description 匹配,根据字符和正则表达式进行匹配
* @param str 源字符串
* @param regex 正则表达式
* @return true:匹配成功 false:匹配失败
*/
private
static
boolean
match
(
String
str
,
String
regex
){
Pattern
pattern
=
Pattern
.
compile
(
regex
);
Matcher
matcher
=
pattern
.
matcher
(
str
);
return
matcher
.
find
();
}
}
src/main/resources/application.yml
View file @
c02dd4e7
...
...
@@ -17,6 +17,8 @@ springdoc:
dify
:
api_base
:
https://app-api.tech.breezeai.cn/v1
api_key
:
app-mJFu7K2wl3qEYsILkQBgRAKO
chat_api_base
:
https://ai-api.tech.breezeai.cn/v1
chat_api_key
:
app-ZpEcSEDYl3A8NoQJcR1dgYYg
---
spring
:
config
:
...
...
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