Skip to content

Commit

Permalink
feat: Adjust embedding types and access
Browse files Browse the repository at this point in the history
  • Loading branch information
marikaner committed Oct 14, 2024
1 parent 461bf37 commit 09c16b4
Show file tree
Hide file tree
Showing 7 changed files with 92 additions and 47 deletions.
5 changes: 5 additions & 0 deletions .changeset/grumpy-apes-beam.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---

Check warning on line 1 in .changeset/grumpy-apes-beam.md

View workflow job for this annotation

GitHub Actions / grammar-check

[vale] reported by reviewdog 🐶 [SAP.Readability] The text is very complex! It has a grade score of >14. Raw Output: {"message": "[SAP.Readability] The text is very complex! It has a grade score of \u003e14.", "location": {"path": ".changeset/grumpy-apes-beam.md", "range": {"start": {"line": 1, "column": 1}}}, "severity": "WARNING"}
'@sap-ai-sdk/foundation-models': minor
---

[New Functionality] Add convenience method to access all embeddings in an Azure OpenAI response (`AzureOpenAiEmbeddingResponse`).
5 changes: 5 additions & 0 deletions .changeset/many-zebras-repair.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@sap-ai-sdk/foundation-models': minor
---

[Compatibility Note] Adjust `AzureOpenAiEmbeddingOutput` type to include multiple embedding responses as opposed to one.
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,57 @@ import { createLogger } from '@sap-cloud-sdk/util';
import { jest } from '@jest/globals';
import { parseMockResponse } from '../../../../test-util/mock-http.js';
import { AzureOpenAiEmbeddingResponse } from './azure-openai-embedding-response.js';
import type { HttpResponse } from '@sap-cloud-sdk/http-client';
import type { AzureOpenAiEmbeddingOutput } from './azure-openai-embedding-types.js';

describe('Azure OpenAI embedding response', () => {
const mockResponse = parseMockResponse<AzureOpenAiEmbeddingResponse>(
'foundation-models',
'azure-openai-embeddings-success-response.json'
);
const rawResponse = {
data: mockResponse,
status: 200,
headers: {},
request: {}
};
const embeddingResponse = new AzureOpenAiEmbeddingResponse(rawResponse);
let embeddingResponse: AzureOpenAiEmbeddingResponse;
let rawResponse: HttpResponse;
let mockedData: AzureOpenAiEmbeddingOutput;
beforeAll(async () => {
mockedData = await parseMockResponse<AzureOpenAiEmbeddingOutput>(
'foundation-models',
'azure-openai-embeddings-success-response.json'
);

rawResponse = {
data: mockedData,
status: 200,
headers: {},
request: {}
};
embeddingResponse = new AzureOpenAiEmbeddingResponse(rawResponse);
});

it('should return the embedding response', () => {
expect(embeddingResponse.data).toStrictEqual(mockResponse);
expect(embeddingResponse.data).toStrictEqual(mockedData);
});

it('should return raw response', () => {
expect(embeddingResponse.rawResponse).toBe(rawResponse);
});

it('should return the first embedding', () => {
expect(embeddingResponse.getEmbedding()).toEqual(
mockedData.data[0].embedding
);
});

it('should return undefined when convenience function is called with incorrect index', () => {
const logger = createLogger({
package: 'foundation-models',
messageContext: 'azure-openai-embedding-response'
});
const errorSpy = jest.spyOn(logger, 'error');
expect(embeddingResponse.getEmbedding(1)).toBeUndefined();
expect(errorSpy).toHaveBeenCalledWith('Data index 1 is out of bounds.');
expect(embeddingResponse.getEmbedding(2)).toBeUndefined();
expect(errorSpy).toHaveBeenCalledWith('Data index 2 is out of bounds.');
expect(errorSpy).toHaveBeenCalledTimes(1);
});

it('should return all embeddings', () => {
expect(embeddingResponse.getEmbeddings()).toEqual([
mockedData.data[0].embedding,
mockedData.data[1]?.embedding
]);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,14 @@ export class AzureOpenAiEmbeddingResponse {
return this.data.data[dataIndex]?.embedding;
}

/**
* Parses the Azure OpenAI response and returns all embeddings.
* @returns The embedding vectors.
*/
getEmbeddings(): number[][] | undefined {
return this.data.data.map(({ embedding }) => embedding);
}

private logInvalidDataIndex(dataIndex: number): void {
if (dataIndex < 0 || dataIndex >= this.data.data.length) {
logger.error(`Data index ${dataIndex} is out of bounds.`);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,22 +27,20 @@ export interface AzureOpenAiEmbeddingOutput {
/**
* Array of result candidates.
*/
data: [
{
/**
* Embedding object.
*/
object: 'embedding';
/**
* Array of size `1536` (Azure OpenAI's embedding size) containing embedding vector.
*/
embedding: number[];
/**
* Index of choice.
*/
index: number;
}
];
data: {
/**
* Embedding object.
*/
object: 'embedding';
/**
* Array of size `1536` (Azure OpenAI's embedding size) containing embedding vector.
*/
embedding: number[];
/**
* Index of choice.
*/
index: number;
}[];
/**
* Token Usage.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,15 @@
],
"index": 0,
"object": "embedding"
},
{
"embedding": [
-0.011352594, -0.006521842, 0.0059352037, -0.021066532, -0.0062957075,
0.024606025, -0.02332132, 0.016792923, 0.0029676019, -0.04000937,
0.0143283885, 0.025274595, -0.0006419426, -0.0014493892, -0.006269489
],
"index": 1,
"object": "embedding"
}
],
"model": "ada",
Expand Down
32 changes: 15 additions & 17 deletions test-util/mock-http.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
import {
DestinationAuthToken,
HttpDestination,
ServiceCredentials
} from '@sap-cloud-sdk/connectivity';
import { readFile } from 'node:fs/promises';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import nock from 'nock';
import { type EndpointOptions } from '@sap-ai-sdk/core';
import {
type FoundationModel,
type DeploymentResolutionOptions
} from '@sap-ai-sdk/ai-api/internal.js';
import { dummyToken } from './mock-jwt.js';
import type {
DestinationAuthToken,
HttpDestination,
ServiceCredentials
} from '@sap-cloud-sdk/connectivity';

// Get the directory of this file
const __filename = fileURLToPath(import.meta.url);
Expand Down Expand Up @@ -121,7 +121,7 @@ export function mockDeploymentsList(
): nock.Scope {
const nockOpts = {
reqheaders: {
'ai-resource-group': opts?.resourceGroup ?? 'default',
'ai-resource-group': opts?.resourceGroup ?? 'default'
}
};
const query = {
Expand All @@ -143,14 +143,12 @@ export function mockDeploymentsList(
/**
* @internal
*/
export function parseMockResponse<T>(client: string, fileName: string): T {
const fileContent = fs.readFileSync(
path.join(
__dirname,
'data',
client,
fileName
),
export async function parseMockResponse<T>(
client: string,
fileName: string
): Promise<T> {
const fileContent = await readFile(
path.join(__dirname, 'data', client, fileName),
'utf-8'
);
return JSON.parse(fileContent);
Expand Down

0 comments on commit 09c16b4

Please sign in to comment.