File size: 3,973 Bytes
ff50694
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
// Intel Summary Module - Mission intel generation and display
APP.ui.intel = {};

APP.ui.intel.setIntelStatus = function (kind, text) {
    const { $ } = APP.core.utils;
    const intelStamp = $("#intelStamp");
    const intelDot = $("#intelDot");

    if (!intelStamp || !intelDot) return;

    intelStamp.innerHTML = text;
    intelDot.className = "dot" + (kind === "warn" ? " warn" : (kind === "bad" ? " bad" : ""));
    intelDot.style.width = "7px";
    intelDot.style.height = "7px";
    intelDot.style.boxShadow = "none";
};

APP.ui.intel.setIntelThumb = function (i, dataUrl) {
    const { $ } = APP.core.utils;
    const thumbs = [$("#intelThumb0"), $("#intelThumb1"), $("#intelThumb2")];
    const img = thumbs[i];
    if (!img) return;
    img.src = dataUrl || "";
};

APP.ui.intel.resetIntelUI = function () {
    const { $ } = APP.core.utils;
    const intelSummaryBox = $("#intelSummaryBox");

    if (!intelSummaryBox) return;
    intelSummaryBox.innerHTML = 'Upload a video, then click <b>Reason</b> to generate an unbiased scene summary.';
    APP.ui.intel.setIntelStatus("warn", "Idle");
    APP.ui.intel.setIntelThumb(0, "");
    APP.ui.intel.setIntelThumb(1, "");
    APP.ui.intel.setIntelThumb(2, "");
};

// External hook for intel summary (can be replaced by user)
APP.ui.intel.externalIntel = async function (frames) {
    console.log("externalIntel called with", frames.length, "frames");
    return "Video processed. No external intel provider connected.";
};

APP.ui.intel.computeIntelSummary = async function () {
    const { state } = APP.core;
    const { $ } = APP.core.utils;
    const { log } = APP.ui.logging;

    const intelSummaryBox = $("#intelSummaryBox");
    const videoHidden = $("#videoHidden");
    const videoEngage = $("#videoEngage");

    if (!intelSummaryBox) return;
    if (!state.videoLoaded) {
        APP.ui.intel.resetIntelUI();
        return;
    }
    if (state.intelBusy) return;

    state.intelBusy = true;
    APP.ui.intel.setIntelStatus("warn", "Generating…");
    intelSummaryBox.textContent = "Sampling frames and running analysis…";

    try {
        const videoEl = videoHidden || videoEngage;
        const dur = videoEl ? (videoEl.duration || 0) : 0;
        const times = [0, dur ? dur * 0.33 : 1, dur ? dur * 0.66 : 2];
        const frames = [];

        for (let i = 0; i < times.length; i++) {
            await APP.core.video.seekTo(videoEl, times[i]);

            const canvas = document.createElement("canvas");
            canvas.width = 640;
            canvas.height = 360;
            const ctx = canvas.getContext("2d");
            ctx.drawImage(videoEl, 0, 0, canvas.width, canvas.height);
            const dataUrl = canvas.toDataURL("image/jpeg", 0.6);
            frames.push(dataUrl);

            try {
                APP.ui.intel.setIntelThumb(i, dataUrl);
            } catch (_) { }
        }

        const summary = await APP.ui.intel.externalIntel(frames);

        intelSummaryBox.textContent = summary;
        APP.ui.intel.setIntelStatus("good", `Updated · ${new Date().toLocaleTimeString()}`);
    } catch (err) {
        APP.ui.intel.setIntelStatus("bad", "Summary unavailable");
        intelSummaryBox.textContent = `Unable to generate summary: ${err.message}`;
        console.error(err);
    } finally {
        state.intelBusy = false;
    }
};

// Render mission context (if applicable)
APP.ui.intel.renderMissionContext = function () {
    const { state } = APP.core;
    const { $ } = APP.core.utils;

    const missionClassesEl = $("#missionClasses");
    const missionIdEl = $("#missionId");

    if (missionClassesEl) {
        if (state.hf.queries && state.hf.queries.length > 0) {
            missionClassesEl.textContent = state.hf.queries.join(", ");
        } else {
            missionClassesEl.textContent = "All objects (no filter)";
        }
    }

    if (missionIdEl) {
        missionIdEl.textContent = state.hf.missionId || "—";
    }
};