Toggle navigation
Toggle navigation
This project
Loading...
Sign in
万朱浩
/
Venue-Ops
Go to a project
Toggle navigation
Projects
Groups
Snippets
Help
Toggle navigation pinning
Project
Activity
Repository
Pipelines
Graphs
Issues
0
Merge Requests
0
Wiki
Network
Create a new issue
Builds
Commits
Authored by
马一丁
2025-12-19 12:04:14 +0800
Browse Files
Options
Browse Files
Download
Email Patches
Plain Diff
Commit
b3b0ff1641c0f4e16fe09b1740d39ac5859514f3
b3b0ff16
1 parent
73da6ae7
Display GraphRAG on the front-end page
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
352 additions
and
0 deletions
templates/index.html
templates/index.html
View file @
b3b0ff1
...
...
@@ -8,6 +8,7 @@
<!-- PDF导出依赖 -->
<script
src=
"https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"
></script>
<script
src=
"https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"
></script>
<script
src=
"https://unpkg.com/vis-network/standalone/umd/vis-network.min.js"
></script>
<style>
*
{
margin
:
0
;
...
...
@@ -1485,6 +1486,91 @@
color
:
#666
;
font-size
:
14px
;
}
/* 知识图谱迷你面板 */
.graph-mini-panel
{
border
:
2px
solid
#000000
;
background-color
:
#f7f7f7
;
padding
:
10px
12px
;
width
:
280px
;
align-self
:
flex-start
;
display
:
none
;
box-shadow
:
4px
4px
0
#0000001
a
;
}
.graph-mini-panel.collapsed
.graph-mini-body
{
display
:
none
;
}
.graph-mini-header
{
display
:
flex
;
align-items
:
center
;
justify-content
:
space-between
;
gap
:
8px
;
margin-bottom
:
8px
;
}
.graph-mini-title
{
font-weight
:
bold
;
font-size
:
14px
;
}
.graph-mini-subtitle
{
font-size
:
12px
;
color
:
#555555
;
line-height
:
1.2
;
}
.graph-mini-actions
{
display
:
flex
;
gap
:
6px
;
}
.graph-mini-button
{
border
:
1px
solid
#000000
;
background-color
:
#ffffff
;
padding
:
6px
10px
;
cursor
:
pointer
;
font-size
:
12px
;
font-weight
:
bold
;
transition
:
background-color
0.2s
ease
,
color
0.2s
ease
;
}
.graph-mini-button
:hover
{
background-color
:
#000000
;
color
:
#ffffff
;
}
.graph-mini-body
{
position
:
relative
;
height
:
240px
;
width
:
240px
;
border
:
1px
dashed
#000000
;
background-color
:
#ffffff
;
overflow
:
hidden
;
}
.graph-mini-placeholder
{
position
:
absolute
;
inset
:
0
;
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
text-align
:
center
;
padding
:
8px
;
font-size
:
12px
;
color
:
#666666
;
}
.graph-mini-placeholder.error
{
color
:
#b42318
;
}
.graph-mini-canvas
{
height
:
100%
;
width
:
100%
;
display
:
none
;
}
</style>
<!-- PDF中文字体数据 (优化后的子集字体,包含6763个GB2312汉字) -->
...
...
@@ -1648,6 +1734,11 @@
let
customTemplate
=
''
;
// 存储用户上传的自定义模板内容
let
configValues
=
{};
let
configDirty
=
false
;
let
graphragEnabled
=
false
;
let
graphragSettingLoaded
=
false
;
let
graphMiniNetwork
=
null
;
let
graphMiniPreferredTaskId
=
null
;
let
graphMiniLoading
=
false
;
let
configAutoRefreshTimer
=
null
;
let
systemStarted
=
false
;
let
systemStarting
=
false
;
...
...
@@ -2038,6 +2129,30 @@
query
:
8503
};
function
syncGraphragFlag
(
config
)
{
if
(
!
config
||
!
Object
.
prototype
.
hasOwnProperty
.
call
(
config
,
'GRAPHRAG_ENABLED'
))
{
return
;
}
graphragEnabled
=
String
(
config
.
GRAPHRAG_ENABLED
).
toLowerCase
()
===
'true'
;
graphragSettingLoaded
=
true
;
}
async
function
ensureGraphragSetting
(
force
=
false
)
{
if
(
!
force
&&
graphragSettingLoaded
)
{
return
graphragEnabled
;
}
try
{
const
response
=
await
fetch
(
CONFIG_ENDPOINT
,
{
cache
:
'no-store'
});
const
data
=
await
response
.
json
();
if
(
data
&&
data
.
success
&&
data
.
config
)
{
syncGraphragFlag
(
data
.
config
);
}
}
catch
(
error
)
{
console
.
warn
(
'读取GraphRAG配置失败:'
,
error
);
}
return
graphragEnabled
;
}
const
configFieldGroups
=
[
{
title
:
'数据库连接'
,
...
...
@@ -2420,6 +2535,7 @@
throw
new
Error
(
data
.
message
||
'读取配置失败'
);
}
configValues
=
data
.
config
||
{};
syncGraphragFlag
(
configValues
);
renderConfigForm
(
configValues
);
configDirty
=
false
;
if
(
messageOverride
)
{
...
...
@@ -2713,6 +2829,7 @@
throw
new
Error
(
data
.
message
||
'保存失败'
);
}
configValues
=
data
.
config
||
{};
syncGraphragFlag
(
configValues
);
renderConfigForm
(
configValues
);
configDirty
=
false
;
if
(
silent
)
{
...
...
@@ -4765,6 +4882,24 @@ function getConsoleContainer() {
<!--
任务进度区域
-->
<
div
id
=
"taskProgressArea"
><
/div
>
<!--
知识图谱迷你预览(
GraphRAG
开启时显示)
-->
<
div
class
=
"graph-mini-panel"
id
=
"graphMiniPanel"
>
<
div
class
=
"graph-mini-header"
>
<
div
>
<
div
class
=
"graph-mini-title"
>
知识图谱
<
/div
>
<
div
class
=
"graph-mini-subtitle"
>
GraphRAG
生成概览
<
/div
>
<
/div
>
<
div
class
=
"graph-mini-actions"
>
<
button
class
=
"graph-mini-button"
id
=
"graphMiniRefresh"
title
=
"刷新知识图谱"
>
刷新
<
/button
>
<
button
class
=
"graph-mini-button"
id
=
"graphMiniToggle"
title
=
"折叠/展开"
>
折叠
<
/button
>
<
/div
>
<
/div
>
<
div
class
=
"graph-mini-body"
id
=
"graphMiniBody"
>
<
div
class
=
"graph-mini-placeholder"
id
=
"graphMiniPlaceholder"
>
等待图谱生成
...
<
/div
>
<
div
class
=
"graph-mini-canvas"
id
=
"graphMiniCanvas"
><
/div
>
<
/div
>
<
/div
>
<!--
报告预览区域
-->
<
div
class
=
"report-preview"
id
=
"reportPreview"
>
<
div
class
=
"report-loading"
>
...
...
@@ -4775,6 +4910,7 @@ function getConsoleContainer() {
reportContent
.
innerHTML
=
interfaceHTML
;
initializeReportControls
();
initializeGraphMiniPanel
(
statusData
);
resetReportStreamOutput
(
'等待新的Report任务启动...'
);
updateReportStreamStatus
(
'idle'
);
...
...
@@ -4806,6 +4942,215 @@ function getConsoleContainer() {
}
}
async
function
initializeGraphMiniPanel
(
statusData
)
{
const
panel
=
document
.
getElementById
(
'graphMiniPanel'
);
if
(
!
panel
)
return
;
const
enabled
=
await
ensureGraphragSetting
();
if
(
!
enabled
)
{
panel
.
style
.
display
=
'none'
;
return
;
}
panel
.
style
.
display
=
'block'
;
bindGraphMiniEvents
();
const
currentTaskId
=
statusData
&&
statusData
.
current_task
?
statusData
.
current_task
.
task_id
:
(
lastCompletedReportTask
?
lastCompletedReportTask
.
task_id
:
null
);
const
currentTaskStatus
=
statusData
&&
statusData
.
current_task
?
statusData
.
current_task
.
status
:
''
;
if
(
currentTaskId
)
{
graphMiniPreferredTaskId
=
currentTaskId
;
}
if
(
currentTaskStatus
===
'running'
)
{
setGraphMiniWaiting
(
currentTaskId
);
return
;
}
if
(
panel
.
classList
.
contains
(
'collapsed'
))
{
setGraphMiniPlaceholder
(
'展开以查看知识图谱'
);
return
;
}
refreshGraphMini
(
graphMiniPreferredTaskId
,
true
);
}
function
bindGraphMiniEvents
()
{
const
toggleBtn
=
document
.
getElementById
(
'graphMiniToggle'
);
const
refreshBtn
=
document
.
getElementById
(
'graphMiniRefresh'
);
if
(
toggleBtn
&&
!
toggleBtn
.
dataset
.
bound
)
{
toggleBtn
.
dataset
.
bound
=
'true'
;
toggleBtn
.
addEventListener
(
'click'
,
toggleGraphMiniPanel
);
}
if
(
refreshBtn
&&
!
refreshBtn
.
dataset
.
bound
)
{
refreshBtn
.
dataset
.
bound
=
'true'
;
refreshBtn
.
addEventListener
(
'click'
,
()
=>
refreshGraphMini
(
graphMiniPreferredTaskId
,
true
));
}
}
function
toggleGraphMiniPanel
()
{
const
panel
=
document
.
getElementById
(
'graphMiniPanel'
);
const
toggleBtn
=
document
.
getElementById
(
'graphMiniToggle'
);
if
(
!
panel
)
return
;
const
collapsed
=
panel
.
classList
.
toggle
(
'collapsed'
);
if
(
toggleBtn
)
{
toggleBtn
.
textContent
=
collapsed
?
'展开'
:
'折叠'
;
}
if
(
!
collapsed
)
{
refreshGraphMini
(
graphMiniPreferredTaskId
,
true
);
}
else
{
setGraphMiniPlaceholder
(
'已折叠,展开以查看知识图谱'
);
}
}
function
setGraphMiniPlaceholder
(
message
,
type
=
''
)
{
const
placeholder
=
document
.
getElementById
(
'graphMiniPlaceholder'
);
const
canvas
=
document
.
getElementById
(
'graphMiniCanvas'
);
if
(
!
placeholder
||
!
canvas
)
return
;
placeholder
.
textContent
=
message
||
''
;
if
(
type
===
'error'
)
{
placeholder
.
classList
.
add
(
'error'
);
}
else
{
placeholder
.
classList
.
remove
(
'error'
);
}
placeholder
.
style
.
display
=
'flex'
;
canvas
.
style
.
display
=
'none'
;
}
async
function
fetchGraphData
(
taskId
=
null
)
{
const
url
=
taskId
?
`
/
api
/
graph
/
$
{
taskId
}
`
:
'/api/graph/latest'
;
try
{
const
response
=
await
fetch
(
url
,
{
cache
:
'no-store'
});
const
data
=
await
response
.
json
();
if
(
!
response
.
ok
||
!
data
.
success
||
!
data
.
graph
)
{
return
null
;
}
return
data
;
}
catch
(
error
)
{
console
.
warn
(
'获取知识图谱失败:'
,
error
);
return
null
;
}
}
function
renderGraphMini
(
graph
)
{
const
canvas
=
document
.
getElementById
(
'graphMiniCanvas'
);
const
placeholder
=
document
.
getElementById
(
'graphMiniPlaceholder'
);
if
(
!
canvas
||
!
placeholder
)
return
;
if
(
!
(
window
.
vis
&&
window
.
vis
.
Network
))
{
setGraphMiniPlaceholder
(
'图谱组件未加载,请检查网络后重试'
,
'error'
);
return
;
}
const
nodes
=
new
vis
.
DataSet
((
graph
.
nodes
||
[]).
map
(
node
=>
({
id
:
node
.
id
,
label
:
node
.
label
||
node
.
id
,
group
:
node
.
group
||
node
.
type
,
title
:
node
.
title
||
''
,
size
:
12
})));
const
edges
=
new
vis
.
DataSet
((
graph
.
edges
||
[]).
map
(
edge
=>
({
from
:
edge
.
from
,
to
:
edge
.
to
,
label
:
edge
.
label
||
''
,
arrows
:
'to'
,
color
:
'#444444'
,
font
:
{
align
:
'top'
,
size
:
10
}
})));
const
options
=
{
height
:
'100%'
,
width
:
'100%'
,
interaction
:
{
hover
:
true
,
dragView
:
true
,
zoomView
:
true
},
nodes
:
{
shape
:
'dot'
,
borderWidth
:
1
,
font
:
{
size
:
12
},
scaling
:
{
min
:
8
,
max
:
18
}
},
edges
:
{
smooth
:
true
,
color
:
'#999999'
,
width
:
1
},
physics
:
{
stabilization
:
true
,
barnesHut
:
{
avoidOverlap
:
0.5
,
springLength
:
80
,
springConstant
:
0.02
}
}
};
if
(
graphMiniNetwork
)
{
graphMiniNetwork
.
destroy
();
}
placeholder
.
style
.
display
=
'none'
;
canvas
.
style
.
display
=
'block'
;
graphMiniNetwork
=
new
vis
.
Network
(
canvas
,
{
nodes
,
edges
},
options
);
const
fitOnce
=
()
=>
{
graphMiniNetwork
.
fit
({
animation
:
{
duration
:
300
,
easing
:
'easeInOutQuad'
}
});
graphMiniNetwork
.
off
(
'stabilizationIterationsDone'
,
fitOnce
);
};
graphMiniNetwork
.
on
(
'stabilizationIterationsDone'
,
fitOnce
);
}
async
function
refreshGraphMini
(
taskId
=
null
,
allowFallback
=
true
)
{
const
panel
=
document
.
getElementById
(
'graphMiniPanel'
);
if
(
!
panel
)
return
;
const
enabled
=
await
ensureGraphragSetting
();
if
(
!
enabled
)
{
panel
.
style
.
display
=
'none'
;
return
;
}
if
(
panel
.
classList
.
contains
(
'collapsed'
))
{
return
;
}
bindGraphMiniEvents
();
panel
.
style
.
display
=
'block'
;
if
(
taskId
)
{
graphMiniPreferredTaskId
=
taskId
;
}
if
(
graphMiniLoading
)
{
return
;
}
const
targetTaskId
=
taskId
||
graphMiniPreferredTaskId
||
(
lastCompletedReportTask
?
lastCompletedReportTask
.
task_id
:
null
);
setGraphMiniPlaceholder
(
'加载知识图谱...'
);
graphMiniLoading
=
true
;
try
{
let
data
=
await
fetchGraphData
(
targetTaskId
);
if
(
!
data
&&
allowFallback
&&
targetTaskId
)
{
data
=
await
fetchGraphData
(
null
);
}
if
(
data
&&
data
.
graph
)
{
renderGraphMini
(
data
.
graph
);
}
else
{
setGraphMiniPlaceholder
(
'暂未找到知识图谱,请稍后点击刷新重试'
,
'error'
);
}
}
finally
{
graphMiniLoading
=
false
;
}
}
function
setGraphMiniWaiting
(
taskId
)
{
graphMiniPreferredTaskId
=
taskId
||
graphMiniPreferredTaskId
;
ensureGraphragSetting
().
then
(
enabled
=>
{
if
(
!
enabled
)
return
;
const
panel
=
document
.
getElementById
(
'graphMiniPanel'
);
if
(
!
panel
)
return
;
panel
.
style
.
display
=
'block'
;
bindGraphMiniEvents
();
setGraphMiniPlaceholder
(
'等待图谱生成...'
);
});
}
function
initializeReportControls
()
{
const
generateButton
=
document
.
getElementById
(
'generateReportButton'
);
if
(
generateButton
&&
!
generateButton
.
dataset
.
bound
)
{
...
...
@@ -5203,6 +5548,7 @@ function getConsoleContainer() {
if
(
data
.
success
)
{
reportTaskId
=
data
.
task_id
;
showMessage
(
'报告生成已启动'
,
'success'
);
setGraphMiniWaiting
(
reportTaskId
);
// 更新任务状态显示
updateTaskProgressStatus
({
...
...
@@ -5292,6 +5638,8 @@ function getConsoleContainer() {
if
(
data
.
task
.
status
===
'completed'
)
{
stopProgressPolling
();
showMessage
(
'报告生成完成!'
,
'success'
);
graphMiniPreferredTaskId
=
data
.
task
.
task_id
;
refreshGraphMini
(
data
.
task
.
task_id
,
true
);
// 自动显示报告
viewReport
(
taskId
);
...
...
@@ -5581,11 +5929,13 @@ function getConsoleContainer() {
if
(
eventType
===
'status'
&&
task
)
{
if
(
task
.
status
===
'running'
)
{
resetReportLogsForNewTask
(
task
.
task_id
,
'收到流式状态事件,已重置日志'
);
setGraphMiniWaiting
(
task
.
task_id
);
}
updateTaskProgressStatus
(
task
);
reportTaskId
=
task
.
status
===
'running'
?
task
.
task_id
:
null
;
if
(
task
.
status
===
'completed'
)
{
lastCompletedReportTask
=
task
;
graphMiniPreferredTaskId
=
task
.
task_id
;
setGenerateButtonState
(
false
);
}
else
if
(
task
.
status
===
'running'
)
{
setGenerateButtonState
(
true
);
...
...
@@ -5677,6 +6027,8 @@ function getConsoleContainer() {
if
(
task
)
{
lastCompletedReportTask
=
task
;
updateDownloadButtonState
(
task
);
graphMiniPreferredTaskId
=
task
.
task_id
;
refreshGraphMini
(
task
.
task_id
,
true
);
}
if
(
eventData
.
task_id
&&
!
reportAutoPreviewLoaded
)
{
viewReport
(
eventData
.
task_id
);
...
...
Please
register
or
login
to post a comment