Skip to content

Commit 7acf72d

Browse files
authored
chore(test): Implement custom interaction with Audio To Text AI App service (#3112)
1 parent d69d649 commit 7acf72d

File tree

2 files changed

+86
-21
lines changed

2 files changed

+86
-21
lines changed
344 KB
Binary file not shown.

tests/playwright/src/ai-lab-extension.spec.ts

Lines changed: 86 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,14 @@
1616
* SPDX-License-Identifier: Apache-2.0
1717
***********************************************************************/
1818

19-
import type { Locator } from '@playwright/test';
19+
/**
20+
* The 'test-audio-to-text.wav' file used in this test was sourced from the
21+
* whisper.cpp project (https://github.com/ggml-org/whisper.cpp).
22+
* It is licensed under the MIT License (see https://github.com/ggml-org/whisper.cpp/blob/master/LICENSE for details).
23+
* This specific WAV file is used solely for Playwright testing purposes within this repository.
24+
*/
25+
26+
import type { APIResponse, Locator } from '@playwright/test';
2027
import type { NavigationBar, ExtensionsPage } from '@podman-desktop/tests-playwright';
2128
import {
2229
expect as playExpect,
@@ -40,6 +47,9 @@ import {
4047
reopenAILabDashboard,
4148
waitForExtensionToInitialize,
4249
} from './utils/aiLabHandler';
50+
import * as fs from 'node:fs';
51+
import * as path from 'node:path';
52+
import { fileURLToPath } from 'node:url';
4353

4454
const AI_LAB_EXTENSION_OCI_IMAGE =
4555
process.env.EXTENSION_OCI_IMAGE ?? 'ghcr.io/containers/podman-desktop-extension-ai-lab:nightly';
@@ -52,6 +62,31 @@ const runnerOptions = {
5262
aiLabModelUploadDisabled: isWindows ? true : false,
5363
};
5464

65+
interface AiApp {
66+
appName: string;
67+
appModel: string;
68+
}
69+
70+
const AI_APPS: AiApp[] = [
71+
{ appName: 'Audio to Text', appModel: 'ggerganov/whisper.cpp' },
72+
{ appName: 'ChatBot', appModel: 'ibm-granite/granite-3.3-8b-instruct-GGUF' },
73+
{ appName: 'Summarizer', appModel: 'ibm-granite/granite-3.3-8b-instruct-GGUF' },
74+
{ appName: 'Code Generation', appModel: 'ibm-granite/granite-3.3-8b-instruct-GGUF' },
75+
{ appName: 'RAG Chatbot', appModel: 'ibm-granite/granite-3.3-8b-instruct-GGUF' },
76+
{ appName: 'Function calling', appModel: 'ibm-granite/granite-3.3-8b-instruct-GGUF' },
77+
];
78+
79+
const __filename = fileURLToPath(import.meta.url);
80+
const __dirname = path.dirname(__filename);
81+
const TEST_AUDIO_FILE_PATH: string = path.resolve(
82+
__dirname,
83+
'..',
84+
'..',
85+
'playwright',
86+
'resources',
87+
`test-audio-to-text.wav`,
88+
);
89+
5590
test.use({
5691
runnerOptions: new RunnerOptions(runnerOptions),
5792
});
@@ -476,7 +511,7 @@ test.describe.serial(`AI Lab extension installation and verification`, () => {
476511
});
477512
});
478513

479-
['Audio to Text', 'ChatBot', 'Summarizer', 'Code Generation', 'RAG Chatbot', 'Function calling'].forEach(appName => {
514+
AI_APPS.forEach(({ appName, appModel }) => {
480515
test.describe.serial(`AI Recipe installation`, () => {
481516
test.skip(
482517
!process.env.EXT_TEST_RAG_CHATBOT && appName === 'RAG Chatbot',
@@ -500,41 +535,71 @@ test.describe.serial(`AI Lab extension installation and verification`, () => {
500535
});
501536

502537
test(`Verify that model service for the ${appName} is working`, async ({ request }) => {
503-
test.skip(appName !== 'Function calling');
538+
test.skip(appName !== 'Function calling' && appName !== 'Audio to Text');
539+
test.fail(
540+
appName === 'Audio to Text',
541+
'Expected failure due to issue #3111: https://github.com/containers/podman-desktop-extension-ai-lab/issues/3111',
542+
);
504543
test.setTimeout(600_000);
505544

506545
const modelServicePage = await aiLabPage.navigationBar.openServices();
507-
const serviceDetailsPage = await modelServicePage.openServiceDetails(
508-
'ibm-granite/granite-3.3-8b-instruct-GGUF',
509-
);
546+
const serviceDetailsPage = await modelServicePage.openServiceDetails(appModel);
510547

511548
await playExpect
512549
// eslint-disable-next-line sonarjs/no-nested-functions
513550
.poll(async () => await serviceDetailsPage.getServiceState(), { timeout: 60_000 })
514551
.toBe('RUNNING');
552+
515553
const port = await serviceDetailsPage.getInferenceServerPort();
516-
const url = `http://localhost:${port}/v1/chat/completions`;
554+
const baseUrl = `http://localhost:${port}`;
517555

518-
const response = await request.post(url, {
519-
data: {
520-
messages: [
521-
{
522-
content: 'You are a helpful assistant.',
523-
role: 'system',
556+
let response: APIResponse;
557+
let expectedResponse: string;
558+
559+
switch (appModel) {
560+
case 'ggerganov/whisper.cpp': {
561+
expectedResponse =
562+
'And so my fellow Americans, ask not what your country can do for you, ask what you can do for your country';
563+
const audioFileContent = fs.readFileSync(TEST_AUDIO_FILE_PATH);
564+
565+
response = await request.post(`${baseUrl}/inference`, {
566+
headers: {
567+
Accept: 'application/json',
568+
},
569+
multipart: {
570+
file: {
571+
name: 'test.wav',
572+
mimeType: 'audio/wav',
573+
buffer: audioFileContent,
574+
},
524575
},
525-
{
526-
content: 'What is the capital of Czech Republic?',
527-
role: 'user',
576+
timeout: 600_000,
577+
});
578+
break;
579+
}
580+
581+
case 'ibm-granite/granite-3.3-8b-instruct-GGUF': {
582+
expectedResponse = 'Prague';
583+
response = await request.post(`${baseUrl}/v1/chat/completions`, {
584+
data: {
585+
messages: [
586+
{ role: 'system', content: 'You are a helpful assistant.' },
587+
{ role: 'user', content: 'What is the capital of Czech Republic?' },
588+
],
528589
},
529-
],
530-
},
531-
timeout: 600_000,
532-
});
590+
timeout: 600_000,
591+
});
592+
break;
593+
}
594+
595+
default:
596+
throw new Error(`Unhandled model type: ${appModel}`);
597+
}
533598

534599
playExpect(response.ok()).toBeTruthy();
535600
const body = await response.body();
536601
const text = body.toString();
537-
playExpect(text).toContain('Prague');
602+
playExpect(text).toContain(expectedResponse);
538603
});
539604

540605
test(`${appName}: Restart, Stop, Delete. Clean up model service`, async () => {

0 commit comments

Comments
 (0)