Files
Open-AutoGLM/dashboard/static/js/video-learning.js
let5sne.win10 5b3f214e20 Add Video Learning Agent for short video platforms
Features:
- VideoLearningAgent for automated video watching on Douyin/Kuaishou/TikTok
- Web dashboard UI for video learning sessions
- Real-time progress tracking with screenshot capture
- App detection using get_current_app() for accurate recording
- Session management with pause/resume/stop controls

Technical improvements:
- Simplified video detection logic using direct app detection
- Full base64 hash for sensitive screenshot change detection
- Immediate stop when target video count is reached
- Fixed circular import issues with ModelConfig

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-09 22:54:57 +08:00

201 lines
6.6 KiB
JavaScript

/**
* Video Learning Module for AutoGLM Dashboard
*
* This module provides UI and functionality for the Video Learning Agent,
* allowing users to watch and learn from short video platforms.
*/
const VideoLearningModule = {
// Current session state
currentSessionId: null,
currentSessionStatus: null,
videos: [],
isPolling: false,
// Create a new learning session
async createSession(deviceId, options = {}) {
const {
platform = 'douyin',
targetCount = 10,
category = null,
watchDuration = 3.0,
} = options;
try {
const response = await axios.post('/api/video-learning/sessions', {
device_id: deviceId,
platform: platform,
target_count: targetCount,
category: category,
watch_duration: watchDuration,
});
this.currentSessionId = response.data.session_id;
this.startPolling();
return response.data;
} catch (error) {
console.error('Error creating session:', error);
throw error;
}
},
// Start a session
async startSession(sessionId) {
try {
const response = await axios.post(`/api/video-learning/sessions/${sessionId}/start`);
return response.data;
} catch (error) {
console.error('Error starting session:', error);
throw error;
}
},
// Control a session (pause/resume/stop)
async controlSession(sessionId, action) {
try {
const response = await axios.post(`/api/video-learning/sessions/${sessionId}/control`, {
action: action,
});
return response.data;
} catch (error) {
console.error('Error controlling session:', error);
throw error;
}
},
// Get session status
async getSessionStatus(sessionId) {
try {
const response = await axios.get(`/api/video-learning/sessions/${sessionId}/status`);
this.currentSessionStatus = response.data;
return response.data;
} catch (error) {
console.error('Error getting session status:', error);
throw error;
}
},
// Get session videos
async getSessionVideos(sessionId) {
try {
const response = await axios.get(`/api/video-learning/sessions/${sessionId}/videos`);
this.videos = response.data;
return response.data;
} catch (error) {
console.error('Error getting session videos:', error);
throw error;
}
},
// List all active sessions
async listSessions() {
try {
const response = await axios.get('/api/video-learning/sessions');
return response.data;
} catch (error) {
console.error('Error listing sessions:', error);
throw error;
}
},
// Delete a session
async deleteSession(sessionId) {
try {
const response = await axios.delete(`/api/video-learning/sessions/${sessionId}`);
if (this.currentSessionId === sessionId) {
this.currentSessionId = null;
this.currentSessionStatus = null;
this.stopPolling();
}
return response.data;
} catch (error) {
console.error('Error deleting session:', error);
throw error;
}
},
// Start polling for session updates
startPolling(intervalMs = 1000) {
if (this.isPolling) return;
this.isPolling = true;
this.pollInterval = setInterval(async () => {
if (this.currentSessionId) {
try {
await this.getSessionStatus(this.currentSessionId);
await this.getSessionVideos(this.currentSessionId);
// Trigger custom event for UI updates
window.dispatchEvent(new CustomEvent('videoLearningUpdate', {
detail: {
sessionId: this.currentSessionId,
status: this.currentSessionStatus,
videos: this.videos,
}
}));
// Stop polling if session is complete, but do one final update
if (this.currentSessionStatus && !this.currentSessionStatus.is_active) {
console.log('[VideoLearning] Session completed, doing final update...');
// Do one final update to ensure we have the latest data
await this.getSessionStatus(this.currentSessionId);
await this.getSessionVideos(this.currentSessionId);
window.dispatchEvent(new CustomEvent('videoLearningUpdate', {
detail: {
sessionId: this.currentSessionId,
status: this.currentSessionStatus,
videos: this.videos,
}
}));
console.log('[VideoLearning] Final update complete, stopping poll');
this.stopPolling();
}
} catch (error) {
console.error('Error polling session status:', error);
// Don't stop polling on error, just log it
}
}
}, intervalMs);
console.log(`[VideoLearning] Started polling with ${intervalMs}ms interval`);
},
// Stop polling
stopPolling() {
if (this.pollInterval) {
clearInterval(this.pollInterval);
this.pollInterval = null;
console.log('[VideoLearning] Stopped polling');
}
this.isPolling = false;
},
// Format duration
formatDuration(seconds) {
if (seconds < 60) {
return `${seconds.toFixed(1)}s`;
}
const minutes = Math.floor(seconds / 60);
const remainingSeconds = seconds % 60;
return `${minutes}m ${remainingSeconds.toFixed(1)}s`;
},
// Format number with K/M suffix
formatNumber(num) {
if (num === null || num === undefined) return 'N/A';
if (num >= 1000000) {
return `${(num / 1000000).toFixed(1)}M`;
} else if (num >= 1000) {
return `${(num / 1000).toFixed(1)}K`;
}
return num.toString();
},
};
// Export for use in other modules
if (typeof module !== 'undefined' && module.exports) {
module.exports = VideoLearningModule;
}