main
HuangHai 2 months ago
parent 5004788c89
commit a67e4051aa

@ -0,0 +1,176 @@
<!DOCTYPE html>
<html>
<head>
<title>SQL Data Lineage Visualization</title>
<script src="https://d3js.org/d3.v7.min.js"></script>
<style>
body {
font-family: Arial, sans-serif;
margin: 20px;
}
<style>
.node rect {
stroke: #333;
fill: #f8f8f8;
stroke-width: 1.5px;
rx: 5;
ry: 5;
}
.node text {
font-size: 12px;
fill: #333;
}
.link {
stroke: #666;
stroke-opacity: 0.8;
stroke-width: 2px;
}
.arrow {
fill: #666;
}
.title {
color: #333;
font-size: 20px;
margin-bottom: 20px;
}
</style>
.node text {
font-size: 12px;
}
.link {
stroke: #999;
stroke-opacity: 0.6;
stroke-width: 2px;
}
.arrow {
fill: #999;
stroke-opacity: 0.6;
}
.title {
font-size: 18px;
font-weight: bold;
margin-bottom: 20px;
}
</style>
</head>
<body>
<div class="title">SQL Data Lineage Visualization</div>
<div id="lineage"></div>
<script>
const data = {
nodes: [
{ id: "t_sys_loginperson", name: "t_sys_loginperson", columns: ["person_id", "person_name", "mz", "xb"] },
{ id: "t_dm_mz", name: "t_dm_mz", columns: ["mz_id", "mz_name"] },
{ id: "t_dm_xb", name: "t_dm_xb", columns: ["xb_id", "xb_name"] },
{ id: "result", name: "Result", columns: ["person_id", "person_name", "mz", "mz_name", "xb", "xb_name"] }
],
links: [
{ source: "t_sys_loginperson", target: "result", columns: ["person_id", "person_name", "mz", "xb"] },
{ source: "t_dm_mz", target: "result", columns: ["mz_name"], join: "t_sys_loginperson.mz = t_dm_mz.mz_id" },
{ source: "t_dm_xb", target: "result", columns: ["xb_name"], join: "t_sys_loginperson.xb = t_dm_xb.xb_id" }
]
};
const width = 800;
const height = 500;
const svg = d3.select("#lineage")
.append("svg")
.attr("width", width)
.attr("height", height);
const simulation = d3.forceSimulation(data.nodes)
.force("link", d3.forceLink(data.links).id(d => d.id).distance(150))
.force("charge", d3.forceManyBody().strength(-500))
.force("center", d3.forceCenter(width / 2, height / 2));
const link = svg.append("g")
.selectAll("line")
.data(data.links)
.enter().append("line")
.attr("class", "link")
.attr("marker-end", "url(#arrow)");
const node = svg.append("g")
.selectAll("g")
.data(data.nodes)
.enter().append("g")
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended));
node.append("rect")
.attr("width", d => Math.max(120, d.name.length * 8))
.attr("height", d => 40 + d.columns.length * 20)
.attr("rx", 5)
.attr("ry", 5);
node.append("text")
.attr("x", 10)
.attr("y", 20)
.attr("font-weight", "bold")
.text(d => d.name);
data.nodes.forEach(d => {
const columnGroup = node.append("g")
.attr("transform", `translate(10, 30)`);
d.columns.forEach((col, i) => {
columnGroup.append("text")
.attr("x", 0)
.attr("y", 20 + i * 20)
.text(col);
});
});
svg.append("defs").append("marker")
.attr("id", "arrow")
.attr("viewBox", "0 -5 10 10")
.attr("refX", 25)
.attr("refY", 0)
.attr("markerWidth", 6)
.attr("markerHeight", 6)
.attr("orient", "auto")
.append("path")
.attr("class", "arrow")
.attr("d", "M0,-5L10,0L0,5");
simulation.on("tick", () => {
link
.attr("x1", d => d.source.x)
.attr("y1", d => d.source.y)
.attr("x2", d => d.target.x)
.attr("y2", d => d.target.y);
node.attr("transform", d => `translate(${d.x - Math.max(120, d.name.length * 8) / 2},${d.y - (40 + d.columns.length * 20) / 2})`);
});
function dragstarted(event, d) {
if (!event.active) simulation.alphaTarget(0.3).restart();
d.fx = d.x;
d.fy = d.y;
}
function dragged(event, d) {
d.fx = event.x;
d.fy = event.y;
}
function dragended(event, d) {
if (!event.active) simulation.alphaTarget(0);
d.fx = null;
d.fy = null;
}
node.on("mouseover", function() {
d3.select(this).select("rect")
.style("fill", "#e6f7ff");
}).on("mouseout", function() {
d3.select(this).select("rect")
.style("fill", "#f8f8f8");
});
</script>
</body>
</html>

@ -8,7 +8,9 @@ import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONArray;
import com.jfinal.kit.PathKit;
import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
public class CallDeepSeek {
private static final String API_KEY = "sk-44ae895eeb614aa1a9c6460579e322f1"; // 请替换为您的API KEY
@ -19,8 +21,25 @@ public class CallDeepSeek {
StringBuilder fullResponse = new StringBuilder();
try {
// 修改提示词确保只返回HTML
String htmlPrompt = prompt + "请只返回HTML代码不要包含任何解释或Markdown格式。" +
"确保HTML是完整的包含<!DOCTYPE html>和<html>标签。";
String htmlPrompt = prompt + "请严格按照以下HTML模板格式输出SQL血缘关系图只返回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" +
" [请在此处插入mermaid格式的血缘关系图]\n" +
" </div>\n" +
" <script>mermaid.initialize({startOnLoad:true});</script>\n" +
"</body>\n" +
"</html>";
JSONObject json = new JSONObject();
json.set("model", "deepseek-chat");
@ -42,36 +61,45 @@ public class CallDeepSeek {
HttpResponse response = request.execute();
if (response.isOk()) {
String[] lines = response.body().split("\\r?\\n");
for (String line : lines) {
if (line.startsWith("data:")) {
String data = line.substring(5).trim();
if (!data.equals("[DONE]")) {
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);
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(response.bodyStream(), "UTF-8"))) {
String line;
while ((line = reader.readLine()) != null) {
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);
// 实时输出到控制台
System.out.print(content);
System.out.flush();
listener.onData(content);
}
}
} catch (Exception e) {
System.err.println("解析SSE数据错误: " + e.getMessage());
}
}
}
}
}
// 保存HTML到文件
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");
}
}
// 保存HTML到文件
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("API请求失败: " + response.getStatus());
listener.onError("返回内容不是有效的HTML");
}
} catch (Exception e) {
listener.onError(e.getMessage());
@ -81,7 +109,7 @@ public class CallDeepSeek {
public static void main(String[] args) {
String sql = FileUtil.readUtf8String(new File(PathKit.getRootClassPath()+"/XueYuan.sql"));
String prompt = "你是一个数据库SQL的血缘关系分析专家我将提供SQL语句给你帮我整理数据血缘关系并且绘制HTML页面以展示最终的可视化展现。";
String prompt = "你是一个数据库SQL的血缘关系分析专家我将提供SQL语句给你帮我整理数据血缘关系并且绘制HTML页面以展示最终的可视化形式展现。";
callDeepSeekStream(prompt + "\n" + sql, new SSEListener() {
@Override

Loading…
Cancel
Save