feat: 添加AI服务模块实现代码分析和评估功能

This commit is contained in:
2026-01-20 16:40:21 +08:00
parent 439fdf90c4
commit 51d16ea077
6 changed files with 264 additions and 0 deletions

View File

@@ -0,0 +1,72 @@
package cn.meowrain.aioj.backend.aiservice.service.impl;
import cn.meowrain.aioj.backend.aiservice.service.AIService;
import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.openai.OpenAiChatModel;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
/**
* AI 服务实现
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class AIServiceImpl implements AIService {
private final ChatLanguageModel chatLanguageModel;
@Override
public String analyzeCode(String code, String language) {
String prompt = buildPrompt("代码分析", language, code,
"请分析以下代码的质量、潜在问题和改进建议。");
log.info("执行代码分析: language={}, codeLength={}", language, code.length());
return chatLanguageModel.generate(prompt);
}
@Override
public String optimizeCode(String code, String language) {
String prompt = buildPrompt("代码优化", language, code,
"请提供以下代码的优化建议,包括性能优化、代码风格改进等。");
log.info("执行代码优化: language={}, codeLength={}", language, code.length());
return chatLanguageModel.generate(prompt);
}
@Override
public String generateTestCases(String code, String language) {
String prompt = buildPrompt("测试用例生成", language, code,
"请为以下代码生成完整的测试用例,包括边界条件和异常情况。");
log.info("生成测试用例: language={}, codeLength={}", language, code.length());
return chatLanguageModel.generate(prompt);
}
@Override
public String explainCode(String code, String language) {
String prompt = buildPrompt("代码解释", language, code,
"请详细解释以下代码的功能、逻辑和实现方式。");
log.info("解释代码: language={}, codeLength={}", language, code.length());
return chatLanguageModel.generate(prompt);
}
/**
* 构建提示词
*/
private String buildPrompt(String task, String language, String code, String instruction) {
return String.format("""
# 任务:%s
# 编程语言:%s
# 代码:
```%s
%s
```
# 要求:
%s
请提供详细、准确的分析结果。
""", task, language, language, code, instruction);
}
}

View File

@@ -0,0 +1,28 @@
spring:
data:
redis:
host: 10.0.0.10
port: 6379
password: 123456
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://10.0.0.10/aioj_dev
username: root
password: root
cloud:
nacos:
discovery:
enabled: true
register-enabled: true
server-addr: 10.0.0.10:8848
username: nacos
password: nacos
# AI 服务配置 - 开发环境
ai:
openai:
api-key: ${OPENAI_API_KEY:sk-dev-key}
base-url: ${OPENAI_BASE_URL:https://api.openai.com}
model: gpt-4
max-tokens: 2000
temperature: 0.7

View File

@@ -0,0 +1,28 @@
spring:
data:
redis:
host: ${REDIS_HOST:localhost}
port: ${REDIS_PORT:6379}
password: ${REDIS_PASSWORD}
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://${DB_HOST}:${DB_PORT}/${DB_NAME}
username: ${DB_USERNAME}
password: ${DB_PASSWORD}
cloud:
nacos:
discovery:
enabled: true
register-enabled: true
server-addr: ${NACOS_ADDR}
username: ${NACOS_USERNAME}
password: ${NACOS_PASSWORD}
# AI 服务配置 - 生产环境
ai:
openai:
api-key: ${OPENAI_API_KEY}
base-url: ${OPENAI_BASE_URL:https://api.openai.com}
model: ${OPENAI_MODEL:gpt-4}
max-tokens: ${OPENAI_MAX_TOKENS:2000}
temperature: ${OPENAI_TEMPERATURE:0.7}

View File

@@ -0,0 +1,25 @@
spring:
data:
redis:
host: localhost
port: 6379
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost/aioj_test
username: root
password: root
cloud:
nacos:
discovery:
enabled: true
register-enabled: true
server-addr: localhost:8848
# AI 服务配置 - 测试环境
ai:
openai:
api-key: ${OPENAI_API_KEY:sk-test-key}
base-url: ${OPENAI_BASE_URL:https://api.openai.com}
model: gpt-4
max-tokens: 2000
temperature: 0.7

View File

@@ -0,0 +1,57 @@
spring:
application:
name: aioj-ai-service
profiles:
active: @env@
server:
port: 18084
servlet:
context-path: /api
error:
include-stacktrace: never
springdoc:
api-docs:
enabled: true
path: /v3/api-docs
default-flat-param-object: true
swagger-ui:
path: /swagger-ui.html
tags-sorter: alpha
operations-sorter: alpha
group-configs:
- group: 'default'
paths-to-match: '/api/**'
packages-to-scan: cn.meowrain.aioj.backend.aiservice.controller
knife4j:
basic:
enable: true
setting:
language: zh_cn
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
mapper-locations: classpath*:/mapper/**/*.xml
# JWT 配置(必须与 auth-service 保持一致)
jwt:
enabled: true
secret: "12345678901234567890123456789012" # 至少32字节
access-expire: 900000 # 15分钟
refresh-expire: 604800000 # 7天
# AI 服务配置
ai:
openai:
api-key: ${OPENAI_API_KEY:your-api-key}
base-url: ${OPENAI_BASE_URL:https://api.openai.com}
model: ${OPENAI_MODEL:gpt-4}
max-tokens: ${OPENAI_MAX_TOKENS:2000}
temperature: ${OPENAI_TEMPERATURE:0.7}
aioj:
log:
enabled: true
max-length: 20000
logging:
file:
path: ./logs/${spring.application.name}

View File

@@ -0,0 +1,54 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<!-- 日志输出位置 -->
<springProperty scope="context" name="LOG_HOME" source="logging.file.path" defaultValue="./logs/aioj-ai-service"/>
<!-- 控制台输出 -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- 文件输出 -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/aioj-ai-service.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/aioj-ai-service.%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- 错误日志单独输出 -->
<appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/aioj-ai-service-error.log</file>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/aioj-ai-service-error.%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- 日志级别 -->
<root level="INFO">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="FILE"/>
<appender-ref ref="ERROR_FILE"/>
</root>
<!-- SQL日志 -->
<logger name="cn.meowrain.aioj.backend.aiservice.dao.mapper" level="DEBUG"/>
</configuration>