@myscheme/voice-navigation-sdk 0.1.6 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -5
- package/dist/actions.d.ts.map +1 -1
- package/dist/actions.js +172 -32
- package/dist/microphone-handler.d.ts +6 -0
- package/dist/microphone-handler.d.ts.map +1 -1
- package/dist/microphone-handler.js +87 -22
- package/dist/navigation-controller.d.ts +4 -0
- package/dist/navigation-controller.d.ts.map +1 -1
- package/dist/navigation-controller.js +162 -1
- package/dist/server/azure-speech-handler.d.ts +1 -0
- package/dist/server/azure-speech-handler.d.ts.map +1 -1
- package/dist/server/azure-speech-handler.js +55 -16
- package/dist/server/bedrock-embedding-handler.d.ts +1 -0
- package/dist/server/bedrock-embedding-handler.d.ts.map +1 -1
- package/dist/server/bedrock-embedding-handler.js +84 -24
- package/dist/server/bedrock-handler.d.ts +1 -0
- package/dist/server/bedrock-handler.d.ts.map +1 -1
- package/dist/server/bedrock-handler.js +79 -22
- package/dist/server/index.d.ts +3 -0
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +3 -0
- package/dist/services/bedrock.d.ts +3 -0
- package/dist/services/bedrock.d.ts.map +1 -1
- package/dist/services/bedrock.js +122 -0
- package/dist/services/voice-feedback.d.ts +46 -0
- package/dist/services/voice-feedback.d.ts.map +1 -0
- package/dist/services/voice-feedback.js +332 -0
- package/dist/types.d.ts +4 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -2,6 +2,7 @@ import { MicrophoneHandler } from "./microphone-handler.js";
|
|
|
2
2
|
import { AzureSpeechService } from "./services/azure-speech.js";
|
|
3
3
|
import { BedrockService } from "./services/bedrock.js";
|
|
4
4
|
import { PageRegistry } from "./services/page-registry.js";
|
|
5
|
+
import { VoiceFeedbackService } from "./services/voice-feedback.js";
|
|
5
6
|
import { loadNavigationPages } from "./services/xml-parser.js";
|
|
6
7
|
import { VectorSearchService, } from "./services/vector-search.js";
|
|
7
8
|
import { performAgentAction, formatActionLabel, extractAgentAction, setPageRegistry, } from "./actions.js";
|
|
@@ -99,6 +100,15 @@ export class VoiceNavigationController {
|
|
|
99
100
|
bedrockService: this.bedrockService,
|
|
100
101
|
language: this.config.language || "en-IN",
|
|
101
102
|
});
|
|
103
|
+
const voiceFeedbackEnabled = this.config.voiceFeedback?.enabled !== false;
|
|
104
|
+
console.log("[VoiceNavigation] Initializing voice feedback service - enabled:", voiceFeedbackEnabled);
|
|
105
|
+
this.voiceFeedbackService = new VoiceFeedbackService({
|
|
106
|
+
enabled: voiceFeedbackEnabled,
|
|
107
|
+
language: this.config.language || "en-IN",
|
|
108
|
+
azureSpeechService: this.azureSpeechService,
|
|
109
|
+
bedrockService: this.bedrockService,
|
|
110
|
+
});
|
|
111
|
+
console.log("[VoiceNavigation] Voice feedback service initialized successfully");
|
|
102
112
|
if (openSearchConfig) {
|
|
103
113
|
try {
|
|
104
114
|
this.vectorSearchService = new VectorSearchService(openSearchConfig);
|
|
@@ -439,6 +449,30 @@ export class VoiceNavigationController {
|
|
|
439
449
|
query,
|
|
440
450
|
originalText,
|
|
441
451
|
});
|
|
452
|
+
if (actionResult.performed && actionResult.info?.pendingNavigation) {
|
|
453
|
+
console.log("[VoiceNavigation] Search result with navigation - waiting for feedback:", action);
|
|
454
|
+
try {
|
|
455
|
+
await this.provideActionFeedback(action, actionResult, originalText);
|
|
456
|
+
console.log("[VoiceNavigation] Search feedback complete, now navigating to:", actionResult.info.navigationUrl);
|
|
457
|
+
if (actionResult.info.navigationUrl) {
|
|
458
|
+
window.location.href = actionResult.info.navigationUrl;
|
|
459
|
+
actionResult.info.navigated = true;
|
|
460
|
+
actionResult.info.pendingNavigation = false;
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
catch (err) {
|
|
464
|
+
console.error("[VoiceNavigation] Voice feedback error (search):", err);
|
|
465
|
+
if (actionResult.info.navigationUrl) {
|
|
466
|
+
window.location.href = actionResult.info.navigationUrl;
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
else if (actionResult.performed) {
|
|
471
|
+
console.log("[VoiceNavigation] Search result without navigation - non-blocking feedback");
|
|
472
|
+
void this.provideActionFeedback(action, actionResult, originalText).catch((err) => {
|
|
473
|
+
console.error("[VoiceNavigation] Voice feedback error (search):", err);
|
|
474
|
+
});
|
|
475
|
+
}
|
|
442
476
|
if (typeof this.config.actionHandlers?.[action] === "function") {
|
|
443
477
|
try {
|
|
444
478
|
this.config.actionHandlers[action]({
|
|
@@ -475,6 +509,75 @@ export class VoiceNavigationController {
|
|
|
475
509
|
query: query,
|
|
476
510
|
},
|
|
477
511
|
});
|
|
512
|
+
console.log("[VoiceNavigation] Action performed:", action, "result:", actionResult.performed);
|
|
513
|
+
const isCriticalAction = action.startsWith("navigate_") ||
|
|
514
|
+
action === "focus_next" ||
|
|
515
|
+
action === "tab_next" ||
|
|
516
|
+
action === "focus_previous" ||
|
|
517
|
+
action === "tab_back" ||
|
|
518
|
+
action === "go_back" ||
|
|
519
|
+
action === "go_forward" ||
|
|
520
|
+
action === "reload_page";
|
|
521
|
+
if (actionResult.performed && isCriticalAction) {
|
|
522
|
+
console.log("[VoiceNavigation] Critical action - waiting for voice feedback to complete:", action);
|
|
523
|
+
try {
|
|
524
|
+
await this.provideActionFeedback(action, actionResult, originalText);
|
|
525
|
+
console.log("[VoiceNavigation] Voice feedback completed for critical action:", action);
|
|
526
|
+
if (actionResult.info?.pendingNavigation) {
|
|
527
|
+
if (actionResult.info.navigationUrl) {
|
|
528
|
+
console.log("[VoiceNavigation] Feedback complete, now navigating to:", actionResult.info.navigationUrl);
|
|
529
|
+
window.location.href = actionResult.info.navigationUrl;
|
|
530
|
+
actionResult.info.navigated = true;
|
|
531
|
+
actionResult.info.pendingNavigation = false;
|
|
532
|
+
}
|
|
533
|
+
else if (actionResult.info.navigationType === "back") {
|
|
534
|
+
console.log("[VoiceNavigation] Feedback complete, navigating back");
|
|
535
|
+
window.history.back();
|
|
536
|
+
actionResult.info.navigated = true;
|
|
537
|
+
actionResult.info.pendingNavigation = false;
|
|
538
|
+
}
|
|
539
|
+
else if (actionResult.info.navigationType === "forward") {
|
|
540
|
+
console.log("[VoiceNavigation] Feedback complete, navigating forward");
|
|
541
|
+
window.history.forward();
|
|
542
|
+
actionResult.info.navigated = true;
|
|
543
|
+
actionResult.info.pendingNavigation = false;
|
|
544
|
+
}
|
|
545
|
+
else if (actionResult.info.navigationType === "reload") {
|
|
546
|
+
console.log("[VoiceNavigation] Feedback complete, reloading page");
|
|
547
|
+
window.location.reload();
|
|
548
|
+
actionResult.info.reloaded = true;
|
|
549
|
+
actionResult.info.pendingNavigation = false;
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
catch (err) {
|
|
554
|
+
console.error("[VoiceNavigation] Voice feedback error (critical action):", err);
|
|
555
|
+
if (actionResult.info?.pendingNavigation) {
|
|
556
|
+
if (actionResult.info.navigationUrl) {
|
|
557
|
+
console.log("[VoiceNavigation] Feedback failed, but proceeding with navigation:", actionResult.info.navigationUrl);
|
|
558
|
+
window.location.href = actionResult.info.navigationUrl;
|
|
559
|
+
}
|
|
560
|
+
else if (actionResult.info.navigationType === "back") {
|
|
561
|
+
window.history.back();
|
|
562
|
+
}
|
|
563
|
+
else if (actionResult.info.navigationType === "forward") {
|
|
564
|
+
window.history.forward();
|
|
565
|
+
}
|
|
566
|
+
else if (actionResult.info.navigationType === "reload") {
|
|
567
|
+
window.location.reload();
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
else if (actionResult.performed) {
|
|
573
|
+
console.log("[VoiceNavigation] Non-critical action - providing feedback non-blocking:", action);
|
|
574
|
+
void this.provideActionFeedback(action, actionResult, originalText).catch((err) => {
|
|
575
|
+
console.error("[VoiceNavigation] Voice feedback error:", err);
|
|
576
|
+
});
|
|
577
|
+
}
|
|
578
|
+
else {
|
|
579
|
+
console.log("[VoiceNavigation] Action not performed, skipping voice feedback");
|
|
580
|
+
}
|
|
478
581
|
if (typeof this.config.actionHandlers?.[action] === "function") {
|
|
479
582
|
try {
|
|
480
583
|
this.config.actionHandlers[action]({
|
|
@@ -503,6 +606,62 @@ export class VoiceNavigationController {
|
|
|
503
606
|
}
|
|
504
607
|
setLanguage(language) {
|
|
505
608
|
this.microphoneHandler.setLanguage(language);
|
|
609
|
+
this.voiceFeedbackService.setLanguage(language);
|
|
610
|
+
}
|
|
611
|
+
setVoiceFeedback(enabled) {
|
|
612
|
+
this.voiceFeedbackService.setEnabled(enabled);
|
|
613
|
+
}
|
|
614
|
+
isVoiceFeedbackEnabled() {
|
|
615
|
+
return this.voiceFeedbackService.isEnabled();
|
|
616
|
+
}
|
|
617
|
+
async provideActionFeedback(action, actionResult, transcript) {
|
|
618
|
+
console.log("[VoiceNavigation] provideActionFeedback called for action:", action);
|
|
619
|
+
if (!this.voiceFeedbackService) {
|
|
620
|
+
console.error("[VoiceNavigation] Voice feedback service not initialized!");
|
|
621
|
+
return;
|
|
622
|
+
}
|
|
623
|
+
console.log("[VoiceNavigation] Voice feedback service exists, checking if enabled...");
|
|
624
|
+
console.log("[VoiceNavigation] Voice feedback enabled:", this.voiceFeedbackService.isEnabled());
|
|
625
|
+
try {
|
|
626
|
+
if (action.startsWith("navigate_") && actionResult.info?.pageName) {
|
|
627
|
+
console.log("[VoiceNavigation] Handling navigation feedback");
|
|
628
|
+
await this.voiceFeedbackService.provideFeedback({
|
|
629
|
+
action,
|
|
630
|
+
actionResult,
|
|
631
|
+
transcript,
|
|
632
|
+
});
|
|
633
|
+
return;
|
|
634
|
+
}
|
|
635
|
+
if ((action === "focus_next" ||
|
|
636
|
+
action === "tab_next" ||
|
|
637
|
+
action === "focus_previous" ||
|
|
638
|
+
action === "tab_back") &&
|
|
639
|
+
actionResult.performed) {
|
|
640
|
+
console.log("[VoiceNavigation] Handling focus feedback");
|
|
641
|
+
const focusedElement = document.activeElement;
|
|
642
|
+
if (focusedElement && focusedElement !== document.body) {
|
|
643
|
+
await this.voiceFeedbackService.announceFocusChange(focusedElement, actionResult.info.direction === "next" ||
|
|
644
|
+
actionResult.info.direction === "forward"
|
|
645
|
+
? "next"
|
|
646
|
+
: "previous");
|
|
647
|
+
return;
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
if (actionResult.performed) {
|
|
651
|
+
console.log("[VoiceNavigation] Handling general action feedback");
|
|
652
|
+
await this.voiceFeedbackService.provideFeedback({
|
|
653
|
+
action,
|
|
654
|
+
actionResult,
|
|
655
|
+
transcript,
|
|
656
|
+
});
|
|
657
|
+
}
|
|
658
|
+
else {
|
|
659
|
+
console.log("[VoiceNavigation] Action not performed in feedback check");
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
catch (error) {
|
|
663
|
+
console.error("[VoiceNavigation] Failed to provide voice feedback:", error);
|
|
664
|
+
}
|
|
506
665
|
}
|
|
507
666
|
async executeVectorSearchAction(options) {
|
|
508
667
|
const vectorService = this.vectorSearchService;
|
|
@@ -628,7 +787,9 @@ export class VoiceNavigationController {
|
|
|
628
787
|
});
|
|
629
788
|
this.prepareForNavigation({ target: resolvedUrl });
|
|
630
789
|
baseInfo.message = "Opening the best matching result.";
|
|
631
|
-
|
|
790
|
+
baseInfo.pendingNavigation = true;
|
|
791
|
+
baseInfo.navigationUrl = resolvedUrl;
|
|
792
|
+
baseInfo.navigated = false;
|
|
632
793
|
return {
|
|
633
794
|
performed: true,
|
|
634
795
|
info: baseInfo,
|
|
@@ -8,5 +8,6 @@ type NextApiResponse = {
|
|
|
8
8
|
setHeader: (name: string, value: string | string[]) => void;
|
|
9
9
|
};
|
|
10
10
|
export declare function azureSpeechTokenHandler(req: NextApiRequest, res: NextApiResponse): Promise<void>;
|
|
11
|
+
export declare function POST(_request: Request): Promise<Response>;
|
|
11
12
|
export {};
|
|
12
13
|
//# sourceMappingURL=azure-speech-handler.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"azure-speech-handler.d.ts","sourceRoot":"","sources":["../../src/server/azure-speech-handler.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"azure-speech-handler.d.ts","sourceRoot":"","sources":["../../src/server/azure-speech-handler.ts"],"names":[],"mappings":"AAwBA,KAAK,cAAc,GAAG;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB,CAAC;AAEF,KAAK,eAAe,GAAG;IACrB,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,eAAe,CAAC;IAC1C,IAAI,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IAC9B,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,KAAK,IAAI,CAAC;CAC7D,CAAC;AA6EF,wBAAsB,uBAAuB,CAC3C,GAAG,EAAE,cAAc,EACnB,GAAG,EAAE,eAAe,GACnB,OAAO,CAAC,IAAI,CAAC,CAqBf;AAMD,wBAAsB,IAAI,CAAC,QAAQ,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,CAmB/D"}
|
|
@@ -1,18 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
if (req.method !== "POST") {
|
|
3
|
-
res.setHeader("Allow", ["POST"]);
|
|
4
|
-
res.status(405).json({ error: "Method not allowed" });
|
|
5
|
-
return;
|
|
6
|
-
}
|
|
1
|
+
async function getAzureSpeechToken() {
|
|
7
2
|
const key = process.env.AZURE_SPEECH_KEY;
|
|
8
3
|
const region = process.env.AZURE_SPEECH_REGION;
|
|
9
4
|
if (!key || !region) {
|
|
10
5
|
console.error("[VoiceNavigation] Missing Azure Speech credentials. Set AZURE_SPEECH_KEY and AZURE_SPEECH_REGION in your .env file");
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
6
|
+
return {
|
|
7
|
+
success: false,
|
|
8
|
+
statusCode: 500,
|
|
9
|
+
error: {
|
|
10
|
+
error: "Azure Speech configuration is missing",
|
|
11
|
+
hint: "Set AZURE_SPEECH_KEY and AZURE_SPEECH_REGION environment variables",
|
|
12
|
+
},
|
|
13
|
+
};
|
|
16
14
|
}
|
|
17
15
|
try {
|
|
18
16
|
const url = `https://${region}.api.cognitive.microsoft.com/sts/v1.0/issueToken`;
|
|
@@ -26,15 +24,56 @@ export async function azureSpeechTokenHandler(req, res) {
|
|
|
26
24
|
throw new Error(`Azure API responded with status ${response.status}`);
|
|
27
25
|
}
|
|
28
26
|
const token = await response.text();
|
|
29
|
-
res.setHeader("Cache-Control", "no-store, no-cache, max-age=0, must-revalidate");
|
|
30
27
|
const responseData = { token, region };
|
|
31
|
-
|
|
28
|
+
return {
|
|
29
|
+
success: true,
|
|
30
|
+
statusCode: 200,
|
|
31
|
+
data: responseData,
|
|
32
|
+
};
|
|
32
33
|
}
|
|
33
34
|
catch (error) {
|
|
34
35
|
console.error("[VoiceNavigation] Failed to fetch Azure speech token:", error);
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
return {
|
|
37
|
+
success: false,
|
|
38
|
+
statusCode: 500,
|
|
39
|
+
error: {
|
|
40
|
+
error: "Failed to get token",
|
|
41
|
+
message: error instanceof Error ? error.message : "Unknown error",
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
export async function azureSpeechTokenHandler(req, res) {
|
|
47
|
+
if (req.method !== "POST") {
|
|
48
|
+
res.setHeader("Allow", ["POST"]);
|
|
49
|
+
res.status(405).json({ error: "Method not allowed" });
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const result = await getAzureSpeechToken();
|
|
53
|
+
res.setHeader("Cache-Control", "no-store, no-cache, max-age=0, must-revalidate");
|
|
54
|
+
if (result.success && result.data) {
|
|
55
|
+
res.status(result.statusCode).json(result.data);
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
res.status(result.statusCode).json(result.error);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
export async function POST(_request) {
|
|
62
|
+
const result = await getAzureSpeechToken();
|
|
63
|
+
const headers = {
|
|
64
|
+
"Content-Type": "application/json",
|
|
65
|
+
"Cache-Control": "no-store, no-cache, max-age=0, must-revalidate",
|
|
66
|
+
};
|
|
67
|
+
if (result.success && result.data) {
|
|
68
|
+
return new Response(JSON.stringify(result.data), {
|
|
69
|
+
status: result.statusCode,
|
|
70
|
+
headers,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
return new Response(JSON.stringify(result.error), {
|
|
75
|
+
status: result.statusCode,
|
|
76
|
+
headers,
|
|
38
77
|
});
|
|
39
78
|
}
|
|
40
79
|
}
|
|
@@ -11,5 +11,6 @@ type NextApiResponse = {
|
|
|
11
11
|
setHeader: (name: string, value: string | string[]) => void;
|
|
12
12
|
};
|
|
13
13
|
export declare function bedrockEmbeddingHandler(req: NextApiRequest, res: NextApiResponse): Promise<void>;
|
|
14
|
+
export declare function BedrockEmbeddingPOST(request: Request): Promise<Response>;
|
|
14
15
|
export {};
|
|
15
16
|
//# sourceMappingURL=bedrock-embedding-handler.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bedrock-embedding-handler.d.ts","sourceRoot":"","sources":["../../src/server/bedrock-embedding-handler.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"bedrock-embedding-handler.d.ts","sourceRoot":"","sources":["../../src/server/bedrock-embedding-handler.ts"],"names":[],"mappings":"AA4BA,KAAK,cAAc,GAAG;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE;QACL,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;QACzB,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;CACH,CAAC;AAEF,KAAK,eAAe,GAAG;IACrB,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,eAAe,CAAC;IAC1C,IAAI,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IAC9B,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,KAAK,IAAI,CAAC;CAC7D,CAAC;AA0MF,wBAAsB,uBAAuB,CAC3C,GAAG,EAAE,cAAc,EACnB,GAAG,EAAE,eAAe,GACnB,OAAO,CAAC,IAAI,CAAC,CAiBf;AAMD,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,OAAO,GACf,OAAO,CAAC,QAAQ,CAAC,CAkCnB"}
|
|
@@ -9,12 +9,7 @@ function getSignatureKey(key, dateStamp, region, service) {
|
|
|
9
9
|
const kSigning = sign(kService, "aws4_request");
|
|
10
10
|
return kSigning;
|
|
11
11
|
}
|
|
12
|
-
|
|
13
|
-
if (req.method !== "POST") {
|
|
14
|
-
res.setHeader("Allow", ["POST"]);
|
|
15
|
-
res.status(405).json({ error: "Method not allowed" });
|
|
16
|
-
return;
|
|
17
|
-
}
|
|
12
|
+
async function generateBedrockEmbedding(text, inputType = "search_query") {
|
|
18
13
|
const region = process.env.AWS_REGION || "ap-south-1";
|
|
19
14
|
const accessKey = process.env.AWS_ACCESS_KEY_ID;
|
|
20
15
|
const secretKey = process.env.AWS_SECRET_ACCESS_KEY;
|
|
@@ -22,20 +17,28 @@ export async function bedrockEmbeddingHandler(req, res) {
|
|
|
22
17
|
const embeddingModelId = process.env.AWS_EMBEDDING_MODEL_ID || "cohere.embed-multilingual-v3";
|
|
23
18
|
if (!accessKey || !secretKey) {
|
|
24
19
|
console.error("[VoiceNavigation] Missing AWS credentials. Set AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY in your .env file");
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
20
|
+
return {
|
|
21
|
+
success: false,
|
|
22
|
+
statusCode: 500,
|
|
23
|
+
error: {
|
|
24
|
+
error: "Missing AWS credentials",
|
|
25
|
+
hint: "Set AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY environment variables",
|
|
26
|
+
},
|
|
27
|
+
};
|
|
30
28
|
}
|
|
31
29
|
if (!embeddingModelId) {
|
|
32
|
-
|
|
33
|
-
|
|
30
|
+
return {
|
|
31
|
+
success: false,
|
|
32
|
+
statusCode: 500,
|
|
33
|
+
error: { error: "Missing AWS_EMBEDDING_MODEL_ID" },
|
|
34
|
+
};
|
|
34
35
|
}
|
|
35
|
-
const { text, inputType = "search_query" } = req.body || {};
|
|
36
36
|
if (!text) {
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
return {
|
|
38
|
+
success: false,
|
|
39
|
+
statusCode: 400,
|
|
40
|
+
error: { error: "Missing text parameter" },
|
|
41
|
+
};
|
|
39
42
|
}
|
|
40
43
|
const requestBody = {
|
|
41
44
|
texts: Array.isArray(text) ? text : [text],
|
|
@@ -104,20 +107,77 @@ export async function bedrockEmbeddingHandler(req, res) {
|
|
|
104
107
|
if (!response.ok) {
|
|
105
108
|
const errorText = await response.text();
|
|
106
109
|
console.error("[VoiceNavigation] Bedrock Embedding API error:", response.status, errorText);
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
110
|
+
return {
|
|
111
|
+
success: false,
|
|
112
|
+
statusCode: response.status,
|
|
113
|
+
error: {
|
|
114
|
+
error: "Bedrock Embedding API error",
|
|
115
|
+
details: errorText,
|
|
116
|
+
},
|
|
117
|
+
};
|
|
112
118
|
}
|
|
113
119
|
const json = await response.json();
|
|
114
|
-
|
|
120
|
+
return {
|
|
121
|
+
success: true,
|
|
122
|
+
statusCode: 200,
|
|
123
|
+
data: json,
|
|
124
|
+
};
|
|
115
125
|
}
|
|
116
126
|
catch (error) {
|
|
117
127
|
console.error("[VoiceNavigation] Bedrock embedding generation error:", error);
|
|
118
|
-
|
|
119
|
-
|
|
128
|
+
return {
|
|
129
|
+
success: false,
|
|
130
|
+
statusCode: 500,
|
|
131
|
+
error: {
|
|
132
|
+
error: "Failed to generate embeddings",
|
|
133
|
+
message: error instanceof Error ? error.message : "Unknown error",
|
|
134
|
+
},
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
export async function bedrockEmbeddingHandler(req, res) {
|
|
139
|
+
if (req.method !== "POST") {
|
|
140
|
+
res.setHeader("Allow", ["POST"]);
|
|
141
|
+
res.status(405).json({ error: "Method not allowed" });
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
const { text, inputType = "search_query" } = req.body || {};
|
|
145
|
+
const result = await generateBedrockEmbedding(text, inputType);
|
|
146
|
+
if (result.success && result.data) {
|
|
147
|
+
res.status(result.statusCode).json(result.data);
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
res.status(result.statusCode).json(result.error);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
export async function BedrockEmbeddingPOST(request) {
|
|
154
|
+
try {
|
|
155
|
+
const body = await request.json();
|
|
156
|
+
const { text, inputType = "search_query" } = body || {};
|
|
157
|
+
const result = await generateBedrockEmbedding(text, inputType);
|
|
158
|
+
const headers = {
|
|
159
|
+
"Content-Type": "application/json",
|
|
160
|
+
};
|
|
161
|
+
if (result.success && result.data) {
|
|
162
|
+
return new Response(JSON.stringify(result.data), {
|
|
163
|
+
status: result.statusCode,
|
|
164
|
+
headers,
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
else {
|
|
168
|
+
return new Response(JSON.stringify(result.error), {
|
|
169
|
+
status: result.statusCode,
|
|
170
|
+
headers,
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
catch (error) {
|
|
175
|
+
return new Response(JSON.stringify({
|
|
176
|
+
error: "Invalid request",
|
|
120
177
|
message: error instanceof Error ? error.message : "Unknown error",
|
|
178
|
+
}), {
|
|
179
|
+
status: 400,
|
|
180
|
+
headers: { "Content-Type": "application/json" },
|
|
121
181
|
});
|
|
122
182
|
}
|
|
123
183
|
}
|
|
@@ -10,5 +10,6 @@ type NextApiResponse = {
|
|
|
10
10
|
setHeader: (name: string, value: string | string[]) => void;
|
|
11
11
|
};
|
|
12
12
|
export declare function bedrockHandler(req: NextApiRequest, res: NextApiResponse): Promise<void>;
|
|
13
|
+
export declare function BedrockPOST(request: Request): Promise<Response>;
|
|
13
14
|
export {};
|
|
14
15
|
//# sourceMappingURL=bedrock-handler.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bedrock-handler.d.ts","sourceRoot":"","sources":["../../src/server/bedrock-handler.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"bedrock-handler.d.ts","sourceRoot":"","sources":["../../src/server/bedrock-handler.ts"],"names":[],"mappings":"AA4BA,KAAK,cAAc,GAAG;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE;QACL,IAAI,CAAC,EAAE,OAAO,CAAC;KAChB,CAAC;CACH,CAAC;AAEF,KAAK,eAAe,GAAG;IACrB,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,eAAe,CAAC;IAC1C,IAAI,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IAC9B,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,KAAK,IAAI,CAAC;CAC7D,CAAC;AAqLF,wBAAsB,cAAc,CAClC,GAAG,EAAE,cAAc,EACnB,GAAG,EAAE,eAAe,GACnB,OAAO,CAAC,IAAI,CAAC,CAkBf;AAMD,wBAAsB,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,CAkCrE"}
|
|
@@ -9,12 +9,7 @@ function getSignatureKey(key, dateStamp, region, service) {
|
|
|
9
9
|
const kSigning = sign(kService, "aws4_request");
|
|
10
10
|
return kSigning;
|
|
11
11
|
}
|
|
12
|
-
|
|
13
|
-
if (req.method !== "POST") {
|
|
14
|
-
res.setHeader("Allow", ["POST"]);
|
|
15
|
-
res.status(405).json({ error: "Method not allowed" });
|
|
16
|
-
return;
|
|
17
|
-
}
|
|
12
|
+
async function invokeBedrock(requestBody) {
|
|
18
13
|
const region = process.env.AWS_REGION || "ap-south-1";
|
|
19
14
|
const accessKey = process.env.AWS_ACCESS_KEY_ID;
|
|
20
15
|
const secretKey = process.env.AWS_SECRET_ACCESS_KEY;
|
|
@@ -22,16 +17,21 @@ export async function bedrockHandler(req, res) {
|
|
|
22
17
|
const modelId = process.env.AWS_MODEL_ID || "anthropic.claude-3-sonnet-20240229-v1:0";
|
|
23
18
|
if (!accessKey || !secretKey) {
|
|
24
19
|
console.error("[VoiceNavigation] Missing AWS credentials. Set AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY in your .env file");
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
20
|
+
return {
|
|
21
|
+
success: false,
|
|
22
|
+
statusCode: 500,
|
|
23
|
+
error: {
|
|
24
|
+
error: "Missing AWS credentials",
|
|
25
|
+
hint: "Set AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY environment variables",
|
|
26
|
+
},
|
|
27
|
+
};
|
|
30
28
|
}
|
|
31
|
-
const requestBody = req.body?.body;
|
|
32
29
|
if (!requestBody) {
|
|
33
|
-
|
|
34
|
-
|
|
30
|
+
return {
|
|
31
|
+
success: false,
|
|
32
|
+
statusCode: 400,
|
|
33
|
+
error: { error: "Missing request body" },
|
|
34
|
+
};
|
|
35
35
|
}
|
|
36
36
|
const body = JSON.stringify(requestBody);
|
|
37
37
|
const service = "bedrock";
|
|
@@ -95,20 +95,77 @@ export async function bedrockHandler(req, res) {
|
|
|
95
95
|
if (!response.ok) {
|
|
96
96
|
const errorText = await response.text();
|
|
97
97
|
console.error("[VoiceNavigation] Bedrock API error:", response.status, errorText);
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
98
|
+
return {
|
|
99
|
+
success: false,
|
|
100
|
+
statusCode: response.status,
|
|
101
|
+
error: {
|
|
102
|
+
error: "Bedrock API error",
|
|
103
|
+
details: errorText,
|
|
104
|
+
},
|
|
105
|
+
};
|
|
103
106
|
}
|
|
104
107
|
const json = await response.json();
|
|
105
|
-
|
|
108
|
+
return {
|
|
109
|
+
success: true,
|
|
110
|
+
statusCode: 200,
|
|
111
|
+
data: json,
|
|
112
|
+
};
|
|
106
113
|
}
|
|
107
114
|
catch (error) {
|
|
108
115
|
console.error("[VoiceNavigation] Bedrock action extraction error:", error);
|
|
109
|
-
|
|
110
|
-
|
|
116
|
+
return {
|
|
117
|
+
success: false,
|
|
118
|
+
statusCode: 500,
|
|
119
|
+
error: {
|
|
120
|
+
error: "Failed to extract action",
|
|
121
|
+
message: error instanceof Error ? error.message : "Unknown error",
|
|
122
|
+
},
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
export async function bedrockHandler(req, res) {
|
|
127
|
+
if (req.method !== "POST") {
|
|
128
|
+
res.setHeader("Allow", ["POST"]);
|
|
129
|
+
res.status(405).json({ error: "Method not allowed" });
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
const requestBody = req.body?.body;
|
|
133
|
+
const result = await invokeBedrock(requestBody);
|
|
134
|
+
if (result.success && result.data) {
|
|
135
|
+
res.status(result.statusCode).json(result.data);
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
res.status(result.statusCode).json(result.error);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
export async function BedrockPOST(request) {
|
|
142
|
+
try {
|
|
143
|
+
const body = await request.json();
|
|
144
|
+
const requestBody = body?.body;
|
|
145
|
+
const result = await invokeBedrock(requestBody);
|
|
146
|
+
const headers = {
|
|
147
|
+
"Content-Type": "application/json",
|
|
148
|
+
};
|
|
149
|
+
if (result.success && result.data) {
|
|
150
|
+
return new Response(JSON.stringify(result.data), {
|
|
151
|
+
status: result.statusCode,
|
|
152
|
+
headers,
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
return new Response(JSON.stringify(result.error), {
|
|
157
|
+
status: result.statusCode,
|
|
158
|
+
headers,
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
catch (error) {
|
|
163
|
+
return new Response(JSON.stringify({
|
|
164
|
+
error: "Invalid request",
|
|
111
165
|
message: error instanceof Error ? error.message : "Unknown error",
|
|
166
|
+
}), {
|
|
167
|
+
status: 400,
|
|
168
|
+
headers: { "Content-Type": "application/json" },
|
|
112
169
|
});
|
|
113
170
|
}
|
|
114
171
|
}
|
package/dist/server/index.d.ts
CHANGED
|
@@ -2,6 +2,9 @@ export { azureSpeechTokenHandler } from "./azure-speech-handler.js";
|
|
|
2
2
|
export { bedrockHandler } from "./bedrock-handler.js";
|
|
3
3
|
export { bedrockEmbeddingHandler } from "./bedrock-embedding-handler.js";
|
|
4
4
|
export { openSearchSearchHandler, openSearchSuggestHandler, } from "./opensearch-env-handler.js";
|
|
5
|
+
export { POST } from "./azure-speech-handler.js";
|
|
6
|
+
export { BedrockPOST } from "./bedrock-handler.js";
|
|
7
|
+
export { BedrockEmbeddingPOST } from "./bedrock-embedding-handler.js";
|
|
5
8
|
export { createOpenSearchProxyHandler, DEFAULT_OPENSEARCH_PROXY_PATH, } from "./opensearch-handler.js";
|
|
6
9
|
export type { VectorSearchProxyRequest, VectorSearchProxyResponse, } from "./opensearch-handler.js";
|
|
7
10
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAkCA,OAAO,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AACpE,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AACzE,OAAO,EACL,uBAAuB,EACvB,wBAAwB,GACzB,MAAM,6BAA6B,CAAC;AAGrC,OAAO,EAAE,IAAI,EAAE,MAAM,2BAA2B,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,EAAE,oBAAoB,EAAE,MAAM,gCAAgC,CAAC;AAGtE,OAAO,EACL,4BAA4B,EAC5B,6BAA6B,GAC9B,MAAM,yBAAyB,CAAC;AACjC,YAAY,EACV,wBAAwB,EACxB,yBAAyB,GAC1B,MAAM,yBAAyB,CAAC"}
|
package/dist/server/index.js
CHANGED
|
@@ -2,4 +2,7 @@ export { azureSpeechTokenHandler } from "./azure-speech-handler.js";
|
|
|
2
2
|
export { bedrockHandler } from "./bedrock-handler.js";
|
|
3
3
|
export { bedrockEmbeddingHandler } from "./bedrock-embedding-handler.js";
|
|
4
4
|
export { openSearchSearchHandler, openSearchSuggestHandler, } from "./opensearch-env-handler.js";
|
|
5
|
+
export { POST } from "./azure-speech-handler.js";
|
|
6
|
+
export { BedrockPOST } from "./bedrock-handler.js";
|
|
7
|
+
export { BedrockEmbeddingPOST } from "./bedrock-embedding-handler.js";
|
|
5
8
|
export { createOpenSearchProxyHandler, DEFAULT_OPENSEARCH_PROXY_PATH, } from "./opensearch-handler.js";
|
|
@@ -27,5 +27,8 @@ export declare class BedrockService {
|
|
|
27
27
|
embedText(text: string): Promise<number[]>;
|
|
28
28
|
private embedTextViaProxy;
|
|
29
29
|
private embedTextDirect;
|
|
30
|
+
generateFeedbackMessage(prompt: string, language: string): Promise<string>;
|
|
31
|
+
private generateFeedbackViaProxy;
|
|
32
|
+
private generateFeedbackDirect;
|
|
30
33
|
}
|
|
31
34
|
//# sourceMappingURL=bedrock.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bedrock.d.ts","sourceRoot":"","sources":["../../src/services/bedrock.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,mBAAmB,EAAmB,MAAM,aAAa,CAAC;AACxE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD,MAAM,WAAW,aAAa;IAE5B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAG3B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAClC;
|
|
1
|
+
{"version":3,"file":"bedrock.d.ts","sourceRoot":"","sources":["../../src/services/bedrock.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,mBAAmB,EAAmB,MAAM,aAAa,CAAC;AACxE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD,MAAM,WAAW,aAAa;IAE5B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAG3B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAClC;AAyCD,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAqC;IACnD,OAAO,CAAC,aAAa,CAAuB;IAC5C,OAAO,CAAC,gBAAgB,CAAgB;IACxC,OAAO,CAAC,YAAY,CAA6B;IACjD,OAAO,CAAC,eAAe,CAAuB;IAC9C,OAAO,CAAC,oBAAoB,CAAuB;IACnD,OAAO,CAAC,QAAQ,CAAkB;gBAEtB,MAAM,EAAE,aAAa;IA6CjC,eAAe,CAAC,QAAQ,EAAE,YAAY,GAAG,IAAI;IAO7C,OAAO,CAAC,iBAAiB;IA+BnB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC;YAWtD,qBAAqB;YA2ErB,mBAAmB;IAyEjC,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,aAAa,GAAG,cAAc;IAO9C,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;YAWlC,iBAAiB;YAkFjB,eAAe;IAwFvB,uBAAuB,CAC3B,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,MAAM,CAAC;YA0BJ,wBAAwB;YAwExB,sBAAsB;CA+DrC"}
|