You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

179 lines
9.4 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package com.dsideal.Res.Test;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONArray;
import com.jfinal.kit.PathKit;
import org.apache.commons.codec.digest.DigestUtils;
import java.io.File;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.CompletableFuture;
public class CallDeepSeek {
private static final String API_KEY = "sk-44ae895eeb614aa1a9c6460579e322f1"; // 请替换为您的API KEY
private static final String API_URL = "https://api.deepseek.com/v1/chat/completions";
public static void callDeepSeekStream(String prompt, SSEListener listener) {
new Thread(() -> {
StringBuilder fullResponse = new StringBuilder();
try {
// 修改htmlPrompt变量在提示词中明确要求输出格式
String htmlPrompt = prompt + "请严格按照以下mermaid配置输出SQL血缘关系图\n" +
"1. 使用以下固定样式配置:\n" +
" graph TD\n" +
" classDef default fill:#f9f9f9,stroke:#333,stroke-width:1px\n" +
" classDef input fill:#D6EAF8,stroke:#333\n" +
" classDef output fill:#D5F5E3,stroke:#333\n" +
" linkStyle default stroke:#333,stroke-width:2px\n" +
"2. 按照以下HTML模板格式输出不要生成html以外的其它文字\n" +
"<!DOCTYPE html>\n" +
"<html>\n" +
"<head>\n" +
" <title>SQL血缘关系图</title>\n" +
" <script src='https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js'></script>\n" +
" <style>\n" +
" .mermaid { margin: 20px auto; }\n" +
" body { font-family: Arial; text-align: center; }\n" +
" </style>\n" +
"</head>\n" +
"<body>\n" +
" <h2>SQL血缘关系图</h2>\n" +
" <div class='mermaid'>\n" +
" graph TD\n" +
" classDef default fill:#f9f9f9,stroke:#333,stroke-width:1px\n" +
" classDef input fill:#D6EAF8,stroke:#333\n" +
" classDef output fill:#D5F5E3,stroke:#333\n" +
" linkStyle default stroke:#333,stroke-width:2px\n" +
" [请在此处插入mermaid格式的血缘关系图]\n" +
" </div>\n" +
" <script>mermaid.initialize({startOnLoad:true, theme: 'default'});</script>\n" +
"</body>\n" +
"</html>\n";
JSONObject jsonPayload = new JSONObject();
jsonPayload.set("model", "deepseek-chat");
JSONObject message = new JSONObject();
message.set("role", "user");
message.set("content", htmlPrompt);
JSONArray messages = new JSONArray();
messages.add(message);
jsonPayload.set("messages", messages);
jsonPayload.set("stream", true);
HttpClient client = HttpClient.newBuilder()
.version(HttpClient.Version.HTTP_1_1) // 明确指定HTTP版本
.build();
java.net.http.HttpRequest request = java.net.http.HttpRequest.newBuilder()
.uri(URI.create(API_URL))
.header("Content-Type", "application/json")
.header("Authorization", "Bearer " + API_KEY)
.header("Accept", "text/event-stream") // 确保Accept头正确
.POST(java.net.http.HttpRequest.BodyPublishers.ofString(jsonPayload.toString(), StandardCharsets.UTF_8))
.build();
// 使用 BodyHandlers.ofLines() 来处理流式响应
CompletableFuture<Void> future = client.sendAsync(request, HttpResponse.BodyHandlers.ofLines())
.thenAccept(response -> {
if (response.statusCode() == 200) {
response.body().forEach(line -> {
if (line.startsWith("data:")) {
String data = line.substring(5).trim();
if (!data.equals("[DONE]")) {
try {
JSONObject jsonData = JSONUtil.parseObj(data);
if (jsonData.containsKey("choices")) {
String content = jsonData.getJSONArray("choices")
.getJSONObject(0)
.getJSONObject("delta")
.getStr("content", "");
if (content != null && !content.isEmpty()) {
fullResponse.append(content);
listener.onData(content); // 回调监听器
}
}
} catch (Exception e) {
System.err.println("解析SSE JSON数据错误: " + data + " \nError: " + e.getMessage());
}
}
}
});
// 流结束后的处理
String htmlContent = fullResponse.toString();
if (htmlContent.contains("<!DOCTYPE html>") && htmlContent.contains("</html>")) {
FileUtil.writeString(htmlContent, new File("C:\\1.html"), "UTF-8");
listener.onComplete("HTML已成功保存到C:\\1.html");
} else {
listener.onError("最终返回内容不是有效的HTML: " + htmlContent.substring(0, Math.min(htmlContent.length(), 200)) + "...");
}
} else {
listener.onError("API请求失败: " + response.statusCode() + " Body: " + response.body().toString());
}
}).exceptionally(e -> {
listener.onError("请求或处理异常: " + e.getMessage());
e.printStackTrace();
return null;
});
future.join(); // 等待异步操作完成对于main线程的简单示例是必要的
} catch (Exception e) {
listener.onError("发生意外错误: " + e.getMessage());
e.printStackTrace();
}
}).start();
}
public static void main(String[] args) {
String sqlContent = FileUtil.readString("XueYuan.sql", CharsetUtil.CHARSET_UTF_8);
String md5 = DigestUtils.md5Hex(sqlContent);
String outputPath = "C:\\" + md5 + ".html";
File outputFile = new File(outputPath);
if (outputFile.exists()) {
System.out.println("文件已存在,跳过生成:" + outputPath);
return;
}
String prompt = "你是一个数据库SQL的血缘关系分析专家我将提供SQL语句给你帮我整理数据血缘关系并且绘制HTML页面以展示最终的可视化展现。";
callDeepSeekStream(prompt + "\n" + sqlContent, new SSEListener() {
@Override
public void onData(String data) {
System.out.print(data); // 实时打印
System.out.flush(); // 确保立即刷新到控制台
}
@Override
public void onComplete(String fullResponse) {
System.out.println("\n\n完整回复: " + fullResponse);
}
@Override
public void onError(String error) {
System.err.println("错误: " + error);
}
});
// 移除 Thread.sleep(30000);
// 如果主线程需要等待SSE完成可以考虑使用更优雅的同步机制
// 例如 CountDownLatch或者让 callDeepSeekStream 方法返回一个 Future。
// 但对于简单的控制台流式输出演示,移除休眠即可观察到流式效果。
}
public interface SSEListener {
void onData(String data);
void onComplete(String fullResponse);
void onError(String error);
}
}