From 55954ae38e13b712cdf7d746bea1a99145abf390 Mon Sep 17 00:00:00 2001 From: Kalki Date: Thu, 14 Sep 2023 18:02:43 +0530 Subject: [PATCH 01/12] Models Hosting 1 --- .../Content/Models/AddModelMarketPlace.js | 2 +- gui/pages/Content/Models/ModelDetails.js | 10 +++++++- gui/pages/Content/Models/ModelInfo.js | 24 ++++++++++++------- gui/pages/Content/Models/ModelReadMe.js | 15 ++++++++++++ gui/public/images/javascript_logo.svg | 9 +++++++ gui/public/images/python_logo.svg | 9 +++++++ 6 files changed, 59 insertions(+), 10 deletions(-) create mode 100644 gui/pages/Content/Models/ModelReadMe.js create mode 100644 gui/public/images/javascript_logo.svg create mode 100644 gui/public/images/python_logo.svg diff --git a/gui/pages/Content/Models/AddModelMarketPlace.js b/gui/pages/Content/Models/AddModelMarketPlace.js index 79981feef..a3dfe1dc2 100644 --- a/gui/pages/Content/Models/AddModelMarketPlace.js +++ b/gui/pages/Content/Models/AddModelMarketPlace.js @@ -111,7 +111,7 @@ export default function AddModelMarketPlace({ template, getModels, sendModelData } {templateData.provider === 'Hugging Face' &&
- error-icon + info-icon
In order to get the endpoint for this model, you will need to deploy it on your Replicate dashboard. Once you have deployed your model on Hugging Face, you will be able to access the endpoint through the Hugging Face dashboard. The endpoint is a URL that you can use to send requests to your model. +
} {selectedOption === 'metrics' && !isLoading && } - {selectedOption === 'details' && !isLoading && } + {selectedOption === 'details' && !isLoading && } + {selectedOption === 'readme' && !isLoading && } {isLoading &&
{loadingText}
} ) diff --git a/gui/pages/Content/Models/ModelInfo.js b/gui/pages/Content/Models/ModelInfo.js index 745aee8ef..02990e6be 100644 --- a/gui/pages/Content/Models/ModelInfo.js +++ b/gui/pages/Content/Models/ModelInfo.js @@ -1,30 +1,38 @@ import React, {useState, useEffect} from "react"; import Image from "next/image"; -export default function ModelInfo(modelDetails){ - const [modelData, setModelData] = useState(modelDetails?.modelDetails) +export default function ModelInfo({modelDetails, goToTab}){ + return(

+
+ info-icon +
+ Please follow the ReadMe provided to setup this model and start using it. + +
+
+ Installation Type
- {modelData === 'Marketplace' && marketplace_logo} - {modelData.type} + {modelDetails === 'Marketplace' && marketplace_logo} + {modelDetails.type}
Model Provider - {modelData.model_provider} + {modelDetails.model_provider} - {modelData.end_point &&
+ {modelDetails.end_point &&
Model Endpoint - {modelData.end_point} + {modelDetails.end_point}
} Token Limit - +
diff --git a/gui/pages/Content/Models/ModelReadMe.js b/gui/pages/Content/Models/ModelReadMe.js new file mode 100644 index 000000000..5eb573a96 --- /dev/null +++ b/gui/pages/Content/Models/ModelReadMe.js @@ -0,0 +1,15 @@ +import React, {useEffect, useState} from "react"; + +export default function ModelReadMe({modelDetails}) { + const [isLoading, setIsLoading] = useState(true) + const [loadingText, setLoadingText] = useState("Loading ReadMe"); + + return ( +
+
+
+
+ {isLoading &&
{loadingText}
} +
+ ) +} \ No newline at end of file diff --git a/gui/public/images/javascript_logo.svg b/gui/public/images/javascript_logo.svg new file mode 100644 index 000000000..649ae26ca --- /dev/null +++ b/gui/public/images/javascript_logo.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/gui/public/images/python_logo.svg b/gui/public/images/python_logo.svg new file mode 100644 index 000000000..ee2485763 --- /dev/null +++ b/gui/public/images/python_logo.svg @@ -0,0 +1,9 @@ + + + + + + + + + From fe42980f44ab47d904fc03fa6ab76d70447f32e4 Mon Sep 17 00:00:00 2001 From: Kalki Date: Thu, 14 Sep 2023 18:14:58 +0530 Subject: [PATCH 02/12] Models Hosting 2 --- gui/pages/Content/Models/ModelDetails.js | 2 +- gui/pages/Content/Models/ModelInfo.js | 1 - gui/pages/Content/Models/ModelReadMe.js | 1 - gui/pages/_app.css | 5 +++++ 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/gui/pages/Content/Models/ModelDetails.js b/gui/pages/Content/Models/ModelDetails.js index 48fa069e6..6fe711012 100644 --- a/gui/pages/Content/Models/ModelDetails.js +++ b/gui/pages/Content/Models/ModelDetails.js @@ -36,7 +36,7 @@ export default function ModelDetails({modelId, modelName}){ {!isLoading &&
{ modelDetails.name ? (modelDetails.name.split('/')[1] || modelDetails.name) : ""} {modelDetails.description} -
+
+
+ + +

{template.description} diff --git a/gui/pages/api/DashboardService.js b/gui/pages/api/DashboardService.js index c26330d25..6a60eb903 100644 --- a/gui/pages/api/DashboardService.js +++ b/gui/pages/api/DashboardService.js @@ -378,6 +378,10 @@ export const fetchMarketPlaceModel = () => { return api.get(`/models_controller/get/list`) } +export const deleteModel = (model_name) => { + return api.post(`/models_controller/delete_model`, { model: model_name }); +} + export const getToolMetrics = (toolName) => { return api.get(`analytics/tools/${toolName}/usage`) } diff --git a/superagi/controllers/models_controller.py b/superagi/controllers/models_controller.py index f3704d05c..1328b903e 100644 --- a/superagi/controllers/models_controller.py +++ b/superagi/controllers/models_controller.py @@ -27,9 +27,11 @@ class StoreModelRequest(BaseModel): type: str version: str + class ModelName (BaseModel): model: str + @router.post("/store_api_keys", status_code=200) async def store_api_keys(request: ValidateAPIKeyRequest, organisation=Depends(get_user_organisation)): try: @@ -102,6 +104,15 @@ async def fetch_data(request: ModelName, organisation=Depends(get_user_organisat raise HTTPException(status_code=500, detail="Internal Server Error") +@router.post("/delete_model", status_code=200) +async def delete_model(request: ModelName, organisation=Depends(get_user_organisation)): + try: + return Models.delete_model(db.session, organisation.id, request.model) + except Exception as e: + logging.error(f"Error Deleting Model: {str(e)}") + raise HTTPException(status_code=500, detail="Internal Server Error") + + @router.get("/get/list", status_code=200) def get_models_list(page: int = 0, organisation=Depends(get_user_organisation)): """ @@ -123,9 +134,9 @@ def get_models_list(page: int = 0, organisation=Depends(get_user_organisation)): @router.get("/marketplace/list/{page}", status_code=200) def get_marketplace_models_list(page: int = 0): - organisation_id = get_config("MARKETPLACE_ORGANISATION_ID") - if organisation_id is not None: - organisation_id = int(organisation_id) + organisation_id = 2 + # if organisation_id is not None: + # organisation_id = int(organisation_id) page_size = 16 query = db.session.query(Models).filter(Models.org_id == organisation_id) diff --git a/superagi/models/models.py b/superagi/models/models.py index 23832af0f..c5e072349 100644 --- a/superagi/models/models.py +++ b/superagi/models/models.py @@ -6,8 +6,8 @@ from superagi.helper.encyption_helper import decrypt_data import requests, logging -marketplace_url = "https://app.superagi.com/api" -# marketplace_url = "http://localhost:8001" +# marketplace_url = "https://app.superagi.com/api" +marketplace_url = "http://localhost:8001" class Models(DBBaseModel): @@ -73,6 +73,8 @@ def get_model_install_details(cls, session, marketplace_models, organisation_id, model_counts_dict = dict( session.query(Models.model_name, func.count(Models.org_id)).group_by(Models.model_name).all() ) + print("////////////////////////////////////") + print(model_counts_dict) installed_models_dict = {model.model_name: True for model in installed_models} for model in marketplace_models: @@ -80,7 +82,12 @@ def get_model_install_details(cls, session, marketplace_models, organisation_id, if type == ModelsTypes.MARKETPLACE.value: model["is_installed"] = False else: - model["is_installed"] = installed_models_dict.get(model["model_name"], False) + user_model = session.query(Models).filter(Models.model_name == model["model_name"], + Models.org_id == organisation_id).first() + if user_model.state == 'INSTALLED': + model["is_installed"] = True + else: + model["is_installed"] = False model["installs"] = model_counts_dict.get(model["model_name"], 0) model["provider"] = session.query(ModelsConfig).filter( ModelsConfig.id == model["model_provider_id"]).first().provider @@ -108,7 +115,8 @@ def fetch_model_tokens(cls, session, organisation_id) -> Dict[str, int]: return {"error": "Unexpected Error Occured"} @classmethod - def store_model_details(cls, session, organisation_id, model_name, description, end_point, model_provider_id, token_limit, type, version): + def store_model_details(cls, session, organisation_id, model_name, description, end_point, model_provider_id, + token_limit, type, version): from superagi.models.models_config import ModelsConfig if not model_name: return {"error": "Model Name is empty or undefined"} @@ -120,9 +128,20 @@ def store_model_details(cls, session, organisation_id, model_name, description, return {"error": "Token Limit is null or undefined or 0"} # Check if model_name already exists in the database - existing_model = session.query(Models).filter(Models.model_name == model_name, Models.org_id == organisation_id).first() - if existing_model: + existing_model = session.query(Models).filter(Models.model_name == model_name, + Models.org_id == organisation_id).first() + if existing_model and existing_model.state == 'INSTALLED': return {"error": "Model Name already exists"} + elif existing_model: + existing_model.description = description + existing_model.end_point = end_point + existing_model.token_limit = token_limit + existing_model.model_provider_id = model_provider_id + existing_model.type = type + existing_model.version = version + existing_model.state = 'INSTALLED' + session.commit() + return {"success": "Model Details updated successfully", "model_id": existing_model.id} # Get the provider of the model if type == 'Marketplace': @@ -188,7 +207,7 @@ def fetch_models(cls, session, organisation_id) -> Union[Dict[str, str], List[Di models = session.query(Models.id, Models.model_name, Models.description, ModelsConfig.provider).join( ModelsConfig, Models.model_provider_id == ModelsConfig.id).filter( - Models.org_id == organisation_id).all() + Models.org_id == organisation_id, Models.state == 'INSTALLED').all() result = [] for model in models: @@ -234,3 +253,18 @@ def fetch_model_details(cls, session, organisation_id, model_id: int) -> Dict[st except Exception as e: logging.error(f"Unexpected Error Occured: {e}") return {"error": "Unexpected Error Occured"} + + @classmethod + def delete_model(cls, session, organisation_id, model_name: str): + try: + model = (session.query(Models).filter(Models.model_name == model_name, Models.org_id == organisation_id) + .first()) + if model: + model.state = 'UNINSTALLED' + session.commit() + return {"success": "Model state changed to UNINSTALLED successfully"} + else: + return {"error": "Model not found"} + except Exception as e: + logging.error(f"Unexpected Error Occured: {e}") + return {"error": "Unexpected Error Occured"} From f9184363a12f2c1b98b37ad7e5f81127e60f3d81 Mon Sep 17 00:00:00 2001 From: Kalki Date: Mon, 18 Sep 2023 13:02:00 +0530 Subject: [PATCH 05/12] Models Uninstall 2 --- superagi/controllers/types/is_installed.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 superagi/controllers/types/is_installed.py diff --git a/superagi/controllers/types/is_installed.py b/superagi/controllers/types/is_installed.py new file mode 100644 index 000000000..d9c8adfa6 --- /dev/null +++ b/superagi/controllers/types/is_installed.py @@ -0,0 +1,15 @@ +from enum import Enum + +class IsInstalled(Enum): + INSTALLED = 'INSTALLED' + UNINSTALLED = 'UNINSTALLED' + + @classmethod + def get_install_state(cls, is_installed): + if is_installed is None: + raise ValueError("Queue status type cannot be None.") + is_installed = is_installed.upper() + + if is_installed in cls.__members__: + return cls[is_installed] + raise ValueError(f"{is_installed} is not a valid storage name.") \ No newline at end of file From ea23187650b1040af3a7b6e3dea8a7fe0f41a3aa Mon Sep 17 00:00:00 2001 From: Kalki Date: Mon, 18 Sep 2023 13:04:31 +0530 Subject: [PATCH 06/12] Models Uninstall 2 --- superagi/models/models.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/superagi/models/models.py b/superagi/models/models.py index c5e072349..73102e944 100644 --- a/superagi/models/models.py +++ b/superagi/models/models.py @@ -3,6 +3,7 @@ from typing import List, Dict, Union from superagi.models.base_model import DBBaseModel from superagi.controllers.types.models_types import ModelsTypes +from superagi.controllers.types.is_installed import IsInstalled from superagi.helper.encyption_helper import decrypt_data import requests, logging @@ -38,7 +39,7 @@ class Models(DBBaseModel): token_limit = Column(Integer, nullable=False) type = Column(String, nullable=False) version = Column(String, nullable=False) - state = Column(String, nullable=False, default='INSTALLED') + state = Column(String, nullable=False, default=IsInstalled.INSTALLED.value) org_id = Column(Integer, nullable=False) model_features = Column(String, nullable=False) @@ -73,8 +74,7 @@ def get_model_install_details(cls, session, marketplace_models, organisation_id, model_counts_dict = dict( session.query(Models.model_name, func.count(Models.org_id)).group_by(Models.model_name).all() ) - print("////////////////////////////////////") - print(model_counts_dict) + installed_models_dict = {model.model_name: True for model in installed_models} for model in marketplace_models: @@ -84,7 +84,7 @@ def get_model_install_details(cls, session, marketplace_models, organisation_id, else: user_model = session.query(Models).filter(Models.model_name == model["model_name"], Models.org_id == organisation_id).first() - if user_model.state == 'INSTALLED': + if user_model.state == IsInstalled.INSTALLED.value: model["is_installed"] = True else: model["is_installed"] = False @@ -130,7 +130,7 @@ def store_model_details(cls, session, organisation_id, model_name, description, # Check if model_name already exists in the database existing_model = session.query(Models).filter(Models.model_name == model_name, Models.org_id == organisation_id).first() - if existing_model and existing_model.state == 'INSTALLED': + if existing_model and existing_model.state == IsInstalled.INSTALLED.value: return {"error": "Model Name already exists"} elif existing_model: existing_model.description = description @@ -139,7 +139,7 @@ def store_model_details(cls, session, organisation_id, model_name, description, existing_model.model_provider_id = model_provider_id existing_model.type = type existing_model.version = version - existing_model.state = 'INSTALLED' + existing_model.state = IsInstalled.INSTALLED.value session.commit() return {"success": "Model Details updated successfully", "model_id": existing_model.id} @@ -207,7 +207,7 @@ def fetch_models(cls, session, organisation_id) -> Union[Dict[str, str], List[Di models = session.query(Models.id, Models.model_name, Models.description, ModelsConfig.provider).join( ModelsConfig, Models.model_provider_id == ModelsConfig.id).filter( - Models.org_id == organisation_id, Models.state == 'INSTALLED').all() + Models.org_id == organisation_id, Models.state == IsInstalled.INSTALLED.value).all() result = [] for model in models: @@ -260,9 +260,9 @@ def delete_model(cls, session, organisation_id, model_name: str): model = (session.query(Models).filter(Models.model_name == model_name, Models.org_id == organisation_id) .first()) if model: - model.state = 'UNINSTALLED' + model.state = IsInstalled.UNINSTALLED.value session.commit() - return {"success": "Model state changed to UNINSTALLED successfully"} + return {"success": "Model has been Successfully Uninstalled"} else: return {"error": "Model not found"} except Exception as e: From c33afe30e2da9f8f82469ffd28c65d60197e08dc Mon Sep 17 00:00:00 2001 From: Kalki Date: Mon, 18 Sep 2023 13:45:54 +0530 Subject: [PATCH 07/12] Models Uninstall Test --- tests/unit_tests/models/test_models.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tests/unit_tests/models/test_models.py b/tests/unit_tests/models/test_models.py index 3bdc43075..f2583da3b 100644 --- a/tests/unit_tests/models/test_models.py +++ b/tests/unit_tests/models/test_models.py @@ -3,6 +3,7 @@ import pytest from superagi.models.models import Models +from superagi.controllers.types.is_installed import IsInstalled @pytest.fixture def mock_session(): @@ -39,13 +40,14 @@ def test_repr_method_models(mock_session): model_type = "example_type" version = "v1.0" org_id = 1 + state = "INSTALLED" model_features = "example_model_feature" mock_session.query.return_value.filter_by.return_value.first.return_value = None # Act model = Models(model_name=model_name, end_point=end_point, model_provider_id=model_provider_id, token_limit=token_limit, - type=model_type, version=version, org_id=org_id, model_features=model_features) + type=model_type, version=version, state=state, org_id=org_id, model_features=model_features) model_repr = repr(model) # Assert @@ -54,6 +56,7 @@ def test_repr_method_models(mock_session): f"token_limit={token_limit}, " \ f"type={model_type}, " \ f"version={version}, " \ + f"state={state}, " \ f"org_id={org_id}, " \ f"model_features={model_features})" @@ -119,7 +122,9 @@ def test_fetch_model_tokens(mock_session): def test_store_model_details_when_model_exists(mock_session): # Arrange - mock_session.query.return_value.filter.return_value.first.return_value = MagicMock() + mock_existing_model = MagicMock() + mock_existing_model.state = IsInstalled.INSTALLED.value + mock_session.query.return_value.filter.return_value.first.return_value = mock_existing_model mock_session.add = MagicMock() # Act From 3e4158272ec4b7af2bbade12d4c58adcaf299a58 Mon Sep 17 00:00:00 2001 From: Kalki Date: Mon, 18 Sep 2023 13:51:34 +0530 Subject: [PATCH 08/12] Models Uninstall Test Cases --- .../controllers/test_models_controller.py | 11 +++++++++++ tests/unit_tests/models/test_models.py | 19 +++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/tests/unit_tests/controllers/test_models_controller.py b/tests/unit_tests/controllers/test_models_controller.py index 489cff636..dfa37b70e 100644 --- a/tests/unit_tests/controllers/test_models_controller.py +++ b/tests/unit_tests/controllers/test_models_controller.py @@ -100,3 +100,14 @@ def test_get_marketplace_models_list_success(mock_get_db): patch('superagi.helper.auth.db') as mock_auth_db: response = client.get("/models_controller/marketplace/list/0") assert response.status_code == 200 + + +@patch('superagi.controllers.models_controller.db') +def test_delete_model(mock_get_db): + request = { + "model": "model_name" + } + with patch('superagi.helper.auth.get_user_organisation') as mock_get_user_org, \ + patch('superagi.helper.auth.db') as mock_auth_db: + response = client.post("/models_controller/delete_model", json=request) + assert response.status_code == 200 diff --git a/tests/unit_tests/models/test_models.py b/tests/unit_tests/models/test_models.py index f2583da3b..a9ade6ec7 100644 --- a/tests/unit_tests/models/test_models.py +++ b/tests/unit_tests/models/test_models.py @@ -236,4 +236,23 @@ def test_fetch_model_details(mock_models_config, mock_session): "model_provider": "example_provider" } +@patch('superagi.models.models.Models') +def test_delete_model_when_model_exists(mock_session): + # Arrange + mock_existing_model = MagicMock() + mock_session.query.return_value.filter.return_value.first.return_value = mock_existing_model + mock_session.commit = MagicMock() + + # Act + response = Models.delete_model( + mock_session, + organisation_id=1, + model_name="example_model", + ) + + # Assert + assert response == {"success": "Model has been Successfully Uninstalled"} + assert mock_existing_model.state == IsInstalled.UNINSTALLED.value + mock_session.commit.assert_called_once() + From 7751381827da0ca4b9f0e6e07b54f03d79552cbe Mon Sep 17 00:00:00 2001 From: Kalki Date: Mon, 18 Sep 2023 14:29:50 +0530 Subject: [PATCH 09/12] Models Hosting --- ...9c23_create_models_readme_content_table.py | 38 +++++++++++++++++++ .../f35c9b59b5a6_auto_generated_migration.py | 24 ------------ superagi/models/readme_content.py | 31 +++++++++++++++ 3 files changed, 69 insertions(+), 24 deletions(-) create mode 100644 migrations/versions/7d4a89ef9c23_create_models_readme_content_table.py delete mode 100644 migrations/versions/f35c9b59b5a6_auto_generated_migration.py create mode 100644 superagi/models/readme_content.py diff --git a/migrations/versions/7d4a89ef9c23_create_models_readme_content_table.py b/migrations/versions/7d4a89ef9c23_create_models_readme_content_table.py new file mode 100644 index 000000000..757bb2137 --- /dev/null +++ b/migrations/versions/7d4a89ef9c23_create_models_readme_content_table.py @@ -0,0 +1,38 @@ +"""create models_readme_content table + +Revision ID: 7d4a89ef9c23 +Revises: f35c9b59b5a6 +Create Date: 2023-09-18 08:53:41.247571 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '7d4a89ef9c23' +down_revision = '661ec8a4c32e' +branch_labels = None +depends_on = None + + +def upgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.create_table('models_readme_content', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('content', sa.String(), nullable=False), + sa.Column('model_id', sa.Integer(), nullable=False), + sa.Column('org_id', sa.Integer(), nullable=False), + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.Column('updated_at', sa.DateTime(), nullable=True), + sa.PrimaryKeyConstraint('id') + ) + op.add_column('models', sa.Column('state', sa.String(), nullable=False, server_default='INSTALLED')) + # ### end Alembic commands ### + + +def downgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.drop_column('models', 'state') + op.drop_table('models_readme_content') + # ### end Alembic commands ### diff --git a/migrations/versions/f35c9b59b5a6_auto_generated_migration.py b/migrations/versions/f35c9b59b5a6_auto_generated_migration.py deleted file mode 100644 index 95f45ebc3..000000000 --- a/migrations/versions/f35c9b59b5a6_auto_generated_migration.py +++ /dev/null @@ -1,24 +0,0 @@ -"""auto-generated migration - -Revision ID: f35c9b59b5a6 -Revises: 661ec8a4c32e -Create Date: 2023-09-15 12:47:15.594246 - -""" -from alembic import op -import sqlalchemy as sa - - -# revision identifiers, used by Alembic. -revision = 'f35c9b59b5a6' -down_revision = '661ec8a4c32e' -branch_labels = None -depends_on = None - - -def upgrade() -> None: - op.add_column('models', sa.Column('state', sa.String(), nullable=False, server_default='INSTALLED')) - - -def downgrade() -> None: - op.drop_column('models', 'state') diff --git a/superagi/models/readme_content.py b/superagi/models/readme_content.py new file mode 100644 index 000000000..15f51ef81 --- /dev/null +++ b/superagi/models/readme_content.py @@ -0,0 +1,31 @@ +from superagi.models.base_model import DBBaseModel +from sqlalchemy.sql import func +from sqlalchemy import Column, Integer, String, and_ + + +class ReadmeContent(DBBaseModel): + """ + Represents a Readme Content record in the database + + Attributes: + id (Integer): The unique identifier of the event. + content (String): The HTML content to be displayed. + model_id (Integer): The unique identifier of the model from the Models table. + org_id (Integer): The ID of the organisation. + """ + + __tablename__ = 'models_readme_content' + + id = Column(Integer, primary_key=True) + content = Column(String, nullable=False) + model_id = Column(Integer, nullable=False) + org_id = Column(Integer, nullable=False) + + def __repr__(self): + """ + Represents a string representation of the Readme Content instance. + """ + + return f"ModelsReadmeContent(id={self.id}, content={self.content}, " \ + f"model_id={self.model_id}, org_id={self.org_id})" + From bad44cc85c7bd116250ecc88abe216db84a96ccf Mon Sep 17 00:00:00 2001 From: Kalki Date: Mon, 18 Sep 2023 16:57:26 +0530 Subject: [PATCH 10/12] Models Hosting --- gui/pages/api/DashboardService.js | 6 ++++- ...9c23_create_models_readme_content_table.py | 1 + superagi/controllers/models_controller.py | 10 ++++++++ superagi/models/readme_content.py | 24 ++++++++++++++++--- 4 files changed, 37 insertions(+), 4 deletions(-) diff --git a/gui/pages/api/DashboardService.js b/gui/pages/api/DashboardService.js index 6a60eb903..58bec8d4d 100644 --- a/gui/pages/api/DashboardService.js +++ b/gui/pages/api/DashboardService.js @@ -379,7 +379,11 @@ export const fetchMarketPlaceModel = () => { } export const deleteModel = (model_name) => { - return api.post(`/models_controller/delete_model`, { model: model_name }); + return api.post(`/models_controller/delete_model`, { model: model_name }) +} + +export const fetchModelReadme = (model_id) => { + return api.get(`/models_controller/fetch_model_readme/${model_id}`) } export const getToolMetrics = (toolName) => { diff --git a/migrations/versions/7d4a89ef9c23_create_models_readme_content_table.py b/migrations/versions/7d4a89ef9c23_create_models_readme_content_table.py index 757bb2137..78847dfa2 100644 --- a/migrations/versions/7d4a89ef9c23_create_models_readme_content_table.py +++ b/migrations/versions/7d4a89ef9c23_create_models_readme_content_table.py @@ -22,6 +22,7 @@ def upgrade() -> None: sa.Column('id', sa.Integer(), nullable=False), sa.Column('content', sa.String(), nullable=False), sa.Column('model_id', sa.Integer(), nullable=False), + sa.Column('code_language', sa.String(), nullable=False), sa.Column('org_id', sa.Integer(), nullable=False), sa.Column('created_at', sa.DateTime(), nullable=True), sa.Column('updated_at', sa.DateTime(), nullable=True), diff --git a/superagi/controllers/models_controller.py b/superagi/controllers/models_controller.py index 1328b903e..543a222b6 100644 --- a/superagi/controllers/models_controller.py +++ b/superagi/controllers/models_controller.py @@ -2,6 +2,7 @@ from superagi.helper.auth import check_auth, get_user_organisation from superagi.helper.models_helper import ModelsHelper from superagi.apm.call_log_helper import CallLogHelper +from superagi.models.readme_content import ReadmeContent from superagi.models.models import Models from superagi.models.models_config import ModelsConfig from superagi.config.config import get_config @@ -113,6 +114,15 @@ async def delete_model(request: ModelName, organisation=Depends(get_user_organis raise HTTPException(status_code=500, detail="Internal Server Error") +@router.get("/fetch_model_readme/{model_id}", status_code=200) +async def model_readme(model_id: int, organisation=Depends(get_user_organisation)): + try: + return ReadmeContent.fetch_model_readme(db.session, organisation.id, model_id) + except Exception as e: + logging.error(f"Error Fetching the Model Readme: {str(e)}") + raise HTTPException(status_code=500, detail="Internal Server Error") + + @router.get("/get/list", status_code=200) def get_models_list(page: int = 0, organisation=Depends(get_user_organisation)): """ diff --git a/superagi/models/readme_content.py b/superagi/models/readme_content.py index 15f51ef81..1acc39616 100644 --- a/superagi/models/readme_content.py +++ b/superagi/models/readme_content.py @@ -1,7 +1,7 @@ from superagi.models.base_model import DBBaseModel from sqlalchemy.sql import func from sqlalchemy import Column, Integer, String, and_ - +import logging class ReadmeContent(DBBaseModel): """ @@ -11,6 +11,7 @@ class ReadmeContent(DBBaseModel): id (Integer): The unique identifier of the event. content (String): The HTML content to be displayed. model_id (Integer): The unique identifier of the model from the Models table. + code_language (String): The language used of the code snippets. org_id (Integer): The ID of the organisation. """ @@ -19,6 +20,7 @@ class ReadmeContent(DBBaseModel): id = Column(Integer, primary_key=True) content = Column(String, nullable=False) model_id = Column(Integer, nullable=False) + code_language = Column(String, nullable=False) org_id = Column(Integer, nullable=False) def __repr__(self): @@ -27,5 +29,21 @@ def __repr__(self): """ return f"ModelsReadmeContent(id={self.id}, content={self.content}, " \ - f"model_id={self.model_id}, org_id={self.org_id})" - + f"model_id={self.model_id}, code_language={self.code_language}, org_id={self.org_id})" + + @classmethod + def fetch_model_readme(cls, session, organisation_id, model_id): + try: + readmes = session.query(ReadmeContent).filter(ReadmeContent.model_id == model_id, + ReadmeContent.org_id == organisation_id).all() + if readmes: + return [{'model_id': readme.model_id, + 'org_id': readme.org_id, + 'content': readme.content, + 'language': readme.code_language, + } for readme in readmes] + else: + return {"error": "Readme not found"} + except Exception as e: + logging.error(f"Unexpected Error Occured: {e}") + return {"error": "Unexpected Error Occured"} \ No newline at end of file From ec104d5a919f28f6879b3713f39532fa8f8eb268 Mon Sep 17 00:00:00 2001 From: Kalki Date: Mon, 18 Sep 2023 18:22:41 +0530 Subject: [PATCH 11/12] Models Hosting --- gui/pages/Content/Models/ModelDetails.js | 3 +- gui/pages/Content/Models/ModelReadMe.js | 40 +++++++++++++++++++++--- gui/pages/_app.css | 23 ++++++++++++++ 3 files changed, 60 insertions(+), 6 deletions(-) diff --git a/gui/pages/Content/Models/ModelDetails.js b/gui/pages/Content/Models/ModelDetails.js index 6fe711012..71ffa8520 100644 --- a/gui/pages/Content/Models/ModelDetails.js +++ b/gui/pages/Content/Models/ModelDetails.js @@ -1,5 +1,4 @@ import React, {useState, useEffect} from "react"; -import Image from "next/image"; import ModelMetrics from "./ModelMetrics"; import ModelInfo from "./ModelInfo"; import ModelReadMe from "./ModelReadMe"; @@ -10,7 +9,7 @@ export default function ModelDetails({modelId, modelName}){ const [modelDetails, setModelDetails] = useState([]) const [selectedOption, setSelectedOption] = useState('metrics') const [isLoading, setIsLoading] = useState(true) - const [loadingText, setLoadingText] = useState("Loading Models"); + const [loadingText, setLoadingText] = useState("Loading Models") useEffect(() => { loadingTextEffect('Loading Models', setLoadingText, 500); diff --git a/gui/pages/Content/Models/ModelReadMe.js b/gui/pages/Content/Models/ModelReadMe.js index 879d696d6..c52314fcd 100644 --- a/gui/pages/Content/Models/ModelReadMe.js +++ b/gui/pages/Content/Models/ModelReadMe.js @@ -1,14 +1,46 @@ import React, {useEffect, useState} from "react"; +import {fetchModelReadme} from "@/pages/api/DashboardService"; +import Image from "next/image"; export default function ModelReadMe({modelDetails}) { const [isLoading, setIsLoading] = useState(true) - const [loadingText, setLoadingText] = useState("Loading ReadMe"); + const [loadingText, setLoadingText] = useState("Loading ReadMe") + const [readmeContent, setReadmeContent] = useState(null) + const [contentType, setContentType] = useState("python") + const [allReadmeContent, setAllReadmeContent] = useState(null) + + useEffect(() => { + fetchAllReadmeContent().then().catch() + }, []) + + async function fetchAllReadmeContent() { + const response = await fetchModelReadme(modelDetails.id); + if(response) { + setAllReadmeContent(response.data); + filterReadmeContent(response.data); + } + } + + function filterReadmeContent(data) { + const filteredData = data.filter(item => item.language === contentType); + setReadmeContent(filteredData); + } + + async function handleSelection(code_language) { + setContentType(code_language) + filterReadmeContent(allReadmeContent) + } return ( -
-
+
+
+ +
- {isLoading &&
{loadingText}
} + {readmeContent &&
} + {/*{isLoading &&
{loadingText}
}*/}
) } \ No newline at end of file diff --git a/gui/pages/_app.css b/gui/pages/_app.css index 652c65dfd..9ff80f003 100644 --- a/gui/pages/_app.css +++ b/gui/pages/_app.css @@ -1894,3 +1894,26 @@ tr{ } + + +/*----------------------------------------------------------------------------------*/ + +.public_sans { + font-family: Public Sans, sans-serif; + font-style: normal; + line-height: 16px; +} +.text_18 {font-size: 18px;} +.code_box { + display: flex; + padding: 16px 8px; + align-items: flex-start; + gap: 10px; + align-self: stretch; + border: 1px solid rgba(255, 255, 255, 0.10); + background: rgba(255, 255, 255, 0.04); + font-family: Space Mono, monospace; + line-height: 16px; + font-style: normal; +} + From 9b8adf48a026dd5eb2ff0279d6545497322d4f72 Mon Sep 17 00:00:00 2001 From: Kalki Date: Tue, 19 Sep 2023 16:56:55 +0530 Subject: [PATCH 12/12] Conflicts with the dev branch have been resolved --- .../versions/7d4a89ef9c23_create_models_readme_content_table.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/migrations/versions/7d4a89ef9c23_create_models_readme_content_table.py b/migrations/versions/7d4a89ef9c23_create_models_readme_content_table.py index 78847dfa2..108fd0695 100644 --- a/migrations/versions/7d4a89ef9c23_create_models_readme_content_table.py +++ b/migrations/versions/7d4a89ef9c23_create_models_readme_content_table.py @@ -11,7 +11,7 @@ # revision identifiers, used by Alembic. revision = '7d4a89ef9c23' -down_revision = '661ec8a4c32e' +down_revision = '3867bb00a495' branch_labels = None depends_on = None