appwrite/app/controllers/api/project.php

435 lines
20 KiB
PHP
Raw Normal View History

<?php
2025-01-17 04:31:39 +00:00
use Appwrite\SDK\AuthType;
use Appwrite\SDK\Method;
use Appwrite\SDK\Response as SDKResponse;
use Appwrite\Utopia\Response;
use Utopia\Database\Database;
use Utopia\Database\Document;
use Utopia\Database\Query;
use Utopia\Database\Validator\Authorization;
2024-03-06 17:34:21 +00:00
use Utopia\Database\Validator\Datetime as DateTimeValidator;
use Utopia\Http\Http;
2024-10-08 07:54:40 +00:00
use Utopia\Validator\WhiteList;
2026-02-04 05:30:22 +00:00
Http::get('/v1/project/usage')
2024-02-26 02:44:20 +00:00
->desc('Get project usage stats')
2023-10-25 07:39:59 +00:00
->groups(['api', 'usage'])
->label('scope', 'projects.read')
2025-01-17 04:31:39 +00:00
->label('sdk', new Method(
namespace: 'project',
group: null,
2025-01-17 04:31:39 +00:00
name: 'getUsage',
description: '/docs/references/project/get-usage.md',
2025-01-17 04:31:39 +00:00
auth: [AuthType::ADMIN],
responses: [
new SDKResponse(
code: Response::STATUS_CODE_OK,
model: Response::MODEL_USAGE_PROJECT,
)
]
))
2023-12-10 09:26:33 +00:00
->param('startDate', '', new DateTimeValidator(), 'Starting date for the usage')
->param('endDate', '', new DateTimeValidator(), 'End date for the usage')
->param('period', '1d', new WhiteList(['1h', '1d']), 'Period used', true)
->inject('response')
2025-03-01 17:45:20 +00:00
->inject('project')
->inject('dbForProject')
2026-01-07 07:04:28 +00:00
->inject('authorization')
2025-03-01 17:45:20 +00:00
->inject('getLogsDB')
2025-01-09 18:33:07 +00:00
->inject('smsRates')
2026-01-07 07:04:28 +00:00
->action(function (string $startDate, string $endDate, string $period, Response $response, Document $project, Database $dbForProject, Authorization $authorization, callable $getLogsDB, array $smsRates) {
2023-11-08 16:12:36 +00:00
$stats = $total = $usage = [];
2023-12-10 09:26:33 +00:00
$format = 'Y-m-d 00:00:00';
$firstDay = (new DateTime($startDate))->format($format);
$lastDay = (new DateTime($endDate))->format($format);
2023-11-08 16:12:36 +00:00
2025-03-01 17:45:20 +00:00
$dbForLogs = call_user_func($getLogsDB, $project);
2023-10-25 07:39:59 +00:00
$metrics = [
2024-03-06 17:34:21 +00:00
'total' => [
2023-11-08 16:12:36 +00:00
METRIC_EXECUTIONS,
2024-07-12 10:02:32 +00:00
METRIC_EXECUTIONS_MB_SECONDS,
METRIC_BUILDS_MB_SECONDS,
2023-11-08 16:12:36 +00:00
METRIC_DOCUMENTS,
METRIC_DOCUMENTS_DOCUMENTSDB,
2023-11-08 16:12:36 +00:00
METRIC_DATABASES,
METRIC_DATABASES_DOCUMENTSDB,
2023-11-08 16:12:36 +00:00
METRIC_USERS,
METRIC_BUCKETS,
2024-07-18 04:58:02 +00:00
METRIC_FILES_STORAGE,
METRIC_DATABASES_STORAGE,
METRIC_DATABASES_STORAGE_DOCUMENTSDB,
METRIC_DEPLOYMENTS_STORAGE,
2025-01-23 13:24:02 +00:00
METRIC_BUILDS_STORAGE,
METRIC_DATABASES_OPERATIONS_READS,
METRIC_DATABASES_OPERATIONS_READS_DOCUMENTSDB,
2025-01-23 13:24:02 +00:00
METRIC_DATABASES_OPERATIONS_WRITES,
METRIC_DATABASES_OPERATIONS_WRITES_DOCUMENTSDB,
METRIC_FILES_IMAGES_TRANSFORMED,
// VectorsDB totals
METRIC_DATABASES_VECTORSDB,
METRIC_COLLECTIONS_VECTORSDB,
METRIC_DOCUMENTS_VECTORSDB,
METRIC_DATABASES_STORAGE_VECTORSDB,
METRIC_DATABASES_OPERATIONS_READS_VECTORSDB,
METRIC_DATABASES_OPERATIONS_WRITES_VECTORSDB,
// Embeddings totals
METRIC_EMBEDDINGS_TEXT,
METRIC_EMBEDDINGS_TEXT_TOTAL_TOKENS,
METRIC_EMBEDDINGS_TEXT_TOTAL_DURATION,
METRIC_EMBEDDINGS_TEXT_TOTAL_ERROR
2024-03-06 17:34:21 +00:00
],
'period' => [
2023-11-08 16:12:36 +00:00
METRIC_NETWORK_REQUESTS,
METRIC_NETWORK_INBOUND,
METRIC_NETWORK_OUTBOUND,
2023-12-11 15:19:08 +00:00
METRIC_USERS,
2024-07-18 04:58:02 +00:00
METRIC_EXECUTIONS,
METRIC_DATABASES_STORAGE,
METRIC_DATABASES_STORAGE_DOCUMENTSDB,
2024-07-12 10:02:32 +00:00
METRIC_EXECUTIONS_MB_SECONDS,
2025-01-23 13:24:02 +00:00
METRIC_BUILDS_MB_SECONDS,
METRIC_DATABASES_OPERATIONS_READS,
METRIC_DATABASES_OPERATIONS_READS_DOCUMENTSDB,
2025-01-23 13:24:02 +00:00
METRIC_DATABASES_OPERATIONS_WRITES,
METRIC_DATABASES_OPERATIONS_WRITES_DOCUMENTSDB,
METRIC_FILES_IMAGES_TRANSFORMED,
// VectorsDB time series
METRIC_DATABASES_VECTORSDB,
METRIC_COLLECTIONS_VECTORSDB,
METRIC_DOCUMENTS_VECTORSDB,
METRIC_DATABASES_STORAGE_VECTORSDB,
METRIC_DATABASES_OPERATIONS_READS_VECTORSDB,
METRIC_DATABASES_OPERATIONS_WRITES_VECTORSDB,
// Embeddings time series
METRIC_EMBEDDINGS_TEXT,
METRIC_EMBEDDINGS_TEXT_TOTAL_TOKENS,
METRIC_EMBEDDINGS_TEXT_TOTAL_DURATION,
METRIC_EMBEDDINGS_TEXT_TOTAL_ERROR
2024-03-06 17:34:21 +00:00
]
2023-10-25 07:39:59 +00:00
];
2023-03-11 16:06:02 +00:00
2023-12-10 09:26:33 +00:00
$factor = match ($period) {
'1h' => 3600,
'1d' => 86400,
};
$limit = match ($period) {
2023-12-11 15:19:08 +00:00
'1h' => (new DateTime($startDate))->diff(new DateTime($endDate))->days * 24,
'1d' => (new DateTime($startDate))->diff(new DateTime($endDate))->days
2023-12-10 09:26:33 +00:00
};
$format = match ($period) {
'1h' => 'Y-m-d\TH:00:00.000P',
'1d' => 'Y-m-d\T00:00:00.000P',
};
2026-01-07 07:04:28 +00:00
$authorization->skip(function () use ($dbForProject, $dbForLogs, $firstDay, $lastDay, $period, $metrics, $limit, &$total, &$stats) {
2023-11-08 16:12:36 +00:00
foreach ($metrics['total'] as $metric) {
2025-03-01 17:45:20 +00:00
$db = ($metric === METRIC_FILES_IMAGES_TRANSFORMED) ? $dbForLogs : $dbForProject;
$result = $db->findOne('stats', [
2023-11-08 16:12:36 +00:00
Query::equal('metric', [$metric]),
Query::equal('period', ['inf'])
]);
$total[$metric] = $result['value'] ?? 0;
}
foreach ($metrics['period'] as $metric) {
2025-03-01 17:45:20 +00:00
$db = ($metric === METRIC_FILES_IMAGES_TRANSFORMED) ? $dbForLogs : $dbForProject;
$results = $db->find('stats', [
2023-10-25 07:39:59 +00:00
Query::equal('metric', [$metric]),
2023-10-25 12:06:54 +00:00
Query::equal('period', [$period]),
2023-12-10 09:26:33 +00:00
Query::greaterThanEqual('time', $firstDay),
Query::lessThan('time', $lastDay),
Query::limit($limit),
2023-10-25 07:39:59 +00:00
Query::orderDesc('time'),
]);
2023-08-20 12:29:43 +00:00
2023-10-25 07:39:59 +00:00
$stats[$metric] = [];
foreach ($results as $result) {
$stats[$metric][$result->getAttribute('time')] = [
'value' => $result->getAttribute('value'),
];
}
}
});
2023-08-20 12:29:43 +00:00
2023-12-10 19:58:38 +00:00
$now = time();
2023-12-10 09:26:33 +00:00
foreach ($metrics['period'] as $metric) {
$usage[$metric] = [];
2023-12-10 19:58:38 +00:00
$leap = $now - ($limit * $factor);
while ($leap < $now) {
2023-12-10 09:26:33 +00:00
$leap += $factor;
$formatDate = date($format, $leap);
$usage[$metric][] = [
2023-12-10 19:58:38 +00:00
'value' => $stats[$metric][$formatDate]['value'] ?? 0,
'date' => $formatDate,
2023-12-10 09:26:33 +00:00
];
}
2023-03-11 16:06:02 +00:00
}
2023-12-10 09:26:33 +00:00
2023-12-11 15:33:15 +00:00
$executionsBreakdown = array_map(function ($function) use ($dbForProject) {
2023-12-11 15:19:08 +00:00
$id = $function->getId();
$name = $function->getAttribute('name');
$metric = str_replace(['{resourceType}', '{resourceInternalId}'], [RESOURCE_TYPE_FUNCTIONS, $function->getSequence()], METRIC_RESOURCE_TYPE_ID_EXECUTIONS);
2024-02-12 09:10:52 +00:00
$value = $dbForProject->findOne('stats', [
2023-12-11 15:19:08 +00:00
Query::equal('metric', [$metric]),
Query::equal('period', ['inf'])
]);
return [
'resourceId' => $id,
'name' => $name,
'value' => $value['value'] ?? 0,
];
}, $dbForProject->find('functions'));
2024-07-12 10:02:32 +00:00
$executionsMbSecondsBreakdown = array_map(function ($function) use ($dbForProject) {
$id = $function->getId();
$name = $function->getAttribute('name');
$metric = str_replace(['{resourceType}', '{resourceInternalId}'], [RESOURCE_TYPE_FUNCTIONS, $function->getSequence()], METRIC_RESOURCE_TYPE_ID_EXECUTIONS_MB_SECONDS);
2024-07-12 10:02:32 +00:00
$value = $dbForProject->findOne('stats', [
Query::equal('metric', [$metric]),
Query::equal('period', ['inf'])
]);
return [
'resourceId' => $id,
'name' => $name,
'value' => $value['value'] ?? 0,
];
}, $dbForProject->find('functions'));
$buildsMbSecondsBreakdown = array_map(function ($function) use ($dbForProject) {
$id = $function->getId();
$name = $function->getAttribute('name');
$metric = str_replace(['{resourceType}', '{resourceInternalId}'], [RESOURCE_TYPE_FUNCTIONS, $function->getSequence()], METRIC_RESOURCE_TYPE_ID_BUILDS_MB_SECONDS);
2024-07-12 10:02:32 +00:00
$value = $dbForProject->findOne('stats', [
Query::equal('metric', [$metric]),
Query::equal('period', ['inf'])
]);
return [
'resourceId' => $id,
'name' => $name,
'value' => $value['value'] ?? 0,
];
}, $dbForProject->find('functions'));
2023-12-11 15:33:15 +00:00
$bucketsBreakdown = array_map(function ($bucket) use ($dbForProject) {
2023-12-11 15:19:08 +00:00
$id = $bucket->getId();
$name = $bucket->getAttribute('name');
2025-05-26 05:42:11 +00:00
$metric = str_replace('{bucketInternalId}', $bucket->getSequence(), METRIC_BUCKET_ID_FILES_STORAGE);
2024-02-12 09:10:52 +00:00
$value = $dbForProject->findOne('stats', [
2023-12-11 15:19:08 +00:00
Query::equal('metric', [$metric]),
Query::equal('period', ['inf'])
]);
return [
'resourceId' => $id,
'name' => $name,
'value' => $value['value'] ?? 0,
];
}, $dbForProject->find('buckets'));
2024-07-18 04:58:02 +00:00
$databasesStorageBreakdown = array_map(function ($database) use ($dbForProject) {
$id = $database->getId();
$name = $database->getAttribute('name');
2025-05-26 05:42:11 +00:00
$metric = str_replace('{databaseInternalId}', $database->getSequence(), METRIC_DATABASE_ID_STORAGE);
2024-07-18 04:58:02 +00:00
$value = $dbForProject->findOne('stats', [
Query::equal('metric', [$metric]),
Query::equal('period', ['inf'])
]);
return [
'resourceId' => $id,
'name' => $name,
'value' => $value['value'] ?? 0,
];
}, $dbForProject->find('databases'));
$functionsStorageBreakdown = array_map(function ($function) use ($dbForProject) {
$id = $function->getId();
$name = $function->getAttribute('name');
$deploymentMetric = str_replace(['{resourceType}', '{resourceInternalId}'], [RESOURCE_TYPE_FUNCTIONS, $function->getSequence()], METRIC_RESOURCE_TYPE_ID_DEPLOYMENTS_STORAGE);
$deploymentValue = $dbForProject->findOne('stats', [
Query::equal('metric', [$deploymentMetric]),
Query::equal('period', ['inf'])
]);
$buildMetric = str_replace(['{resourceType}', '{resourceInternalId}'], [RESOURCE_TYPE_FUNCTIONS, $function->getSequence()], METRIC_RESOURCE_TYPE_ID_BUILDS_STORAGE);
$buildValue = $dbForProject->findOne('stats', [
Query::equal('metric', [$buildMetric]),
Query::equal('period', ['inf'])
]);
$value = ($buildValue['value'] ?? 0) + ($deploymentValue['value'] ?? 0);
return [
'resourceId' => $id,
'name' => $name,
'value' => $value,
];
}, $dbForProject->find('functions'));
2024-07-30 08:53:28 +00:00
$executionsMbSecondsBreakdown = array_map(function ($function) use ($dbForProject) {
$id = $function->getId();
$name = $function->getAttribute('name');
$metric = str_replace(['{resourceType}', '{resourceInternalId}'], [RESOURCE_TYPE_FUNCTIONS, $function->getSequence()], METRIC_RESOURCE_TYPE_ID_EXECUTIONS_MB_SECONDS);
2024-07-30 08:53:28 +00:00
$value = $dbForProject->findOne('stats', [
Query::equal('metric', [$metric]),
Query::equal('period', ['inf'])
]);
2024-07-30 08:53:28 +00:00
return [
'resourceId' => $id,
'name' => $name,
'value' => $value['value'] ?? 0,
];
}, $dbForProject->find('functions'));
$buildsMbSecondsBreakdown = array_map(function ($function) use ($dbForProject) {
$id = $function->getId();
$name = $function->getAttribute('name');
$metric = str_replace(['{resourceType}', '{resourceInternalId}'], [RESOURCE_TYPE_FUNCTIONS, $function->getSequence()], METRIC_RESOURCE_TYPE_ID_BUILDS_MB_SECONDS);
$value = $dbForProject->findOne('stats', [
Query::equal('metric', [$metric]),
Query::equal('period', ['inf'])
]);
return [
'resourceId' => $id,
'name' => $name,
'value' => $value['value'] ?? 0,
];
}, $dbForProject->find('functions'));
2025-01-09 16:35:40 +00:00
// This total is includes free and paid SMS usage
2026-01-07 07:04:28 +00:00
$authPhoneTotal = $authorization->skip(fn () => $dbForProject->sum('stats', 'value', [
2025-01-09 16:35:40 +00:00
Query::equal('metric', [METRIC_AUTH_METHOD_PHONE]),
Query::equal('period', ['1d']),
Query::greaterThanEqual('time', $firstDay),
Query::lessThan('time', $lastDay),
]));
// This estimate is only for paid SMS usage
2026-01-07 07:04:28 +00:00
$authPhoneMetrics = $authorization->skip(fn () => $dbForProject->find('stats', [
2025-01-10 17:33:08 +00:00
Query::startsWith('metric', METRIC_AUTH_METHOD_PHONE . '.'),
2025-01-09 16:35:40 +00:00
Query::equal('period', ['1d']),
Query::greaterThanEqual('time', $firstDay),
Query::lessThan('time', $lastDay),
]));
$authPhoneEstimate = 0.0;
$authPhoneCountryBreakdown = [];
foreach ($authPhoneMetrics as $metric) {
$parts = explode('.', $metric->getAttribute('metric'));
$countryCode = $parts[3] ?? null;
if ($countryCode === null) {
continue;
}
$value = $metric->getAttribute('value', 0);
2025-01-09 19:03:25 +00:00
if (isset($smsRates[$countryCode])) {
2025-01-09 18:33:07 +00:00
$authPhoneEstimate += $value * $smsRates[$countryCode];
2025-01-09 16:35:40 +00:00
}
$authPhoneCountryBreakdown[] = [
'name' => $countryCode,
'value' => $value,
2025-01-09 19:03:25 +00:00
'estimate' => isset($smsRates[$countryCode])
2025-01-09 18:33:07 +00:00
? $value * $smsRates[$countryCode]
2025-01-09 16:35:40 +00:00
: 0.0,
];
}
2024-02-19 06:04:29 +00:00
// merge network inbound + outbound
$projectBandwidth = [];
foreach ($usage[METRIC_NETWORK_INBOUND] as $item) {
$projectBandwidth[$item['date']] ??= 0;
$projectBandwidth[$item['date']] += $item['value'];
}
foreach ($usage[METRIC_NETWORK_OUTBOUND] as $item) {
$projectBandwidth[$item['date']] ??= 0;
$projectBandwidth[$item['date']] += $item['value'];
}
$network = [];
foreach ($projectBandwidth as $date => $value) {
$network[] = [
'date' => $date,
'value' => $value
];
}
2023-10-25 07:39:59 +00:00
$response->dynamic(new Document([
2023-11-08 16:12:36 +00:00
'requests' => ($usage[METRIC_NETWORK_REQUESTS]),
2024-02-19 06:04:29 +00:00
'network' => $network,
2023-12-11 15:19:08 +00:00
'users' => ($usage[METRIC_USERS]),
'executions' => ($usage[METRIC_EXECUTIONS]),
2023-11-08 16:12:36 +00:00
'executionsTotal' => $total[METRIC_EXECUTIONS],
2024-07-12 10:02:32 +00:00
'executionsMbSecondsTotal' => $total[METRIC_EXECUTIONS_MB_SECONDS],
'buildsMbSecondsTotal' => $total[METRIC_BUILDS_MB_SECONDS],
2023-11-08 16:12:36 +00:00
'documentsTotal' => $total[METRIC_DOCUMENTS],
2025-05-08 14:17:35 +00:00
'rowsTotal' => $total[METRIC_DOCUMENTS],
'documentsdbDocumentsTotal' => $total[METRIC_DOCUMENTS_DOCUMENTSDB],
2023-11-08 16:12:36 +00:00
'databasesTotal' => $total[METRIC_DATABASES],
'documentsdbTotal' => $total[METRIC_DATABASES_DOCUMENTSDB],
2024-07-18 04:58:02 +00:00
'databasesStorageTotal' => $total[METRIC_DATABASES_STORAGE],
'documentsdbDatabasesStorageTotal' => $total[METRIC_DATABASES_STORAGE_DOCUMENTSDB],
2023-11-08 16:12:36 +00:00
'usersTotal' => $total[METRIC_USERS],
'bucketsTotal' => $total[METRIC_BUCKETS],
'filesStorageTotal' => $total[METRIC_FILES_STORAGE],
2024-09-16 11:49:13 +00:00
'functionsStorageTotal' => $total[METRIC_DEPLOYMENTS_STORAGE] + $total[METRIC_BUILDS_STORAGE],
2024-09-16 09:58:08 +00:00
'buildsStorageTotal' => $total[METRIC_BUILDS_STORAGE],
'deploymentsStorageTotal' => $total[METRIC_DEPLOYMENTS_STORAGE],
2025-01-23 13:24:02 +00:00
'databasesReadsTotal' => $total[METRIC_DATABASES_OPERATIONS_READS],
'databasesWritesTotal' => $total[METRIC_DATABASES_OPERATIONS_WRITES],
'documentsdbDatabasesReadsTotal' => $total[METRIC_DATABASES_OPERATIONS_READS_DOCUMENTSDB],
'documentsdbDatabasesWritesTotal' => $total[METRIC_DATABASES_OPERATIONS_WRITES_DOCUMENTSDB],
'vectorsdbDatabasesTotal' => $total[METRIC_DATABASES_VECTORSDB] ?? 0,
'vectorsdbCollectionsTotal' => $total[METRIC_COLLECTIONS_VECTORSDB] ?? 0,
'vectorsdbDocumentsTotal' => $total[METRIC_DOCUMENTS_VECTORSDB] ?? 0,
'vectorsdbDatabasesStorageTotal' => $total[METRIC_DATABASES_STORAGE_VECTORSDB] ?? 0,
'vectorsdbDatabasesReadsTotal' => $total[METRIC_DATABASES_OPERATIONS_READS_VECTORSDB] ?? 0,
'vectorsdbDatabasesWritesTotal' => $total[METRIC_DATABASES_OPERATIONS_WRITES_VECTORSDB] ?? 0,
2023-12-11 15:19:08 +00:00
'executionsBreakdown' => $executionsBreakdown,
2024-07-18 04:58:02 +00:00
'bucketsBreakdown' => $bucketsBreakdown,
2025-01-23 13:24:02 +00:00
'databasesReads' => $usage[METRIC_DATABASES_OPERATIONS_READS],
'databasesWrites' => $usage[METRIC_DATABASES_OPERATIONS_WRITES],
'documentsdbDatabasesReads' => $usage[METRIC_DATABASES_OPERATIONS_READS_DOCUMENTSDB],
'documentsdbDatabasesWrites' => $usage[METRIC_DATABASES_OPERATIONS_WRITES_DOCUMENTSDB],
'documentsdbDatabasesStorage' => $usage[METRIC_DATABASES_STORAGE_DOCUMENTSDB],
'vectorsdbDatabases' => $usage[METRIC_DATABASES_VECTORSDB] ?? [],
'vectorsdbCollections' => $usage[METRIC_COLLECTIONS_VECTORSDB] ?? [],
'vectorsdbDocuments' => $usage[METRIC_DOCUMENTS_VECTORSDB] ?? [],
'vectorsdbDatabasesStorage' => $usage[METRIC_DATABASES_STORAGE_VECTORSDB] ?? [],
'vectorsdbDatabasesReads' => $usage[METRIC_DATABASES_OPERATIONS_READS_VECTORSDB] ?? [],
'vectorsdbDatabasesWrites' => $usage[METRIC_DATABASES_OPERATIONS_WRITES_VECTORSDB] ?? [],
2024-07-18 04:58:02 +00:00
'databasesStorageBreakdown' => $databasesStorageBreakdown,
2024-07-12 10:02:32 +00:00
'executionsMbSecondsBreakdown' => $executionsMbSecondsBreakdown,
'buildsMbSecondsBreakdown' => $buildsMbSecondsBreakdown,
'functionsStorageBreakdown' => $functionsStorageBreakdown,
2025-01-09 16:35:40 +00:00
'authPhoneTotal' => $authPhoneTotal,
'authPhoneEstimate' => $authPhoneEstimate,
'authPhoneCountryBreakdown' => $authPhoneCountryBreakdown,
'imageTransformations' => $usage[METRIC_FILES_IMAGES_TRANSFORMED],
'imageTransformationsTotal' => $total[METRIC_FILES_IMAGES_TRANSFORMED],
'embeddingsText' => $usage[METRIC_EMBEDDINGS_TEXT] ?? [],
'embeddingsTextTokens' => $usage[METRIC_EMBEDDINGS_TEXT_TOTAL_TOKENS] ?? [],
'embeddingsTextDuration' => $usage[METRIC_EMBEDDINGS_TEXT_TOTAL_DURATION] ?? [],
'embeddingsTextErrors' => $usage[METRIC_EMBEDDINGS_TEXT_TOTAL_ERROR] ?? [],
'embeddingsTextTotal' => $total[METRIC_EMBEDDINGS_TEXT] ?? 0,
'embeddingsTextTokensTotal' => $total[METRIC_EMBEDDINGS_TEXT_TOTAL_TOKENS] ?? 0,
'embeddingsTextDurationTotal' => $total[METRIC_EMBEDDINGS_TEXT_TOTAL_DURATION] ?? 0,
'embeddingsTextErrorsTotal' => $total[METRIC_EMBEDDINGS_TEXT_TOTAL_ERROR] ?? 0,
2023-10-25 07:39:59 +00:00
]), Response::MODEL_USAGE_PROJECT);
2023-03-11 16:06:02 +00:00
});