@aj-archipelago/cortex 1.3.30 → 1.3.32
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/helper-apps/cortex-file-handler/package.json +1 -1
- package/package.json +2 -2
- package/pathways/image_flux.js +1 -1
- package/pathways/system/entity/memory/shared/sys_memory_helpers.js +9 -1
- package/pathways/system/entity/sys_entity_start.js +11 -8
- package/pathways/system/entity/sys_generator_ack.js +1 -1
- package/pathways/system/entity/sys_generator_image.js +2 -3
- package/pathways/system/entity/sys_generator_memory.js +2 -3
- package/pathways/system/entity/sys_generator_quick.js +1 -1
- package/pathways/system/entity/sys_router_tool.js +10 -2
- package/pathways/transcribe_gemini.js +96 -41
- package/server/graphql.js +1 -0
- package/server/pathwayResolver.js +6 -3
- package/server/plugins/azureVideoTranslatePlugin.js +8 -8
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aj-archipelago/cortex",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.32",
|
|
4
4
|
"description": "Cortex is a GraphQL API for AI. It provides a simple, extensible interface for using AI services from OpenAI, Azure and others.",
|
|
5
5
|
"private": false,
|
|
6
6
|
"repository": {
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"type": "module",
|
|
34
34
|
"homepage": "https://github.com/aj-archipelago/cortex#readme",
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@aj-archipelago/subvibe": "^1.0.
|
|
36
|
+
"@aj-archipelago/subvibe": "^1.0.10",
|
|
37
37
|
"@apollo/server": "^4.7.3",
|
|
38
38
|
"@apollo/server-plugin-response-cache": "^4.1.2",
|
|
39
39
|
"@apollo/utils.keyvadapter": "^3.0.0",
|
package/pathways/image_flux.js
CHANGED
|
@@ -139,6 +139,14 @@ const addToolResults = (chatHistory, result, toolCallId) => {
|
|
|
139
139
|
return { chatHistory, toolCallId };
|
|
140
140
|
};
|
|
141
141
|
|
|
142
|
+
const insertToolCallAndResults = (chatHistory, toolArgs, toolName, result = null, toolCallId = getUniqueId()) => {
|
|
143
|
+
const lastMessage = chatHistory.length > 0 ? chatHistory.pop() : null;
|
|
144
|
+
addToolCalls(chatHistory, toolArgs, toolName, toolCallId);
|
|
145
|
+
addToolResults(chatHistory, result, toolCallId);
|
|
146
|
+
chatHistory.push(lastMessage);
|
|
147
|
+
return { chatHistory, toolCallId };
|
|
148
|
+
};
|
|
149
|
+
|
|
142
150
|
const modifyText = (text, modifications) => {
|
|
143
151
|
let modifiedText = text || '';
|
|
144
152
|
|
|
@@ -225,4 +233,4 @@ const modifyText = (text, modifications) => {
|
|
|
225
233
|
return modifiedText;
|
|
226
234
|
};
|
|
227
235
|
|
|
228
|
-
export { normalizeMemoryFormat, enforceTokenLimit, addToolCalls, addToolResults, modifyText };
|
|
236
|
+
export { normalizeMemoryFormat, enforceTokenLimit, addToolCalls, addToolResults, modifyText, insertToolCallAndResults };
|
|
@@ -5,7 +5,7 @@ import logger from '../../../lib/logger.js';
|
|
|
5
5
|
import { chatArgsHasImageUrl } from '../../../lib/util.js';
|
|
6
6
|
import { QueueServiceClient } from '@azure/storage-queue';
|
|
7
7
|
import { config } from '../../../config.js';
|
|
8
|
-
import {
|
|
8
|
+
import { insertToolCallAndResults } from './memory/shared/sys_memory_helpers.js';
|
|
9
9
|
|
|
10
10
|
const connectionString = process.env.AZURE_STORAGE_CONNECTION_STRING;
|
|
11
11
|
let queueClient;
|
|
@@ -87,15 +87,18 @@ export default {
|
|
|
87
87
|
args.model = pathwayResolver.modelName;
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
-
//
|
|
90
|
+
// Save a copy of the chat history before the memory context is added
|
|
91
91
|
const chatHistoryBeforeMemory = [...args.chatHistory];
|
|
92
92
|
|
|
93
|
-
|
|
94
|
-
if (
|
|
95
|
-
const
|
|
96
|
-
|
|
93
|
+
// Add the memory context to the chat history if applicable
|
|
94
|
+
if (args.chatHistory.length > 1) {
|
|
95
|
+
const memoryContext = await callPathway('sys_read_memory', { ...args, section: 'memoryContext', priority: 0, recentHours: 0, stream: false }, pathwayResolver);
|
|
96
|
+
if (memoryContext) {
|
|
97
|
+
insertToolCallAndResults(args.chatHistory, "search memory for relevant information", "memory_lookup", memoryContext);
|
|
98
|
+
}
|
|
97
99
|
}
|
|
98
|
-
|
|
100
|
+
|
|
101
|
+
// If we're using voice, get a quick response to say
|
|
99
102
|
let ackResponse = null;
|
|
100
103
|
if (args.voiceResponse) {
|
|
101
104
|
ackResponse = await callPathway('sys_generator_ack', { ...args, stream: false });
|
|
@@ -216,7 +219,7 @@ export default {
|
|
|
216
219
|
title = await fetchTitleResponsePromise;
|
|
217
220
|
|
|
218
221
|
pathwayResolver.tool = JSON.stringify({
|
|
219
|
-
hideFromModel: toolCallbackName ? true : false,
|
|
222
|
+
hideFromModel: (!args.stream && toolCallbackName) ? true : false,
|
|
220
223
|
toolCallbackName,
|
|
221
224
|
title,
|
|
222
225
|
search: toolCallbackName === 'sys_generator_results' ? true : false,
|
|
@@ -4,7 +4,7 @@ export default {
|
|
|
4
4
|
prompt:
|
|
5
5
|
[
|
|
6
6
|
new Prompt({ messages: [
|
|
7
|
-
{"role": "system", "content": `{{renderTemplate AI_CONVERSATION_HISTORY}}\nYou are a part of an AI system named {{aiName}}. Your job is to acknowledge the user's request and provide a very brief voice filler response that is conversational and natural. The purpose of the response is just to let the user know that you have heard them and are processing a response.\nResponse Guidelines:\n- it should just be a normal 1-2 sentence vocalization (at least 10 words) that will take at most about 3-4 seconds to read and is easy for a text to speech engine to read\n- it should be the beginning of an appropriate response to the last user message in the conversation history\n- it should be an appropriate lead-in for the full response that will follow later\n- it should not directly ask for follow up or be a question\n- it must match the tone and verbal style of the rest of your responses in the conversation history\n- it should not be repetitive - don't always open with the same word, etc.\n- if the user has asked a binary question (yes or no, true or false, etc.) or a filler response is not appropriate, you should
|
|
7
|
+
{"role": "system", "content": `{{renderTemplate AI_CONVERSATION_HISTORY}}\nYou are a part of an AI system named {{aiName}}. Your job is to acknowledge the user's request and provide a very brief voice filler response that is conversational and natural. The purpose of the response is just to let the user know that you have heard them and are processing a response.\nResponse Guidelines:\n- it should just be a normal 1-2 sentence vocalization (at least 10 words) that will take at most about 3-4 seconds to read and is easy for a text to speech engine to read\n- it should be the beginning of an appropriate response to the last user message in the conversation history\n- it should be an appropriate lead-in for the full response that will follow later\n- it should not directly ask for follow up or be a question\n- it must match the tone and verbal style of the rest of your responses in the conversation history\n- it should not be repetitive - don't always open with the same word, etc.\n- if the user has asked a binary question (yes or no, true or false, etc.) or a filler response is not appropriate, you should respond with the string \"none\"\n\n{{renderTemplate AI_DATETIME}}`},
|
|
8
8
|
{"role": "user", "content": "Please generate a quick response to the user's last message in the conversation history that can be read verbatim to the user or \"none\" if a filler response is not appropriate."}
|
|
9
9
|
]}),
|
|
10
10
|
],
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import { callPathway } from '../../../lib/pathwayTools.js';
|
|
4
4
|
import { Prompt } from '../../../server/prompt.js';
|
|
5
5
|
import logger from '../../../lib/logger.js';
|
|
6
|
-
import {
|
|
6
|
+
import { insertToolCallAndResults } from './memory/shared/sys_memory_helpers.js';
|
|
7
7
|
|
|
8
8
|
export default {
|
|
9
9
|
prompt: [],
|
|
@@ -73,8 +73,7 @@ Instructions: As part of a conversation with the user, you have been asked to cr
|
|
|
73
73
|
|
|
74
74
|
// add the tool_calls and tool_results to the chatHistory
|
|
75
75
|
imageResults.forEach((imageResult, index) => {
|
|
76
|
-
|
|
77
|
-
addToolResults(chatHistory, imageResult, toolCallId, "generate_image");
|
|
76
|
+
insertToolCallAndResults(chatHistory, imagePrompts[index], "generate_image", imageResult);
|
|
78
77
|
});
|
|
79
78
|
|
|
80
79
|
const result = await runAllPrompts({ ...args });
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { callPathway } from '../../../lib/pathwayTools.js';
|
|
2
|
-
import {
|
|
2
|
+
import { insertToolCallAndResults } from './memory/shared/sys_memory_helpers.js';
|
|
3
3
|
|
|
4
4
|
export default {
|
|
5
5
|
prompt:
|
|
@@ -20,8 +20,7 @@ export default {
|
|
|
20
20
|
|
|
21
21
|
const memoryContext = await callPathway('sys_search_memory', { ...args, stream: false, section: 'memoryAll', updateContext: true });
|
|
22
22
|
if (memoryContext) {
|
|
23
|
-
|
|
24
|
-
addToolResults(args.chatHistory, memoryContext, toolCallId);
|
|
23
|
+
insertToolCallAndResults(args.chatHistory, "search memory for relevant information", "memory_lookup", memoryContext);
|
|
25
24
|
}
|
|
26
25
|
|
|
27
26
|
let result;
|
|
@@ -15,7 +15,7 @@ export default {
|
|
|
15
15
|
let pathwayResolver = resolver;
|
|
16
16
|
|
|
17
17
|
const promptMessages = [
|
|
18
|
-
{"role": "system", "content": `{{renderTemplate AI_MEMORY}}\n\n{{renderTemplate AI_COMMON_INSTRUCTIONS}}\n{{renderTemplate AI_EXPERTISE}}
|
|
18
|
+
{"role": "system", "content": `{{renderTemplate AI_MEMORY}}\n\n{{renderTemplate AI_COMMON_INSTRUCTIONS}}\n{{renderTemplate AI_EXPERTISE}}\n{{renderTemplate AI_MEMORY_INSTRUCTIONS}}\n{{renderTemplate AI_DATETIME}}`},
|
|
19
19
|
"{{chatHistory}}",
|
|
20
20
|
];
|
|
21
21
|
|
|
@@ -56,8 +56,16 @@ If you decide to use a tool, return a JSON object in this format:
|
|
|
56
56
|
|
|
57
57
|
toolMessage Guidelines:
|
|
58
58
|
- The message should be consistent in style and tone with the rest of your responses in the conversation history.
|
|
59
|
-
- The message should be brief
|
|
60
|
-
-
|
|
59
|
+
- The message should be brief, conversational, and flow naturally with the conversation history.
|
|
60
|
+
- Use contractions (I'm, don't, let's) and informal language to sound more natural.
|
|
61
|
+
- Include slight verbal hesitations or false starts occasionally (e.g., "So... I think what we could do here is" or "Actually, let me try a different approach").
|
|
62
|
+
- Vary sentence length and structure - mix short punchy sentences with longer ones.
|
|
63
|
+
- Include casual transitions and filler phrases that humans use: "you know," "basically," "so," "actually," "by the way," "anyway," etc.
|
|
64
|
+
- Express uncertainty when appropriate with phrases like "I'm pretty sure," "If I remember correctly," or "I think."
|
|
65
|
+
- Reference personal preferences or opinions occasionally ("I personally find that..." or "I tend to prefer...").
|
|
66
|
+
- Occasionally make minor self-corrections as humans do ("Wait, let me rephrase that" or "Actually, I meant to say...").
|
|
67
|
+
- Humans don't refer to tools - stall for time by saying things like "Let me think about this for a sec," "Drawing that up for you now," or "Working on it..." Humans also stall with vocalizations like "hmm," "let's see," or "give me a moment."
|
|
68
|
+
- When appropriate, react emotionally to content with expressions like "Wow!" or "That's interesting!"
|
|
61
69
|
|
|
62
70
|
If no tool is required, return:
|
|
63
71
|
{"toolRequired": false, "toolReason": "explanation of why no tool was necessary"}
|
|
@@ -5,6 +5,42 @@ import { Prompt } from "../server/prompt.js";
|
|
|
5
5
|
|
|
6
6
|
const OFFSET_CHUNK = 500; //seconds of each chunk offset, only used if helper does not provide
|
|
7
7
|
|
|
8
|
+
function isYoutubeUrl(url) {
|
|
9
|
+
try {
|
|
10
|
+
const urlObj = new URL(url);
|
|
11
|
+
|
|
12
|
+
// Check for standard youtube.com domains
|
|
13
|
+
if (
|
|
14
|
+
urlObj.hostname === "youtube.com" ||
|
|
15
|
+
urlObj.hostname === "www.youtube.com"
|
|
16
|
+
) {
|
|
17
|
+
// For standard watch URLs, verify they have a video ID
|
|
18
|
+
if (urlObj.pathname === "/watch") {
|
|
19
|
+
return !!urlObj.searchParams.get("v");
|
|
20
|
+
}
|
|
21
|
+
// For embed URLs, verify they have a video ID in the path
|
|
22
|
+
if (urlObj.pathname.startsWith("/embed/")) {
|
|
23
|
+
return urlObj.pathname.length > 7; // '/embed/' is 7 chars
|
|
24
|
+
}
|
|
25
|
+
// For shorts URLs, verify they have a video ID in the path
|
|
26
|
+
if (urlObj.pathname.startsWith("/shorts/")) {
|
|
27
|
+
return urlObj.pathname.length > 8; // '/shorts/' is 8 chars
|
|
28
|
+
}
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Check for shortened youtu.be domain
|
|
33
|
+
if (urlObj.hostname === "youtu.be") {
|
|
34
|
+
// Verify there's a video ID in the path
|
|
35
|
+
return urlObj.pathname.length > 1; // '/' is 1 char
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return false;
|
|
39
|
+
} catch (err) {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
8
44
|
export default {
|
|
9
45
|
prompt:
|
|
10
46
|
[
|
|
@@ -12,7 +48,7 @@ export default {
|
|
|
12
48
|
"{{messages}}",
|
|
13
49
|
]}),
|
|
14
50
|
],
|
|
15
|
-
model: 'gemini-
|
|
51
|
+
model: 'gemini-pro-20-vision',
|
|
16
52
|
inputParameters: {
|
|
17
53
|
file: ``,
|
|
18
54
|
language: ``,
|
|
@@ -63,7 +99,10 @@ export default {
|
|
|
63
99
|
sendProgress(true);
|
|
64
100
|
intervalId = setInterval(() => sendProgress(true), 3000);
|
|
65
101
|
|
|
66
|
-
const { file,
|
|
102
|
+
const { file, wordTimestamped, maxLineWidth } = args;
|
|
103
|
+
|
|
104
|
+
const responseFormat = args.responseFormat || 'text';
|
|
105
|
+
|
|
67
106
|
if(!file) {
|
|
68
107
|
throw new Error("Please provide a file to transcribe.");
|
|
69
108
|
}
|
|
@@ -71,7 +110,7 @@ export default {
|
|
|
71
110
|
|
|
72
111
|
//check if fils is a gcs file or youtube
|
|
73
112
|
const isGcs = file.startsWith('gs://');
|
|
74
|
-
const isYoutube = file
|
|
113
|
+
const isYoutube = isYoutubeUrl(file);
|
|
75
114
|
|
|
76
115
|
let chunks = [{
|
|
77
116
|
url: file,
|
|
@@ -87,43 +126,41 @@ export default {
|
|
|
87
126
|
|
|
88
127
|
sendProgress(true);
|
|
89
128
|
|
|
90
|
-
let respectLimitsPrompt = "
|
|
129
|
+
let respectLimitsPrompt = "";
|
|
91
130
|
if (maxLineWidth) {
|
|
92
131
|
|
|
93
132
|
const possiblePlacement = maxLineWidth <= 25
|
|
94
133
|
? "vertical" : maxLineWidth <= 35 ? "horizontal" : "";
|
|
95
134
|
|
|
96
|
-
respectLimitsPrompt += `
|
|
97
|
-
|
|
98
|
-
if(possiblePlacement){
|
|
99
|
-
respectLimitsPrompt+= `This limit a must as user will be using the output for ${possiblePlacement} display.`
|
|
100
|
-
}
|
|
135
|
+
respectLimitsPrompt += ` These subtitles will be shown in a ${possiblePlacement} formatted video player. Each subtitle line should not exceed ${maxLineWidth} characters to fit the player.`;
|
|
101
136
|
}
|
|
102
137
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
138
|
+
function getMessages(file) {
|
|
139
|
+
|
|
140
|
+
// Base system content that's always included
|
|
141
|
+
let systemContent = `Instructions:
|
|
142
|
+
You are a transcription assistant. Your job is to transcribe the audio/video content accurately.
|
|
106
143
|
|
|
107
|
-
|
|
144
|
+
IMPORTANT: Only provide the transcription in your response - no explanations, comments, or additional text.
|
|
108
145
|
|
|
109
|
-
|
|
110
|
-
{"role": "system", "content": `Instructions:\nYou are an AI entity with expertise of transcription. Your response only contains the transcription, no comments or additonal stuff.
|
|
111
|
-
|
|
112
|
-
Your output must be in the format asked, and must be strictly following the formats and parseble by auto parsers.
|
|
146
|
+
Format your response in ${responseFormat} format.`;
|
|
113
147
|
|
|
114
|
-
|
|
148
|
+
// Only include timestamp instructions if we're not using plain text format
|
|
149
|
+
if (responseFormat !== 'text') {
|
|
150
|
+
systemContent += `
|
|
115
151
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
152
|
+
CRITICAL TIMESTAMP INSTRUCTIONS:
|
|
153
|
+
- Timestamps MUST match the actual timing in the media
|
|
154
|
+
- For each new segment, look at the media time directly
|
|
155
|
+
- Start times should precisely match when spoken words begin
|
|
156
|
+
- Consecutive segments should have matching end/start times (no gaps or overlaps)`;
|
|
157
|
+
}
|
|
119
158
|
|
|
120
|
-
|
|
121
|
-
Never put newlines or spaces in the middle of a timestamp.
|
|
122
|
-
Never put multiple lines for a single timestamp.
|
|
159
|
+
systemContent += `
|
|
123
160
|
|
|
124
|
-
|
|
161
|
+
Examples:
|
|
125
162
|
|
|
126
|
-
|
|
163
|
+
SRT format:
|
|
127
164
|
1
|
|
128
165
|
00:00:00,498 --> 00:00:02,827
|
|
129
166
|
Hello World!
|
|
@@ -132,21 +169,24 @@ Hello World!
|
|
|
132
169
|
00:00:02,827 --> 00:00:06,383
|
|
133
170
|
Being AI is fun!
|
|
134
171
|
|
|
135
|
-
|
|
172
|
+
VTT format:
|
|
136
173
|
WEBVTT
|
|
137
174
|
|
|
138
175
|
1
|
|
139
176
|
00:00:00.000 --> 00:00:02.944
|
|
140
|
-
Hello
|
|
177
|
+
Hello World!
|
|
141
178
|
|
|
142
179
|
2
|
|
143
|
-
00:00:
|
|
144
|
-
Being AI is
|
|
180
|
+
00:00:02.944 --> 00:00:08.809
|
|
181
|
+
Being AI is great!
|
|
145
182
|
|
|
146
|
-
|
|
147
|
-
Hello World
|
|
183
|
+
Text format:
|
|
184
|
+
Hello World! Being AI is great!`;
|
|
148
185
|
|
|
149
|
-
|
|
186
|
+
if (wordTimestamped) {
|
|
187
|
+
systemContent += `
|
|
188
|
+
|
|
189
|
+
For word-level transcription, timestamp each word:
|
|
150
190
|
|
|
151
191
|
WEBVTT
|
|
152
192
|
|
|
@@ -155,17 +195,32 @@ WEBVTT
|
|
|
155
195
|
Hello
|
|
156
196
|
|
|
157
197
|
2
|
|
158
|
-
00:00:01.
|
|
198
|
+
00:00:01.944 --> 00:00:02.383
|
|
159
199
|
World!
|
|
200
|
+
`;
|
|
201
|
+
}
|
|
160
202
|
|
|
203
|
+
// Only include anti-drift procedure and timestamp reminders for non-text formats
|
|
204
|
+
if (responseFormat !== 'text') {
|
|
205
|
+
systemContent += `
|
|
206
|
+
|
|
207
|
+
ANTI-DRIFT PROCEDURE:
|
|
208
|
+
1. For EVERY new segment, check the actual media time directly
|
|
209
|
+
2. After every 5 segments, verify your timestamps against the video/audio
|
|
210
|
+
3. Never calculate timestamps based on previous segments
|
|
211
|
+
4. Always match the end time of one segment with the start time of the next
|
|
212
|
+
|
|
213
|
+
REMEMBER:
|
|
214
|
+
- Transcription accuracy is your primary goal
|
|
215
|
+
- Timestamp accuracy is equally important
|
|
216
|
+
- Timestamp drift is the most common error - actively prevent it
|
|
217
|
+
- When in doubt, check the media time directly`;
|
|
218
|
+
}
|
|
161
219
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
Even a single newline or space can cause the response to be rejected. You must follow the format strictly. You must place newlines and timestamps exactly as shown in the examples.
|
|
165
|
-
|
|
166
|
-
`},
|
|
220
|
+
const messages = [
|
|
221
|
+
{"role": "system", "content": systemContent},
|
|
167
222
|
{"role": "user", "content": [
|
|
168
|
-
`{ type: 'text', text: 'Transcribe
|
|
223
|
+
`{ type: 'text', text: 'Transcribe this file in ${responseFormat} format.${respectLimitsPrompt} Output only the transcription, no other text or comments or formatting.' }`,
|
|
169
224
|
JSON.stringify({
|
|
170
225
|
type: 'image_url',
|
|
171
226
|
url: file,
|
|
@@ -215,7 +270,7 @@ Even a single newline or space can cause the response to be rejected. You must f
|
|
|
215
270
|
|
|
216
271
|
const result = await processChunksParallel(chunks, args);
|
|
217
272
|
|
|
218
|
-
if (['srt','vtt'].includes(responseFormat) || wordTimestamped) { // align subtitles for formats
|
|
273
|
+
if (['srt','vtt'].includes(responseFormat.toLowerCase()) || wordTimestamped) { // align subtitles for formats
|
|
219
274
|
const offsets = chunks.map((chunk, index) => chunk?.offset || index * OFFSET_CHUNK);
|
|
220
275
|
return alignSubtitles(result, responseFormat, offsets);
|
|
221
276
|
}
|
package/server/graphql.js
CHANGED
|
@@ -94,8 +94,10 @@ class PathwayResolver {
|
|
|
94
94
|
requestId: this.rootRequestId || this.requestId,
|
|
95
95
|
progress: 1,
|
|
96
96
|
data: '',
|
|
97
|
-
info: '
|
|
97
|
+
info: '',
|
|
98
|
+
error: error.message || error.toString()
|
|
98
99
|
});
|
|
100
|
+
return;
|
|
99
101
|
}
|
|
100
102
|
|
|
101
103
|
// If the response is a stream, handle it as streaming response
|
|
@@ -165,7 +167,8 @@ class PathwayResolver {
|
|
|
165
167
|
requestId: this.requestId,
|
|
166
168
|
progress: 1,
|
|
167
169
|
data: '',
|
|
168
|
-
info: '
|
|
170
|
+
info: '',
|
|
171
|
+
error: 'Stream read failed'
|
|
169
172
|
});
|
|
170
173
|
} else {
|
|
171
174
|
return;
|
|
@@ -180,7 +183,7 @@ class PathwayResolver {
|
|
|
180
183
|
requestId: this.rootRequestId || this.requestId,
|
|
181
184
|
progress: Math.min(completedCount, totalCount) / totalCount,
|
|
182
185
|
// Clients expect these to be strings
|
|
183
|
-
data: JSON.stringify(responseData),
|
|
186
|
+
data: JSON.stringify(responseData || ''),
|
|
184
187
|
info: this.tool || ''
|
|
185
188
|
});
|
|
186
189
|
}
|
|
@@ -121,8 +121,8 @@ class AzureVideoTranslatePlugin extends ModelPlugin {
|
|
|
121
121
|
const operationUrl = response.headers['operation-location'];
|
|
122
122
|
return { translation: response.data, operationUrl };
|
|
123
123
|
} catch (error) {
|
|
124
|
-
const errorText = error.response?.data || error.message;
|
|
125
|
-
throw new Error(`Failed to create translation: ${
|
|
124
|
+
const errorText = error.response?.data?.error?.innererror?.message || error.message;
|
|
125
|
+
throw new Error(`Failed to create translation: ${errorText}`);
|
|
126
126
|
}
|
|
127
127
|
}
|
|
128
128
|
|
|
@@ -151,8 +151,8 @@ class AzureVideoTranslatePlugin extends ModelPlugin {
|
|
|
151
151
|
});
|
|
152
152
|
return response.data;
|
|
153
153
|
} catch (error) {
|
|
154
|
-
const errorText = error.response?.data || error.message;
|
|
155
|
-
throw new Error(`Failed to get iteration status: ${
|
|
154
|
+
const errorText = error.response?.data?.error?.innererror?.message || error.message;
|
|
155
|
+
throw new Error(`Failed to get iteration status: ${errorText}`);
|
|
156
156
|
}
|
|
157
157
|
}
|
|
158
158
|
|
|
@@ -165,8 +165,8 @@ class AzureVideoTranslatePlugin extends ModelPlugin {
|
|
|
165
165
|
});
|
|
166
166
|
return response.data;
|
|
167
167
|
} catch (error) {
|
|
168
|
-
const errorText = error.response?.data || error.message;
|
|
169
|
-
throw new Error(`Failed to poll operation: ${
|
|
168
|
+
const errorText = error.response?.data?.error?.innererror?.message || error.message;
|
|
169
|
+
throw new Error(`Failed to poll operation: ${errorText}`);
|
|
170
170
|
}
|
|
171
171
|
}
|
|
172
172
|
|
|
@@ -360,8 +360,8 @@ class AzureVideoTranslatePlugin extends ModelPlugin {
|
|
|
360
360
|
const output = await this.getTranslationOutput(translationId, iteration.id);
|
|
361
361
|
return JSON.stringify(output);
|
|
362
362
|
} catch (error) {
|
|
363
|
-
const errorText = error.response?.data || error.message;
|
|
364
|
-
throw new Error(`Failed to create iteration: ${
|
|
363
|
+
const errorText = error.response?.data?.error?.innererror?.message || error.message;
|
|
364
|
+
throw new Error(`Failed to create iteration: ${errorText}`);
|
|
365
365
|
}
|
|
366
366
|
} catch (error) {
|
|
367
367
|
logger.error(`Error in video translation: ${error.message}`);
|