From 52fce1beee07f705e4183fb32e2c299533a61596 Mon Sep 17 00:00:00 2001 From: axel7083 <42176370+axel7083@users.noreply.github.com> Date: Fri, 19 Jan 2024 11:48:03 +0100 Subject: [PATCH] fix: moving utility methods out of the Studio API implementation Signed-off-by: axel7083 <42176370+axel7083@users.noreply.github.com> --- .../backend/src/managers/catalogManager.ts | 54 +++++++++++++++++++ packages/backend/src/studio-api-impl.ts | 54 ++++++------------- packages/backend/src/studio.ts | 15 +++++- 3 files changed, 82 insertions(+), 41 deletions(-) create mode 100644 packages/backend/src/managers/catalogManager.ts diff --git a/packages/backend/src/managers/catalogManager.ts b/packages/backend/src/managers/catalogManager.ts new file mode 100644 index 000000000..ef8bf68ab --- /dev/null +++ b/packages/backend/src/managers/catalogManager.ts @@ -0,0 +1,54 @@ +import type { Catalog } from '@shared/src/models/ICatalog'; +import path from 'node:path'; +import fs from 'node:fs'; +import defaultCatalog from '../ai.json'; +import { Category } from '@shared/src/models/ICategory'; +import { Recipe } from '@shared/src/models/IRecipe'; +import { ModelInfo } from '@shared/src/models/IModelInfo'; + +export class CatalogManager { + private catalog: Catalog; + + constructor(private appUserDirectory: string) { + // We start with an empty catalog, for the methods to work before the catalog is loaded + this.catalog = { + categories: [], + models: [], + recipes: [], + }; + } + + public getCategories(): Category[] { + return this.catalog.categories; + } + + public getModels(): ModelInfo[] { + return this.catalog.models; + } + public getRecipes(): Recipe[] { + return this.catalog.recipes; + } + + + async loadCatalog() { + const catalogPath = path.resolve(this.appUserDirectory, 'catalog.json'); + try { + if (!fs.existsSync(catalogPath)) { + this.setCatalog(defaultCatalog); + return; + } + // TODO(feloy): watch catalog file and update catalog with new content + const data = await fs.promises.readFile(catalogPath, 'utf-8'); + const cat = JSON.parse(data) as Catalog; + this.setCatalog(cat); + } catch (err: unknown) { + console.error('unable to read catalog file, reverting to default catalog', err); + this.setCatalog(defaultCatalog); + } + } + + setCatalog(newCatalog: Catalog) { + // TODO(feloy): send message to frontend with new catalog + this.catalog = newCatalog; + } +} diff --git a/packages/backend/src/studio-api-impl.ts b/packages/backend/src/studio-api-impl.ts index 754a22748..e978ff19c 100644 --- a/packages/backend/src/studio-api-impl.ts +++ b/packages/backend/src/studio-api-impl.ts @@ -15,47 +15,19 @@ import type { Catalog } from '@shared/src/models/ICatalog'; import * as path from 'node:path'; import * as fs from 'node:fs'; +import { CatalogManager } from './managers/catalogManager'; export const RECENT_CATEGORY_ID = 'recent-category'; export class StudioApiImpl implements StudioAPI { - private catalog: Catalog; constructor( private applicationManager: ApplicationManager, private recipeStatusRegistry: RecipeStatusRegistry, private taskRegistry: TaskRegistry, private playgroundManager: PlayGroundManager, - ) { - // We start with an empty catalog, for the methods to work before the catalog is loaded - this.catalog = { - categories: [], - models: [], - recipes: [], - }; - } - - async loadCatalog() { - const catalogPath = path.resolve(this.applicationManager.appUserDirectory, 'catalog.json'); - try { - if (!fs.existsSync(catalogPath)) { - this.setCatalog(defaultCatalog); - return; - } - // TODO(feloy): watch catalog file and update catalog with new content - const data = await fs.promises.readFile(catalogPath, 'utf-8'); - const cat = JSON.parse(data) as Catalog; - this.setCatalog(cat); - } catch (err: unknown) { - console.error('unable to read catalog file, reverting to default catalog', err); - this.setCatalog(defaultCatalog); - } - } - - setCatalog(newCatalog: Catalog) { - // TODO(feloy): send message to frontend with new catalog - this.catalog = newCatalog; - } + private catalogManager: CatalogManager, + ) {} async openURL(url: string): Promise { return await podmanDesktopApi.env.openExternal(podmanDesktopApi.Uri.parse(url)); @@ -74,23 +46,26 @@ export class StudioApiImpl implements StudioAPI { } async getCategories(): Promise { - return this.catalog.categories; + return this.catalogManager.getCategories(); } async getRecipesByCategory(categoryId: string): Promise { if (categoryId === RECENT_CATEGORY_ID) return this.getRecentRecipes(); - return this.catalog.recipes.filter(recipe => recipe.categories.includes(categoryId)); + // TODO: move logic to catalog manager + return this.catalogManager.getRecipes().filter(recipe => recipe.categories.includes(categoryId)); } async getRecipeById(recipeId: string): Promise { - const recipe = (this.catalog.recipes as Recipe[]).find(recipe => recipe.id === recipeId); + // TODO: move logic to catalog manager + const recipe = this.catalogManager.getRecipes().find(recipe => recipe.id === recipeId); if (recipe) return recipe; throw new Error('Not found'); } async getModelById(modelId: string): Promise { - const model = this.catalog.models.find(m => modelId === m.id); + // TODO: move logic to catalog manager + const model = this.catalogManager.getModels().find(m => modelId === m.id); if (!model) { throw new Error(`No model found having id ${modelId}`); } @@ -98,7 +73,8 @@ export class StudioApiImpl implements StudioAPI { } async getModelsByIds(ids: string[]): Promise { - return this.catalog.models.filter(m => ids.includes(m.id)) ?? []; + // TODO: move logic to catalog manager + return this.catalogManager.getModels().filter(m => ids.includes(m.id)) ?? []; } // eslint-disable-next-line @typescript-eslint/no-unused-vars @@ -107,9 +83,7 @@ export class StudioApiImpl implements StudioAPI { } async pullApplication(recipeId: string): Promise { - console.log('StudioApiImpl pullApplication', recipeId); const recipe: Recipe = await this.getRecipeById(recipeId); - console.log('StudioApiImpl recipe', recipe); // the user should have selected one model, we use the first one for the moment const modelId = recipe.models[0]; @@ -122,9 +96,10 @@ export class StudioApiImpl implements StudioAPI { } async getLocalModels(): Promise { + // TODO: move logic to catalog manager const local = this.applicationManager.getLocalModels(); const localIds = local.map(l => l.id); - return this.catalog.models.filter(m => localIds.includes(m.id)); + return this.catalogManager.getModels().filter(m => localIds.includes(m.id)); } async getTasksByLabel(label: string): Promise { @@ -143,6 +118,7 @@ export class StudioApiImpl implements StudioAPI { } askPlayground(modelId: string, prompt: string): Promise { + const localModelInfo = this.applicationManager.getLocalModels().filter(m => m.id === modelId); if (localModelInfo.length !== 1) { throw new Error('model not found'); diff --git a/packages/backend/src/studio.ts b/packages/backend/src/studio.ts index ce438cff1..7067dcfcd 100644 --- a/packages/backend/src/studio.ts +++ b/packages/backend/src/studio.ts @@ -27,6 +27,7 @@ import { RecipeStatusRegistry } from './registries/RecipeStatusRegistry'; import * as fs from 'node:fs'; import { TaskRegistry } from './registries/TaskRegistry'; import { PlayGroundManager } from './managers/playground'; +import { CatalogManager } from './managers/catalogManager'; export class Studio { readonly #extensionContext: ExtensionContext; @@ -36,6 +37,7 @@ export class Studio { rpcExtension: RpcExtension; studioApi: StudioApiImpl; playgroundManager: PlayGroundManager; + catalogManager: CatalogManager; constructor(readonly extensionContext: ExtensionContext) { this.#extensionContext = extensionContext; @@ -93,8 +95,17 @@ export class Studio { const recipeStatusRegistry = new RecipeStatusRegistry(taskRegistry); const applicationManager = new ApplicationManager(gitManager, recipeStatusRegistry, this.#extensionContext); this.playgroundManager = new PlayGroundManager(this.#panel.webview); - this.studioApi = new StudioApiImpl(applicationManager, recipeStatusRegistry, taskRegistry, this.playgroundManager); - await this.studioApi.loadCatalog(); + this.catalogManager = new CatalogManager(applicationManager.appUserDirectory); + this.studioApi = new StudioApiImpl( + applicationManager, + recipeStatusRegistry, + taskRegistry, + this.playgroundManager, + this.catalogManager + ); + + await this.catalogManager.loadCatalog(); + // Register the instance this.rpcExtension.registerInstance(StudioApiImpl, this.studioApi); }