fix async model loading
This commit is contained in:
@@ -147,14 +147,19 @@ class AnnotationDashboard:
|
|||||||
if self.data_provider:
|
if self.data_provider:
|
||||||
self._enable_unified_storage_async()
|
self._enable_unified_storage_async()
|
||||||
|
|
||||||
# ANNOTATE doesn't need orchestrator - skip ML model loading for fast startup
|
# ANNOTATE doesn't need orchestrator immediately - load async for fast startup
|
||||||
self.orchestrator = None
|
self.orchestrator = None
|
||||||
|
self.models_loading = True
|
||||||
|
self.available_models = []
|
||||||
|
|
||||||
# Initialize ANNOTATE components
|
# Initialize ANNOTATE components
|
||||||
self.annotation_manager = AnnotationManager()
|
self.annotation_manager = AnnotationManager()
|
||||||
# Use REAL training adapter - NO SIMULATION!
|
# Use REAL training adapter - NO SIMULATION!
|
||||||
self.training_adapter = RealTrainingAdapter(None, self.data_provider)
|
self.training_adapter = RealTrainingAdapter(None, self.data_provider)
|
||||||
|
|
||||||
|
# Start async model loading in background
|
||||||
|
self._start_async_model_loading()
|
||||||
|
|
||||||
# Initialize data loader with existing DataProvider
|
# Initialize data loader with existing DataProvider
|
||||||
self.data_loader = HistoricalDataLoader(self.data_provider) if self.data_provider else None
|
self.data_loader = HistoricalDataLoader(self.data_provider) if self.data_provider else None
|
||||||
self.time_range_manager = TimeRangeManager(self.data_loader) if self.data_loader else None
|
self.time_range_manager = TimeRangeManager(self.data_loader) if self.data_loader else None
|
||||||
@@ -168,6 +173,60 @@ class AnnotationDashboard:
|
|||||||
|
|
||||||
logger.info("Annotation Dashboard initialized")
|
logger.info("Annotation Dashboard initialized")
|
||||||
|
|
||||||
|
def _start_async_model_loading(self):
|
||||||
|
"""Load ML models asynchronously in background thread"""
|
||||||
|
import threading
|
||||||
|
|
||||||
|
def load_models():
|
||||||
|
try:
|
||||||
|
logger.info("🔄 Starting async model loading...")
|
||||||
|
|
||||||
|
# Initialize orchestrator with models
|
||||||
|
if TradingOrchestrator:
|
||||||
|
self.orchestrator = TradingOrchestrator(
|
||||||
|
data_provider=self.data_provider,
|
||||||
|
enhanced_rl_training=True
|
||||||
|
)
|
||||||
|
|
||||||
|
# Initialize ML models
|
||||||
|
logger.info("Initializing ML models...")
|
||||||
|
self.orchestrator._initialize_ml_models()
|
||||||
|
|
||||||
|
# Update training adapter with orchestrator
|
||||||
|
self.training_adapter.orchestrator = self.orchestrator
|
||||||
|
|
||||||
|
# Get available models from orchestrator
|
||||||
|
available = []
|
||||||
|
if hasattr(self.orchestrator, 'rl_agent') and self.orchestrator.rl_agent:
|
||||||
|
available.append('DQN')
|
||||||
|
if hasattr(self.orchestrator, 'cnn_model') and self.orchestrator.cnn_model:
|
||||||
|
available.append('CNN')
|
||||||
|
if hasattr(self.orchestrator, 'transformer_model') and self.orchestrator.transformer_model:
|
||||||
|
available.append('Transformer')
|
||||||
|
|
||||||
|
self.available_models = available
|
||||||
|
|
||||||
|
if available:
|
||||||
|
logger.info(f"✅ Models loaded: {', '.join(available)}")
|
||||||
|
else:
|
||||||
|
logger.warning("⚠️ No models were initialized")
|
||||||
|
|
||||||
|
self.models_loading = False
|
||||||
|
logger.info("✅ Async model loading complete")
|
||||||
|
else:
|
||||||
|
logger.warning("⚠️ TradingOrchestrator not available")
|
||||||
|
self.models_loading = False
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"❌ Error loading models: {e}")
|
||||||
|
self.models_loading = False
|
||||||
|
self.available_models = []
|
||||||
|
|
||||||
|
# Start loading in background thread
|
||||||
|
thread = threading.Thread(target=load_models, daemon=True)
|
||||||
|
thread.start()
|
||||||
|
logger.info("🚀 Model loading started in background (UI remains responsive)")
|
||||||
|
|
||||||
def _enable_unified_storage_async(self):
|
def _enable_unified_storage_async(self):
|
||||||
"""Enable unified storage system in background thread"""
|
"""Enable unified storage system in background thread"""
|
||||||
def enable_storage():
|
def enable_storage():
|
||||||
@@ -967,21 +1026,33 @@ class AnnotationDashboard:
|
|||||||
|
|
||||||
@self.server.route('/api/available-models', methods=['GET'])
|
@self.server.route('/api/available-models', methods=['GET'])
|
||||||
def get_available_models():
|
def get_available_models():
|
||||||
"""Get list of available models"""
|
"""Get list of available models with loading status"""
|
||||||
try:
|
try:
|
||||||
if not self.training_adapter:
|
if not self.training_adapter:
|
||||||
return jsonify({
|
return jsonify({
|
||||||
'success': False,
|
'success': False,
|
||||||
|
'loading': False,
|
||||||
'error': {
|
'error': {
|
||||||
'code': 'TRAINING_UNAVAILABLE',
|
'code': 'TRAINING_UNAVAILABLE',
|
||||||
'message': 'Real training adapter not available'
|
'message': 'Real training adapter not available'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
# Check if models are still loading
|
||||||
|
if self.models_loading:
|
||||||
|
return jsonify({
|
||||||
|
'success': True,
|
||||||
|
'loading': True,
|
||||||
|
'models': [],
|
||||||
|
'message': 'Models are loading in background...'
|
||||||
|
})
|
||||||
|
|
||||||
|
# Models loaded - get the list
|
||||||
models = self.training_adapter.get_available_models()
|
models = self.training_adapter.get_available_models()
|
||||||
|
|
||||||
return jsonify({
|
return jsonify({
|
||||||
'success': True,
|
'success': True,
|
||||||
|
'loading': False,
|
||||||
'models': models
|
'models': models
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -989,6 +1060,7 @@ class AnnotationDashboard:
|
|||||||
logger.error(f"Error getting available models: {e}")
|
logger.error(f"Error getting available models: {e}")
|
||||||
return jsonify({
|
return jsonify({
|
||||||
'success': False,
|
'success': False,
|
||||||
|
'loading': False,
|
||||||
'error': {
|
'error': {
|
||||||
'code': 'MODEL_LIST_ERROR',
|
'code': 'MODEL_LIST_ERROR',
|
||||||
'message': str(e)
|
'message': str(e)
|
||||||
|
|||||||
@@ -27,10 +27,10 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
// Export annotations
|
// Export annotations
|
||||||
document.getElementById('export-annotations-btn').addEventListener('click', function() {
|
document.getElementById('export-annotations-btn').addEventListener('click', function () {
|
||||||
fetch('/api/export-annotations', {
|
fetch('/api/export-annotations', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {'Content-Type': 'application/json'},
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
symbol: appState.currentSymbol,
|
symbol: appState.currentSymbol,
|
||||||
format: 'json'
|
format: 'json'
|
||||||
@@ -54,7 +54,7 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Clear all annotations
|
// Clear all annotations
|
||||||
document.getElementById('clear-all-annotations-btn').addEventListener('click', function() {
|
document.getElementById('clear-all-annotations-btn').addEventListener('click', function () {
|
||||||
if (appState.annotations.length === 0) {
|
if (appState.annotations.length === 0) {
|
||||||
showError('No annotations to clear');
|
showError('No annotations to clear');
|
||||||
return;
|
return;
|
||||||
@@ -66,7 +66,7 @@
|
|||||||
|
|
||||||
fetch('/api/clear-all-annotations', {
|
fetch('/api/clear-all-annotations', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {'Content-Type': 'application/json'},
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
symbol: appState.currentSymbol
|
symbol: appState.currentSymbol
|
||||||
})
|
})
|
||||||
@@ -153,17 +153,17 @@
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
// Add event listeners
|
// Add event listeners
|
||||||
item.querySelector('.view-annotation-btn').addEventListener('click', function(e) {
|
item.querySelector('.view-annotation-btn').addEventListener('click', function (e) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
viewAnnotation(annotation);
|
viewAnnotation(annotation);
|
||||||
});
|
});
|
||||||
|
|
||||||
item.querySelector('.generate-testcase-btn').addEventListener('click', function(e) {
|
item.querySelector('.generate-testcase-btn').addEventListener('click', function (e) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
generateTestCase(annotation.annotation_id);
|
generateTestCase(annotation.annotation_id);
|
||||||
});
|
});
|
||||||
|
|
||||||
item.querySelector('.delete-annotation-btn').addEventListener('click', function(e) {
|
item.querySelector('.delete-annotation-btn').addEventListener('click', function (e) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
console.log('=== Delete annotation button clicked ===');
|
console.log('=== Delete annotation button clicked ===');
|
||||||
console.log('Annotation ID:', annotation.annotation_id);
|
console.log('Annotation ID:', annotation.annotation_id);
|
||||||
@@ -214,8 +214,8 @@
|
|||||||
function generateTestCase(annotationId) {
|
function generateTestCase(annotationId) {
|
||||||
fetch('/api/generate-test-case', {
|
fetch('/api/generate-test-case', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {'Content-Type': 'application/json'},
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({annotation_id: annotationId})
|
body: JSON.stringify({ annotation_id: annotationId })
|
||||||
})
|
})
|
||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then(data => {
|
.then(data => {
|
||||||
|
|||||||
@@ -102,32 +102,65 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
// Load available models on page load
|
// Load available models on page load with polling for async loading
|
||||||
|
let modelLoadingPollInterval = null;
|
||||||
|
|
||||||
function loadAvailableModels() {
|
function loadAvailableModels() {
|
||||||
fetch('/api/available-models')
|
fetch('/api/available-models')
|
||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then(data => {
|
.then(data => {
|
||||||
const modelSelect = document.getElementById('model-select');
|
const modelSelect = document.getElementById('model-select');
|
||||||
|
|
||||||
|
if (data.loading) {
|
||||||
|
// Models still loading - show loading message and poll
|
||||||
|
modelSelect.innerHTML = '<option value="">🔄 Loading models...</option>';
|
||||||
|
|
||||||
|
// Start polling if not already polling
|
||||||
|
if (!modelLoadingPollInterval) {
|
||||||
|
console.log('Models loading in background, will poll for completion...');
|
||||||
|
modelLoadingPollInterval = setInterval(loadAvailableModels, 2000); // Poll every 2 seconds
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Models loaded - stop polling
|
||||||
|
if (modelLoadingPollInterval) {
|
||||||
|
clearInterval(modelLoadingPollInterval);
|
||||||
|
modelLoadingPollInterval = null;
|
||||||
|
}
|
||||||
|
|
||||||
modelSelect.innerHTML = '';
|
modelSelect.innerHTML = '';
|
||||||
|
|
||||||
if (data.success && data.models.length > 0) {
|
if (data.success && data.models.length > 0) {
|
||||||
|
// Show success notification
|
||||||
|
if (window.showSuccess) {
|
||||||
|
window.showSuccess(`✅ ${data.models.length} models loaded and ready for training`);
|
||||||
|
}
|
||||||
|
|
||||||
data.models.forEach(model => {
|
data.models.forEach(model => {
|
||||||
const option = document.createElement('option');
|
const option = document.createElement('option');
|
||||||
option.value = model;
|
option.value = model;
|
||||||
option.textContent = model;
|
option.textContent = model;
|
||||||
modelSelect.appendChild(option);
|
modelSelect.appendChild(option);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
console.log(`✅ Models loaded: ${data.models.join(', ')}`);
|
||||||
} else {
|
} else {
|
||||||
const option = document.createElement('option');
|
const option = document.createElement('option');
|
||||||
option.value = '';
|
option.value = '';
|
||||||
option.textContent = 'No models available';
|
option.textContent = 'No models available';
|
||||||
modelSelect.appendChild(option);
|
modelSelect.appendChild(option);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
console.error('Error loading models:', error);
|
console.error('Error loading models:', error);
|
||||||
const modelSelect = document.getElementById('model-select');
|
const modelSelect = document.getElementById('model-select');
|
||||||
modelSelect.innerHTML = '<option value="">Error loading models</option>';
|
modelSelect.innerHTML = '<option value="">Error loading models</option>';
|
||||||
|
|
||||||
|
// Stop polling on error
|
||||||
|
if (modelLoadingPollInterval) {
|
||||||
|
clearInterval(modelLoadingPollInterval);
|
||||||
|
modelLoadingPollInterval = null;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user