Skip to content

Commit b3e97c6

Browse files
committed
add FF14Translator
1 parent a0d1dc6 commit b3e97c6

11 files changed

Lines changed: 1240 additions & 90 deletions

File tree

.env

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,9 @@ LEANCLOUD_APP_KEY=1xNZMz1XUVSLDTAv3XoVBgni
1919
CLOUDFLARE_API_TOKEN=XfJvEzGOKAMIn18NRE5MvkqU4C64s_ic3iNXRk1y
2020

2121
# Scrapestack配置
22-
SCRAPESTACK_ACCESS_KEY=ebdc1b9aa7e4f9f1c776d9ad2c90628e
22+
SCRAPESTACK_ACCESS_KEY=ebdc1b9aa7e4f9f1c776d9ad2c90628e
23+
24+
# OpenAI配置
25+
OPENAI_API_KEY=sk-kjurnyrzfpwgtxehipwixwlkpdxuezlrvjbqybywxiovafwr
26+
OPENAI_BASE_URL=https://api.siliconflow.cn/v1/chat/completions
27+
OPENAI_MODEL_NAME=Qwen/Qwen3-8B

.idea/workspace.xml

Lines changed: 100 additions & 88 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -358,7 +358,7 @@
358358
<!-- <artifactId>dotenv-java</artifactId>-->
359359
<!-- <version>2.3.2</version>-->
360360
<!-- </dependency>-->
361-
<!-- ONNX Runtime -->
361+
<!-- ONNX Runtime (唯一依赖) -->
362362
<dependency>
363363
<groupId>com.microsoft.onnxruntime</groupId>
364364
<artifactId>onnxruntime</artifactId>
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package com.phantoms.phantomsbackend.common.LLM;
2+
3+
import lombok.extern.slf4j.Slf4j;
4+
import org.springframework.core.io.ClassPathResource;
5+
import org.springframework.stereotype.Component;
6+
7+
import jakarta.annotation.PostConstruct;
8+
import java.io.IOException;
9+
import java.nio.charset.StandardCharsets;
10+
import java.nio.file.Files;
11+
import java.nio.file.Path;
12+
import java.nio.file.Paths;
13+
14+
@Slf4j
15+
@Component
16+
public class FF14Prompt {
17+
private static String SYSTEM_PROMPT;
18+
19+
@PostConstruct
20+
public void init() {
21+
try {
22+
ClassPathResource resource = new ClassPathResource("prompts/ff14-translator-prompt.md");
23+
Path path = Paths.get(resource.getURI());
24+
SYSTEM_PROMPT = Files.readString(path, StandardCharsets.UTF_8);
25+
log.info("FF14翻译提示词加载成功,长度: {} 字符", SYSTEM_PROMPT.length());
26+
} catch (IOException e) {
27+
log.error("加载FF14翻译提示词失败", e);
28+
SYSTEM_PROMPT = "你是最终幻想14专用翻译器。";
29+
}
30+
}
31+
32+
public static String getSystemPrompt() {
33+
return SYSTEM_PROMPT;
34+
}
35+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package com.phantoms.phantomsbackend.common.LLM;
2+
3+
import org.springframework.stereotype.Component;
4+
import javax.annotation.PostConstruct;
5+
6+
@Component
7+
public class FF14Translator {
8+
private static LLMClient llmClientStatic;
9+
10+
private final LLMClient llmClient;
11+
12+
public FF14Translator(LLMClient llmClient) {
13+
this.llmClient = llmClient;
14+
}
15+
16+
@PostConstruct
17+
private void init() {
18+
llmClientStatic = this.llmClient;
19+
}
20+
21+
public static String translate(String text) {
22+
try {
23+
return llmClientStatic.chat(FF14Prompt.getSystemPrompt(), text);
24+
} catch (Exception e) {
25+
e.printStackTrace();
26+
return "翻译失败:" + e.getMessage();
27+
}
28+
}
29+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
package com.phantoms.phantomsbackend.common.LLM;
2+
3+
import com.fasterxml.jackson.databind.ObjectMapper;
4+
import com.phantoms.phantomsbackend.common.config.LLMProperties;
5+
import lombok.extern.slf4j.Slf4j;
6+
import okhttp3.*;
7+
import org.springframework.stereotype.Component;
8+
import javax.annotation.PostConstruct;
9+
import java.util.Map;
10+
11+
@Slf4j
12+
@Component
13+
public class LLMClient {
14+
private final LLMProperties llmProperties;
15+
private static final OkHttpClient HTTP_CLIENT = new OkHttpClient.Builder()
16+
.connectTimeout(30, java.util.concurrent.TimeUnit.SECONDS)
17+
.readTimeout(60, java.util.concurrent.TimeUnit.SECONDS)
18+
.writeTimeout(30, java.util.concurrent.TimeUnit.SECONDS)
19+
.build();
20+
private static final ObjectMapper MAPPER = new ObjectMapper();
21+
22+
public LLMClient(LLMProperties llmProperties) {
23+
this.llmProperties = llmProperties;
24+
}
25+
26+
@PostConstruct
27+
public void init() {
28+
log.info("=== LLM配置 ===");
29+
log.info("API URL: {}", llmProperties.getApiUrl());
30+
log.info("API Key: {}", llmProperties.getApiKey() != null ? llmProperties.getApiKey().substring(0, Math.min(10, llmProperties.getApiKey().length())) + "***" : "null");
31+
log.info("Model Name: {}", llmProperties.getModelName());
32+
log.info("Temperature: {}", llmProperties.getTemperature());
33+
log.info("===============");
34+
}
35+
36+
public String chat(String systemPrompt, String userInput) throws Exception {
37+
Object[] messages = {
38+
Map.of("role", "system", "content", systemPrompt),
39+
Map.of("role", "user", "content", userInput)
40+
};
41+
42+
var body = Map.of(
43+
"model", llmProperties.getModelName(),
44+
"messages", messages,
45+
"temperature", llmProperties.getTemperature()
46+
);
47+
48+
String json = MAPPER.writeValueAsString(body);
49+
RequestBody requestBody = RequestBody.create(json, MediaType.parse("application/json; charset=utf-8"));
50+
51+
Request request = new Request.Builder()
52+
.url(llmProperties.getApiUrl())
53+
.header("Authorization", "Bearer " + llmProperties.getApiKey())
54+
.post(requestBody)
55+
.build();
56+
57+
try (Response response = HTTP_CLIENT.newCall(request).execute()) {
58+
if (!response.isSuccessful()) {
59+
throw new RuntimeException("LLM请求失败:" + response.code());
60+
}
61+
Map<String, Object> resMap = MAPPER.readValue(response.body().string(), Map.class);
62+
var choices = (Map<?, ?>) ((java.util.List<?>) resMap.get("choices")).get(0);
63+
var msg = (Map<?, ?>) choices.get("message");
64+
return (String) msg.get("content");
65+
}
66+
}
67+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package com.phantoms.phantomsbackend.common.config;
2+
3+
import lombok.Data;
4+
import org.springframework.boot.context.properties.ConfigurationProperties;
5+
import org.springframework.stereotype.Component;
6+
7+
@Data
8+
@Component
9+
@ConfigurationProperties(prefix = "app.llm.openai")
10+
public class LLMProperties {
11+
private String apiUrl;
12+
private String apiKey;
13+
private String modelName;
14+
private double temperature;
15+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package com.phantoms.phantomsbackend.controller;
2+
3+
4+
import io.swagger.v3.oas.annotations.Operation;
5+
import io.swagger.v3.oas.annotations.tags.Tag;
6+
import lombok.extern.slf4j.Slf4j;
7+
import org.springframework.http.ResponseEntity;
8+
import org.springframework.web.bind.annotation.PostMapping;
9+
import org.springframework.web.bind.annotation.RequestBody;
10+
import org.springframework.web.bind.annotation.RequestMapping;
11+
import org.springframework.web.bind.annotation.RestController;
12+
13+
import com.phantoms.phantomsbackend.common.LLM.FF14Translator;
14+
15+
import java.util.Map;
16+
17+
@Slf4j
18+
@RestController
19+
@RequestMapping("/api/ff14")
20+
@Tag(name = "FF14 Translator", description = "FF14龙语翻译接口")
21+
public class FF14TranslatorController {
22+
23+
@PostMapping("/translate")
24+
@Operation(
25+
summary = "翻译文本为FF14龙语",
26+
description = "将用户输入的中文翻译为龙语、妖灵语和高位妖精语"
27+
)
28+
public ResponseEntity<Map<String, String>> translate(@RequestBody Map<String, String> request) {
29+
String text = request.get("text");
30+
if (text == null || text.isBlank()) {
31+
return ResponseEntity.badRequest().body(Map.of("error", "text不能为空"));
32+
}
33+
log.info("收到翻译请求: {}", text);
34+
String result = FF14Translator.translate(text);
35+
log.info("翻译结果: {}", result);
36+
return ResponseEntity.ok(Map.of("result", result));
37+
}
38+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
# ?? dotenv
2+
# Load .env file
3+
spring.config.import=optional:file:.env[.properties]
24
dotenv.enabled=true
35
dotenv.location=./.env

src/main/resources/application.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
# 应用基础配置
22
app:
33
version: 1.0.0
4+
llm:
5+
openai:
6+
api-url: ${OPENAI_BASE_URL}
7+
api-key: ${OPENAI_API_KEY}
8+
model-name: ${OPENAI_MODEL_NAME:gpt-3.5-turbo}
9+
temperature: ${OPENAI_TEMP:0.1}
410

511
server:
612
port: 8080

0 commit comments

Comments
 (0)