diff --git a/aioj-backend-ai-service/src/main/java/cn/meowrain/aioj/backend/aiservice/service/impl/AIServiceImpl.java b/aioj-backend-ai-service/src/main/java/cn/meowrain/aioj/backend/aiservice/service/impl/AIServiceImpl.java new file mode 100644 index 0000000..9f879f2 --- /dev/null +++ b/aioj-backend-ai-service/src/main/java/cn/meowrain/aioj/backend/aiservice/service/impl/AIServiceImpl.java @@ -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); + } +} diff --git a/aioj-backend-ai-service/src/main/resources/application-dev.yml b/aioj-backend-ai-service/src/main/resources/application-dev.yml new file mode 100644 index 0000000..12805ed --- /dev/null +++ b/aioj-backend-ai-service/src/main/resources/application-dev.yml @@ -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 diff --git a/aioj-backend-ai-service/src/main/resources/application-prod.yml b/aioj-backend-ai-service/src/main/resources/application-prod.yml new file mode 100644 index 0000000..66ec453 --- /dev/null +++ b/aioj-backend-ai-service/src/main/resources/application-prod.yml @@ -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} diff --git a/aioj-backend-ai-service/src/main/resources/application-test.yml b/aioj-backend-ai-service/src/main/resources/application-test.yml new file mode 100644 index 0000000..9ba9bc9 --- /dev/null +++ b/aioj-backend-ai-service/src/main/resources/application-test.yml @@ -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 diff --git a/aioj-backend-ai-service/src/main/resources/application.yml b/aioj-backend-ai-service/src/main/resources/application.yml new file mode 100644 index 0000000..1b2e0a0 --- /dev/null +++ b/aioj-backend-ai-service/src/main/resources/application.yml @@ -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} diff --git a/aioj-backend-ai-service/src/main/resources/logback-spring.xml b/aioj-backend-ai-service/src/main/resources/logback-spring.xml new file mode 100644 index 0000000..610aaf8 --- /dev/null +++ b/aioj-backend-ai-service/src/main/resources/logback-spring.xml @@ -0,0 +1,54 @@ + + + + + + + + + %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n + UTF-8 + + + + + + ${LOG_HOME}/aioj-ai-service.log + + ${LOG_HOME}/aioj-ai-service.%d{yyyy-MM-dd}.log + 30 + + + %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n + UTF-8 + + + + + + ${LOG_HOME}/aioj-ai-service-error.log + + ERROR + ACCEPT + DENY + + + ${LOG_HOME}/aioj-ai-service-error.%d{yyyy-MM-dd}.log + 30 + + + %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n + UTF-8 + + + + + + + + + + + + +