| import { Readable } from "node:stream"; | |
| async function relayError(response, res) { | |
| const contentType = response.headers.get("content-type") ?? "application/json"; | |
| const rawBody = await response.text(); | |
| res.status(response.status); | |
| res.setHeader("content-type", contentType); | |
| res.send(rawBody); | |
| } | |
| export function createChatController({ | |
| openAiService, | |
| requestNormalizationService, | |
| responseNormalizationService | |
| }) { | |
| return async function chatController(req, res, next) { | |
| try { | |
| const { normalizedBody, responseContext } = await requestNormalizationService.normalize(req.body); | |
| const upstreamResponse = await openAiService.createChatCompletion(normalizedBody); | |
| if (!upstreamResponse.ok) { | |
| await relayError(upstreamResponse, res); | |
| return; | |
| } | |
| if (normalizedBody.stream) { | |
| res.status(upstreamResponse.status); | |
| res.setHeader("content-type", upstreamResponse.headers.get("content-type") ?? "text/event-stream"); | |
| Readable.fromWeb(upstreamResponse.body).pipe(res); | |
| return; | |
| } | |
| const responseJson = await upstreamResponse.json(); | |
| const publicBaseUrl = `${req.protocol}://${req.get("host")}`; | |
| const normalizedResponse = responseNormalizationService.normalize(responseJson, { | |
| publicBaseUrl, | |
| audioFormat: responseContext.audioFormat, | |
| exposeMediaUrls: responseContext.exposeMediaUrls | |
| }); | |
| res.status(upstreamResponse.status).json(normalizedResponse); | |
| } catch (error) { | |
| next(error); | |
| } | |
| }; | |
| } | |