diff --git a/docs/.vitepress/theme/components/price-estimator/LabCard.vue b/docs/.vitepress/theme/components/price-estimator/LabCard.vue index b7d9ed602a..02b17f1aef 100644 --- a/docs/.vitepress/theme/components/price-estimator/LabCard.vue +++ b/docs/.vitepress/theme/components/price-estimator/LabCard.vue @@ -21,6 +21,7 @@ const computeHeaders = ref([ { title: "CPU cores", align: "start", sortable: true, key: "core_count" }, { title: "Memory [GB]", align: "start", sortable: true, key: "ram" }, { title: "GPU", align: "start", sortable: true, key: "gpu" }, + { title: "GPU count", align: "start", sortable: true, key: "gpu_count" }, { title: "Subscription", align: "start", sortable: true, key: "subscription" }, { title: "Price / month", align: "start", sortable: true, key: "monthlyPrice" }, { title: "Price / year", align: "start", sortable: true, key: "yearlyPrice" }, diff --git a/docs/.vitepress/theme/components/price-estimator/MachineModal.vue b/docs/.vitepress/theme/components/price-estimator/MachineModal.vue index 32241bf317..7539fb2a4c 100644 --- a/docs/.vitepress/theme/components/price-estimator/MachineModal.vue +++ b/docs/.vitepress/theme/components/price-estimator/MachineModal.vue @@ -20,6 +20,7 @@ const formData = ref({ name: undefined, machine_type: undefined, gpu: undefined, + gpu_count: 1, subscription: undefined, }) @@ -62,11 +63,15 @@ const getComputePriceMonth = computed((): string | number => { }) const getGpuPriceYear = computed((): string | number => { - if (!formData.value.gpu) { + const gpu = formData.value.gpu + const gpuCount = formData.value.gpu_count + + if (!gpu || !gpuCount) { return 0 } - const price = priceEstimatorStore.catalogue.gpuPrices.find((item: PriceListItem) => item["service.unit"] === formData.value.gpu && item["service.level"] === "ONDEMAND") - return price ? Number(price["price.nok.ex.vat"]).toFixed(2) : 0 + const price = priceEstimatorStore.catalogue.gpuPrices.find((item: PriceListItem) => item["service.unit"] === gpu && item["service.level"] === "ONDEMAND") + + return price ? (Number(price["price.nok.ex.vat"]) * gpuCount).toFixed(2) : 0 }) const getGpuPriceMonth = computed((): string | number => { @@ -90,6 +95,21 @@ const getGpus = computed(() => { }) }) +const gpuCount = computed({ + get: () => (formData.value.gpu ? formData.value.gpu_count : undefined), + set: (val) => { + if (formData.value.gpu) formData.value.gpu_count = val + }, +}) + +const getMaxGpuCount = computed((): number => { + if (!formData.value.gpu) return 1 + + const selectedGpu = priceEstimatorStore.catalogue.availableGpus.find((item: GpuModel) => item["type"] === formData.value.gpu) + + return selectedGpu?.max ?? 1 +}) + const close = () => { emit("close") } @@ -110,6 +130,10 @@ const save = () => { const machineWithGpu = formData.value.machine_type const subscription = formData.value.subscription const gpu = formData.value.gpu + var gpuCount + if (gpu) { + gpuCount = formData.value.gpu_count + } if (props.editData) { priceEstimatorStore.editComputeInLab(props.labId, props.editData.id, { @@ -119,6 +143,7 @@ const save = () => { ram: ram, subscription: subscription!, gpu: gpu, + gpuCount: gpuCount, }) } else { // Add new compute @@ -129,6 +154,7 @@ const save = () => { ram: ram, subscription: subscription!, gpu: gpu, + gpu_count: gpuCount, }) } @@ -148,6 +174,7 @@ onMounted(() => { } else { formData.value.machine_type = props.editData.machine_type formData.value.gpu = props.editData.gpu + formData.value.gpu_count = props.editData.gpu_count } } else { formData.value.id = props.computeId @@ -197,6 +224,9 @@ onMounted(() => { + + + diff --git a/docs/.vitepress/theme/components/price-estimator/api/pricesApi.js b/docs/.vitepress/theme/components/price-estimator/api/pricesApi.js index be3e776214..ae0c97a974 100644 --- a/docs/.vitepress/theme/components/price-estimator/api/pricesApi.js +++ b/docs/.vitepress/theme/components/price-estimator/api/pricesApi.js @@ -11,7 +11,6 @@ export default { async getPriceList() { try { const res = await axios.get(price_list_url) - // console.log("Fetched price list:", res.data) return res.data } catch (error) { console.error("Error fetching price list:", error) diff --git a/docs/.vitepress/theme/components/price-estimator/stores/priceEstimatorStore.ts b/docs/.vitepress/theme/components/price-estimator/stores/priceEstimatorStore.ts index 1d37b54d0c..1ee2405910 100644 --- a/docs/.vitepress/theme/components/price-estimator/stores/priceEstimatorStore.ts +++ b/docs/.vitepress/theme/components/price-estimator/stores/priceEstimatorStore.ts @@ -72,6 +72,7 @@ export const priceEstimatorStore = reactive({ ram: comp.ram, subscription: comp.subscription, gpu: comp.gpu, + gpu_count: comp.gpu_count, }) } } @@ -109,11 +110,18 @@ export const priceEstimatorStore = reactive({ const priceListPromise = pricesApi.getPriceList().then((json: PriceListItem[]) => { this.catalogue.computePrices = json.filter((item) => item["service.group"] === "cpu").map(this.convertPricesToYearly) this.catalogue.storagePrices = json.filter((item) => item["service.family"] === "store") - this.catalogue.gpuPrices = json.filter((item) => item["service.group"] === "gpu").map(this.convertPricesToYearly) + this.catalogue.gpuPrices = json + .filter((item) => item["service.group"] === "gpu") + .map((item) => ({ ...item, "service.unit": item["service.unit"]?.replace("nvidia.", "") })) + .map(this.convertPricesToYearly) this.catalogue.labPrices = json.filter((item) => item["service.group"] === "lab") }) const gpusPromise = pricesApi.getAvailableGPUS().then((gpus: GpuModel[]) => { + gpus = gpus.map((item) => ({ + ...item, + type: item.type.replace("nvidia.", ""), + })) this.catalogue.availableGpus = gpus }) @@ -412,7 +420,7 @@ export const priceEstimatorStore = reactive({ /* Compute helpers */ - getComputePriceFromCatalogue(machineType: string, type: string, machineWithGpu?: string) { + getComputePriceFromCatalogue(machineType: string, type: string, machineWithGpu?: string, gpuCount: number = 1) { let totalYearlyPrice = 0 let totalMonthlyPrice = 0 let mainMachineTypePrice: number | undefined @@ -443,7 +451,7 @@ export const priceEstimatorStore = reactive({ if (machineWithGpu) { const gpuPrice = this.catalogue.gpuPrices.find((p) => p["service.unit"] === machineWithGpu && p["service.level"] === "ONDEMAND") if (gpuPrice) { - gpuYearly = gpuPrice["price.nok.ex.vat"] + gpuYearly = gpuPrice["price.nok.ex.vat"] * gpuCount totalYearlyPrice += gpuYearly totalMonthlyPrice = totalMonthlyPrice + Number(gpuYearly / 12) } @@ -454,18 +462,19 @@ export const priceEstimatorStore = reactive({ } }, - addComputeToLab(labId: number, payload: { name: string; machine_type: string; core_count: number; ram: number; subscription: string; gpu?: string }) { + addComputeToLab(labId: number, payload: { name: string; machine_type: string; core_count: number; ram: number; subscription: string; gpu?: string; gpu_count?: number }) { const lab = this.labs.find((l) => l.id === labId) if (!lab) return const compId = lab.selectedCompute?.length || 0 - const prices = this.getComputePriceFromCatalogue(payload.machine_type, payload.subscription, payload.gpu) + const prices = this.getComputePriceFromCatalogue(payload.machine_type, payload.subscription, payload.gpu, payload.gpu_count) const newCompute: ComputeUnit = { id: compId, name: payload.name, machine_type: payload.machine_type, core_count: payload.core_count, gpu: payload.gpu, + gpu_count: payload.gpu_count, ram: payload.ram, subscription: payload.subscription as SubscriptionType, monthlyPrice: prices.monthlyPrice, @@ -477,7 +486,11 @@ export const priceEstimatorStore = reactive({ this.saveStateToLocal() }, - editComputeInLab(labId: number, computeId: number, payload: { name: string; machine_type: string; core_count: number; ram: number; subscription: string; gpu?: string }) { + editComputeInLab( + labId: number, + computeId: number, + payload: { name: string; machine_type: string; core_count: number; ram: number; subscription: string; gpu?: string; gpuCount?: number }, + ) { const lab = this.labs.find((l) => l.id === labId) if (!lab || !lab.selectedCompute) return @@ -491,6 +504,7 @@ export const priceEstimatorStore = reactive({ machine_type: payload.machine_type, core_count: payload.core_count, gpu: payload.gpu, + gpu_count: payload.gpuCount, ram: payload.ram, subscription: payload.subscription as SubscriptionType, monthlyPrice: prices.monthlyPrice, @@ -652,6 +666,7 @@ export const priceEstimatorStore = reactive({ ram: comp.ram, subscription: comp.subscription, gpu: comp.gpu, + gpu_count: comp.gpu_count, }) } } diff --git a/docs/.vitepress/theme/components/price-estimator/types/index.ts b/docs/.vitepress/theme/components/price-estimator/types/index.ts index 4ead3f8960..3b97766937 100644 --- a/docs/.vitepress/theme/components/price-estimator/types/index.ts +++ b/docs/.vitepress/theme/components/price-estimator/types/index.ts @@ -28,6 +28,7 @@ export interface ComputeUnit { core_count: number ram: number gpu?: string + gpu_count?: number subscription: SubscriptionType monthlyPrice: number yearlyPrice: number @@ -46,6 +47,7 @@ export interface StorageUnit { export interface GpuModel { type: string vram: number + max: number } export interface MachineType { @@ -87,6 +89,7 @@ export interface MachineFormData { name?: string machine_type?: string gpu?: string + gpu_count?: number subscription?: SubscriptionType }