feat(web): 前端集成 LLM 预警推送与二次判断结果展示
This commit is contained in:
@@ -346,6 +346,9 @@ import {
|
|||||||
} from '@element-plus/icons-vue'
|
} from '@element-plus/icons-vue'
|
||||||
import { detectionApi } from '@/api/detection'
|
import { detectionApi } from '@/api/detection'
|
||||||
import DetectionConfig from './DetectionConfig.vue'
|
import DetectionConfig from './DetectionConfig.vue'
|
||||||
|
import { useAlertStore } from '@/stores/alertStore'
|
||||||
|
|
||||||
|
const alertStore = useAlertStore()
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
models: {
|
models: {
|
||||||
@@ -787,6 +790,23 @@ const handleFightVideoSuccess = (response) => {
|
|||||||
const detCount = response.data.stats?.total_detections || 0
|
const detCount = response.data.stats?.total_detections || 0
|
||||||
ElMessage.success(`检测完成:${detCount} 个目标,已提取 ${kfCount} 张关键帧`)
|
ElMessage.success(`检测完成:${detCount} 个目标,已提取 ${kfCount} 张关键帧`)
|
||||||
|
|
||||||
|
// MVP-3: 将 LLM 管道产出的预警推送到 AlertList
|
||||||
|
const frameResults = response.data.frame_results || []
|
||||||
|
let llmAlertCount = 0
|
||||||
|
for (const fr of frameResults) {
|
||||||
|
const alerts = fr.alert_events || []
|
||||||
|
for (const alert of alerts) {
|
||||||
|
alertStore.addAlert({
|
||||||
|
...alert,
|
||||||
|
llm_results: fr.llm_results || [],
|
||||||
|
})
|
||||||
|
llmAlertCount++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (llmAlertCount > 0) {
|
||||||
|
ElMessage.success(`LLM 二次判断完成,已生成 ${llmAlertCount} 条预警记录`)
|
||||||
|
}
|
||||||
|
|
||||||
// 如果后端提示编码不兼容,自动标记视频错误
|
// 如果后端提示编码不兼容,自动标记视频错误
|
||||||
if (response.data.video_codec_warning) {
|
if (response.data.video_codec_warning) {
|
||||||
console.warn('视频编码不兼容浏览器,将以关键帧形式展示')
|
console.warn('视频编码不兼容浏览器,将以关键帧形式展示')
|
||||||
|
|||||||
@@ -156,6 +156,28 @@
|
|||||||
<span v-if="det.track_id" class="track-id">#{{ det.track_id }}</span>
|
<span v-if="det.track_id" class="track-id">#{{ det.track_id }}</span>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- MVP-3: LLM 二次判断结果 -->
|
||||||
|
<div v-if="alert.llm_results && alert.llm_results.length > 0" class="llm-result">
|
||||||
|
<el-tag
|
||||||
|
:type="alert.llm_results[0].llm_confirmed ? 'success' : 'danger'"
|
||||||
|
effect="light"
|
||||||
|
round
|
||||||
|
size="small"
|
||||||
|
>
|
||||||
|
{{ alert.llm_results[0].llm_confirmed ? 'LLM确认' : 'LLM否决' }}
|
||||||
|
</el-tag>
|
||||||
|
<span class="llm-confidence">
|
||||||
|
LLM置信度: {{ ((alert.llm_results[0].llm_confidence || 0) * 100).toFixed(0) }}%
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
v-if="alert.llm_results[0].llm_reasoning"
|
||||||
|
class="llm-reasoning"
|
||||||
|
:title="alert.llm_results[0].llm_reasoning"
|
||||||
|
>
|
||||||
|
{{ alert.llm_results[0].llm_reasoning.slice(0, 50) }}...
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="alert-actions">
|
<div class="alert-actions">
|
||||||
@@ -534,6 +556,33 @@ onMounted(() => {
|
|||||||
opacity: 0.8;
|
opacity: 0.8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* MVP-3: LLM 二次判断结果样式 */
|
||||||
|
.llm-result {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
margin-top: 8px;
|
||||||
|
padding: 6px 10px;
|
||||||
|
background: rgba(99, 102, 241, 0.06);
|
||||||
|
border-left: 3px solid #818CF8;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.llm-confidence {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #A5B4FC;
|
||||||
|
}
|
||||||
|
|
||||||
|
.llm-reasoning {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #9CA3AF;
|
||||||
|
max-width: 200px;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
cursor: help;
|
||||||
|
}
|
||||||
|
|
||||||
.alert-actions {
|
.alert-actions {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|||||||
Reference in New Issue
Block a user