From 523905ece6d99bf48a8952d39ced6a13f3b9a84e Mon Sep 17 00:00:00 2001 From: David Brazda Date: Fri, 8 Dec 2023 19:11:08 +0100 Subject: [PATCH] gui ml modal view --- v2realbot/main.py | 25 +++++++ v2realbot/static/index.html | 24 +++++++ v2realbot/static/js/ml.js | 69 +++++++++++++++++-- v2realbot/static/js/mytables.js | 2 + v2realbot/static/main.css | 25 ++++++- v2realbot/strategy/base.py | 2 +- .../indicators/custom/__init__.py | 4 +- .../indicators/custom/classes/__init__.py | 5 +- 8 files changed, 144 insertions(+), 12 deletions(-) diff --git a/v2realbot/main.py b/v2realbot/main.py index ac669e2..70f2821 100644 --- a/v2realbot/main.py +++ b/v2realbot/main.py @@ -37,6 +37,8 @@ from traceback import format_exc import v2realbot.reporting.analyzer as ci import shutil from starlette.responses import JSONResponse +import mlroom +import mlroom.utils.mlutils as ml #from async io import Queue, QueueEmpty # # install() @@ -841,6 +843,29 @@ def download_model(model_name: str): else: raise HTTPException(status_code=404, detail="Model not found.") +@app.get("/model/metadata/{model_name}", dependencies=[Depends(api_key_auth)]) +def get_metadata(model_name: str): + try: + model_instance = ml.load_model(file=model_name, directory=MODEL_DIR) + try: + metadata = model_instance.metadata + except Exception as e: + metadata = "No Metada" + str(e) + format_exc() + return metadata + except Exception as e: + raise HTTPException(status_code=404, detail="Model not found."+str(e) + format_exc()) + + # model_path = os.path.join(MODEL_DIR, model_name) + # if os.path.exists(model_path): + # # Example: Retrieve metadata from a file or generate it + # metadata = { + # "name": model_name, + # "size": os.path.getsize(model_path), + # "last_modified": os.path.getmtime(model_path), + # # ... other metadata fields ... + # } + + # Thread function to insert data from the queue into the database def insert_queue2db(): print("starting insert_queue2db thread") diff --git a/v2realbot/static/index.html b/v2realbot/static/index.html index f2f03e8..97451b3 100644 --- a/v2realbot/static/index.html +++ b/v2realbot/static/index.html @@ -798,6 +798,30 @@ + +
diff --git a/v2realbot/static/js/ml.js b/v2realbot/static/js/ml.js index fa756e9..cce5853 100644 --- a/v2realbot/static/js/ml.js +++ b/v2realbot/static/js/ml.js @@ -1,3 +1,8 @@ +//ML Model GUI section + +let model_editor_json +let model_editor_python + $(document).ready(function() { function fetchModels() { $.ajax({ @@ -14,7 +19,8 @@ $(document).ready(function() { const models = response.models; models.forEach(function(model) { $('#model-list').append(` -

${model} +

${model} + [🔍] [↓] [x]

@@ -24,7 +30,7 @@ $(document).ready(function() { } }, error: function(xhr, status, error) { - $('#model-list').html('An error occurred: ' + error); + $('#model-list').html('An error occurred: ' + error + xhr.responseText + status); } }); } @@ -40,7 +46,7 @@ $(document).ready(function() { fetchModels(); // Refresh the list after deletion }, error: function(xhr, status, error) { - alert('Error deleting model: ' + error); + alert('Error deleting model: ' + error + xhr.responseText + status); } }); } @@ -60,7 +66,7 @@ $(document).ready(function() { alert('Model uploaded successfully'); }, error: function(xhr, status, error) { - alert('Error uploading model: ' + error); + alert('Error uploading model: ' + error + xhr.responseText + status); } }); } @@ -86,11 +92,53 @@ $(document).ready(function() { a.remove(); }, error: function(xhr, status, error) { - alert('Error downloading model: ' + error); + alert('Error downloading model: ' + error + xhr.responseText + status); } }); - } + } + // Function to fetch metadata + function fetchMetadata(modelName) { + $.ajax({ + url: '/model/metadata/' + modelName, + type: 'GET', + beforeSend: function (xhr) { + xhr.setRequestHeader('X-API-Key', API_KEY); + }, + success: function(response) { + show_metadata(response, modelName) + }, + error: function(xhr, status, error) { + $('#metadata-container').html('Error fetching metadata: ' + error + xhr.responseText + status); + } + }); + } + + function show_metadata(response, name) { + // var formattedMetadata = '
cfg:' + JSON.stringify(response.cfg, null, 4) + '
'; + // formattedMetadata += '
arch_function:' + response.arch_function + '
'; + // $('#metadata-container').html(formattedMetadata); + //console.log(response) + console.log(JSON.stringify(response,null,4)) + $('#metadata_label').html(name); + + require(["vs/editor/editor.main"], () => { + model_editor_json = monaco.editor.create(document.getElementById('toml-editor-container'), { + value: response.cfg_toml, + language: 'toml', + theme: 'tomlTheme-dark', + automaticLayout: true, + readOnly: true + }); + model_editor_python = monaco.editor.create(document.getElementById('python-editor-container'), { + value: response.arch_function, + language: 'python', + theme: 'tomlTheme-dark', + automaticLayout: true, + readOnly: true + }); + }); + } // Fetch models on page load fetchModels(); @@ -119,6 +167,15 @@ $(document).ready(function() { uploadModel(formData); }); + // Event handler for the inspect icon + $('#model-list').on('click', '.inspect-model', function() { + if (model_editor_json) {model_editor_json.dispose()} + if (model_editor_python) {model_editor_python.dispose()} + const modelName = $(this).data('model'); + fetchMetadata(modelName); + window.$('#modelModal').modal('show'); + }); + //Handler to download the model $('#model-list').on('click', '.download-model', function() { const modelName = $(this).data('model'); diff --git a/v2realbot/static/js/mytables.js b/v2realbot/static/js/mytables.js index e652400..f106f8e 100644 --- a/v2realbot/static/js/mytables.js +++ b/v2realbot/static/js/mytables.js @@ -88,6 +88,8 @@ $(document).ready(function () { require(["vs/editor/editor.main"], () => { + monaco.languages.register({ id: 'python' }); + monaco.languages.register({ id: 'json' }); // Register the TOML language monaco.languages.register({ id: 'toml' }); diff --git a/v2realbot/static/main.css b/v2realbot/static/main.css index 7305161..54e2f20 100644 --- a/v2realbot/static/main.css +++ b/v2realbot/static/main.css @@ -49,15 +49,36 @@ } .scrollable-div { - width: 262px; + width: 328px; height: 143px; overflow-y: auto; border: 1px solid #585858; padding: 10px; } +/* #metadata-container { + overflow-y: auto; + height: 500px; +} */ + +#metadata-container { + display: flex; + flex-direction: column; + height: 100%; /* Adjust this as needed */ +} + +#toml-editor-container { + height: 60%; /* Adjust this as needed */ +} + +#python-editor-container { + height: 40%; /* Adjust this as needed */ + margin-top: 3rem; +} + + /* ... existing CSS ... */ -.download-model, .delete-model { +.download-model, .delete-model, .inspect-model { cursor: pointer; padding: 0 5px; } diff --git a/v2realbot/strategy/base.py b/v2realbot/strategy/base.py index 5abfa01..e7ac173 100644 --- a/v2realbot/strategy/base.py +++ b/v2realbot/strategy/base.py @@ -435,7 +435,7 @@ class Strategy: if self.signal_stop: print(current_thread().name, "Stopping signal - internal") break - if self.state.time is not None and self.state.time > self.state.today_market_close: + if self.state.time is not None and self.state.today_market_close is not None and self.state.time > self.state.today_market_close: print(current_thread().name, "MARKET CLOSE - Stopping signal - internal") break #check signals - external signal stops also batch diff --git a/v2realbot/strategyblocks/indicators/custom/__init__.py b/v2realbot/strategyblocks/indicators/custom/__init__.py index b71e431..2a56f22 100644 --- a/v2realbot/strategyblocks/indicators/custom/__init__.py +++ b/v2realbot/strategyblocks/indicators/custom/__init__.py @@ -1,8 +1,10 @@ import os # import importlib # from v2realbot.strategyblocks.indicators.custom.opengap import opengap +# Get the directory of the current file (__init__.py) +current_dir = os.path.dirname(os.path.abspath(__file__)) -for filename in os.listdir("v2realbot/strategyblocks/indicators/custom"): +for filename in os.listdir(current_dir): if filename.endswith(".py") and filename != "__init__.py": # __import__(filename[:-3]) __import__(f"v2realbot.strategyblocks.indicators.custom.{filename[:-3]}") diff --git a/v2realbot/strategyblocks/indicators/custom/classes/__init__.py b/v2realbot/strategyblocks/indicators/custom/classes/__init__.py index d9dccd9..bc637ea 100644 --- a/v2realbot/strategyblocks/indicators/custom/classes/__init__.py +++ b/v2realbot/strategyblocks/indicators/custom/classes/__init__.py @@ -1,8 +1,9 @@ # import os # # import importlib -# # from v2realbot.strategyblocks.indicators.custom.opengap import opengap +# Get the directory of the current file (__init__.py) +# current_dir = os.path.dirname(os.path.abspath(__file__)) -# for filename in os.listdir("v2realbot/strategyblocks/indicators/custom"): +# for filename in os.listdir(current_dir): # if filename.endswith(".py") and filename != "__init__.py": # # __import__(filename[:-3]) # __import__(f"v2realbot.strategyblocks.indicators.custom.{filename[:-3]}")