Commit fc19145a by 王一诺

模型管理

parents
Showing with 3777 additions and 0 deletions
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
### IntelliJ IDEA ###
.idea/modules.xml
.idea/jarRepositories.xml
.idea/compiler.xml
.idea/libraries/
*.iws
*.iml
*.ipr
### Eclipse ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/
### VS Code ###
.vscode/
### Mac OS ###
.DS_Store
\ No newline at end of file
File mode changed
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding">
<file url="file://$PROJECT_DIR$/api-llm/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/common-llm/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/service-llm-picture/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/service-llm/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/src/main/resources" 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="ExternalStorageConfigurationManager" enabled="true" />
<component name="MavenProjectsManager">
<option name="originalFiles">
<list>
<option value="$PROJECT_DIR$/pom.xml" />
<option value="$PROJECT_DIR$/common-llm/pom.xml" />
</list>
</option>
<option name="ignoredFiles">
<set>
<option value="$PROJECT_DIR$/service-llm-picture/pom.xml" />
</set>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8" 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="AutoImportSettings">
<option name="autoReloadType" value="SELECTIVE" />
</component>
<component name="ChangeListManager">
<list default="true" id="6879e488-b2d7-4692-a578-ccef01aca622" name="Changes" 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="FileTemplateManagerImpl">
<option name="RECENT_TEMPLATES">
<list>
<option value="FxmlFile" />
<option value="Interface" />
<option value="Class" />
</list>
</option>
</component>
<component name="KubernetesApiPersistence">{}</component>
<component name="KubernetesApiProvider">{
&quot;isMigrated&quot;: true
}</component>
<component name="ProblemsViewState">
<option name="selectedTabId" value="ProjectErrors" />
</component>
<component name="ProjectColorInfo">{
&quot;associatedIndex&quot;: 3
}</component>
<component name="ProjectId" id="2tKhtS8ctVEzT1zOOe0OW4tg7TG" />
<component name="ProjectViewState">
<option name="hideEmptyMiddlePackages" value="true" />
<option name="showLibraryContents" value="true" />
</component>
<component name="PropertiesComponent">{
&quot;keyToString&quot;: {
&quot;Application.LLMClient.executor&quot;: &quot;Run&quot;,
&quot;Maven. [org.apache.maven.plugins:maven-archetype-plugin:RELEASE:generate].executor&quot;: &quot;Run&quot;,
&quot;Maven.api-llm [clean].executor&quot;: &quot;Run&quot;,
&quot;Maven.api-llm [package].executor&quot;: &quot;Run&quot;,
&quot;Maven.common-llm [clean].executor&quot;: &quot;Run&quot;,
&quot;Maven.common-llm [compile].executor&quot;: &quot;Run&quot;,
&quot;Maven.common-llm [install].executor&quot;: &quot;Run&quot;,
&quot;Maven.common-llm [package].executor&quot;: &quot;Run&quot;,
&quot;Maven.large-language-model [clean].executor&quot;: &quot;Run&quot;,
&quot;Maven.large-language-model [package].executor&quot;: &quot;Run&quot;,
&quot;Maven.llm-api [clean].executor&quot;: &quot;Run&quot;,
&quot;Maven.llm-api [compile].executor&quot;: &quot;Run&quot;,
&quot;Maven.llm-api [package].executor&quot;: &quot;Run&quot;,
&quot;Maven.llm-api [test].executor&quot;: &quot;Run&quot;,
&quot;Maven.service-llm [clean].executor&quot;: &quot;Run&quot;,
&quot;Maven.service-llm [package].executor&quot;: &quot;Run&quot;,
&quot;Maven.service-llm-text [clean].executor&quot;: &quot;Run&quot;,
&quot;Maven.service-llm-text [compile].executor&quot;: &quot;Run&quot;,
&quot;Maven.service-llm-text [package].executor&quot;: &quot;Run&quot;,
&quot;RequestMappingsPanelOrder0&quot;: &quot;0&quot;,
&quot;RequestMappingsPanelOrder1&quot;: &quot;1&quot;,
&quot;RequestMappingsPanelWidth0&quot;: &quot;75&quot;,
&quot;RequestMappingsPanelWidth1&quot;: &quot;75&quot;,
&quot;RunOnceActivity.ShowReadmeOnStart&quot;: &quot;true&quot;,
&quot;Spring Boot.LLMApiApplication.executor&quot;: &quot;Run&quot;,
&quot;Spring Boot.ServiceLlmApplication.executor&quot;: &quot;Run&quot;,
&quot;com.codeium.enabled&quot;: &quot;true&quot;,
&quot;kotlin-language-version-configured&quot;: &quot;true&quot;,
&quot;last_opened_file_path&quot;: &quot;/Users/wangyinuo/workspace/code/java/large-language-model/api-llm/src/main/resources&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;Modules&quot;,
&quot;project.structure.proportion&quot;: &quot;0.0&quot;,
&quot;project.structure.side.proportion&quot;: &quot;0.0&quot;,
&quot;settings.editor.selected.configurable&quot;: &quot;build.tools&quot;,
&quot;vue.rearranger.settings.migration&quot;: &quot;true&quot;
}
}</component>
<component name="ReactorSettings">
<option name="notificationShown" value="true" />
</component>
<component name="RecentsManager">
<key name="CopyFile.RECENT_KEYS">
<recent name="$PROJECT_DIR$/api-llm/src/main/resources" />
<recent name="$PROJECT_DIR$/service-llm/src/main/resources" />
<recent name="$PROJECT_DIR$/llm-api/src/main/java/com/coolook/llm/api/remote" />
<recent name="$PROJECT_DIR$/llm-api/src/main/java/com/coolook/llm/api/service/impl" />
<recent name="$PROJECT_DIR$/common-llm/src/main/java/com/coolook/common/llm/utils" />
</key>
<key name="CopyClassDialog.RECENTS_KEY">
<recent name="com.coolook.common.llm.request" />
<recent name="com.coolook.common.llm.dto" />
<recent name="com.coolook.common.llm.response" />
<recent name="com.coolook.service.llm.controller" />
<recent name="com.coolook.common.llm.pojo" />
</key>
</component>
<component name="RunDashboard">
<option name="configurationTypes">
<set>
<option value="SpringBootApplicationConfigurationType" />
</set>
</option>
</component>
<component name="RunManager" selected="Spring Boot.LLMApiApplication">
<configuration name="LLMClient" type="Application" factoryName="Application" temporary="true" nameIsGenerated="true">
<option name="MAIN_CLASS_NAME" value="com.coolook.service.llm.remote.LLMClient" />
<module name="service-llm" />
<extension name="coverage">
<pattern>
<option name="PATTERN" value="com.coolook.service.llm.remote.*" />
<option name="ENABLED" value="true" />
</pattern>
</extension>
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
<configuration name="LLMApiApplication" type="SpringBootApplicationConfigurationType" factoryName="Spring Boot" temporary="true" nameIsGenerated="true">
<module name="api-llm" />
<option name="SPRING_BOOT_MAIN_CLASS" value="com.coolook.llm.api.LLMApiApplication" />
<extension name="coverage">
<pattern>
<option name="PATTERN" value="com.coolook.llm.api.*" />
<option name="ENABLED" value="true" />
</pattern>
</extension>
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
<configuration name="ServiceLlmApplication" type="SpringBootApplicationConfigurationType" factoryName="Spring Boot" temporary="true" nameIsGenerated="true">
<module name="service-llm" />
<option name="SPRING_BOOT_MAIN_CLASS" value="com.coolook.service.llm.ServiceLlmApplication" />
<extension name="coverage">
<pattern>
<option name="PATTERN" value="com.coolook.service.llm.*" />
<option name="ENABLED" value="true" />
</pattern>
</extension>
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
<recent_temporary>
<list>
<item itemvalue="Spring Boot.ServiceLlmApplication" />
<item itemvalue="Spring Boot.LLMApiApplication" />
<item itemvalue="Application.LLMClient" />
</list>
</recent_temporary>
</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="application-level" UseSingleDictionary="true" transferred="true" />
<component name="TaskManager">
<task active="true" id="Default" summary="Default task">
<changelist id="6879e488-b2d7-4692-a578-ccef01aca622" name="Changes" comment="" />
<created>1740106887990</created>
<option name="number" value="Default" />
<option name="presentableId" value="Default" />
<updated>1740106887990</updated>
<workItem from="1740106889011" duration="3424000" />
<workItem from="1740111014438" duration="1212000" />
<workItem from="1740118150831" duration="17023000" />
<workItem from="1740363911117" duration="6271000" />
<workItem from="1740377623449" duration="25499000" />
<workItem from="1740464056677" duration="18976000" />
<workItem from="1740536294375" duration="38327000" />
<workItem from="1740714465315" duration="10064000" />
<workItem from="1740734658778" duration="3256000" />
<workItem from="1740984133778" duration="12002000" />
<workItem from="1740998242171" duration="1097000" />
<workItem from="1740999579004" duration="137000" />
<workItem from="1741063899512" duration="55538000" />
<workItem from="1741244026827" duration="34456000" />
<workItem from="1741345466036" duration="58000" />
<workItem from="1741658875595" duration="3576000" />
<workItem from="1741674765597" duration="907000" />
<workItem from="1741681794467" duration="3596000" />
<workItem from="1741744942594" duration="630000" />
<workItem from="1741750927988" duration="626000" />
<workItem from="1741763252244" duration="2269000" />
<workItem from="1741849776608" duration="4299000" />
<workItem from="1741855572336" duration="3031000" />
<workItem from="1741920343491" duration="1645000" />
<workItem from="1741931944414" duration="27842000" />
<workItem from="1742177794559" duration="6136000" />
<workItem from="1742193641040" duration="4084000" />
</task>
<servers />
</component>
<component name="TypeScriptGeneratedFilesManager">
<option name="version" value="3" />
</component>
<component name="XDebuggerManager">
<breakpoint-manager>
<breakpoints>
<breakpoint enabled="true" type="java-exception">
<properties class="java.lang.NullPointerException" package="java.lang" />
<option name="timeStamp" value="1" />
</breakpoint>
<line-breakpoint enabled="true" type="java-line">
<url>file://$PROJECT_DIR$/service-llm/src/main/java/com/coolook/service/llm/service/ModelService.java</url>
<line>101</line>
<option name="timeStamp" value="2" />
</line-breakpoint>
</breakpoints>
</breakpoint-manager>
<watches-manager>
<configuration name="SpringBootApplicationConfigurationType">
<watch expression="availableollamaModelList" />
</configuration>
</watches-manager>
</component>
</project>
\ No newline at end of file
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.coolook</groupId>
<artifactId>large-language-model</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>api-llm</artifactId>
<packaging>jar</packaging>
<name>api-llm</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-loadbalancer</artifactId>
</dependency>
<dependency>
<groupId>com.coolook</groupId>
<artifactId>common-llm</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
<build>
<finalName>${name}</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring.version}</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
package com.coolook.llm.api;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
/**
* @author: Wang Yinuo
* @create: 2025-02-21:AM11:12
*/
@SpringBootApplication
@EnableFeignClients
public class LLMApiApplication {
public static void main(String[] args) {
SpringApplication.run(LLMApiApplication.class, args);
}
}
package com.coolook.llm.api.controller;
import com.coolook.common.llm.constant.AiStatus;
import com.coolook.common.llm.dto.Message;
import com.coolook.common.llm.response.ResponseResult;
import com.coolook.llm.api.service.IAiService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
/**
* @author: Wang Yinuo
* @create: 2025-02-21:AM11:13
*/
@RestController
public class ModelApiController {
@Autowired
private IAiService aiService;
@PostMapping("/ask")
public ResponseResult<Message> ask(@RequestBody Message msg) throws Exception{
if (StringUtils.isEmpty(msg.getAiQuestion())){
msg.setStatus(AiStatus.ERROR);
return ResponseResult.fail(msg);
}
return aiService.ask(msg);
}
@PostMapping("/webAsk")
public ResponseResult<Message> webAsk(@RequestBody Message msg) throws Exception{
if (StringUtils.isEmpty(msg.getAiQuestion())){
msg.setStatus(AiStatus.ERROR);
return ResponseResult.fail(msg);
}
return aiService.webAsk(msg);
}
}
\ No newline at end of file
package com.coolook.llm.api.remote;
import com.coolook.common.llm.dto.ModelsDto;
import com.coolook.common.llm.response.ResponseResult;
import com.coolook.common.llm.request.OpenAiTextRequest;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.http.HttpEntity;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import java.util.List;
import java.util.Map;
/**
* @author: Wang Yinuo
* @create: 2025-03-06:PM2:28
*/
@FeignClient("service-llm")
public interface ServiceLLMClient {
@RequestMapping(method = RequestMethod.POST, value ="/text/v1/chat/completions")
public ResponseEntity<String> chat(@RequestBody OpenAiTextRequest content);
@RequestMapping(method = RequestMethod.GET, value ="/v1/models")
public HttpEntity<List<ModelsDto>> getAvailableModelList();
}
package com.coolook.llm.api.service;
import com.coolook.common.llm.dto.Message;
import com.coolook.common.llm.response.ResponseResult;
/**
* @author: WangYinuo
* @create: 2024-12-18:PM2:18
*/
public interface IAiService {
ResponseResult<Message> ask(Message msg) throws Exception;
ResponseResult<Message> webAsk(Message msg) throws Exception;
}
package com.coolook.llm.api.service.impl;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.coolook.common.llm.constant.AiStatus;
import com.coolook.common.llm.dto.Message;
import com.coolook.common.llm.dto.ModelsDto;
import com.coolook.common.llm.request.OpenAiTextRequest;
import com.coolook.common.llm.request.TextContent;
import com.coolook.common.llm.request.TextMessage;
import com.coolook.common.llm.response.ResponseResult;
import com.coolook.common.llm.utils.SecurityUtils;
import com.coolook.llm.api.remote.ServiceLLMClient;
import com.coolook.llm.api.service.IAiService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import lombok.extern.slf4j.Slf4j;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* @author: WangYinuo
* @create: 2024-12-18:PM2:19
*/
@Slf4j
@Service
public class AiServiceImpl implements IAiService {
@Autowired
private ServiceLLMClient serviceLlmClient;
@Value("${app.displacementDictionary}")
private String displacementDictionary;
@Override
public ResponseResult<Message> webAsk(Message msg) throws Exception {
String msgId = msg.getMsgId();
String key = SecurityUtils.displacementEncrypt(msgId, displacementDictionary);
String ivStr = "1234567890123456";
try {
String encryptStr = SecurityUtils.aesEncrypt(msg.getAiQuestion(), key, ivStr);
msg.setAiQuestion(ivStr + encryptStr);
log.info("msg:{}", msg);
Message aiMsg = ask(msg).getData();
String cipherText = aiMsg.getAiAnswer().substring(16);
String decryptStr = SecurityUtils.aesDecrypt(cipherText, key, ivStr);
aiMsg.setAiAnswer(decryptStr);
return ResponseResult.success(aiMsg);
} catch (Exception e) {
log.error("getWebTranslatedMsg error", e);
}
Message error = new Message();
error.setStatus(AiStatus.ERROR);
error.setMsgId(msgId);
return ResponseResult.success(error);
}
@Override
public ResponseResult<Message> ask(Message msg) {
String msgId = msg.getMsgId().replace("_forword", "");;
String msgUserId = msg.getUserId();
try {
String hexKey = SecurityUtils.displacementEncrypt(msgId, displacementDictionary);
String srcContent = msg.getAiQuestion();
log.info("srcContent:{}", srcContent);
String ivStr = srcContent.substring(0, 16);
String cipherText = srcContent.substring(16);
log.info(" cipherText: {},hexKey: {},ivStr:{}", cipherText, hexKey, ivStr);
String decryptStr = SecurityUtils.aesDecrypt(cipherText, hexKey, ivStr);
msg.setAiQuestion(decryptStr);
// String encryptStr = SecurityUtils.aesEncrypt("我收到了:" + decryptStr , hexKey, ivStr);
// msg.setAiAnswer(ivStr + encryptStr);
// msg.setStatus(AiStatus.SUCCESS);
// return BaseResponse.success(msg);
HttpEntity<List<ModelsDto>> availableModelEntity = serviceLlmClient.getAvailableModelList();
List<ModelsDto> textModelList = availableModelEntity.getBody();
OpenAiTextRequest openAiTextRequest = new OpenAiTextRequest();
openAiTextRequest.setModel(textModelList.get(0).getId());
List<TextMessage> messageList = new ArrayList();
messageList.add(new TextMessage("user", msg.getAiQuestion()));
openAiTextRequest.setMessages(messageList);
ResponseEntity<String> responseMsg = serviceLlmClient.chat(openAiTextRequest);
String content = parseResponseEntity(responseMsg.getBody());
log.info("responseMsg:{}", responseMsg);
if (responseMsg != null) {
Message aiMessage = new Message();
String aiAnswer = content;
String encryptStr = SecurityUtils.aesEncrypt(aiAnswer, hexKey, ivStr);
aiMessage.setAiAnswer(ivStr + encryptStr);
aiMessage.setStatus(AiStatus.SUCCESS);
aiMessage.setMsgId(msgId);
aiMessage.setUserId(msgUserId);
aiMessage.setAiSession(msg.getAiSession());
return ResponseResult.success(aiMessage);
}
} catch (Exception e) {
log.info("ask error:{}", e.toString());
}
Message failedMsg = new Message();
failedMsg.setStatus(AiStatus.ERROR);
failedMsg.setMsgId(msgId);
failedMsg.setUserId(msgUserId);
return ResponseResult.success(failedMsg);
}
public String parseResponseEntity(String responseBody) {
JSONObject jsonObject = JSONObject.parseObject(responseBody);
try {
if (jsonObject.containsKey("choices")) {
JSONArray choices = jsonObject.getJSONArray("choices");
for (int i = choices.size() - 1; i >= 0; i--) {
JSONObject obj = choices.getJSONObject(i);
if (obj.containsKey("message")) {
JSONObject message = obj.getJSONObject("message");
if (message.containsKey("role") && "assistant".equals(message.getString("role"))) {
if (message.containsKey("content")) {
return message.getString("content");
}
}
}
}
}
} catch (Exception e) {
log.error("parseResponseEntity error:{}", e.getMessage());
}
return null;
}
}
# 日志配置
logging:
level:
com.coolook: info
root: info
spring:
cloud:
nacos:
discovery:
server-addr: 129.150.53.251:8848
\ No newline at end of file
# 日志配置
logging:
level:
com.coolook: info
root: error
spring:
cloud:
nacos:
discovery:
server-addr: 158.178.244.87
\ No newline at end of file
# 日志配置
logging:
level:
com.coolook: info
root: info
spring:
cloud:
nacos:
discovery:
server-addr: localhost:8848
# 日志配置
logging:
level:
com.coolook: info
root: error
spring:
cloud:
nacos:
discovery:
server-addr: 132.145.115.85:8848
\ No newline at end of file
server:
port: 8900
servlet:
# 应用的访问路径
context-path: /ai-server
spring:
application:
name: llm-api
profiles:
active: local
app:
displacementDictionary: "aigmzp79Y6FOodkI4etj5XbfxGrRSHEZcAw0UDPn8LBhV1yqMuvKWsJlCN3T2Q"
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="10 seconds">
<!-- 日志级别从低到高分为TRACE < DEBUG < INFO < WARN < ERROR < FATAL,如果设置为WARN,则低于WARN的信息都不会输出 -->
<!-- scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true -->
<!-- scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。 -->
<!-- debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。 -->
<contextName>logback</contextName>
<property name="log.path" value="logs"></property>
<property name="Console_Pattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level [%logger{50}] - %msg%n"/>
<appender name="Console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<Pattern>${Console_Pattern}</Pattern>
<!-- 设置字符集 -->
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- 时间滚动输出 level为 INFO 日志 -->
<appender name="RollingFileInfo" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/info.log</file>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level [%logger{50}] - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 每天日志归档路径以及格式 -->
<fileNamePattern>${log.path}/info/log-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文件保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
<!-- 此日志文件只记录info级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>WARN</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 时间滚动输出 level为 WARN 日志 -->
<appender name="RollingFileWarn" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/warn.log</file>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level [%logger{50}] - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/warn/log-warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<maxHistory>15</maxHistory>
</rollingPolicy>
<!-- 此日志文件只记录warn级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>warn</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 时间滚动输出 level为 ERROR 日志 -->
<appender name="RollingFileError" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/error.log</file>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level [%logger{50}] - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/error/log-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文件保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
<!-- 此日志文件只记录ERROR级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!--additivity:是否继承root节点,默认是true继承。默认情况下子Logger会继承父Logger的appender,
也就是说子Logger会在父Logger的appender里输出。
若是additivity设为false,则子Logger只会在自己的appender里输出,而不会在父Logger的appender里输出。-->
<logger name="org.springframework" level="INFO" additivity="false">
<appender-ref ref="Console"/>
<appender-ref ref="RollingFileInfo"/>
</logger>
<logger name="org.mybatis" level="INFO"></logger>
<Logger name="org.apache.catalina" level="info"/>
<Logger name="org.apache.tomcat.util" level="info"/>
<!-- 从低到高为:All < Trace < Debug < Info < Warn < Error < Fatal < OFF-->
<root level="ALL">
<appender-ref ref="Console"/>
<appender-ref ref="RollingFileWarn"/>
<appender-ref ref="RollingFileError"/>
</root>
<!--生产环境:输出到文件-->
<springProfile name="pro">
<root level="INFO">
<appender-ref ref="Console"/>
<appender-ref ref="RollingFileInfo"/>
<appender-ref ref="RollingFileWarn"/>
<appender-ref ref="RollingFileError"/>
</root>
</springProfile>
</configuration>
\ No newline at end of file
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.coolook</groupId>
<artifactId>large-language-model</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>common-llm</artifactId>
<packaging>jar</packaging>
<name>common-llm</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
</project>
package com.coolook.common.llm.constant;
/**
* @author: WangYinuo
* @create: 2024-08-08:10:46
*/
public class AiStatus {
//操作成功
public static final int SUCCESS = 0;
//操作失败
public static final int ERROR = -1;
}
package com.coolook.common.llm.constant;
import lombok.Getter;
import lombok.Setter;
import org.springframework.stereotype.Service;
/**
* @author: WangYinuo
* @create: 2025-01-03:PM1:37
*/
public enum CommonStatusEnum {
SUCCESS("200", "success"),
FAIL("500", "fail");
@Getter
private String code;
@Getter
private String value;
CommonStatusEnum(String code, String value) {
this.code = code;
this.value = value;
}
}
package com.coolook.common.llm.constant;
/**
* @author: Wang Yinuo
* @create: 2025-02-21:PM2:18
*/
public class ModelConstant {
public static final String GET_MODEL_LIST_URI = "/api/tags";
public static final String MODEL_CHECK_URI = "/v1/chat/completions";
public static final int AVAILABLE = 1;
public static final int UNAVAILABLE = 0;
public static final int MODEL_TYPE_TEXT = 1;
public static final int MODEL_TYPE_IMAGE = 2;
public static final int MODEL_IS_ACTIVE = 1;
public static final int MODEL_IS_NOT_ACTIVE = -1;
public static final int MODEL_NOT_AVAILABLE = 0;
}
\ No newline at end of file
package com.coolook.common.llm.dto;
import lombok.Data;
/**
* @author: Wang Yinuo
* @create: 2025-03-14:PM2:44
*/
@Data
public class Choices {
private Message message;
private String logprobs;
private String finish_reason;
private Integer index;
}
package com.coolook.common.llm.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* @author: WangYinuo
* @create: 2024-08-05:19:01
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Message implements Serializable {
private String msgId;
private String userId;
private String aiSession;
//问题
private String aiQuestion;
//回答
private String aiAnswer;
//结果状态 0:成功 -1:失败
private Integer status;
}
package com.coolook.common.llm.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* @author: Wang Yinuo
* @create: 2025-02-21:AM11:04
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Models implements Serializable {
private Long id;
private String url;
private String model;
private int modelType;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") // 格式化 JSON 输出
@JsonSerialize(using = LocalDateTimeSerializer.class) // 自定义序列化
@JsonDeserialize(using = LocalDateTimeDeserializer.class) // 自定义反序列化
private LocalDateTime createAt;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") // 格式化 JSON 输出
@JsonSerialize(using = LocalDateTimeSerializer.class) // 自定义序列化
@JsonDeserialize(using = LocalDateTimeDeserializer.class) // 自定义反序列化
private LocalDateTime lastCheckedAt;
private int totalCount;
private int successCount;
private int failureCount;
private int consecutiveFailure;
private Long latestSpeed;
private int isActive;
}
package com.coolook.common.llm.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.Value;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* @author: Wang Yinuo
* @create: 2025-02-21:AM11:04
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ModelsDto implements Serializable {
private String id;
private String object = "model";
private Long created;
private String owned_by = "library";
}
package com.coolook.common.llm.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import lombok.Data;
import java.time.LocalDateTime;
/**
* @author: Wang Yinuo
* @create: 2025-02-24:PM12:00
*/
@Data
public class Url {
private Long id;
private String url;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") // 格式化 JSON 输出
@JsonSerialize(using = LocalDateTimeSerializer.class) // 自定义序列化
@JsonDeserialize(using = LocalDateTimeDeserializer.class) // 自定义反序列化
private LocalDateTime createAt;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") // 格式化 JSON 输出
@JsonSerialize(using = LocalDateTimeSerializer.class) // 自定义序列化
@JsonDeserialize(using = LocalDateTimeDeserializer.class) // 自定义反序列化
private LocalDateTime lastCheckedAt;
private int countryCode;
private String countryName;
private String region;
private String city;
private String longitude;
private String latitude;
private int consecutiveFailure;
private int isActive;
}
package com.coolook.common.llm.dto;
import lombok.Data;
/**
* @author: Wang Yinuo
* @create: 2025-03-14:PM2:42
*/
@Data
public class Usage {
private int prompt_tokens;
private int completion_tokens;
private int total_tokens;
}
package com.coolook.common.llm.request;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
/**
* @author: Wang Yinuo
* @create: 2025-03-03:PM4:11
*/
@Data
public class ImageContent {
public String type;
public String text;
@JsonProperty("image_url")
public ImageUrl imageUrl;
}
package com.coolook.common.llm.request;
import lombok.Data;
import java.util.List;
/**
* @author: Wang Yinuo
* @create: 2025-03-03:PM4:12
*/
@Data
public class ImageMessage {
public String role;
public List<ImageContent> content;
}
package com.coolook.common.llm.request;
import lombok.Data;
/**
* @author: Wang Yinuo
* @create: 2025-03-03:PM4:11
*/
@Data
public class ImageUrl {
public String url;
}
package com.coolook.common.llm.request;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* @author: Wang Yinuo
* @create: 2025-02-21:AM11:04
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ModelsRequest implements Serializable {
private Long id;
private String url;
private String model;
private int modelType;
private int totalCount;
private int successCount;
private int failureCount;
private int consecutiveFailure;
private Long latestSpeed;
private int isActive;
}
package com.coolook.common.llm.request;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.util.List;
/**
* @author: Wang Yinuo
* @create: 2025-03-03:PM3:20
*/
@Data
public class OpenAiImageRequest {
private String model;
private List<ImageMessage> messages;
private double temperature;
@JsonProperty("max_tokens")
private int maxTokens;
@JsonProperty("top_p")
private double topP;
@JsonProperty("frequency_penalty")
private double frequencyPenalty;
@JsonProperty("presence_penalty")
private double presencePenalty;
}
package com.coolook.common.llm.request;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
/**
* @author: Wang Yinuo
* @create: 2025-03-03:PM3:20
*/
@Data
public class OpenAiTextRequest implements Serializable {
private String model;
private List<TextMessage> messages;
}
package com.coolook.common.llm.request;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
/**
* @author: Wang Yinuo
* @create: 2025-03-03:PM4:11
*/
@Data
public class TextContent {
public String type;
public String text;
}
package com.coolook.common.llm.request;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* @author: Wang Yinuo
* @create: 2025-03-03:PM3:21
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class TextMessage {
private String role;
//private List<TextContent> content;
private String content;
}
package com.coolook.common.llm.request;
import lombok.Data;
/**
* @author: Wang Yinuo
* @create: 2025-02-24:PM12:00
*/
@Data
public class UrlRequest {
private Long id;
private String url;
private int countryCode;
private String countryName;
private String region;
private String city;
private String longitude;
private String latitude;
private int consecutiveFailure;
private int isActive;
}
package com.coolook.common.llm.response;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import java.time.LocalDateTime;
/**
* @author: Wang Yinuo
* @create: 2025-02-21:AM11:04
*/
public class ModelResponse {
private Long uid;
private String url;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") // 格式化 JSON 输出
@JsonSerialize(using = LocalDateTimeSerializer.class) // 自定义序列化
@JsonDeserialize(using = LocalDateTimeDeserializer.class) // 自定义反序列化
private LocalDateTime createAt;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") // 格式化 JSON 输出
@JsonSerialize(using = LocalDateTimeSerializer.class) // 自定义序列化
@JsonDeserialize(using = LocalDateTimeDeserializer.class) // 自定义反序列化
private LocalDateTime lastCheckedAt;
private int countryCode;
private String countryName;
private String region;
private String city;
private String longitude;
private String latitude;
private int consecutiveFailure;
private int isActive;
}
package com.coolook.common.llm.response;
import lombok.Data;
import java.util.List;
/**
* @author: Wang Yinuo
* @create: 2025-03-07:AM11:29
*/
@Data
public class PageResponse {
private Long totalPage;
private List<?> list;
}
package com.coolook.common.llm.response;
import com.coolook.common.llm.constant.CommonStatusEnum;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* @author: WangYinuo
* @create: 2025-01-03:PM1:39
*/
@Data
@Accessors(chain = true)
public class ResponseResult<T> {
private String code;
private String message;
private T data;
public static <T> ResponseResult<T> success() {
return new ResponseResult<T>().setCode(CommonStatusEnum.SUCCESS.getCode()).setMessage(CommonStatusEnum.SUCCESS.getValue());
}
public static <T> ResponseResult<T> success(T data) {
return new ResponseResult<T>().setCode(CommonStatusEnum.SUCCESS.getCode()).setMessage(CommonStatusEnum.SUCCESS.getValue()).setData(data);
}
public static <T> ResponseResult<T> fail(T data) {
return new ResponseResult<T>().setData(data);
}
public static <T> ResponseResult<T> fail(String code, String message) {
return new ResponseResult<T>().setCode(code).setMessage(message);
}
public static <T> ResponseResult<T> fail(String code,String message, T data) {
return new ResponseResult<T>().setCode(code).setMessage(message).setData(data);
}
}
package com.coolook.common.llm.response;
import com.coolook.common.llm.constant.CommonStatusEnum;
import com.coolook.common.llm.dto.Choices;
import com.coolook.common.llm.dto.Usage;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.List;
/**
* @author: WangYinuo
* @create: 2025-01-03:PM1:39
*/
@Data
public class ResponseStandardModel {
private String id;
private String object;
private Long created;
private String model;
private Usage usage;
private List<Choices> choices;
}
package com.coolook.common.llm.response;
import com.coolook.common.llm.dto.Choices;
import com.coolook.common.llm.dto.Usage;
import lombok.Data;
import java.util.List;
/**
* @author: WangYinuo
* @create: 2025-01-03:PM1:39
*/
@Data
public class ResponseStandardModelError {
private ErrorDetail error;
public ResponseStandardModelError(String message, String type, String param, String code) {
this.error = new ErrorDetail(message, type, param, code);
}
public ErrorDetail getError() {
return error;
}
public static class ErrorDetail {
private String message;
private String type;
private String param;
private String code;
public ErrorDetail(String message, String type, String param, String code) {
this.message = message;
this.type = type;
this.param = param;
this.code = code;
}
public String getMessage() {
return message;
}
public String getType() {
return type;
}
public String getParam() {
return param;
}
public String getCode() {
return code;
}
}
}
package com.coolook.common.llm.response;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import java.time.LocalDateTime;
/**
* @author: Wang Yinuo
* @create: 2025-02-21:AM11:04
*/
public class UrlResponse {
private Long uid;
private String url;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") // 格式化 JSON 输出
@JsonSerialize(using = LocalDateTimeSerializer.class) // 自定义序列化
@JsonDeserialize(using = LocalDateTimeDeserializer.class) // 自定义反序列化
private LocalDateTime createAt;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") // 格式化 JSON 输出
@JsonSerialize(using = LocalDateTimeSerializer.class) // 自定义序列化
@JsonDeserialize(using = LocalDateTimeDeserializer.class) // 自定义反序列化
private LocalDateTime lastCheckedAt;
private int countryCode;
private String countryName;
private String region;
private String city;
private String longitude;
private String latitude;
private int consecutiveFailure;
private int isActive;
}
package com.coolook.common.llm.utils;
/**
* @author: Wang Yinuo
* @create: 2025-02-25:PM5:04
*/
public class RedisUtil {
public static final String PREFIX = "llm:model:";
public static final String MODEL_FILTER = PREFIX + "*";
public static String getRedisKey(int modeType) {
return "llm:model:" + modeType + ":list";
}
}
package com.coolook.common.llm.utils;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import java.util.UUID;
/**
* @author: WangYinuo
* @create: 2024-08-06:15:00
*/
public class SecurityUtils {
public static String get32UUID() {
return UUID.randomUUID().toString().replace("-", "");
}
private static byte[] getMD5Bytes(String input) throws Exception {
MessageDigest md = MessageDigest.getInstance("MD5");
return md.digest(input.getBytes(StandardCharsets.UTF_8));
}
public static String getMD5Hash(String input) {
try {
// 获取MD5 MessageDigest实例
MessageDigest md = MessageDigest.getInstance("MD5");
// 将输入字符串转换为字节数组并更新消息摘要
byte[] messageDigest = md.digest(input.getBytes(StandardCharsets.UTF_8));
// 将字节数组转换为16进制字符串
BigInteger no = new BigInteger(1, messageDigest);
String hashText = no.toString(16);
// 填充0以确保结果为32位字符
while (hashText.length() < 32) {
hashText = "0" + hashText;
}
return hashText;
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
/**
* AES加密
*/
public static String aesEncrypt(String cipherText, String keyHex, String ivHex) throws Exception {
// 使用密钥和算法初始化密钥规范
SecretKeySpec keySpec = new SecretKeySpec(keyHex.getBytes(StandardCharsets.UTF_8), "AES");
// 初始化向量
IvParameterSpec ivSpec = new IvParameterSpec(ivHex.getBytes(StandardCharsets.UTF_8));
// 获取Cipher实例并初始化加密模式
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); // 注意PKCS#5Padding是PKCS#7Padding的Java实现
cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
// 执行加密
byte[] encryptedBytes = cipher.doFinal(cipherText.getBytes(StandardCharsets.UTF_8));
// 将加密后的字节数组转换为字符串
return Base64.getEncoder().encodeToString(encryptedBytes);
}
/**
* AES解密
*/
public static String aesDecrypt(String cipherText, String keyHex, String ivHex) throws Exception {
// 使用密钥和算法初始化密钥规范
SecretKeySpec keySpec = new SecretKeySpec(keyHex.getBytes(StandardCharsets.UTF_8), "AES");
// 初始化向量
IvParameterSpec ivSpec = new IvParameterSpec(ivHex.getBytes(StandardCharsets.UTF_8));
// 获取Cipher实例并初始化解密模式
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); // 注意PKCS#5Padding是PKCS#7Padding的Java实现
cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
// Base64解码密文
byte[] cipherBytes = Base64.getDecoder().decode(cipherText);
// 执行解密
byte[] decryptedBytes = cipher.doFinal(cipherBytes);
// 将解密后的字节数组转换为字符串
return new String(decryptedBytes, StandardCharsets.UTF_8);
}
/**
* 位移加密
*
* @param s
* @param STR_AZ
* @return
*/
public static String displacementEncrypt(String s, String STR_AZ) {
StringBuffer ss = new StringBuffer();
int k = s.length();//加密算法位移量
for (int i = 0; i < s.length(); i++) {
char tempi = s.charAt(i);
int index = 0;
for (int j = 0; j < STR_AZ.length(); j++) {
//大于最大位后,从初的A取。形成循环
if (tempi == STR_AZ.charAt(j)) {
index = j + k;
if (index / STR_AZ.length() >= 1) {
index = index % STR_AZ.length();
}
ss.append(STR_AZ.charAt(index));
}
}
k--;
}
return ss.toString();
}
public static String YdAESDecode(String encryptedText, String key, String iv) throws Exception {
byte[] keyBytes = getMD5Bytes(key);
byte[] ivBytes = getMD5Bytes(iv);
// 生成 AES 密钥
SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, "AES");
IvParameterSpec ivParameterSpec = new IvParameterSpec(ivBytes);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
encryptedText = encryptedText.replace("-", "+").replace("_", "/");
byte[] decodedBytes = Base64.getDecoder().decode(encryptedText);
byte[] decryptedBytes = cipher.doFinal(decodedBytes);
String decryptedText = new String(decryptedBytes, StandardCharsets.UTF_8);
return decryptedText;
}
public static String md5(String text, String charset) throws Exception {
if (charset == null || charset.length() == 0)
charset = "UTF-8";
byte[] bytes = text.getBytes(charset);
MessageDigest messageDigest = MessageDigest.getInstance("MD5");
messageDigest.update(bytes);
bytes = messageDigest.digest();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < bytes.length; i++) {
if ((bytes[i] & 0xff) < 0x10) {
sb.append("0");
}
sb.append(Long.toString(bytes[i] & 0xff, 16));
}
return sb.toString().toLowerCase();
}
}
2025-03-17 15:43:57.309 [http-nio-8900-exec-2] ERROR [com.coolook.llm.api.service.impl.AiServiceImpl] - getWebTranslatedMsg error
java.lang.NullPointerException: null
at com.coolook.llm.api.service.impl.AiServiceImpl.webAsk(AiServiceImpl.java:51)
at com.coolook.llm.api.controller.ModelApiController.webAsk(ModelApiController.java:39)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1067)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:681)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:764)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:540)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:382)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:895)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1722)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:750)
2025-03-17 15:47:26.344 [http-nio-8900-exec-4] ERROR [com.coolook.llm.api.service.impl.AiServiceImpl] - getWebTranslatedMsg error
java.lang.NullPointerException: null
at com.coolook.llm.api.service.impl.AiServiceImpl.webAsk(AiServiceImpl.java:51)
at com.coolook.llm.api.controller.ModelApiController.webAsk(ModelApiController.java:39)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1067)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:681)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:764)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:540)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:382)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:895)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1722)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:750)
2025-03-17 15:48:58.171 [http-nio-8900-exec-8] ERROR [com.coolook.llm.api.service.impl.AiServiceImpl] - getWebTranslatedMsg error
java.lang.NullPointerException: null
at com.coolook.llm.api.service.impl.AiServiceImpl.webAsk(AiServiceImpl.java:51)
at com.coolook.llm.api.controller.ModelApiController.webAsk(ModelApiController.java:39)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1067)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:681)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:764)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:540)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:382)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:895)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1722)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:750)
2025-03-17 15:50:07.601 [http-nio-8900-exec-1] ERROR [com.coolook.llm.api.service.impl.AiServiceImpl] - getWebTranslatedMsg error
java.lang.NullPointerException: null
at com.coolook.llm.api.service.impl.AiServiceImpl.webAsk(AiServiceImpl.java:51)
at com.coolook.llm.api.controller.ModelApiController.webAsk(ModelApiController.java:39)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1067)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:681)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:764)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:540)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:382)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:895)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1722)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:750)
2025-03-17 15:51:04.320 [http-nio-8900-exec-2] ERROR [com.coolook.llm.api.service.impl.AiServiceImpl] - getWebTranslatedMsg error
java.lang.NullPointerException: null
at com.coolook.llm.api.service.impl.AiServiceImpl.webAsk(AiServiceImpl.java:51)
at com.coolook.llm.api.controller.ModelApiController.webAsk(ModelApiController.java:39)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1067)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:681)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:764)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:540)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:382)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:895)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1722)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:750)
2025-03-17 15:51:59.252 [http-nio-8900-exec-5] ERROR [com.coolook.llm.api.service.impl.AiServiceImpl] - getWebTranslatedMsg error
java.lang.NullPointerException: null
at com.coolook.llm.api.service.impl.AiServiceImpl.webAsk(AiServiceImpl.java:51)
at com.coolook.llm.api.controller.ModelApiController.webAsk(ModelApiController.java:39)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1067)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:681)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:764)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:540)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:382)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:895)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1722)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:750)
2025-03-14 17:21:24.293 [http-nio-8900-exec-1] ERROR [com.coolook.llm.api.service.impl.AiServiceImpl] - getWebTranslatedMsg error
java.lang.NullPointerException: null
at com.coolook.llm.api.service.impl.AiServiceImpl.webAsk(AiServiceImpl.java:50)
at com.coolook.llm.api.controller.ModelApiController.webAsk(ModelApiController.java:39)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1067)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:681)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:764)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:540)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:382)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:895)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1722)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:750)
2025-03-14 17:22:44.526 [http-nio-8900-exec-5] ERROR [com.coolook.llm.api.service.impl.AiServiceImpl] - getWebTranslatedMsg error
java.lang.NullPointerException: null
at com.coolook.llm.api.service.impl.AiServiceImpl.webAsk(AiServiceImpl.java:50)
at com.coolook.llm.api.controller.ModelApiController.webAsk(ModelApiController.java:39)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1067)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:681)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:764)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:540)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:382)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:895)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1722)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:750)
2025-03-17 15:42:47.566 [main] WARN [o.s.c.l.c.LoadBalancerCacheAutoConfiguration$LoadBalancerCaffeineWarnLogger] - Spring Cloud LoadBalancer is currently working with the default cache. You can switch to using Caffeine cache, by adding it and org.springframework.cache.caffeine.CaffeineCacheManager to the classpath.
2025-03-17 15:43:57.200 [http-nio-8900-exec-2] WARN [o.s.c.l.core.ServiceInstanceListSupplierBuilder] - LoadBalancerCacheManager not available, returning delegate without caching.
2025-03-17 15:51:59.248 [boundedElastic-4] WARN [o.s.cloud.loadbalancer.core.RoundRobinLoadBalancer] - No servers available for service: service-llm
2025-03-17 15:51:59.249 [http-nio-8900-exec-5] WARN [o.s.c.o.l.FeignBlockingLoadBalancerClient] - Load balancer does not contain an instance for the service service-llm
2025-03-07 15:25:54.274 [main] WARN [o.s.c.l.c.LoadBalancerCacheAutoConfiguration$LoadBalancerCaffeineWarnLogger] - Spring Cloud LoadBalancer is currently working with the default cache. You can switch to using Caffeine cache, by adding it and org.springframework.cache.caffeine.CaffeineCacheManager to the classpath.
2025-03-07 15:31:48.737 [SpringContextShutdownHook] WARN [o.s.beans.factory.support.DisposableBeanAdapter] - Custom destroy method 'close' on bean with name 'nacosServiceRegistry' threw an exception: java.lang.NullPointerException
2025-03-07 15:31:51.034 [main] WARN [o.s.c.l.c.LoadBalancerCacheAutoConfiguration$LoadBalancerCaffeineWarnLogger] - Spring Cloud LoadBalancer is currently working with the default cache. You can switch to using Caffeine cache, by adding it and org.springframework.cache.caffeine.CaffeineCacheManager to the classpath.
2025-03-07 15:33:15.232 [SpringContextShutdownHook] WARN [o.s.beans.factory.support.DisposableBeanAdapter] - Custom destroy method 'close' on bean with name 'nacosServiceRegistry' threw an exception: java.lang.NullPointerException
2025-03-07 15:33:16.750 [main] WARN [o.s.c.l.c.LoadBalancerCacheAutoConfiguration$LoadBalancerCaffeineWarnLogger] - Spring Cloud LoadBalancer is currently working with the default cache. You can switch to using Caffeine cache, by adding it and org.springframework.cache.caffeine.CaffeineCacheManager to the classpath.
2025-03-07 15:36:11.048 [SpringContextShutdownHook] WARN [o.s.beans.factory.support.DisposableBeanAdapter] - Custom destroy method 'close' on bean with name 'nacosServiceRegistry' threw an exception: java.lang.NullPointerException
2025-03-07 15:36:13.488 [main] WARN [o.s.c.l.c.LoadBalancerCacheAutoConfiguration$LoadBalancerCaffeineWarnLogger] - Spring Cloud LoadBalancer is currently working with the default cache. You can switch to using Caffeine cache, by adding it and org.springframework.cache.caffeine.CaffeineCacheManager to the classpath.
2025-03-07 15:36:22.389 [http-nio-9009-exec-1] WARN [o.s.c.l.core.ServiceInstanceListSupplierBuilder] - LoadBalancerCacheManager not available, returning delegate without caching.
2025-03-07 16:02:57.121 [SpringContextShutdownHook] WARN [o.s.beans.factory.support.DisposableBeanAdapter] - Custom destroy method 'close' on bean with name 'nacosServiceRegistry' threw an exception: java.lang.NullPointerException
2025-03-07 18:10:00.823 [main] WARN [o.s.c.l.c.LoadBalancerCacheAutoConfiguration$LoadBalancerCaffeineWarnLogger] - Spring Cloud LoadBalancer is currently working with the default cache. You can switch to using Caffeine cache, by adding it and org.springframework.cache.caffeine.CaffeineCacheManager to the classpath.
2025-03-07 18:10:12.164 [SpringContextShutdownHook] WARN [o.s.beans.factory.support.DisposableBeanAdapter] - Custom destroy method 'close' on bean with name 'nacosServiceRegistry' threw an exception: java.lang.NullPointerException
2025-03-13 16:54:04.606 [main] WARN [o.s.c.l.c.LoadBalancerCacheAutoConfiguration$LoadBalancerCaffeineWarnLogger] - Spring Cloud LoadBalancer is currently working with the default cache. You can switch to using Caffeine cache, by adding it and org.springframework.cache.caffeine.CaffeineCacheManager to the classpath.
2025-03-13 16:54:32.365 [http-nio-8900-exec-2] WARN [o.s.c.l.core.ServiceInstanceListSupplierBuilder] - LoadBalancerCacheManager not available, returning delegate without caching.
2025-03-13 17:02:59.692 [SpringContextShutdownHook] WARN [o.s.beans.factory.support.DisposableBeanAdapter] - Custom destroy method 'close' on bean with name 'nacosServiceRegistry' threw an exception: java.lang.NullPointerException
2025-03-14 17:21:05.535 [main] WARN [o.s.c.l.c.LoadBalancerCacheAutoConfiguration$LoadBalancerCaffeineWarnLogger] - Spring Cloud LoadBalancer is currently working with the default cache. You can switch to using Caffeine cache, by adding it and org.springframework.cache.caffeine.CaffeineCacheManager to the classpath.
2025-03-14 17:21:14.235 [http-nio-8900-exec-1] WARN [o.s.c.l.core.ServiceInstanceListSupplierBuilder] - LoadBalancerCacheManager not available, returning delegate without caching.
2025-03-14 17:33:17.941 [SpringContextShutdownHook] WARN [o.s.beans.factory.support.DisposableBeanAdapter] - Custom destroy method 'close' on bean with name 'nacosServiceRegistry' threw an exception: java.lang.NullPointerException
2025-03-14 17:33:19.619 [main] WARN [o.s.c.l.c.LoadBalancerCacheAutoConfiguration$LoadBalancerCaffeineWarnLogger] - Spring Cloud LoadBalancer is currently working with the default cache. You can switch to using Caffeine cache, by adding it and org.springframework.cache.caffeine.CaffeineCacheManager to the classpath.
2025-03-14 19:03:48.641 [SpringContextShutdownHook] WARN [o.s.beans.factory.support.DisposableBeanAdapter] - Custom destroy method 'close' on bean with name 'nacosServiceRegistry' threw an exception: java.lang.NullPointerException
2025-03-14 19:03:50.434 [main] WARN [o.s.c.l.c.LoadBalancerCacheAutoConfiguration$LoadBalancerCaffeineWarnLogger] - Spring Cloud LoadBalancer is currently working with the default cache. You can switch to using Caffeine cache, by adding it and org.springframework.cache.caffeine.CaffeineCacheManager to the classpath.
2025-03-14 20:02:36.330 [SpringContextShutdownHook] WARN [o.s.beans.factory.support.DisposableBeanAdapter] - Custom destroy method 'close' on bean with name 'nacosServiceRegistry' threw an exception: java.lang.NullPointerException
2025-03-14 17:33:11.576 [Thread-10] WARN [com.alibaba.nacos.common.notify.NotifyCenter] - [NotifyCenter] Start destroying Publisher
2025-03-14 17:33:11.576 [Thread-4] WARN [com.alibaba.nacos.common.http.HttpClientBeanHolder] - [HttpClientBeanHolder] Start destroying common HttpClient
2025-03-14 17:33:11.576 [Thread-10] WARN [com.alibaba.nacos.common.notify.NotifyCenter] - [NotifyCenter] Destruction of the end
2025-03-14 17:33:11.576 [Thread-4] WARN [com.alibaba.nacos.common.http.HttpClientBeanHolder] - [HttpClientBeanHolder] Destruction of the end
2025-03-14 19:03:40.857 [Thread-10] WARN [com.alibaba.nacos.common.notify.NotifyCenter] - [NotifyCenter] Start destroying Publisher
2025-03-14 19:03:40.857 [Thread-4] WARN [com.alibaba.nacos.common.http.HttpClientBeanHolder] - [HttpClientBeanHolder] Start destroying common HttpClient
2025-03-14 19:03:40.857 [Thread-10] WARN [com.alibaba.nacos.common.notify.NotifyCenter] - [NotifyCenter] Destruction of the end
2025-03-14 19:03:40.857 [Thread-4] WARN [com.alibaba.nacos.common.http.HttpClientBeanHolder] - [HttpClientBeanHolder] Destruction of the end
2025-03-14 20:02:26.260 [Thread-10] WARN [com.alibaba.nacos.common.notify.NotifyCenter] - [NotifyCenter] Start destroying Publisher
2025-03-14 20:02:26.260 [Thread-4] WARN [com.alibaba.nacos.common.http.HttpClientBeanHolder] - [HttpClientBeanHolder] Start destroying common HttpClient
2025-03-14 20:02:26.260 [Thread-10] WARN [com.alibaba.nacos.common.notify.NotifyCenter] - [NotifyCenter] Destruction of the end
2025-03-14 20:02:26.260 [Thread-4] WARN [com.alibaba.nacos.common.http.HttpClientBeanHolder] - [HttpClientBeanHolder] Destruction of the end
2025-03-07 15:31:39.196 [Thread-10] WARN [com.alibaba.nacos.common.notify.NotifyCenter] - [NotifyCenter] Start destroying Publisher
2025-03-07 15:31:39.196 [Thread-4] WARN [com.alibaba.nacos.common.http.HttpClientBeanHolder] - [HttpClientBeanHolder] Start destroying common HttpClient
2025-03-07 15:31:39.196 [Thread-10] WARN [com.alibaba.nacos.common.notify.NotifyCenter] - [NotifyCenter] Destruction of the end
2025-03-07 15:31:39.197 [Thread-4] WARN [com.alibaba.nacos.common.http.HttpClientBeanHolder] - [HttpClientBeanHolder] Destruction of the end
2025-03-07 15:33:09.893 [Thread-10] WARN [com.alibaba.nacos.common.notify.NotifyCenter] - [NotifyCenter] Start destroying Publisher
2025-03-07 15:33:09.893 [Thread-4] WARN [com.alibaba.nacos.common.http.HttpClientBeanHolder] - [HttpClientBeanHolder] Start destroying common HttpClient
2025-03-07 15:33:09.893 [Thread-10] WARN [com.alibaba.nacos.common.notify.NotifyCenter] - [NotifyCenter] Destruction of the end
2025-03-07 15:33:09.893 [Thread-4] WARN [com.alibaba.nacos.common.http.HttpClientBeanHolder] - [HttpClientBeanHolder] Destruction of the end
2025-03-07 15:36:02.388 [Thread-10] WARN [com.alibaba.nacos.common.notify.NotifyCenter] - [NotifyCenter] Start destroying Publisher
2025-03-07 15:36:02.388 [Thread-4] WARN [com.alibaba.nacos.common.http.HttpClientBeanHolder] - [HttpClientBeanHolder] Start destroying common HttpClient
2025-03-07 15:36:02.388 [Thread-10] WARN [com.alibaba.nacos.common.notify.NotifyCenter] - [NotifyCenter] Destruction of the end
2025-03-07 15:36:02.388 [Thread-4] WARN [com.alibaba.nacos.common.http.HttpClientBeanHolder] - [HttpClientBeanHolder] Destruction of the end
2025-03-07 16:02:50.667 [Thread-10] WARN [com.alibaba.nacos.common.notify.NotifyCenter] - [NotifyCenter] Start destroying Publisher
2025-03-07 16:02:50.667 [Thread-4] WARN [com.alibaba.nacos.common.http.HttpClientBeanHolder] - [HttpClientBeanHolder] Start destroying common HttpClient
2025-03-07 16:02:50.668 [Thread-10] WARN [com.alibaba.nacos.common.notify.NotifyCenter] - [NotifyCenter] Destruction of the end
2025-03-07 16:02:50.668 [Thread-4] WARN [com.alibaba.nacos.common.http.HttpClientBeanHolder] - [HttpClientBeanHolder] Destruction of the end
2025-03-07 18:10:05.024 [Thread-10] WARN [com.alibaba.nacos.common.notify.NotifyCenter] - [NotifyCenter] Start destroying Publisher
2025-03-07 18:10:05.024 [Thread-4] WARN [com.alibaba.nacos.common.http.HttpClientBeanHolder] - [HttpClientBeanHolder] Start destroying common HttpClient
2025-03-07 18:10:05.025 [Thread-10] WARN [com.alibaba.nacos.common.notify.NotifyCenter] - [NotifyCenter] Destruction of the end
2025-03-07 18:10:05.025 [Thread-4] WARN [com.alibaba.nacos.common.http.HttpClientBeanHolder] - [HttpClientBeanHolder] Destruction of the end
2025-03-13 17:02:51.770 [Thread-13] WARN [com.alibaba.nacos.common.notify.NotifyCenter] - [NotifyCenter] Start destroying Publisher
2025-03-13 17:02:51.769 [Thread-7] WARN [com.alibaba.nacos.common.http.HttpClientBeanHolder] - [HttpClientBeanHolder] Start destroying common HttpClient
2025-03-13 17:02:51.771 [Thread-13] WARN [com.alibaba.nacos.common.notify.NotifyCenter] - [NotifyCenter] Destruction of the end
2025-03-13 17:02:51.771 [Thread-7] WARN [com.alibaba.nacos.common.http.HttpClientBeanHolder] - [HttpClientBeanHolder] Destruction of the end
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.13</version>
</parent>
<groupId>com.coolook</groupId>
<artifactId>large-language-model</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<name>large-language-model</name>
<modules>
<module>common-llm</module>
<module>api-llm</module>
<module>service-llm</module>
</modules>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring.version>2.4.13</spring.version>
<druid.version>1.2.2</druid.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2021.1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>2020.0.1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
<version>2.0.31</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
</dependency>
</dependencies>
</project>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.coolook</groupId>
<artifactId>large-language-model</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>service-llm</artifactId>
<packaging>jar</packaging>
<name>service-llm</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>com.coolook</groupId>
<artifactId>common-llm</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.3.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>${druid.version}</version>
</dependency>
</dependencies>
<build>
<finalName>${name}</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring.version}</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
package com.coolook.service.llm;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
/**
* @author: Wang Yinuo
* @create: 2025-02-21:AM11:23
*/
@SpringBootApplication
@MapperScan("com.coolook.service.llm.mapper")
public class ServiceLlmApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceLlmApplication.class, args);
}
@Bean
public RestTemplate getRestTemplate() {
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
factory.setConnectTimeout(10000);
factory.setReadTimeout(30000);
return new RestTemplate(factory);
}
}
package com.coolook.service.llm.config;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.util.ContentCachingResponseWrapper;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @author: Wang Yinuo
* @create: 2025-03-14:PM10:31
*/
public class AddContentLengthFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
ContentCachingResponseWrapper cacheResponseWrapper;
if (!(response instanceof ContentCachingResponseWrapper)) {
cacheResponseWrapper = new ContentCachingResponseWrapper(response);
} else {
cacheResponseWrapper = (ContentCachingResponseWrapper) response;
}
filterChain.doFilter(request, cacheResponseWrapper);
cacheResponseWrapper.copyBodyToResponse();
}
}
package com.coolook.service.llm.config;
import com.google.common.collect.Lists;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.List;
/**
* @author: Wang Yinuo
* @create: 2025-03-14:PM10:31
*/
@Configuration
public class FilterConfig {
/**
* 给特定接口加content-length返回
* @return FilterRegistrationBean
*/
@Bean
public FilterRegistrationBean contentLengthFilterRegistrationBean() {
FilterRegistrationBean filterBean = new FilterRegistrationBean();
filterBean.setFilter(new AddContentLengthFilter());
filterBean.setFilter(new RemoveKeepAliveHeaderFilter());
filterBean.addUrlPatterns("/"); // Apply to all URLs
List<String> urls = Lists.newArrayList();
// 只针对指定接口类型返回content-length
urls.add("/app/clientApi");
filterBean.setUrlPatterns(urls);
return filterBean;
}
}
package com.coolook.service.llm.config;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
/**
* @author: Wang Yinuo
* @create: 2025-02-26:AM11:19
*/
// 反序列化
public class LocalDateTimeDeserializer extends JsonDeserializer<LocalDateTime> {
private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
@Override
public LocalDateTime deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
return LocalDateTime.parse(p.getText(), formatter);
}
}
package com.coolook.service.llm.config;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
/**
* @author: Wang Yinuo
* @create: 2025-02-26:AM11:18
*/
public class LocalDateTimeSerializer extends JsonSerializer<LocalDateTime> {
private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
@Override
public void serialize(LocalDateTime value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
gen.writeString(value.format(formatter));
}
}
package com.coolook.service.llm.config;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author: Wang Yinuo
* @create: 2025-02-25:PM5:40
*/
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor();
paginationInnerInterceptor.setDbType(DbType.MYSQL);
interceptor.addInnerInterceptor(paginationInnerInterceptor);
return interceptor;
}
}
package com.coolook.service.llm.config;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
/**
* @author: Wang Yinuo
* @create: 2025-02-25:PM6:22
*/
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(connectionFactory);
// 使用 Jackson2JsonRedisSerializer 序列化值
Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(Object.class);
redisTemplate.setValueSerializer(serializer);
// 设置键的序列化方式为字符串
redisTemplate.setKeySerializer(redisTemplate.getStringSerializer());
return redisTemplate;
}
}
package com.coolook.service.llm.config;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @author: Wang Yinuo
* @create: 2025-03-17:AM11:33
*/
@WebFilter("/*") // This will apply to all requests
public class RemoveKeepAliveHeaderFilter implements Filter {
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
// Remove Keep-Alive and Connection headers
httpServletResponse.setHeader("Connection", "close");
httpServletResponse.setHeader("Keep-Alive", "timeout=0");
chain.doFilter(request, response);
}
@Override
public void destroy() {
}
}
\ No newline at end of file
package com.coolook.service.llm.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;
/**
* @author: Wang Yinuo
* @create: 2025-03-05:AM10:33
*/
@Component
@ConfigurationProperties(prefix = "search.config")
@RefreshScope // 允许动态刷新
public class SearchConfig {
@Value("${search.config.value}")
private Boolean value;
public Boolean getValue() { return value; }
public void setValue(Boolean value) { this.value = value; }
}
package com.coolook.service.llm.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.List;
/**
* @author: Wang Yinuo
* @create: 2025-03-14:PM6:14
*/
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Bean
public HttpMessageConverter<?> responseBodyConverter() {
// 通过 MappingJackson2HttpMessageConverter 自定义消息转换器
return new MappingJackson2HttpMessageConverter();
}
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
// 清除默认的消息转换器,并添加自定义的消息转换器
converters.clear();
converters.add(responseBodyConverter());
}
}
package com.coolook.service.llm.controller;
import com.coolook.common.llm.dto.ModelsDto;
import com.coolook.common.llm.response.ResponseResult;
import com.coolook.common.llm.request.ModelsRequest;
import com.coolook.common.llm.request.OpenAiImageRequest;
import com.coolook.common.llm.request.OpenAiTextRequest;
import com.coolook.service.llm.service.ModelService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* @author: Wang Yinuo
* @create: 2025-02-21:AM11:30
*/
@Slf4j
@RestController
public class CustomModelController {
@Autowired
private ModelService llmService;
@GetMapping("/v1/models")
public HttpEntity<List<ModelsDto>> getAvailableModelList() {
HttpEntity<List<ModelsDto>> textModelList = llmService.getTextModelList();
// ResponseResult<List<String>> pictureModelList = llmService.getPictureModelList();
return textModelList;
}
@PostMapping("/text/v1/chat/completions")
public ResponseEntity<?> chat(@RequestBody OpenAiTextRequest content) throws JsonProcessingException {
ResponseEntity<?> chat = llmService.chat(content);
ObjectMapper objectMapper = new ObjectMapper();
byte[] responseBytes = objectMapper.writeValueAsBytes(chat.getBody());
HttpHeaders headers = new HttpHeaders();
headers.setContentLength(responseBytes.length);
return ResponseEntity.ok()
.headers(headers)
.body(chat.getBody());
}
@PostMapping("/image/v1/chat/completions")
public ResponseEntity<?> picture(@RequestBody OpenAiImageRequest content) {
return llmService.picture(content);
}
@PostMapping("/add-model")
public ResponseResult addModel(@RequestBody ModelsRequest[] content) {
return llmService.addModel(content);
}
}
\ No newline at end of file
package com.coolook.service.llm.controller;
import com.coolook.common.llm.response.ResponseResult;
import com.coolook.common.llm.request.ModelsRequest;
import com.coolook.common.llm.request.UrlRequest;
import com.coolook.service.llm.service.ModelDataService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* @author: Wang Yinuo
* @create: 2025-03-06:PM2:54
*/
@RestController
@Slf4j
public class DataSyncController {
@Autowired
private ModelDataService modelDataService;
@GetMapping("/get-url-list/{pageNum}")
public ResponseResult getUrlList(@PathVariable("pageNum")int pageNum) {
return modelDataService.getUrlList(pageNum);
}
@GetMapping("/get-model-list/{pageNum}")
public ResponseResult getModelList(@PathVariable("pageNum")int pageNum) {
return modelDataService.getModelList(pageNum);
}
@PostMapping("/update-model")
public ResponseResult updateModel(@RequestBody List<ModelsRequest> modelsRequestList) {
log.info("updateModel: {}", modelsRequestList);
return modelDataService.saveOrUpdateModels(modelsRequestList);
}
@PostMapping("/update-url")
public ResponseResult updateUrl(@RequestBody List<UrlRequest> urlRequestList) {
log.info("updateUrl: {}", urlRequestList);
return modelDataService.saveOrUpdateUrl(urlRequestList);
}
}
package com.coolook.service.llm.controller;
import com.coolook.common.llm.response.ResponseResult;
import com.coolook.service.llm.service.SearchConfigService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
/**
* @author: Wang Yinuo
* @create: 2025-03-05:AM10:37
*/
@RestController
public class SearchConfigController {
@Autowired
private SearchConfigService searchConfigService;
@GetMapping("/get-search-config")
public ResponseResult getSearchConfig() {
return searchConfigService.getSearchConfig();
}
@GetMapping("/set-search-config/{value}")
public ResponseResult setSearchConfig(@PathVariable("value") Boolean value) {
return searchConfigService.setSearchConfig(value);
}
}
package com.coolook.service.llm.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.coolook.common.llm.dto.Models;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
/**
* @author: Wang Yinuo
* @create: 2025-02-21:PM4:46
*/
@Mapper
public interface ModelMapper extends BaseMapper<Models> {
int insertModelList(List<Models> modelList);
}
package com.coolook.service.llm.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.coolook.common.llm.dto.Url;
import org.apache.ibatis.annotations.Mapper;
/**
* @author: Wang Yinuo
* @create: 2025-03-06:PM3:49
*/
@Mapper
public interface UrlMapper extends BaseMapper<Url> {
}
package com.coolook.service.llm.remote;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.coolook.common.llm.constant.ModelConstant;
import com.coolook.common.llm.dto.Models;
import com.coolook.common.llm.request.*;
import com.coolook.common.llm.response.ResponseStandardModelError;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author: Wang Yinuo
* @create: 2025-02-21:PM2:37
*/
@Service
@Slf4j
public class LLMClient {
@Autowired
private RestTemplate restTemplate;
public Models checkModelAvailable(Models model) {
Models checkedModel = new Models();
checkedModel.setUrl(model.getUrl());
checkedModel.setModel(model.getModel());
checkedModel.setModelType(model.getModelType());
checkedModel.setCreateAt(model.getCreateAt());
checkedModel.setLastCheckedAt(LocalDateTime.now());
try {
StringBuilder sb = new StringBuilder();
sb.append(model.getUrl());
// 设置请求头
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
// 构造请求体
Map<String, Object> requestBody = new HashMap<>();
requestBody.put("model", model.getModel());
List<Map<String, String>> messages = new ArrayList<>();
Map<String, String> userMessage = new HashMap<>();
userMessage.put("role", "user");
userMessage.put("content", "say this is a test");
messages.add(userMessage);
requestBody.put("messages", messages);
// 使用 Jackson 序列化
ObjectMapper objectMapper = new ObjectMapper();
String jsonBody = objectMapper.writeValueAsString(requestBody);
// 创建 HttpEntity
HttpEntity<String> requestEntity = new HttpEntity<>(jsonBody, headers);
long start = System.currentTimeMillis();
ResponseEntity<String> response = restTemplate.postForEntity(sb.toString(), requestEntity, String.class);
long end = System.currentTimeMillis();
if (response.getStatusCode() == HttpStatus.OK) {
checkedModel.setIsActive(ModelConstant.MODEL_IS_ACTIVE);
checkedModel.setLatestSpeed(end - start);
checkedModel.setSuccessCount(model.getSuccessCount() + 1);
checkedModel.setTotalCount(model.getTotalCount() + 1);
checkedModel.setFailureCount(model.getFailureCount());
checkedModel.setConsecutiveFailure(model.getConsecutiveFailure());
}
return checkedModel;
} catch (Exception e) {
log.info("model error:{}, {}", e.getMessage(), model);
}
checkedModel.setIsActive(ModelConstant.MODEL_IS_NOT_ACTIVE);
checkedModel.setLatestSpeed(0L);
checkedModel.setSuccessCount(model.getSuccessCount());
checkedModel.setTotalCount(model.getTotalCount() + 1);
checkedModel.setFailureCount(model.getFailureCount() + 1);
checkedModel.setConsecutiveFailure(model.getConsecutiveFailure());
return checkedModel;
}
public ResponseEntity<Map<String, Object>> chat(Models model, OpenAiTextRequest content) {
try {
StringBuilder sb = new StringBuilder();
sb.append(model.getUrl());
// 设置请求头
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
// 构造请求体
Map<String, Object> requestBody = new HashMap<>();
requestBody.put("model", model.getModel());
List<Map<String, Object>> messages = new ArrayList<>();
for (TextMessage message : content.getMessages()) {
Map<String, Object> messageMap = new HashMap<>();
messageMap.put("role", message.getRole());
//为实现标准协议
// List<TextContent> contentList = message.getContent();
// messageMap.put("content", contentList);
messageMap.put("content", message.getContent());
messages.add(messageMap);
}
requestBody.put("messages", messages);
// 使用 Jackson 序列化
ObjectMapper objectMapper = new ObjectMapper();
String jsonBody = objectMapper.writeValueAsString(requestBody);
// 创建 HttpEntity
HttpEntity<String> requestEntity = new HttpEntity<>(jsonBody, headers);
ResponseEntity<String> response = restTemplate.postForEntity(sb.toString(), requestEntity, String.class);
log.info("body:{}", response.getBody());
// String responseContent = parseResponseEntity(response.getBody());
// log.info("resp:{}", responseContent);
// return ResponseResult.success(responseContent);
Map<String, Object> responseBody = objectMapper.readValue(response.getBody(), new TypeReference<Map<String, Object>>() {});
return ResponseEntity.ok(responseBody);
// return ResponseEntity.ok(response.getBody());
} catch (Exception e) {
Map<String, Object> errorResponse = new HashMap<>();
errorResponse.put("error", "Exception");
errorResponse.put("message", e.getMessage());
errorResponse.put("status", 500);
errorResponse.put("model", content.getModel());
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorResponse);
}
}
public ResponseEntity picture(Models model, OpenAiImageRequest request) {
try {
StringBuilder sb = new StringBuilder();
sb.append(model.getUrl());
// 设置请求头
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
// 构造请求体
Map<String, Object> requestBody = new HashMap<>();
requestBody.put("model", request.getModel());
requestBody.put("temperature", request.getTemperature());
requestBody.put("max_tokens", request.getMaxTokens());
requestBody.put("top_p", request.getTopP());
requestBody.put("frequency_penalty", request.getFrequencyPenalty());
requestBody.put("presence_penalty", request.getPresencePenalty());
// 将 "messages" 添加到请求体中
List<Map<String, Object>> messages = new ArrayList<>();
for (ImageMessage msg : request.getMessages()) {
Map<String, Object> messageMap = new HashMap<>();
messageMap.put("role", msg.role);
List<Map<String, Object>> contentList = new ArrayList<>();
for (ImageContent content : msg.content) {
Map<String, Object> contentMap = new HashMap<>();
contentMap.put("type", content.type);
if ("text".equals(content.type)) {
contentMap.put("text", content.text);
} else if ("image_url".equals(content.type) && content.imageUrl != null) {
Map<String, String> imageUrlMap = new HashMap<>();
imageUrlMap.put("url", content.imageUrl.url);
contentMap.put("image_url", imageUrlMap);
}
contentList.add(contentMap);
}
messageMap.put("content", contentList);
messages.add(messageMap);
}
requestBody.put("messages", messages);
// 使用 Jackson 序列化
ObjectMapper objectMapper = new ObjectMapper();
String jsonBody = objectMapper.writeValueAsString(requestBody);
// 创建 HttpEntity
HttpEntity<String> requestEntity = new HttpEntity<>(jsonBody, headers);
ResponseEntity<String> response = restTemplate.postForEntity(sb.toString(), requestEntity, String.class);
// return ResponseResult.success(response);
return ResponseEntity.ok(response.getBody());
} catch (Exception e) {
ResponseStandardModelError error = new ResponseStandardModelError(
e.getMessage(),
"Exception",
request.getModel(),
"500"
);
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(error);
}
}
public String parseResponseEntity(String responseBody) {
JSONObject jsonObject = JSONObject.parseObject(responseBody);
try {
if (jsonObject.containsKey("choices")) {
JSONArray choices = jsonObject.getJSONArray("choices");
for (int i = choices.size() - 1; i >= 0; i--) {
JSONObject obj = choices.getJSONObject(i);
if (obj.containsKey("message")) {
JSONObject message = obj.getJSONObject("message");
if (message.containsKey("role") && "assistant".equals(message.getString("role"))) {
if (message.containsKey("content")) {
return message.getString("content");
}
}
}
}
}
} catch (Exception e) {
log.error("parseResponseEntity error:{}", e.getMessage());
}
return null;
}
}
package com.coolook.service.llm.service;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.coolook.common.llm.constant.ModelConstant;
import com.coolook.common.llm.dto.Models;
import com.coolook.common.llm.dto.Url;
import com.coolook.common.llm.utils.RedisUtil;
import com.coolook.service.llm.mapper.ModelMapper;
import com.coolook.service.llm.remote.LLMClient;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import org.springframework.core.task.TaskExecutor;
/**
* @author: WangYinuo
* @create: 2024-11-04:14:42
*/
@Slf4j
@Service
@EnableScheduling
public class InitializerService {
@Autowired
private ModelMapper modelMapper;
@Autowired
private RedisTemplate redisTemplate;
@Autowired
private LLMClient llmClient;
@Autowired
private TaskExecutor taskExecutor;
public void syncRedis() {
QueryWrapper<Models> textModelQueryWrapper = new QueryWrapper<Models>();
textModelQueryWrapper.eq("is_active", ModelConstant.MODEL_IS_ACTIVE);
textModelQueryWrapper.eq("model_type", ModelConstant.MODEL_TYPE_TEXT);
textModelQueryWrapper.orderByAsc("latest_speed");
textModelQueryWrapper.orderByDesc("last_checked_at");
textModelQueryWrapper.last("LIMIT 500");
List<Models> textModelList = modelMapper.selectList(textModelQueryWrapper);
QueryWrapper<Models> picModelQueryWrapper = new QueryWrapper<Models>();
picModelQueryWrapper.eq("is_active", ModelConstant.MODEL_IS_ACTIVE);
picModelQueryWrapper.eq("model_type", ModelConstant.MODEL_TYPE_IMAGE);
picModelQueryWrapper.orderByAsc("latest_speed");
picModelQueryWrapper.orderByDesc("last_checked_at");
picModelQueryWrapper.last("LIMIT 20");
List<Models> pictureModelList = modelMapper.selectList(picModelQueryWrapper);
redisTemplate.opsForValue().set(RedisUtil.getRedisKey(ModelConstant.MODEL_TYPE_TEXT), textModelList, 1, TimeUnit.HOURS);
redisTemplate.opsForValue().set(RedisUtil.getRedisKey(ModelConstant.MODEL_TYPE_IMAGE), pictureModelList, 1, TimeUnit.HOURS);
}
@Scheduled(cron = "0 0 * * * ?")
public void syncTask() {
log.info("<<<<< start sync >>>>>");
syncRedis();
log.info("<<<<< end sync >>>>>");
}
@PostConstruct
public void initTask() {
log.info("<<<<< start initTask >>>>>");
//syncDatabase();
syncRedis();
log.info("<<<<< end initTask >>>>>");
}
public void syncDatabase() {
int pageNum = 1;
int pageSize = 100;
long total = 0;
do {
Page<Models> page = new Page<>(pageNum, pageSize);
modelMapper.selectPage(page, null);
List<Models> records = page.getRecords();
total = page.getTotal();
if (records.isEmpty()) {
break;
}
syncDBTask(records);
pageNum++;
} while ((pageNum - 1) * pageSize < total);
}
//
public void syncDBTask(List<Models> modelsList) {
List<CompletableFuture<Url>> futures = new ArrayList<>();
for (Models models : modelsList) {
CompletableFuture<Url> future = CompletableFuture.supplyAsync(() -> {
Models checkedModel = llmClient.checkModelAvailable(models);
modelMapper.update(checkedModel, new UpdateWrapper<Models>()
.eq("url", checkedModel.getUrl())
.eq("model", checkedModel.getModel()));
return null;
}, taskExecutor);
futures.add(future);
}
}
}
\ No newline at end of file
package com.coolook.service.llm.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.coolook.common.llm.constant.ModelConstant;
import com.coolook.common.llm.dto.Models;
import com.coolook.common.llm.response.ResponseResult;
import com.coolook.common.llm.dto.Url;
import com.coolook.common.llm.request.ModelsRequest;
import com.coolook.common.llm.request.UrlRequest;
import com.coolook.common.llm.response.PageResponse;
import com.coolook.service.llm.mapper.ModelMapper;
import com.coolook.service.llm.mapper.UrlMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.List;
/**
* @author: Wang Yinuo
* @create: 2025-03-06:PM3:49
*/
@Service
@Slf4j
public class ModelDataService {
@Autowired
private UrlMapper urlMapper;
@Autowired
private ModelMapper modelMapper;
private final static int PAGE_SIZE = 1000;
public ResponseResult getUrlList(int pageNum) {
Page<Url> page = new Page<>(pageNum, PAGE_SIZE);
Page<Url> urlPage = urlMapper.selectPage(page, null);
PageResponse pageResponse = new PageResponse();
pageResponse.setList(urlPage.getRecords());
pageResponse.setTotalPage(urlPage.getPages());
return ResponseResult.success(pageResponse);
}
public ResponseResult getModelList(int pageNum) {
Page<Models> page = new Page<>(pageNum, PAGE_SIZE);
Page<Models> modelsPage = modelMapper.selectPage(page, null);
PageResponse pageResponse = new PageResponse();
pageResponse.setList(modelsPage.getRecords());
pageResponse.setTotalPage(modelsPage.getPages());
return ResponseResult.success(pageResponse);
}
public ResponseResult saveOrUpdateModels(List<ModelsRequest> modelsRequestList) {
if (modelsRequestList == null || modelsRequestList.isEmpty()) {
return ResponseResult.fail("error");
}
LocalDateTime now = LocalDateTime.now();
for (ModelsRequest request : modelsRequestList) {
if (request.getId() == null || request.getId() == 0) {
Models models = new Models();
models.setUrl(request.getUrl());
models.setModel(request.getModel());
models.setModelType(request.getModelType());
models.setIsActive(request.getIsActive());
models.setLatestSpeed(request.getLatestSpeed());
models.setLastCheckedAt(now);
models.setCreateAt(now);
models.setSuccessCount(0);
models.setFailureCount(0);
models.setTotalCount(0);
models.setConsecutiveFailure(0);
// 插入新数据
modelMapper.insert(models);
} else {
Models dbModel = modelMapper.selectById(request.getId());
dbModel.setLastCheckedAt(now);
dbModel.setIsActive(request.getIsActive());
dbModel.setTotalCount(dbModel.getTotalCount() + 1);
dbModel.setLatestSpeed(request.getLatestSpeed());
// 更新已有数据
if (dbModel.getIsActive() == ModelConstant.MODEL_IS_ACTIVE) {
dbModel.setConsecutiveFailure(0);
dbModel.setSuccessCount(dbModel.getSuccessCount() + 1);
} else {
dbModel.setFailureCount(dbModel.getFailureCount() + 1);
dbModel.setConsecutiveFailure(dbModel.getConsecutiveFailure() + 1);
}
modelMapper.updateById(dbModel);
}
}
return ResponseResult.success();
}
public ResponseResult saveOrUpdateUrl(List<UrlRequest> urlRequestList) {
if (urlRequestList == null || urlRequestList.isEmpty()) {
return ResponseResult.fail("error");
}
LocalDateTime now = LocalDateTime.now();
for (UrlRequest request : urlRequestList) {
if (request.getId() == null || request.getId() == 0) {
Url url = new Url();
url.setUrl(request.getUrl());
url.setCountryCode(request.getCountryCode());
url.setCountryName(request.getCountryName());
url.setLastCheckedAt(now);
url.setCreateAt(now);
url.setRegion(request.getRegion());
url.setCity(request.getCity());
url.setConsecutiveFailure(0);
url.setLongitude(request.getLongitude());
url.setLatitude(request.getLatitude());
url.setIsActive(request.getIsActive());
urlMapper.insert(url);
} else {
Url dbUrl = urlMapper.selectById(request.getId());
dbUrl.setLastCheckedAt(now);
dbUrl.setIsActive(request.getIsActive());
if (dbUrl.getIsActive() == ModelConstant.MODEL_IS_ACTIVE) {
dbUrl.setConsecutiveFailure(0);
} else {
dbUrl.setConsecutiveFailure(dbUrl.getConsecutiveFailure() + 1);
}
urlMapper.updateById(dbUrl);
}
}
return ResponseResult.success();
}
}
package com.coolook.service.llm.service;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.coolook.common.llm.constant.CommonStatusEnum;
import com.coolook.common.llm.dto.ModelsDto;
import com.coolook.common.llm.response.ResponseStandardModel;
import com.coolook.common.llm.response.ResponseStandardModelError;
import com.coolook.common.llm.utils.RedisUtil;
import com.coolook.common.llm.constant.ModelConstant;
import com.coolook.common.llm.dto.Models;
import com.coolook.common.llm.response.ResponseResult;
import com.coolook.common.llm.request.ModelsRequest;
import com.coolook.common.llm.request.OpenAiImageRequest;
import com.coolook.common.llm.request.OpenAiTextRequest;
import com.coolook.service.llm.config.SearchConfig;
import com.coolook.service.llm.mapper.ModelMapper;
import com.coolook.service.llm.remote.LLMClient;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
/**
* @author: Wang Yinuo
* @create: 2025-02-21:AM11:20
*/
@Service
@Slf4j
public class ModelService {
@Autowired
private LLMClient llmClient;
@Autowired
private RedisTemplate redisTemplate;
@Autowired
private ObjectMapper objectMapper;
@Autowired
private ModelMapper modelMapper;
@Autowired
private SearchConfig searchConfig;
private static Map<String, Object> unavailableModel = new ConcurrentHashMap<>();
public HttpEntity<List<ModelsDto>> getTextModelList() {
String redisKey = RedisUtil.getRedisKey(ModelConstant.MODEL_TYPE_TEXT);
List<ModelsDto> nameList = new ArrayList<>();
Object obj = redisTemplate.opsForValue().get(redisKey);
if (obj == null) {
QueryWrapper<Models> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("model_type", ModelConstant.MODEL_TYPE_TEXT);
queryWrapper.eq("is_active", ModelConstant.MODEL_IS_ACTIVE);
queryWrapper.last("LIMIT 500");
List<Models> list = modelMapper.selectList(queryWrapper);
obj = list;
redisTemplate.opsForValue().set(RedisUtil.getRedisKey(ModelConstant.MODEL_TYPE_TEXT), list, 1, TimeUnit.HOURS);
}
if (obj instanceof List<?>) {
List<?> rawList = (List<?>) obj;
List<Models> modelList = rawList.stream()
.map(item -> objectMapper.convertValue(item, Models.class))
.collect(Collectors.toList());
for (Models model : modelList) {
String modelName = model.getModel();
String[] modelInfo = modelName.split(":");
String modelType = null;
String modelVersion = null;
if (modelInfo.length > 1) {
modelType = modelInfo[0];
modelVersion = modelInfo[1];
} else {
modelType = modelName;
}
if (modelVersion == null || modelVersion.contains("-") || modelVersion.contains("_")) {
modelVersion = "";
}
modelName = modelType + ":" + modelVersion;
ModelsDto modelDto = new ModelsDto();
modelDto.setId(modelName);
modelDto.setCreated(model.getCreateAt().atZone(ZoneId.of("UTC")).toInstant().toEpochMilli());
if (!nameList.stream().anyMatch(p -> p.getId().equals(modelDto.getId()))) {
nameList.add(modelDto);
}
}
}
return ResponseEntity.ok(nameList);
}
public ResponseResult<List<String>> getPictureModelList() {
String redisKey = RedisUtil.getRedisKey(ModelConstant.MODEL_TYPE_IMAGE);
List<String> nameList = new ArrayList<>();
Object obj = redisTemplate.opsForValue().get(redisKey);
if (obj == null) {
QueryWrapper<Models> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("model_type", ModelConstant.MODEL_TYPE_IMAGE);
queryWrapper.eq("is_active", ModelConstant.MODEL_IS_ACTIVE);
queryWrapper.last("LIMIT 10");
List<Models> list = modelMapper.selectList(queryWrapper);
log.info("redis list:{}", list);
obj = list;
redisTemplate.opsForValue().set(RedisUtil.getRedisKey(ModelConstant.MODEL_TYPE_IMAGE), list, 1, TimeUnit.HOURS);
}
if (obj instanceof List<?>) {
List<?> rawList = (List<?>) obj;
List<Models> modelList = rawList.stream()
.map(item -> objectMapper.convertValue(item, Models.class))
.collect(Collectors.toList());
for (Models model : modelList) {
String modelName = model.getModel();
if (!nameList.contains(modelName)) {
nameList.add(modelName);
}
}
}
return ResponseResult.success(nameList);
}
public ResponseEntity<?> chat(OpenAiTextRequest content) {
String redisKey = RedisUtil.getRedisKey(ModelConstant.MODEL_TYPE_TEXT);
String modelFullName = content.getModel();
String modelName = modelFullName.split(":")[0];
Object obj = redisTemplate.opsForValue().get(redisKey);
if (obj instanceof List<?>) {
List<?> rawList = (List<?>) obj;
List<Models> modelList = rawList.stream()
.map(item -> objectMapper.convertValue(item, Models.class))
.collect(Collectors.toList());
for (Models model : modelList) {
String name = model.getModel().trim();
Boolean flag = false;
// 根据名字寻找合适的模型
if (name.equals(modelName)) {
flag = true;
} else if (searchConfig.getValue()) {
if (name.contains(modelName)) {
flag = true;
}
} else {
flag = true;
}
if (flag) {
if (unavailableModel.putIfAbsent(model.getUrl() + model.getModel(), true) == null) {
return updateAndSendRequestChat(model, content);
}
}
}
}
Map<String, String> errorResponse = new HashMap<>();
errorResponse.put("error", "error");
errorResponse.put("message", "model not found");
errorResponse.put("status", "500");
errorResponse.put("model", content.getModel());
// 将错误响应转换为 JSON 字符串并返回
ObjectMapper objectMapper = new ObjectMapper();
try {
String errorJson = objectMapper.writeValueAsString(errorResponse);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorJson);
} catch (Exception e) {
// 如果序列化失败,返回通用错误消息
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body("{\"error\": \"Serialization error\",\"message\": \"Unable to process error response\"}");
}
}
public ResponseEntity<?> picture(OpenAiImageRequest content) {
String redisKey = RedisUtil.getRedisKey(ModelConstant.MODEL_TYPE_IMAGE);
String modelFullName = content.getModel();
String modelName = modelFullName.split(":")[0];
Object obj = redisTemplate.opsForValue().get(redisKey);
if (obj instanceof List<?>) {
List<?> rawList = (List<?>) obj;
List<Models> modelList = rawList.stream()
.map(item -> objectMapper.convertValue(item, Models.class))
.collect(Collectors.toList());
for (Models model : modelList) {
String name = model.getModel().trim();
Boolean flag = false;
// 根据名字寻找合适的模型
if (name.equals(modelName)) {
flag = true;
} else if (searchConfig.getValue()) {
if (name.contains(modelName)) {
flag = true;
}
} else {
flag = true;
}
if (flag) {
if (unavailableModel.putIfAbsent(model.getUrl() + model.getModel(), true) == null) {
return updateAndSendRequestPic(model, content);
}
}
}
}
ResponseStandardModelError error = new ResponseStandardModelError(
"model:" + content.getModel() + "not found",
"model not found",
content.getModel(),
"500"
);
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(error);
}
public ResponseEntity updateAndSendRequestChat(Models model, OpenAiTextRequest content) {
String key = model.getUrl() + model.getModel();
log.info("updateAndSendRequestChat, modelName;{}", key);
try {
return llmClient.chat(model, content);
} finally {
unavailableModel.remove(key);
}
}
public ResponseEntity updateAndSendRequestPic(Models model, OpenAiImageRequest content) {
String key = model.getUrl() + model.getModel();
log.info("updateAndSendRequestPic, modelName;{}", key);
try {
return llmClient.picture(model, content);
} finally {
unavailableModel.remove(key);
}
}
public ResponseResult addModel(ModelsRequest[] content) {
List<Models> modelList = new ArrayList<>();
for (ModelsRequest modelRequest : content) {
Models models = new Models();
models.setUrl(modelRequest.getUrl());
models.setModel(modelRequest.getModel());
models.setModelType(modelRequest.getModelType());
models.setIsActive(ModelConstant.MODEL_IS_NOT_ACTIVE);
models.setCreateAt(LocalDateTime.now());
models.setLastCheckedAt(LocalDateTime.now());
models.setSuccessCount(0);
models.setFailureCount(0);
models.setTotalCount(0);
models.setConsecutiveFailure(0);
models.setLatestSpeed(0L);
modelList.add(models);
}
modelMapper.insertModelList(modelList);
return ResponseResult.success();
}
}
package com.coolook.service.llm.service;
import com.coolook.common.llm.response.ResponseResult;
import com.coolook.service.llm.config.SearchConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* @author: Wang Yinuo
* @create: 2025-03-05:AM10:40
*/
@Service
public class SearchConfigService {
@Autowired
private SearchConfig searchConfig;
public ResponseResult getSearchConfig() {
return ResponseResult.success(searchConfig.getValue());
}
public ResponseResult setSearchConfig(Boolean value) {
searchConfig.setValue(value);
return ResponseResult.success();
}
}
spring:
cloud:
nacos:
discovery:
server-addr: 129.150.53.251:8848
datasource:
type: com.alibaba.druid.pool.DruidDataSource
druid:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://10.0.20.226:3307/service_llm?useSSL=true&useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Singapore
username: root
password: zwjt123.com
redis:
host: 10.0.20.226
port: 6379
database: 8
cache:
type: redis
\ No newline at end of file
spring:
cloud:
nacos:
discovery:
server-addr: 132.145.115.85:8848
datasource:
type: com.alibaba.druid.pool.DruidDataSource
druid:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://10.0.20.195:3306/service_llm?useSSL=true&useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
username: root
password: zwjt123.com
redis:
host: aaaawxqy5yamgkqc5lii6wutfmzocximcbesvikrwqxn6p4i4drafka-p.redis.ap-tokyo-1.oci.oraclecloud.com
port: 6379
database: 8
cache:
type: redis
spring:
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/service_llm?useSSL=true&useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Singapore
username: root
password: root
redis:
host: localhost
port: 6379
database: 8
cache:
type: redis
spring:
cloud:
nacos:
discovery:
server-addr: 10.0.20.42:8848
ip: 213.35.97.104
datasource:
type: com.alibaba.druid.pool.DruidDataSource
druid:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://10.0.20.195:3306/service_llm?useSSL=true&useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
username: root
password: zwjt123.com
redis:
host: 10.0.20.195
port: 6379
database: 8
cache:
type: redis
# 开发环境配置
server:
port: 8700
spring:
application:
name: service-llm
main:
allow-bean-definition-overriding: true
profiles:
active: local
search:
config:
value: false
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.coolook.service.llm.mapper.ModelMapper">
<insert id="insertModelList" parameterType="java.util.List">
INSERT INTO models (url, model, model_type, create_at, last_checked_at, total_count, success_count, failure_count, consecutive_failure, latest_speed, is_active, work_status)
VALUES
<foreach collection="list" item="models" separator=",">
(
#{models.url},
#{models.model},
#{models.modelType},
#{models.createAt},
#{models.lastCheckedAt},
#{models.totalCount},
#{models.successCount},
#{models.failureCount},
#{models.consecutiveFailure},
#{models.latestSpeed},
#{models.isActive},
#{models.workStatus}
)
</foreach>
</insert>
</mapper>
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 sign in to comment