Skip to content

Instantly share code, notes, and snippets.

@kishida
Created September 11, 2025 08:12
Show Gist options
  • Save kishida/5ac71744da23f677e1eec32a958a4d4f to your computer and use it in GitHub Desktop.
Save kishida/5ac71744da23f677e1eec32a958a4d4f to your computer and use it in GitHub Desktop.
LLM日英翻訳
import dev.langchain4j.data.message.SystemMessage;
import dev.langchain4j.data.message.UserMessage;
import dev.langchain4j.http.client.jdk.JdkHttpClient;
import dev.langchain4j.model.chat.response.StreamingChatResponseHandler;
import dev.langchain4j.model.openai.OpenAiStreamingChatModel;
import java.net.http.HttpClient;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public abstract class LlmStreamEJJE {
enum MODEL { LFM2, PLAMO2 }
OpenAiStreamingChatModel model;
public abstract void translateJE(String message, StreamingChatResponseHandler handler);
public abstract void translateEJ(String message, StreamingChatResponseHandler handler);
static Map<MODEL, LlmStreamEJJE> cache = new HashMap<>();
public static LlmStreamEJJE of(MODEL m) {
return cache.computeIfAbsent(m, md ->
switch (md) {
case LFM2 -> new Lfm2EJJE();
case PLAMO2 -> new Plamo2EJJE();
default -> throw new IllegalArgumentException();
});
}
private LlmStreamEJJE(String modelName) {
model = OpenAiStreamingChatModel.builder()
.baseUrl("http://localhost:1234/v1")
.modelName(modelName)
.httpClientBuilder(JdkHttpClient.builder().httpClientBuilder(
HttpClient.newBuilder().version(HttpClient.Version.HTTP_1_1)))
.build();
}
private static class Lfm2EJJE extends LlmStreamEJJE {
public Lfm2EJJE() {
super("lfm2-350m-enjp-mt");
}
@Override
public void translateJE(String message, StreamingChatResponseHandler handler) {
translate(message, "English", handler);
}
@Override
public void translateEJ(String message, StreamingChatResponseHandler handler) {
translate(message, "Japanese", handler);
}
private void translate(String message, String language, StreamingChatResponseHandler handler) {
model.chat(List.of(
SystemMessage.from("Translate to %s.".formatted(language)),
UserMessage.from(message)), handler);
}
}
private static class Plamo2EJJE extends LlmStreamEJJE {
public Plamo2EJJE() {
super("plamo-2-translate");
}
@Override
public void translateJE(String message, StreamingChatResponseHandler handler) {
translate(message, "Japanese", "English", handler);
}
@Override
public void translateEJ(String message, StreamingChatResponseHandler handler) {
translate(message, "English", "Japanese", handler);
}
private void translate(String message, String from, String to, StreamingChatResponseHandler handler) {
var prompt = """
<|plamo:op|>dataset
translation
<|plamo:op|>input lang=%s
%s
<|plamo:op|>input lang=%s
""".formatted(from, message, to);
model.chat(
List.of(UserMessage.from(prompt)), handler);
}
}
}
import dev.langchain4j.model.chat.response.ChatResponse;
import dev.langchain4j.model.chat.response.StreamingChatResponseHandler;
import module java.desktop;
public class TranslatorFrame {
private void createAndShowGUI() {
JFrame frame = new JFrame("LLM翻訳");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout(8, 8));
frame.setMinimumSize(new Dimension(400, 300));
// 上下に並べるパネル(2行1列)
JPanel centerPanel = new JPanel(new GridLayout(2, 1, 6, 6));
centerPanel.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8));
// テキストエリア1
JTextArea area1 = new JTextArea();
area1.setLineWrap(true);
area1.setWrapStyleWord(true);
area1.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 12));
area1.setText("");
// テキストエリア2
JTextArea area2 = new JTextArea();
area2.setLineWrap(true);
area2.setWrapStyleWord(true);
area2.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 12));
area2.setText("");
JScrollPane sp1 = new JScrollPane(area1,
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
JScrollPane sp2 = new JScrollPane(area2,
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
// 適度な初期高さを指定(GridLayoutなので高さは均等)
sp1.setPreferredSize(new Dimension(200, 150));
sp2.setPreferredSize(new Dimension(200, 150));
centerPanel.add(sp1);
centerPanel.add(sp2);
// 下部のボタンパネル
JPanel bottomPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
JComboBox<LlmStreamEJJE.MODEL> combo = new JComboBox<>(LlmStreamEJJE.MODEL.values());
bottomPanel.add(combo);
JButton jeButton = new JButton("日->英");
bottomPanel.add(jeButton);
JButton ejButton = new JButton("英->日");
bottomPanel.add(ejButton);
frame.add(centerPanel, BorderLayout.CENTER);
frame.add(bottomPanel, BorderLayout.SOUTH);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
StreamingChatResponseHandler handler = new StreamingChatResponseHandler() {
@Override
public void onPartialResponse(String partialResponse) {
area2.append(partialResponse);
}
@Override
public void onCompleteResponse(ChatResponse completeResponse) {
jeButton.setEnabled(true);
ejButton.setEnabled(true);
}
@Override
public void onError(Throwable error) {
jeButton.setEnabled(true);
ejButton.setEnabled(true);
throw new RuntimeException(error);
}
};
jeButton.addActionListener(_ -> {
jeButton.setEnabled(false);
ejButton.setEnabled(false);
LlmStreamEJJE ejje = LlmStreamEJJE.of(combo.getItemAt(combo.getSelectedIndex()));
area2.setText("");
ejje.translateJE(area1.getText(), handler);
});
ejButton.addActionListener(_ -> {
jeButton.setEnabled(false);
ejButton.setEnabled(false);
LlmStreamEJJE ejje = LlmStreamEJJE.of(combo.getItemAt(combo.getSelectedIndex()));
area2.setText("");
ejje.translateEJ(area1.getText(), handler);
});
}
public void main(String[] args) {
SwingUtilities.invokeLater(this::createAndShowGUI);
}
}
@kishida
Copy link
Author

kishida commented Sep 11, 2025

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment