fixed handlers
Browse files- src/controllers/chatController.ts +7 -4
- src/routes/chatRoutes.ts +6 -1
- src/services/chatProtocol.ts +76 -47
- zurri-mock-frontend +0 -1
- zurriwebsite +0 -1
src/controllers/chatController.ts
CHANGED
|
@@ -20,7 +20,7 @@ export class ChatController {
|
|
| 20 |
const { id: agentId } = req.params;
|
| 21 |
const { message, conversationId, metadata } = req.body;
|
| 22 |
const userId = (req as any).user?.id;
|
| 23 |
-
// Extract files from multer
|
| 24 |
interface MulterFile {
|
| 25 |
fieldname: string;
|
| 26 |
originalname: string;
|
|
@@ -29,9 +29,12 @@ export class ChatController {
|
|
| 29 |
size: number;
|
| 30 |
buffer: Buffer;
|
| 31 |
}
|
| 32 |
-
const
|
| 33 |
-
|
| 34 |
-
|
|
|
|
|
|
|
|
|
|
| 35 |
|
| 36 |
// Message is optional if files are provided
|
| 37 |
if (!message && (!files || files.length === 0)) {
|
|
|
|
| 20 |
const { id: agentId } = req.params;
|
| 21 |
const { message, conversationId, metadata } = req.body;
|
| 22 |
const userId = (req as any).user?.id;
|
| 23 |
+
// Extract files from multer - support both 'file' (singular) and 'files' (plural)
|
| 24 |
interface MulterFile {
|
| 25 |
fieldname: string;
|
| 26 |
originalname: string;
|
|
|
|
| 29 |
size: number;
|
| 30 |
buffer: Buffer;
|
| 31 |
}
|
| 32 |
+
const multerFiles = (req as any).files;
|
| 33 |
+
const files = Array.isArray(multerFiles)
|
| 34 |
+
? multerFiles as Array<MulterFile>
|
| 35 |
+
: multerFiles
|
| 36 |
+
? [multerFiles as MulterFile]
|
| 37 |
+
: undefined;
|
| 38 |
|
| 39 |
// Message is optional if files are provided
|
| 40 |
if (!message && (!files || files.length === 0)) {
|
src/routes/chatRoutes.ts
CHANGED
|
@@ -162,7 +162,12 @@ const upload = multer({
|
|
| 162 |
router.post(
|
| 163 |
'/:id/message',
|
| 164 |
optionalAuth,
|
| 165 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 166 |
chatController.sendMessage.bind(chatController)
|
| 167 |
);
|
| 168 |
|
|
|
|
| 162 |
router.post(
|
| 163 |
'/:id/message',
|
| 164 |
optionalAuth,
|
| 165 |
+
(req, res, next) => {
|
| 166 |
+
upload.any()(req, res, (err) => {
|
| 167 |
+
if (err) return next(err);
|
| 168 |
+
next();
|
| 169 |
+
});
|
| 170 |
+
},
|
| 171 |
chatController.sendMessage.bind(chatController)
|
| 172 |
);
|
| 173 |
|
src/services/chatProtocol.ts
CHANGED
|
@@ -125,68 +125,97 @@ export class ChatProtocolService {
|
|
| 125 |
// Determine if we need to send as multipart/form-data or JSON
|
| 126 |
const hasFiles = uploadedFiles.length > 0;
|
| 127 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 128 |
let response;
|
| 129 |
|
| 130 |
if (hasFiles) {
|
| 131 |
// Send as multipart/form-data with files
|
| 132 |
const formData = new FormData();
|
| 133 |
|
| 134 |
-
//
|
| 135 |
-
if (
|
| 136 |
-
|
| 137 |
-
|
| 138 |
-
|
| 139 |
-
formData.append('conversationId', conversationId);
|
| 140 |
-
formData.append('metadata', JSON.stringify(metadata));
|
| 141 |
-
|
| 142 |
-
if (agent.promptTemplate) {
|
| 143 |
-
formData.append('systemPrompt', agent.promptTemplate);
|
| 144 |
-
}
|
| 145 |
-
|
| 146 |
-
// Send actual files directly to agent endpoint (no IPFS upload)
|
| 147 |
-
// Use smart field naming based on file type and count
|
| 148 |
-
if (request.files && request.files.length > 0) {
|
| 149 |
-
const audioFiles = request.files.filter(f => f.mimetype.startsWith('audio/'));
|
| 150 |
|
| 151 |
// If single audio file, use 'audio_file' (common for transcription agents)
|
| 152 |
-
if (audioFiles.length === 1
|
| 153 |
-
|
| 154 |
-
|
| 155 |
-
|
| 156 |
-
|
| 157 |
-
|
| 158 |
-
|
| 159 |
-
}
|
| 160 |
-
}
|
| 161 |
-
// If single file of any type, use 'file'
|
| 162 |
-
else if (request.files.length === 1) {
|
| 163 |
-
const file = request.files[0];
|
| 164 |
formData.append('file', file.buffer, {
|
| 165 |
filename: file.originalname,
|
| 166 |
contentType: file.mimetype,
|
| 167 |
});
|
| 168 |
}
|
| 169 |
-
|
| 170 |
-
|
| 171 |
-
|
| 172 |
-
|
| 173 |
-
|
| 174 |
-
|
| 175 |
-
|
| 176 |
-
|
| 177 |
-
|
| 178 |
-
|
| 179 |
-
|
| 180 |
-
|
| 181 |
-
|
| 182 |
-
|
| 183 |
-
|
| 184 |
-
|
| 185 |
-
|
| 186 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 187 |
});
|
| 188 |
}
|
| 189 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 190 |
}
|
| 191 |
}
|
| 192 |
|
|
|
|
| 125 |
// Determine if we need to send as multipart/form-data or JSON
|
| 126 |
const hasFiles = uploadedFiles.length > 0;
|
| 127 |
|
| 128 |
+
// Detect file-only requests (single file, no message, endpoint suggests file-only)
|
| 129 |
+
const isFileOnly = hasFiles &&
|
| 130 |
+
uploadedFiles.length === 1 &&
|
| 131 |
+
(!request.message || request.message.trim() === '') &&
|
| 132 |
+
(agent.endpoint?.toLowerCase().includes('/remove-background') ||
|
| 133 |
+
agent.endpoint?.toLowerCase().includes('/transcribe') ||
|
| 134 |
+
agent.endpoint?.toLowerCase().includes('/edit'));
|
| 135 |
+
|
| 136 |
let response;
|
| 137 |
|
| 138 |
if (hasFiles) {
|
| 139 |
// Send as multipart/form-data with files
|
| 140 |
const formData = new FormData();
|
| 141 |
|
| 142 |
+
// For file-only requests, only send the file (no message, conversationId, metadata, systemPrompt)
|
| 143 |
+
if (isFileOnly) {
|
| 144 |
+
const file = request.files![0];
|
| 145 |
+
const audioFiles = request.files!.filter(f => f.mimetype.startsWith('audio/'));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 146 |
|
| 147 |
// If single audio file, use 'audio_file' (common for transcription agents)
|
| 148 |
+
if (audioFiles.length === 1) {
|
| 149 |
+
formData.append('audio_file', file.buffer, {
|
| 150 |
+
filename: file.originalname,
|
| 151 |
+
contentType: file.mimetype,
|
| 152 |
+
});
|
| 153 |
+
} else {
|
| 154 |
+
// For other single files, use 'file'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 155 |
formData.append('file', file.buffer, {
|
| 156 |
filename: file.originalname,
|
| 157 |
contentType: file.mimetype,
|
| 158 |
});
|
| 159 |
}
|
| 160 |
+
} else {
|
| 161 |
+
// Regular requests with files - include message, conversationId, metadata
|
| 162 |
+
// Add message
|
| 163 |
+
if (request.message) {
|
| 164 |
+
formData.append('message', request.message);
|
| 165 |
+
}
|
| 166 |
+
|
| 167 |
+
formData.append('conversationId', conversationId);
|
| 168 |
+
formData.append('metadata', JSON.stringify(metadata));
|
| 169 |
+
|
| 170 |
+
if (agent.promptTemplate) {
|
| 171 |
+
formData.append('systemPrompt', agent.promptTemplate);
|
| 172 |
+
}
|
| 173 |
+
|
| 174 |
+
// Send actual files directly to agent endpoint (no IPFS upload)
|
| 175 |
+
// Use smart field naming based on file type and count
|
| 176 |
+
if (request.files && request.files.length > 0) {
|
| 177 |
+
const audioFiles = request.files.filter(f => f.mimetype.startsWith('audio/'));
|
| 178 |
+
|
| 179 |
+
// If single audio file, use 'audio_file' (common for transcription agents)
|
| 180 |
+
if (audioFiles.length === 1 && request.files.length === 1) {
|
| 181 |
+
const audioFile = request.files.find(f => f.mimetype.startsWith('audio/'));
|
| 182 |
+
if (audioFile) {
|
| 183 |
+
formData.append('audio_file', audioFile.buffer, {
|
| 184 |
+
filename: audioFile.originalname,
|
| 185 |
+
contentType: audioFile.mimetype,
|
| 186 |
});
|
| 187 |
}
|
| 188 |
+
}
|
| 189 |
+
// If single file of any type, use 'file'
|
| 190 |
+
else if (request.files.length === 1) {
|
| 191 |
+
const file = request.files[0];
|
| 192 |
+
formData.append('file', file.buffer, {
|
| 193 |
+
filename: file.originalname,
|
| 194 |
+
contentType: file.mimetype,
|
| 195 |
+
});
|
| 196 |
+
}
|
| 197 |
+
// Multiple files - use 'files' array or indexed fields
|
| 198 |
+
else {
|
| 199 |
+
request.files.forEach((file, index) => {
|
| 200 |
+
// Try common field names first
|
| 201 |
+
if (file.mimetype.startsWith('audio/')) {
|
| 202 |
+
formData.append(`audio_file${index > 0 ? `_${index}` : ''}`, file.buffer, {
|
| 203 |
+
filename: file.originalname,
|
| 204 |
+
contentType: file.mimetype,
|
| 205 |
+
});
|
| 206 |
+
} else if (file.mimetype.startsWith('image/')) {
|
| 207 |
+
formData.append(`image_file${index > 0 ? `_${index}` : ''}`, file.buffer, {
|
| 208 |
+
filename: file.originalname,
|
| 209 |
+
contentType: file.mimetype,
|
| 210 |
+
});
|
| 211 |
+
} else {
|
| 212 |
+
formData.append(`file${index > 0 ? `_${index}` : ''}`, file.buffer, {
|
| 213 |
+
filename: file.originalname,
|
| 214 |
+
contentType: file.mimetype,
|
| 215 |
+
});
|
| 216 |
+
}
|
| 217 |
+
});
|
| 218 |
+
}
|
| 219 |
}
|
| 220 |
}
|
| 221 |
|
zurri-mock-frontend
DELETED
|
@@ -1 +0,0 @@
|
|
| 1 |
-
Subproject commit 05aab1df678d680e947fa3e24b05c8fd35266c7b
|
|
|
|
|
|
zurriwebsite
DELETED
|
@@ -1 +0,0 @@
|
|
| 1 |
-
Subproject commit 4013f080c954f64ecc95a16ae6477460eb8b0762
|
|
|
|
|
|