Commit bbc99288 authored by yangyw's avatar yangyw

Merge remote-tracking branch 'origin/sandbox'

parents 4cf47f02 fb56a9e5
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<annotationProcessing>
<profile name="Maven default annotation processors profile" enabled="true">
<sourceOutputDir name="target/generated-sources/annotations" />
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
<outputRelativeToContentRoot value="true" />
<module name="elleai" />
</profile>
</annotationProcessing>
</component>
<component name="JavacSettings">
<option name="ADDITIONAL_OPTIONS_OVERRIDE">
<module name="elleai" options="-parameters" />
</option>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding">
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
<file url="PROJECT" charset="UTF-8" />
</component>
</project>
\ No newline at end of file
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
</profile>
</component>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RemoteRepositoriesConfiguration">
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Central Repository" />
<option name="url" value="https://repo.maven.apache.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Maven Central repository" />
<option name="url" value="https://repo1.maven.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="jboss.community" />
<option name="name" value="JBoss Community repository" />
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
</remote-repository>
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Central Repository" />
<option name="url" value="https://maven.aliyun.com/repository/public" />
</remote-repository>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="MaterialThemeProjectNewConfig">
<option name="metadata">
<MTProjectMetadataState>
<option name="migrated" value="true" />
<option name="pristineConfig" value="false" />
<option name="userId" value="65979ab4:187f1b9bd3a:-8000" />
<option name="version" value="8.6.3" />
</MTProjectMetadataState>
</option>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="MavenProjectsManager">
<option name="originalFiles">
<list>
<option value="$PROJECT_DIR$/pom.xml" />
</list>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="corretto-17" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Palette2">
<group name="Swing">
<item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
</item>
<item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
</item>
<item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.svg" removable="false" auto-create-binding="false" can-attach-label="true">
<default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
</item>
<item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
<initial-values>
<property name="text" value="Button" />
</initial-values>
</item>
<item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="RadioButton" />
</initial-values>
</item>
<item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="CheckBox" />
</initial-values>
</item>
<item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
<initial-values>
<property name="text" value="Label" />
</initial-values>
</item>
<item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
</item>
<item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
</item>
<item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
<preferred-size width="-1" height="20" />
</default-constraints>
</item>
<item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
</item>
<item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
</item>
</group>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="AutoImportSettings">
<option name="autoReloadType" value="SELECTIVE" />
</component>
<component name="ChangeListManager">
<list default="true" id="574a1768-7fe5-4933-b098-93fccbf8bd9d" name="更改" comment="更改" />
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
<option name="LAST_RESOLUTION" value="IGNORE" />
</component>
<component name="Git.Settings">
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
</component>
<component name="MarkdownSettingsMigration">
<option name="stateVersion" value="1" />
</component>
<component name="MavenImportPreferences">
<option name="generalSettings">
<MavenGeneralSettings>
<option name="localRepository" value="D:\maven\repo" />
<option name="mavenHome" value="Use Maven wrapper" />
<option name="threads" value="2" />
<option name="useMavenConfig" value="true" />
<option name="userSettingsFile" value="D:\maven\conf\settings.xml" />
</MavenGeneralSettings>
</option>
</component>
<component name="ProjectColorInfo">{
&quot;associatedIndex&quot;: 4
}</component>
<component name="ProjectId" id="2mE49OlWeB44uOIKLiQwwMQrKYd" />
<component name="ProjectLevelVcsManager" settingsEditedManually="true" />
<component name="ProjectViewState">
<option name="hideEmptyMiddlePackages" value="true" />
<option name="showLibraryContents" value="true" />
</component>
<component name="PropertiesComponent">{
&quot;keyToString&quot;: {
&quot;RunOnceActivity.OpenProjectViewOnStart&quot;: &quot;true&quot;,
&quot;RunOnceActivity.ShowReadmeOnStart&quot;: &quot;true&quot;,
&quot;WebServerToolWindowFactoryState&quot;: &quot;false&quot;,
&quot;git-widget-placeholder&quot;: &quot;master&quot;,
&quot;kotlin-language-version-configured&quot;: &quot;true&quot;,
&quot;last_opened_file_path&quot;: &quot;D:/chain_workspaces/elleai&quot;,
&quot;node.js.detected.package.eslint&quot;: &quot;true&quot;,
&quot;node.js.detected.package.tslint&quot;: &quot;true&quot;,
&quot;node.js.selected.package.eslint&quot;: &quot;(autodetect)&quot;,
&quot;node.js.selected.package.tslint&quot;: &quot;(autodetect)&quot;,
&quot;nodejs_package_manager_path&quot;: &quot;npm&quot;,
&quot;project.structure.last.edited&quot;: &quot;Facet&quot;,
&quot;project.structure.proportion&quot;: &quot;0.0&quot;,
&quot;project.structure.side.proportion&quot;: &quot;0.48216343&quot;,
&quot;settings.editor.selected.configurable&quot;: &quot;MavenSettings&quot;,
&quot;vue.rearranger.settings.migration&quot;: &quot;true&quot;,
&quot;应用程序.CodeGen.executor&quot;: &quot;Run&quot;
}
}</component>
<component name="RecentsManager">
<key name="CopyFile.RECENT_KEYS">
<recent name="D:\workspace\elleai\src\test\java\cn\breeze\elleai\codegen" />
<recent name="D:\workspace\elleai" />
</key>
</component>
<component name="RunManager" selected="Spring Boot.ElleaiApplication">
<configuration name="CodeGen" type="Application" factoryName="Application" temporary="true" nameIsGenerated="true">
<option name="MAIN_CLASS_NAME" value="cn.breeze.elleai.codegen.CodeGen" />
<module name="elleai" />
<extension name="coverage">
<pattern>
<option name="PATTERN" value="cn.breeze.elleai.codegen.*" />
<option name="ENABLED" value="true" />
</pattern>
</extension>
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
<configuration name="ElleaiApplication" type="SpringBootApplicationConfigurationType" factoryName="Spring Boot" nameIsGenerated="true">
<module name="elleai" />
<option name="SPRING_BOOT_MAIN_CLASS" value="cn.breeze.elleai.ElleaiApplication" />
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
</component>
<component name="SharedIndexes">
<attachedChunks>
<set>
<option value="bundled-jdk-9f38398b9061-39b83d9b5494-intellij.indexing.shared.core-IU-241.18034.62" />
<option value="bundled-js-predefined-1d06a55b98c1-0b3e54e931b4-JavaScript-IU-241.18034.62" />
</set>
</attachedChunks>
</component>
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="应用程序级" UseSingleDictionary="true" transferred="true" />
<component name="TaskManager">
<task active="true" id="Default" summary="默认任务">
<changelist id="574a1768-7fe5-4933-b098-93fccbf8bd9d" name="更改" comment="" />
<created>1726628250923</created>
<option name="number" value="Default" />
<option name="presentableId" value="Default" />
<updated>1726628250923</updated>
<workItem from="1726628251854" duration="244000" />
<workItem from="1726628516245" duration="1613000" />
<workItem from="1726630414943" duration="1614000" />
</task>
<servers />
</component>
<component name="TypeScriptGeneratedFilesManager">
<option name="version" value="3" />
</component>
</project>
\ No newline at end of file
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
wrapperVersion=3.3.2
distributionType=only-script
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip
......@@ -201,11 +201,6 @@
<artifactId>tencentcloud-sdk-java-lke</artifactId>
<version>3.1.1221</version>
</dependency>
<dependency>
<groupId>com.tencentcloudapi</groupId>
<artifactId>tencentcloud-sdk-java-lke</artifactId>
<version>3.1.1231</version>
</dependency>
</dependencies>
<build>
......
......@@ -18,6 +18,9 @@ public class HotQaSaveDto implements Serializable {
@Schema(description = "问题")
private String question;
@Schema(description = "助手ID")
private Integer assistantId;
/**
* 答案
*/
......
......@@ -17,9 +17,9 @@ public class PageRequest {
private Integer entId;
@Schema(description = "用户id")
private Long userId;
private String userId;
private Long id;
private String id;
@Schema(description = "状态")
private Integer status;
......
......@@ -20,6 +20,9 @@ public class QaAssistantRequestDto implements Serializable {
@Schema(description = "助手名称")
private String name;
@Schema(description = "助手ID")
private Integer assistantId;
@Schema(description = "状态(0禁用 1启用)")
private Integer status;
}
......@@ -63,14 +63,14 @@ public class ExamineRecordMobileDto implements Serializable {
*/
@Schema(description = "综合评分")
@JsonProperty("overall_score")
private Float overallScore;
private int overallScore;
/**
* 平均分
*/
@Schema(description = "平均分")
@JsonProperty("avg_score")
private Float avgScore;
private int avgScore;
/**
* 综合评价
......
......@@ -28,6 +28,12 @@ public class HotQaDto implements Serializable {
@Schema(description = "答案")
private String answer;
@Schema(description = "助手ID")
private Integer assistantId;
@Schema(description = "助手名称")
private String assistantName;
/**
* 排序优先级
*/
......
package cn.breeze.elleai.application.dto.response;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.io.Serializable;
/**
* AI单题点评结果
*/
@Data
public class SubmitAnswerStreamResultDto implements Serializable {
@Schema(description = "评分")
private Float score;
@Schema(description = "参考答案")
private String answer;
}
......@@ -9,6 +9,7 @@ import cn.breeze.elleai.domain.sparring.model.response.QaAssistantResponseModel;
import cn.breeze.elleai.domain.sparring.service.ChatCompletionService;
import cn.breeze.elleai.domain.sparring.service.KbService;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
......@@ -90,6 +91,46 @@ public class AiPlatformExtensionService {
return null;
}
/**
* 单题评分+点评
* @param sessionId
* @param userId
* @param businessId 单题答题记录ID
*/
public AiSingleEvaluateResultDto run4SingleQaScore(String sessionId, String userId, Integer businessId) {
Map<String, String> inputs = new HashMap<>();
inputs.put("scene", "single_qa_score");
inputs.put("business_id", String.valueOf(businessId));
JSONObject param = new JSONObject();
param.put("query", String.valueOf(businessId));
param.put("inputs", inputs);
param.put("response_mode", "blocking");
param.put("conversation_id", "");
param.put("user", userId);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.setBearerAuth(apiKey);
log.info("异步请求参数1,sessionId = {}", sessionId);
log.info("异步请求参数2,req = {}", JSONObject.toJSONString(param));
HttpEntity<String> postEntity = new HttpEntity<>(param.toJSONString(), headers);
ResponseEntity<String> response = restTemplate.postForEntity(difyBase + "/chat-messages", postEntity, String.class);
String body = response.getBody();
if(Objects.equals(response.getStatusCode(), HttpStatus.OK)) {
JSONObject bodyObject = JSONObject.parseObject(body);
String conversationId = bodyObject.getString("conversation_id");
String answer = bodyObject.getString("answer");
if(NumberUtil.isNumber(answer)) {
AiSingleEvaluateResultDto result = new AiSingleEvaluateResultDto();
result.setScore(Float.valueOf(answer));
result.setDifySessionId(conversationId);
return result;
}
}
return null;
}
/**
* 考试总点评
* @param sessionId
......@@ -209,8 +250,11 @@ public class AiPlatformExtensionService {
List<VectorSegment> vectorSegments =aiService.searchWithRerank(request);
if (CollUtil.isNotEmpty(vectorSegments)) {
//结果不为空,组装结果
int pos = 1;
for (VectorSegment vectorSegment : vectorSegments) {
sb.append(vectorSegment.getContent() + "\n\n");
sb.append("问题" + pos + ":" + vectorSegment.getMetadata().get("question") + "\n");
sb.append("答案" + pos + ":" + vectorSegment.getMetadata().get("answer") + "\n\n");
pos++;
}
updateKbHitStat(vectorSegments);
}
......@@ -241,4 +285,30 @@ public class AiPlatformExtensionService {
}
return "false";
}
public List<VectorSegment> testSearchWithRerank(String query, Integer assistantId, Integer topK, Double score, Integer rerankTopK, Double rerankScore) {
RagSearchRequest request = new RagSearchRequest();
request.setQuery(query);
request.setMinScore(ObjectUtil.defaultIfNull(score, 0d));
request.setTopK(ObjectUtil.defaultIfNull(topK, 5));
request.setEnableRerank(true);
request.setTopKRerank(ObjectUtil.defaultIfNull(rerankTopK, 5));
request.setMinScoreRerank(ObjectUtil.defaultIfNull(rerankScore, 0d));
if (!ObjectUtil.equals(assistantId, 0)) {
//需要过滤分类
QaAssistantResponseModel qaAssistantResponseModel =chatCompletionService.qaAssistantDetail(assistantId);
if (ObjectUtil.isNotNull(qaAssistantResponseModel)) {
if (JSONValidator.from(qaAssistantResponseModel.getCategoryIds()).validate()) {
List<Integer> categoryIds = JSONArray.parseArray(qaAssistantResponseModel.getCategoryIds(), Integer.class);
if (CollUtil.isNotEmpty(categoryIds)) {
Map<String, Object> metadata = new HashMap<>();
metadata.put("tag_id", categoryIds);
request.setMetadata(metadata);
}
}
}
}
log.info("search:{}", request);
return aiService.searchWithRerank(request);
}
}
......@@ -34,7 +34,6 @@ import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.util.*;
import java.util.stream.Collectors;
......@@ -371,8 +370,9 @@ public class AppChatCompletionService {
saveModel.setLastQuestion(request.getContent());
saveModel.setShopId(userPrincipal.getShopId());
saveModel.setShopName(userPrincipal.getShopName());
// 首次提问
if(Objects.isNull(request.getChatCompletionId()) || (Objects.nonNull(ccModel) && StrUtil.isEmpty(ccModel.getFirstQuestion()))) {
// 新会话首次提问
if(Objects.isNull(request.getChatCompletionId())) {
saveModel.setCreateTime(new Date());
saveModel.setFirstQuestion(request.getContent());
}
......@@ -430,8 +430,9 @@ public class AppChatCompletionService {
saveModel.setLastQuestion(request.getContent());
saveModel.setShopId(userPrincipal.getShopId());
saveModel.setShopName(userPrincipal.getShopName());
// 首次提问
if(Objects.isNull(request.getChatCompletionId()) || (Objects.nonNull(ccModel) && StrUtil.isEmpty(ccModel.getFirstQuestion()))) {
// 新会话首次提问
if(Objects.isNull(request.getChatCompletionId())) {
saveModel.setCreateTime(new Date());
saveModel.setFirstQuestion(request.getContent());
}
......@@ -740,7 +741,34 @@ public class AppChatCompletionService {
* @return
*/
public PageResult<HotQaMobileDto> hotQaList(QaAssistantRequestDto request) {
return kbService.hotQaList(request);
// 获取5个随机自定义热门问题
final List<HotQaMobileDto> hots = Lists.newArrayList();
HotQaRequestModel hotQaRequestModel = new HotQaRequestModel();
hotQaRequestModel.setAssistantId(request.getAssistantId());
List<HotQaResponseModel> hotQaList = chatCompletionService.hotQaList(hotQaRequestModel);
if(CollectionUtil.isNotEmpty(hotQaList)) {
Collections.shuffle(hotQaList);
if(hotQaList.size() > 5) {
hotQaList = hotQaList.subList(0, 5);
}
hotQaList.forEach(v -> {
HotQaMobileDto dto = new HotQaMobileDto();
dto.setQuestion(v.getQuestion());
hots.add(dto);
});
}
// 获取5个随机系统判断热门问题
PageResult<HotQaMobileDto> pageResult = kbService.hotQaList(request);
if(Objects.nonNull(pageResult) && CollectionUtil.isNotEmpty(pageResult.getItems())) {
List<HotQaMobileDto> items = pageResult.getItems();
if(items.size() > 5){
Collections.shuffle(items);
items = items.subList(0, 5);
}
hots.addAll(items);
}
pageResult.setItems(hots);
return pageResult;
}
/**
......@@ -760,7 +788,6 @@ public class AppChatCompletionService {
if (StrUtil.isNotBlank(model.getRecordId())) {
try {
tencentCloudFacade.dissMessage(dsAppKey, model.getRecordId());
log.info("提交踩的数据:{}", model.getRecordId());
} catch (TencentCloudSDKException e) {
log.info("提交腾讯云踩数据异常{}", ExceptionUtil.getMessage(e));
}
......@@ -811,6 +838,13 @@ public class AppChatCompletionService {
public HotQaDto hotQaDetail(Integer id) {
HotQaResponseModel model = chatCompletionService.hotQaDetail(id);
HotQaDto result = BeanUtil.copyProperties(model, HotQaDto.class);
result.setAssistantName("");
if (ObjectUtil.isNotNull(model.getAssistantId())) {
QaAssistantResponseModel assistantResponseModel = chatCompletionService.qaAssistantDetail(model.getAssistantId());
if (ObjectUtil.isNotNull(assistantResponseModel)) {
result.setAssistantName(assistantResponseModel.getName());
}
}
return result;
}
......@@ -840,11 +874,18 @@ public class AppChatCompletionService {
PageResult<HotQaDto> pageResult = PageResult.of(request.getPageNo(), request.getPageSize(), (int) page.getTotalRow(), null);
if(CollectionUtil.isNotEmpty(page.getRecords())) {
Set<Integer> assistantIds = page.getRecords().stream().map(HotQaResponseModel::getAssistantId).collect(Collectors.toSet());
final Map<Integer, QaAssistantResponseModel> qaAssistantMap = new HashMap<>();
if (CollUtil.isNotEmpty(assistantIds)) {
List<QaAssistantResponseModel> qaAssistantList = chatCompletionService.qaAssistantListByIds(assistantIds);
Map<Integer, QaAssistantResponseModel> map = qaAssistantList.stream().collect(Collectors.toMap(QaAssistantResponseModel::getId, v -> v));
qaAssistantMap.putAll(map);
}
List<HotQaDto> dtoList = page.getRecords().stream().map(v -> {
HotQaDto dto = BeanUtil.copyProperties(v, HotQaDto.class);
dto.setAssistantName(ObjectUtil.isNotNull(qaAssistantMap.get(v.getAssistantId())) ? qaAssistantMap.get(v.getAssistantId()).getName() : "");
return dto;
}).collect(Collectors.toList());
pageResult.setItems(dtoList);
}
return pageResult;
......
......@@ -163,6 +163,7 @@ public class AppCommonService {
req.setPageNo(1);
req.setPageSize(999);
req.setStatus(1);
req.setLevel(1);
List<KbTagResponseModel> tagList = kbTagService.kbTagList(req);
if(CollectionUtil.isNotEmpty(tagList)) {
result = tagList.stream().map(v -> {
......
package cn.breeze.elleai.application.service;
import cn.breeze.elleai.application.dto.PageResult;
import cn.breeze.elleai.application.dto.inner.AiSingleEvaluateResultDto;
import cn.breeze.elleai.application.dto.inner.ExamineBusinessCacheDto;
import cn.breeze.elleai.application.dto.request.*;
import cn.breeze.elleai.application.dto.response.*;
......@@ -13,24 +14,39 @@ import cn.breeze.elleai.exception.InternalException;
import cn.breeze.elleai.util.Codes;
import cn.breeze.elleai.util.UserPrincipal;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.mybatisflex.core.paginate.Page;
import jakarta.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.codec.ServerSentEvent;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.reactive.function.client.WebClient;
import org.xbill.DNS.InvalidTTLException;
import reactor.core.publisher.Flux;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
......@@ -61,6 +77,25 @@ public class AppExamineService {
private final WikiUserViewService viewService;
@Value("${dify.api_base}")
private String difyBase;
@Value("${dify.api_key}")
private String apiKey;
private final RestTemplate restTemplate = new RestTemplate();
private WebClient webClient;
@PostConstruct
public void init() {
webClient = WebClient.builder().baseUrl(difyBase)
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.defaultHeader(HttpHeaders.AUTHORIZATION, "Bearer "+apiKey)
.defaultHeader(HttpHeaders.CACHE_CONTROL, "no-cache")
.build();
}
/************************************************** 场景分类 **************************************************/
......@@ -602,7 +637,7 @@ public class AppExamineService {
}
return detail;
}).collect(Collectors.toList());
result.setAvgScore(avgScore.floatValue());
result.setAvgScore(avgScore.intValue());
result.setDetails(details);
}
}
......@@ -806,10 +841,6 @@ public class AppExamineService {
ExamineRecordRequestModel requestModel = BeanUtil.copyProperties(request, ExamineRecordRequestModel.class);
ExamineRequestModel rm = new ExamineRequestModel();
rm.setName(request.getUserName());
examineService.examineList(rm);
Page<ExamineRecordResponseModel> page = examineService.examineRecordPaginQuery(requestModel);
PageResult<ExamineRecordDto> pageResult = PageResult.of(request.getPageNo(), request.getPageSize(), (int) page.getTotalRow(), null);
......@@ -905,23 +936,41 @@ public class AppExamineService {
return pageResult;
}
private List<Integer> findLevelOneCategory(List<Integer> categoryIdList) {
Set<Integer> levelOneCategorySet = new HashSet<>();
WikiCategoryRequestModel cr = new WikiCategoryRequestModel();
List<WikiCategoryResponseModel> items = examineService.wikiCategoryList(cr);
Map<Integer, WikiCategoryResponseModel> map = items.stream().collect(Collectors.toMap(WikiCategoryResponseModel::getId, v -> v));
for(Integer id : categoryIdList) {
WikiCategoryResponseModel model = map.get(id);
if(Objects.nonNull(model)) {
if (model.getParentId() == 0) {
levelOneCategorySet.add(id);
} else {
WikiCategoryDto wikiCategoryDto = wikiCategoryDetail(model.getParentId());
if(Objects.nonNull(wikiCategoryDto) && Objects.equals(wikiCategoryDto.getParentId(), 0)) {
levelOneCategorySet.add(wikiCategoryDto.getId());
}
}
}
}
return Lists.newArrayList(levelOneCategorySet);
}
/**
* 资料库分类分页查询
* @param request
* @return
*/
public PageResult<WikiCategoryMobileDto> wikiCategoryMobilePaginQuery(WikiCategoryRequestDto request) {
WikiCategoryRequestModel requestModel = BeanUtil.copyProperties(request, WikiCategoryRequestModel.class);
requestModel.setStatus(1);
requestModel.setPageSize(1000);
List<Integer> categoryIdList = examineService.wikiCategoryUseableList();
requestModel.setIdList(categoryIdList);
requestModel.setIdList(findLevelOneCategory(categoryIdList));
Page<WikiCategoryResponseModel> page = examineService.wikiCategoryPaginQuery(requestModel);
PageResult<WikiCategoryMobileDto> pageResult = PageResult.of(request.getPageNo(), request.getPageSize(), (int) page.getTotalRow(), null);
if(CollectionUtil.isNotEmpty(page.getRecords())) {
List<WikiCategoryMobileDto> dtoList = page.getRecords().stream().map(v -> {
WikiCategoryMobileDto dto = BeanUtil.copyProperties(v, WikiCategoryMobileDto.class);
......@@ -1034,6 +1083,7 @@ public class AppExamineService {
public void saveWiki(WikiSaveDto dto) {
WikiSaveModel model = BeanUtil.copyProperties(dto, WikiSaveModel.class);
model.setWikiCategoryId(dto.getWikiCategoryId());
examineService.saveWiki(model);
}
......@@ -1396,8 +1446,14 @@ public class AppExamineService {
if(Objects.isNull(businessCache)) {
throw new InternalException(-1, "获取不到对练信息");
}
// 更新考试记录状态
Integer recordId = businessCache.getRecordId();
ExamineRecordSaveModel saveModel = new ExamineRecordSaveModel();
saveModel.setId(recordId);
saveModel.setStatus(1);
examineService.saveExamineRecord(saveModel);
// 保存定时任务
ExamineEvaluateJobResponseModel evaluateJob = commonService.getEvaluateJob(1, recordId);
if(Objects.isNull(evaluateJob)) {
ExamineEvaluateJobSaveModel model = new ExamineEvaluateJobSaveModel();
......@@ -1544,4 +1600,147 @@ public class AppExamineService {
return null;
}
/**
* 考试答题
* @param userPrincipal
* @param request
*/
public Flux<ServerSentEvent<SubmitAnswerStreamResultDto>> submitAnswerStream(UserPrincipal userPrincipal, SubmitAnswerMobileRequestDto request) {
String userId = userPrincipal.getUserId();
Integer examineId = request.getExamineId();
String answer = request.getAnswer();
Integer questionId = request.getQuestionId();
String businessNo = request.getBusinessNo();
// 获取缓存考试会话信息
String examBusinessKey = String.format(EXAM_BUSINESS_REDIS_KEY, businessNo);
ExamineBusinessCacheDto businessCache = getExamBusinessCache(businessNo);
if (Objects.isNull(businessCache)) {
throw new InternalException(-1, "获取不到对练信息");
}
// 获取数据库考试信息
Integer recordId;
int answeredNum = 0;
ExamineRecordResponseModel examineRecord = examineService.examineRecordDetail(businessNo);
if (Objects.isNull(examineRecord)) {
// 第一次答题,保存考试信息
ExamineRecordSaveModel saveModel = new ExamineRecordSaveModel();
saveModel.setUserId(userId);
saveModel.setUserName(userPrincipal.getUserName());
saveModel.setShopId(userPrincipal.getShopId());
saveModel.setShopName(userPrincipal.getShopName());
saveModel.setAnsweredNum(1);
saveModel.setExamineId(examineId);
saveModel.setExamineMode(businessCache.getExamineMode());
saveModel.setBusinessNo(businessNo);
examineService.saveExamineRecord(saveModel);
recordId = saveModel.getId();
} else {
recordId = examineRecord.getId();
answeredNum = examineRecord.getAnsweredNum();
}
// 获取有无答题记录
Integer detailRecordId;
ExamineRecordDetailResponseModel examineRecordDetail = examineService.getExamineRecordDetail(recordId, questionId);
if (Objects.isNull(examineRecordDetail)) {
// 更新答题数量
ExamineRecordSaveModel saveModel = new ExamineRecordSaveModel();
saveModel.setId(recordId);
saveModel.setAnsweredNum(answeredNum + 1);
examineService.saveExamineRecord(saveModel);
// 保存单题答题信息
ExamineRecordDetailSaveModel detailSaveModel = new ExamineRecordDetailSaveModel();
detailSaveModel.setRecordId(recordId);
detailSaveModel.setQaId(questionId);
detailSaveModel.setCreateTime(new Date());
detailSaveModel.setAnswer(answer);
examineService.saveExamineRecordDetail(detailSaveModel);
detailRecordId = detailSaveModel.getId();
} else {
// 保存单题答题信息
ExamineRecordDetailSaveModel detailSaveModel = new ExamineRecordDetailSaveModel();
detailSaveModel.setId(examineRecordDetail.getId());
detailSaveModel.setAnswer(answer);
examineService.saveExamineRecordDetail(detailSaveModel);
detailRecordId = examineRecordDetail.getId();
}
Integer businessId = detailRecordId;
Map<String, String> inputs = new HashMap<>();
inputs.put("scene", "single_qa_score");
inputs.put("business_id", String.valueOf(businessId));
JSONObject param = new JSONObject();
param.put("query", String.valueOf(businessId));
param.put("inputs", inputs);
param.put("response_mode", "streaming");
param.put("conversation_id", "");
param.put("user", userId);
final String[] standardAnswer = new String[1];
final StringBuffer replyBuffer = new StringBuffer();
final String[] score = new String[1];
return webClient.post().uri("/chat-messages").accept(MediaType.TEXT_EVENT_STREAM).bodyValue(param.toJSONString()).exchangeToFlux(r -> r.bodyToFlux(String.class))
.mapNotNull(v -> {
JSONObject json = JSONObject.parseObject(v);
String reply = json.getString("answer");
if(Objects.nonNull(reply)) {
replyBuffer.append(reply);
// ai评分正则
Pattern scorePattern = Pattern.compile("\"score\":\"(\\d+)\"");
Matcher scoreMatcher = scorePattern.matcher(replyBuffer.toString());
if (scoreMatcher.find() && StringUtils.isEmpty(score[0])) {
score[0] = scoreMatcher.group(1); // 提取第一个捕获组的内容
}
// 标准答案正则
Pattern answerPattern = Pattern.compile("\"answer\":\"([^\"]*)");
Matcher answerMatcher = answerPattern.matcher(replyBuffer.toString());
if (answerMatcher.find()) {
standardAnswer[0] = answerMatcher.group(1);
}
}
SubmitAnswerStreamResultDto result = new SubmitAnswerStreamResultDto();
if(StringUtils.isNotEmpty(score[0])) {
result.setScore(Float.valueOf(score[0]));
}
result.setAnswer(standardAnswer[0]);
return result;
}).doOnComplete(
() -> {
// 更新答题点评信息
ExamineRecordDetailSaveModel detailSaveModel = new ExamineRecordDetailSaveModel();
detailSaveModel.setId(businessId);
detailSaveModel.setScore(Float.valueOf(score[0]));
examineService.saveExamineRecordDetail(detailSaveModel);
// 定时任务
ExamineEvaluateJobResponseModel evaluateJob = commonService.getEvaluateJob(0, detailRecordId);
if(Objects.isNull(evaluateJob)) {
ExamineEvaluateJobSaveModel model = new ExamineEvaluateJobSaveModel();
model.setBusinessId(detailRecordId);
model.setBusinessNo(businessNo);
model.setType(0);
model.setStatus(0);
model.setUserId(userId);
model.setCreateTime(new Date());
commonService.saveEvaluateJob(model);
}
// 更新缓存
businessCache.setRecordId(recordId);
redisTemplate.opsForValue().set(examBusinessKey, JSONObject.toJSONString(businessCache), 1, TimeUnit.DAYS);
// 最后一题答题,完成考试,执行AI总点评
if(!businessCache.isHasNext()) {
this.completeExamine(userPrincipal, examineId, businessNo);
}
}
).map(v -> ServerSentEvent.builder(v).build());
}
}
......@@ -27,7 +27,7 @@ public class QuartzCronConfig {
public Trigger cronTrigger(JobDetail jobDetail) {
CronTriggerFactoryBean factoryBean = new CronTriggerFactoryBean();
factoryBean.setJobDetail(jobDetail);
factoryBean.setCronExpression("0 0/1 * * * ?"); // 每5分钟执行一次
factoryBean.setCronExpression("*/10 * * * * ?"); // 每5分钟执行一次
factoryBean.setName("cronTrigger");
factoryBean.afterPropertiesSet();
return factoryBean.getObject();
......
package cn.breeze.elleai.controller.extension;
import cn.breeze.elleai.application.dto.langchain.VectorSegment;
import cn.breeze.elleai.application.service.AiPlatformExtensionService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* @author yangyw
*/
......@@ -55,4 +58,16 @@ public class AiPlatformExtensionController {
return extensionService.canAnswerByLlm(assistantId);
}
@Operation(summary = "向量搜索(测试)")
@PostMapping(value = "/test_search_with_rerank")
public List<VectorSegment> testSearchWithRerank(@RequestParam("query") String query,
@RequestParam(value = "assistant_id", required = false, defaultValue = "0") Integer assistantId,
@RequestParam(value = "top_k", required = false, defaultValue = "5") Integer topK,
@RequestParam(value = "score", required = false, defaultValue = "0") Double score,
@RequestParam(value = "rerank_top_k", required = false, defaultValue = "5") Integer rerankTopK,
@RequestParam(value = "rerank_score", required = false, defaultValue = "0") Double rerankScore) {
return extensionService.testSearchWithRerank(query, assistantId, topK, score, rerankTopK, rerankScore);
}
}
......@@ -3,6 +3,7 @@ package cn.breeze.elleai.controller.front;
import cn.breeze.elleai.application.dto.ApiResponse;
import cn.breeze.elleai.application.dto.PageResult;
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.application.service.AppExamineService;
......@@ -13,7 +14,14 @@ import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.http.codec.ServerSentEvent;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
@RestController
@RequestMapping(value = "/front/examine")
......@@ -151,4 +159,12 @@ public class ExamineMobileController {
return ApiResponse.ok("SUCCESS");
}
@Operation(summary = "考试答题")
@PostMapping(value = "submit_answer_stream")
public Flux<ServerSentEvent<SubmitAnswerStreamResultDto>> submitAnswerStream(@Parameter(hidden = true) UserPrincipal userPrincipal,
@RequestBody SubmitAnswerMobileRequestDto request) {
return examineService.submitAnswerStream(userPrincipal, request);
}
}
......@@ -81,4 +81,9 @@ public class ExamineRecordSaveModel implements Serializable {
* 是否删除
*/
private Integer deleted;
/**
* 状态(0进行中 1已完成)
*/
private Integer status;
}
......@@ -14,4 +14,6 @@ public class HotQaRequestModel implements Serializable {
private String name;
private Integer status;
private Integer assistantId;
}
......@@ -20,6 +20,11 @@ public class HotQaSaveModel implements Serializable {
*/
private String answer;
/**
* 助手ID
*/
private Integer assistantId;
/**
* 排序优先级
*/
......
......@@ -14,4 +14,6 @@ public class KbTagRequestModel implements Serializable {
private String name;
private Integer status;
private Integer level;
}
......@@ -21,6 +21,11 @@ public class HotQaResponseModel implements Serializable {
*/
private String answer;
/**
* 助手ID
*/
private Integer assistantId;
/**
* 排序优先级
*/
......
......@@ -10,6 +10,7 @@ import cn.breeze.elleai.domain.sparring.model.response.UserChatCompletionRespons
import com.mybatisflex.core.paginate.Page;
import java.util.List;
import java.util.Set;
public interface ChatCompletionService {
......@@ -59,4 +60,6 @@ public interface ChatCompletionService {
void deleteHotQa(Integer id);
void saveHotQa(HotQaSaveModel dto);
List<QaAssistantResponseModel> qaAssistantListByIds(Set<Integer> assistantIds);
}
......@@ -26,6 +26,7 @@ import org.springframework.stereotype.Service;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import static cn.breeze.elleai.infra.entity.table.QaAssistantTableDef.QA_ASSISTANT_ENTITY;
import static cn.breeze.elleai.infra.entity.table.UserChatCompletionHistoryTableDef.USER_CHAT_COMPLETION_HISTORY_ENTITY;
......@@ -53,6 +54,9 @@ public class ChatCompletionServiceImpl implements ChatCompletionService{
if(StrUtil.isNotEmpty(request.getUserName())) {
queryWrapper.where(USER_CHAT_COMPLETION_ENTITY.USER_NAME.eq(request.getUserName()));
}
if(StrUtil.isNotEmpty(request.getUserId())) {
queryWrapper.and(USER_CHAT_COMPLETION_ENTITY.USER_ID.eq(request.getUserId()));
}
if(StrUtil.isNotEmpty(request.getUserId())) {
queryWrapper.where(USER_CHAT_COMPLETION_ENTITY.USER_ID.eq(request.getUserId()));
......@@ -267,6 +271,10 @@ public class ChatCompletionServiceImpl implements ChatCompletionService{
public List<HotQaResponseModel> hotQaList(HotQaRequestModel request) {
QueryWrapper queryWrapper = QueryWrapper.create()
.where(HOT_QA_ENTITY.DELETED.eq(0));
if (ObjectUtil.isNotNull(request.getAssistantId())) {
queryWrapper.and(HOT_QA_ENTITY.ASSISTANT_ID.eq(request.getAssistantId()));
}
if(StrUtil.isNotEmpty(request.getName())) {
queryWrapper.and(HOT_QA_ENTITY.QUESTION.like("%"+request.getName()+"%"));
}
......@@ -306,4 +314,11 @@ public class ChatCompletionServiceImpl implements ChatCompletionService{
HotQaEntity entity = BeanUtil.toBean(dto, HotQaEntity.class);
hotQaMapper.insertOrUpdateSelective(entity);
}
@Override
public List<QaAssistantResponseModel> qaAssistantListByIds(Set<Integer> assistantIds) {
QueryWrapper queryWrapper = QueryWrapper.create()
.where(QA_ASSISTANT_ENTITY.ID.in(assistantIds));
return qaAssistantMapper.selectListByQueryAs(queryWrapper, QaAssistantResponseModel.class);
}
}
......@@ -430,6 +430,7 @@ public class ExamineServiceImpl implements ExamineService {
QueryWrapper queryWrapper = QueryWrapper.create();
queryWrapper.where(USER_EXAMINE_RECORD_ENTITY.DELETED.eq(0));
queryWrapper.and(USER_EXAMINE_RECORD_ENTITY.STATUS.eq(1));
if(StrUtil.isNotEmpty(request.getUserId())) {
queryWrapper.and(USER_EXAMINE_RECORD_ENTITY.USER_ID.eq(request.getUserId()));
}
......@@ -606,6 +607,7 @@ public class ExamineServiceImpl implements ExamineService {
QueryWrapper queryWrapper = QueryWrapper.create()
.select(WIKI_ENTITY.WIKI_CATEGORY_ID)
.where(WIKI_ENTITY.DELETED.eq(0))
.and(WIKI_ENTITY.STATUS.eq(1))
.and(WIKI_ENTITY.WIKI_CATEGORY_ID.isNotNull());
queryWrapper.groupBy(WIKI_ENTITY.WIKI_CATEGORY_ID);
......
......@@ -7,12 +7,16 @@ import cn.breeze.elleai.domain.sparring.model.request.KbRequestModel;
import cn.breeze.elleai.domain.sparring.model.request.KbSaveModel;
import cn.breeze.elleai.domain.sparring.model.response.KbResponseModel;
import cn.breeze.elleai.infra.entity.KbEntity;
import cn.breeze.elleai.infra.entity.QaAssistantEntity;
import cn.breeze.elleai.infra.mapper.KbMapper;
import cn.breeze.elleai.infra.mapper.KbVectorMapper;
import cn.breeze.elleai.infra.mapper.QaAssistantMapper;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONValidator;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.update.UpdateChain;
......@@ -20,6 +24,7 @@ import com.mybatisflex.spring.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
......@@ -41,6 +46,8 @@ public class KbServiceImpl extends ServiceImpl<KbMapper, KbEntity> implements Kb
private final KbVectorMapper kbVectorMapper;
private final QaAssistantMapper qaAssistantMapper;
@Override
public Page<KbResponseModel> kbPaginQuery(KbRequestModel request) {
Integer pageNo = ObjectUtil.defaultIfNull(request.getPageNo(), 1);
......@@ -142,9 +149,24 @@ public class KbServiceImpl extends ServiceImpl<KbMapper, KbEntity> implements Kb
@Override
public PageResult<HotQaMobileDto> hotQaList(QaAssistantRequestDto request) {
List<Integer> tagIds = new ArrayList<>();
if(Objects.nonNull(request.getAssistantId())) {
QaAssistantEntity entity = qaAssistantMapper.selectOneById(request.getAssistantId());
if (Objects.nonNull(entity)) {
if (StrUtil.isNotBlank(entity.getCategoryIds())) {
if (JSONValidator.from(entity.getCategoryIds()).validate()) {
List<Integer> items = JSONArray.parseArray(entity.getCategoryIds(), Integer.class);
if (CollUtil.isNotEmpty(items)) {
tagIds.addAll(items);
}
}
}
}
}
QueryWrapper qw = QueryWrapper.create()
.select(KB_ENTITY.QUESTION)
.where(KB_ENTITY.STATUS.eq(1).and(KB_ENTITY.DELETED.eq(0)))
.and(KB_ENTITY.TAG_ID.in(tagIds).when(CollUtil.isNotEmpty(tagIds)))
.orderBy(KB_ENTITY.HINT.desc())
.limit(10);
List<String> questions = kbMapper.selectObjectListByQueryAs(qw, String.class);
......
......@@ -61,6 +61,9 @@ public class KbTagServiceImpl extends ServiceImpl<KbTagMapper, KbTagEntity> impl
if(Objects.nonNull(request.getStatus())) {
queryWrapper.and(KB_TAG_ENTITY.STATUS.eq(request.getStatus()));
}
if(Objects.nonNull(request.getLevel())) {
queryWrapper.and(KB_TAG_ENTITY.PARENT_ID.ne(0));
}
queryWrapper.orderBy(KB_TAG_ENTITY.CREATE_AT, false);
return kbTagMapper.selectListByQueryAs(queryWrapper, KbTagResponseModel.class);
......
......@@ -41,6 +41,11 @@ public class HotQaEntity implements Serializable {
*/
private String answer;
/**
* 助手ID
*/
private Integer assistantId;
/**
* 排序优先级
*/
......
......@@ -102,4 +102,9 @@ public class UserExamineRecordEntity implements Serializable {
*/
private Integer deleted;
/**
* 状态(0进行中 1已完成)
*/
private Integer status;
}
......@@ -34,6 +34,11 @@ public class HotQaTableDef extends TableDef {
*/
public final QueryColumn ANSWER = new QueryColumn(this, "answer");
/**
* 助手ID
*/
public final QueryColumn ASSISTANT_ID = new QueryColumn(this, "assistant_id");
/**
* 排序优先级
*/
......@@ -62,7 +67,7 @@ public class HotQaTableDef extends TableDef {
/**
* 默认字段,不包含逻辑删除或者 large 等字段。
*/
public final QueryColumn[] DEFAULT_COLUMNS = new QueryColumn[]{ID, QUESTION, ANSWER, SORT_INDEX, STATUS, DELETED, CREATE_TIME};
public final QueryColumn[] DEFAULT_COLUMNS = new QueryColumn[]{ID, QUESTION, ANSWER,ASSISTANT_ID, SORT_INDEX, STATUS, DELETED, CREATE_TIME};
public HotQaTableDef() {
super("", "ai_hot_qa");
......
......@@ -91,10 +91,15 @@ public class UserExamineRecordTableDef extends TableDef {
public final QueryColumn OVERALL_EVALUATION = new QueryColumn(this, "overall_evaluation");
/**
* 综合评价
* 是否删除
*/
public final QueryColumn DELETED = new QueryColumn(this, "deleted");
/**
* 状态(0进行中 1已完成)
*/
public final QueryColumn STATUS = new QueryColumn(this, "status");
/**
* 所有字段。
*/
......@@ -103,7 +108,7 @@ public class UserExamineRecordTableDef extends TableDef {
/**
* 默认字段,不包含逻辑删除或者 large 等字段。
*/
public final QueryColumn[] DEFAULT_COLUMNS = new QueryColumn[]{ID, USER_ID, USER_NAME, BUSINESS_NO, SHOP_ID, SHOP_NAME, SESSION_ID, EXAMINE_ID, EXAMINE_MODE, ANSWERED_NUM, OVERALL_SCORE, OVERALL_EVALUATION, CREATE_TIME, UPDATE_TIME, DELETED};
public final QueryColumn[] DEFAULT_COLUMNS = new QueryColumn[]{ID, USER_ID, USER_NAME, BUSINESS_NO, SHOP_ID, SHOP_NAME, SESSION_ID, EXAMINE_ID, EXAMINE_MODE, ANSWERED_NUM, OVERALL_SCORE, OVERALL_EVALUATION, CREATE_TIME, UPDATE_TIME, DELETED, STATUS};
public UserExamineRecordTableDef() {
super("", "ai_user_examine_record");
......
......@@ -7,10 +7,7 @@ import cn.breeze.elleai.domain.sparring.model.request.ExamineDetailRecordRequest
import cn.breeze.elleai.domain.sparring.model.request.ExamineEvaluateJobSaveModel;
import cn.breeze.elleai.domain.sparring.model.request.ExamineRecordDetailSaveModel;
import cn.breeze.elleai.domain.sparring.model.request.ExamineRecordSaveModel;
import cn.breeze.elleai.domain.sparring.model.response.ExamineDetailRecordResponseModel;
import cn.breeze.elleai.domain.sparring.model.response.ExamineEvaluateJobResponseModel;
import cn.breeze.elleai.domain.sparring.model.response.ExamineQaResponseModel;
import cn.breeze.elleai.domain.sparring.model.response.ExamineRecordDetailResponseModel;
import cn.breeze.elleai.domain.sparring.model.response.*;
import cn.breeze.elleai.domain.sparring.service.CommonService;
import cn.breeze.elleai.domain.sparring.service.ExamineService;
import cn.breeze.elleai.util.Codes;
......@@ -80,7 +77,11 @@ public class SingleJob extends QuartzJobBean {
// 更新答题点评信息
ExamineRecordDetailSaveModel detailSaveModel = new ExamineRecordDetailSaveModel();
detailSaveModel.setId(businessId);
// 判断对练类型,对练类型需要更新AI评分分数
ExamineRecordResponseModel model = examineService.examineRecordDetail(businessNo);
if(Objects.equals(model.getExamineMode(), 1)) {
detailSaveModel.setScore(evaluateResult.getScore());
}
detailSaveModel.setEvaluation(evaluateResult.getEvaluation());
examineService.saveExamineRecordDetail(detailSaveModel);
......
......@@ -85,6 +85,11 @@ minio-file:
upload-prefix: upload
download-url-prefix: http://10.233.12.210:9000/
rerank:
api-base-url: http://125.94.43.18:9080/v1
embedding:
api-base-url: http://125.94.43.18:9080/v1
---
spring:
config:
......@@ -107,7 +112,7 @@ knife4j:
sso:
user:
mock: false
domain: https://elleai.e-tools.cn
domain: https://ai.mezeron.cn
rerank:
api-base-url: http://10.0.8.210:9997/v1
embedding:
......@@ -128,7 +133,7 @@ minio-file:
endpoint: http://10.0.8.210:9000
secret-id: admin
secret-key: future123456
domain-prefix: https://elleai.e-tools.cn/
domain-prefix: https://ai.mezeron.cn/
intercept-prefix: http://10.0.8.210:9000/
upload-prefix: upload
download-url-prefix: http://10.0.8.210:9000/
......@@ -13,7 +13,6 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
@SpringBootTest
@Profile("dev")
public class AIServiceTestUnit {
......
package cn.breeze.elleai.test;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class ElleaiApplicationTests {
@Test
void contextLoads() {
}
}
spring:
profiles:
active: default
mvc:
pathmatch:
matching-strategy: ant-path-matcher
application:
name: elle-ai
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
default-property-inclusion: non_null
property-naming-strategy: SNAKE_CASE
http:
multipart:
max-file-size: 100Mb
max-request-size: 100Mb
springdoc:
swagger-ui:
path: /swagger-ui.html
dify:
api_base: https://dify-api.aibreeze.cn/v1
api_key: app-Zmm5npksiTEni4J1lJ1c9LhI
chat_api_base: https://ai-api.tech.breezeai.cn/v1
chat_api_key: app-Zmm5npksiTEni4J1lJ1c9LhI
deepseek:
app_id: 1304653544
secret_id: AKIDHMA2jAKD6dwzpPikWR5TbT5RWLtAAuNZ
app_key: imNDldBw
api_base: https://wss.lke.cloud.tencent.com/v1/qbot/chat/sse
diss_api_base: https://lke.tencentcloudapi.com/
---
spring:
config:
activate:
on-profile: default
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://172.18.5.186:4306/elle_ai?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
username: future
password:
future123456
data:
redis:
password: future123456
host: 127.0.0.1
port: 6379
database: 6
minio-file:
store: minio
bucket: files
endpoint: http://minio:9000
secret-id: smartbreeze
secret-key: smartbreeze
domain-prefix: http://files.hc.wxpai.cn/
intercept-prefix: http://minio:9000/
upload-prefix: upload
download-url-prefix: http://minio:9000/
---
spring:
config:
activate:
on-profile: dev
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://172.18.5.186:4306/elle_ai?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
username: future
password: future123456
data:
redis:
host: 172.18.5.187
port: 6379
password: future123456
database: 11
minio-file:
store: minio
bucket: files
endpoint: http://10.233.12.210:9000
secret-id: smartbreeze
secret-key: smartbreeze
domain-prefix: http://files.hc.wxpai.cn/
intercept-prefix: http://10.233.12.210:9000/
upload-prefix: upload
download-url-prefix: http://10.233.12.210:9000/
---
spring:
config:
activate:
on-profile: prd
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://10.0.8.210:3306/elle_ai?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
username: root
password: future123456
data:
redis:
host: 10.0.8.210
port: 6379
password: future123456
database: 0
knife4j:
enable: false
sso:
user:
mock: false
domain: https://elleai.e-tools.cn
rerank:
api-base-url: http://10.0.8.210:9997/v1
embedding:
api-base-url: http://10.0.8.210:9997/v1
milvus:
host: 10.0.8.210
port: 19530
database: default
dify:
api_base: https://dify-api.aibreeze.cn/v1
api_key: app-Zmm5npksiTEni4J1lJ1c9LhI
chat_api_base: https://dify-api.aibreeze.cn/v1
chat_api_key: app-Zmm5npksiTEni4J1lJ1c9LhI
minio-file:
store: minio
bucket: files
endpoint: http://10.0.8.210:9000
secret-id: admin
secret-key: future123456
domain-prefix: https://elleai.e-tools.cn/
intercept-prefix: http://10.0.8.210:9000/
upload-prefix: upload
download-url-prefix: http://10.0.8.210:9000/
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment