mirror of https://github.com/OpenVidu/openvidu.git
openvidu-testapp: added controls for Agent Dispatch API
parent
fdd0441e8e
commit
9d4b11ed58
|
|
@ -127,6 +127,14 @@ mat-chip-row {
|
||||||
margin-bottom: 7px;
|
margin-bottom: 7px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.agent-dispatch-options {
|
||||||
|
margin-bottom: 7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#agent-restart-policy-select {
|
||||||
|
margin-left: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
#ingress-url-type-select {
|
#ingress-url-type-select {
|
||||||
margin-left: 6px;
|
margin-left: 6px;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -256,6 +256,68 @@
|
||||||
|
|
||||||
<mat-divider></mat-divider>
|
<mat-divider></mat-divider>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label class="label">Agent Dispatch API</label>
|
||||||
|
<mat-form-field class="inner-text-input" [style.fontSize.px]=14>
|
||||||
|
<mat-label>Room</mat-label>
|
||||||
|
<input matInput id="agent-room-name-field" placeholder="Room" [(ngModel)]="agentRoomName">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="inner-text-input" [style.fontSize.px]=14>
|
||||||
|
<mat-label>Agent name</mat-label>
|
||||||
|
<input matInput id="agent-name-field" placeholder="Agent name" [(ngModel)]="agentName">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="inner-text-input" [style.fontSize.px]=14>
|
||||||
|
<mat-label>Dispatch ID</mat-label>
|
||||||
|
<input matInput id="agent-dispatch-id-field" placeholder="Dispatch ID" [(ngModel)]="agentDispatchId">
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="button-group">
|
||||||
|
<span style="display: inline-block" [matTooltip]="!agentRoomName ? 'Room required' : 'Agent name required'"
|
||||||
|
[matTooltipDisabled]="!!agentRoomName && !!agentName">
|
||||||
|
<button mat-button id="create-dispatch-api-btn" (click)="createDispatch()"
|
||||||
|
[disabled]="!agentRoomName || !agentName">Create Dispatch</button>
|
||||||
|
</span>
|
||||||
|
<span style="display: inline-block" matTooltip='"Room" required' [matTooltipDisabled]="!!agentRoomName">
|
||||||
|
<button mat-button id="list-dispatch-api-btn" (click)="listDispatch()" [disabled]="!agentRoomName">List
|
||||||
|
Dispatch</button>
|
||||||
|
</span>
|
||||||
|
<span style="display: inline-block" matTooltip='"Room" and "Dispatch ID" required'
|
||||||
|
[matTooltipDisabled]="!!agentRoomName && !!agentDispatchId">
|
||||||
|
<button mat-button id="get-dispatch-api-btn" (click)="getDispatch()"
|
||||||
|
[disabled]="!agentRoomName || !agentDispatchId">Get Dispatch</button>
|
||||||
|
</span>
|
||||||
|
<span style="display: inline-block" matTooltip='"Room" and "Dispatch ID" required'
|
||||||
|
[matTooltipDisabled]="!!agentRoomName && !!agentDispatchId">
|
||||||
|
<button mat-button id="delete-dispatch-api-btn" (click)="deleteDispatch()"
|
||||||
|
[disabled]="!agentRoomName || !agentDispatchId">Delete Dispatch</button>
|
||||||
|
</span>
|
||||||
|
<span style="display: inline-block" matTooltip='"Room" required' [matTooltipDisabled]="!!agentRoomName">
|
||||||
|
<button mat-button id="delete-all-dispatch-api-btn" (click)="deleteAllDispatch()" [disabled]="!agentRoomName"
|
||||||
|
style="font-style: italic; font-size: 0.75rem; margin-left: 5px;">Delete all</button>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<label class="label">Dispatch options</label>
|
||||||
|
<div class="agent-dispatch-options">
|
||||||
|
<mat-form-field class="inner-text-input" [style.fontSize.px]=14>
|
||||||
|
<mat-label>Metadata</mat-label>
|
||||||
|
<input matInput id="agent-metadata-field" placeholder="Metadata" [(ngModel)]="agentMetadata">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field id="agent-restart-policy-select">
|
||||||
|
<mat-label>Restart policy</mat-label>
|
||||||
|
<mat-select [(value)]="agentRestartPolicySelected">
|
||||||
|
@for (policy of AGENT_RESTART_POLICIES; track policy) {
|
||||||
|
<mat-option [value]="policy.value" [id]="'mat-option-' + policy.viewValue">
|
||||||
|
{{policy.viewValue}}
|
||||||
|
</mat-option>
|
||||||
|
}
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<mat-divider></mat-divider>
|
||||||
|
|
||||||
<mat-form-field id="response-text-area" appearance="fill">
|
<mat-form-field id="response-text-area" appearance="fill">
|
||||||
<textarea id="api-response-text-area" [(ngModel)]="response" matInput readonly></textarea>
|
<textarea id="api-response-text-area" [(ngModel)]="response" matInput readonly></textarea>
|
||||||
<button mat-button id="clear-response-text-area-btn" (click)="response=''">Clear</button>
|
<button mat-button id="clear-response-text-area-btn" (click)="response=''">Clear</button>
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ import { MatSelectModule } from '@angular/material/select';
|
||||||
import { MatIconModule } from '@angular/material/icon';
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||||
import { MatSlideToggleModule } from '@angular/material/slide-toggle';
|
import { MatSlideToggleModule } from '@angular/material/slide-toggle';
|
||||||
import { VideoCodec } from '@livekit/protocol';
|
import { JobRestartPolicy, VideoCodec } from '@livekit/protocol';
|
||||||
import { LocalParticipant } from 'livekit-client';
|
import { LocalParticipant } from 'livekit-client';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
|
@ -84,6 +84,17 @@ export class RoomApiDialogComponent {
|
||||||
ingressUrlType: string = 'HTTP';
|
ingressUrlType: string = 'HTTP';
|
||||||
ingressUrlUri: string;
|
ingressUrlUri: string;
|
||||||
|
|
||||||
|
agentRoomName: string;
|
||||||
|
agentName: string = 'speech-processing';
|
||||||
|
agentDispatchId: string;
|
||||||
|
agentMetadata: string;
|
||||||
|
agentRestartPolicySelected: JobRestartPolicy = JobRestartPolicy.JRP_ON_FAILURE;
|
||||||
|
|
||||||
|
AGENT_RESTART_POLICIES: { value: JobRestartPolicy; viewValue: string }[] = [
|
||||||
|
{ value: JobRestartPolicy.JRP_ON_FAILURE, viewValue: 'On failure' },
|
||||||
|
{ value: JobRestartPolicy.JRP_NEVER, viewValue: 'Never' },
|
||||||
|
];
|
||||||
|
|
||||||
response: string;
|
response: string;
|
||||||
|
|
||||||
INGRESS_INPUT_TYPES: { value: IngressInput; viewValue: string }[] = [
|
INGRESS_INPUT_TYPES: { value: IngressInput; viewValue: string }[] = [
|
||||||
|
|
@ -141,6 +152,7 @@ export class RoomApiDialogComponent {
|
||||||
.values()
|
.values()
|
||||||
.next().value?.trackSid!;
|
.next().value?.trackSid!;
|
||||||
this.ingressRoomName = this.room?.name;
|
this.ingressRoomName = this.room?.name;
|
||||||
|
this.agentRoomName = this.room?.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
async listRooms() {
|
async listRooms() {
|
||||||
|
|
@ -365,6 +377,81 @@ export class RoomApiDialogComponent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async createDispatch() {
|
||||||
|
console.log('Creating agent dispatch');
|
||||||
|
try {
|
||||||
|
const dispatch = await this.roomApiService.createDispatch(
|
||||||
|
this.agentRoomName,
|
||||||
|
this.agentName,
|
||||||
|
this.agentMetadata || undefined,
|
||||||
|
this.agentRestartPolicySelected
|
||||||
|
);
|
||||||
|
this.response = JSON.stringify(dispatch, null, 4);
|
||||||
|
this.agentDispatchId = dispatch.id;
|
||||||
|
} catch (error: any) {
|
||||||
|
this.response = error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async getDispatch() {
|
||||||
|
console.log('Getting agent dispatch');
|
||||||
|
try {
|
||||||
|
const dispatch = await this.roomApiService.getDispatch(
|
||||||
|
this.agentDispatchId,
|
||||||
|
this.agentRoomName
|
||||||
|
);
|
||||||
|
this.response = dispatch
|
||||||
|
? JSON.stringify(dispatch, null, 4)
|
||||||
|
: 'Dispatch not found';
|
||||||
|
} catch (error: any) {
|
||||||
|
this.response = error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async listDispatch() {
|
||||||
|
console.log('Listing agent dispatches');
|
||||||
|
try {
|
||||||
|
const dispatches = await this.roomApiService.listDispatch(
|
||||||
|
this.agentRoomName
|
||||||
|
);
|
||||||
|
this.response = JSON.stringify(dispatches, null, 4);
|
||||||
|
} catch (error: any) {
|
||||||
|
this.response = error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async deleteDispatch() {
|
||||||
|
console.log('Deleting agent dispatch');
|
||||||
|
try {
|
||||||
|
await this.roomApiService.deleteDispatch(
|
||||||
|
this.agentDispatchId,
|
||||||
|
this.agentRoomName
|
||||||
|
);
|
||||||
|
this.response = 'Agent dispatch deleted';
|
||||||
|
} catch (error: any) {
|
||||||
|
this.response = error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async deleteAllDispatch() {
|
||||||
|
console.log('Deleting all agent dispatches');
|
||||||
|
try {
|
||||||
|
const promises: Promise<void>[] = [];
|
||||||
|
const dispatches = await this.roomApiService.listDispatch(
|
||||||
|
this.agentRoomName
|
||||||
|
);
|
||||||
|
dispatches.forEach((d) => {
|
||||||
|
promises.push(
|
||||||
|
this.roomApiService.deleteDispatch(d.id, this.agentRoomName)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
await Promise.all(promises);
|
||||||
|
this.response = 'Deleted ' + promises.length + ' agent dispatches';
|
||||||
|
} catch (error: any) {
|
||||||
|
this.response = error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
addRtmpUrl(event: MatChipInputEvent): void {
|
addRtmpUrl(event: MatChipInputEvent): void {
|
||||||
const value = (event.value || '').trim();
|
const value = (event.value || '').trim();
|
||||||
if (value) {
|
if (value) {
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import { Injectable } from '@angular/core';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
AccessToken,
|
AccessToken,
|
||||||
|
AgentDispatchClient,
|
||||||
CreateIngressOptions,
|
CreateIngressOptions,
|
||||||
DirectFileOutput,
|
DirectFileOutput,
|
||||||
EgressClient,
|
EgressClient,
|
||||||
|
|
@ -25,7 +26,9 @@ import {
|
||||||
import { LivekitParamsService } from './livekit-params.service';
|
import { LivekitParamsService } from './livekit-params.service';
|
||||||
import { VideoQuality } from 'livekit-client';
|
import { VideoQuality } from 'livekit-client';
|
||||||
import {
|
import {
|
||||||
|
AgentDispatch,
|
||||||
IngressVideoEncodingOptions,
|
IngressVideoEncodingOptions,
|
||||||
|
JobRestartPolicy,
|
||||||
VideoCodec,
|
VideoCodec,
|
||||||
VideoLayer,
|
VideoLayer,
|
||||||
} from '@livekit/protocol';
|
} from '@livekit/protocol';
|
||||||
|
|
@ -46,6 +49,7 @@ export class RoomApiService {
|
||||||
private roomServiceClient: RoomServiceClient;
|
private roomServiceClient: RoomServiceClient;
|
||||||
private egressClient: EgressClient;
|
private egressClient: EgressClient;
|
||||||
private ingressClient: IngressClient;
|
private ingressClient: IngressClient;
|
||||||
|
private agentDispatchClient: AgentDispatchClient;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private http: HttpClient,
|
private http: HttpClient,
|
||||||
|
|
@ -66,6 +70,11 @@ export class RoomApiService {
|
||||||
this.livekitParamsService.getParams().livekitApiKey,
|
this.livekitParamsService.getParams().livekitApiKey,
|
||||||
this.livekitParamsService.getParams().livekitApiSecret
|
this.livekitParamsService.getParams().livekitApiSecret
|
||||||
);
|
);
|
||||||
|
this.agentDispatchClient = new AgentDispatchClient(
|
||||||
|
this.getRestUrl(),
|
||||||
|
this.livekitParamsService.getParams().livekitApiKey,
|
||||||
|
this.livekitParamsService.getParams().livekitApiSecret
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async createToken(
|
async createToken(
|
||||||
|
|
@ -328,6 +337,38 @@ export class RoomApiService {
|
||||||
return await ingressClient.deleteIngress(ingressId);
|
return await ingressClient.deleteIngress(ingressId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Agent Dispatch API
|
||||||
|
* https://docs.livekit.io/reference/agents/agent-dispatch-service-api/
|
||||||
|
*/
|
||||||
|
|
||||||
|
async createDispatch(
|
||||||
|
roomName: string,
|
||||||
|
agentName: string,
|
||||||
|
metadata?: string,
|
||||||
|
restartPolicy?: JobRestartPolicy
|
||||||
|
): Promise<AgentDispatch> {
|
||||||
|
return await this.agentDispatchClient.createDispatch(roomName, agentName, {
|
||||||
|
metadata,
|
||||||
|
restartPolicy,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async getDispatch(
|
||||||
|
dispatchId: string,
|
||||||
|
roomName: string
|
||||||
|
): Promise<AgentDispatch | undefined> {
|
||||||
|
return await this.agentDispatchClient.getDispatch(dispatchId, roomName);
|
||||||
|
}
|
||||||
|
|
||||||
|
async listDispatch(roomName: string): Promise<AgentDispatch[]> {
|
||||||
|
return await this.agentDispatchClient.listDispatch(roomName);
|
||||||
|
}
|
||||||
|
|
||||||
|
async deleteDispatch(dispatchId: string, roomName: string): Promise<void> {
|
||||||
|
return await this.agentDispatchClient.deleteDispatch(dispatchId, roomName);
|
||||||
|
}
|
||||||
|
|
||||||
private getRestUrl() {
|
private getRestUrl() {
|
||||||
const wsUrl = this.livekitParamsService.getParams().livekitUrl;
|
const wsUrl = this.livekitParamsService.getParams().livekitUrl;
|
||||||
const protocol =
|
const protocol =
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue