93 lines
3.0 KiB
TypeScript
93 lines
3.0 KiB
TypeScript
import { Controller, Get, Post, Body, Res, HttpStatus, UseGuards } from '@nestjs/common';
|
|
import { FastifyReply } from 'fastify';
|
|
import { ProxyService } from './proxy.service';
|
|
import { Observable } from 'rxjs';
|
|
import { OpenAIChatRequest, AnthropicChatRequest } from './interfaces/request-interfaces';
|
|
import { ProxyGuard } from './proxy.guard';
|
|
|
|
@Controller('v1')
|
|
@UseGuards(ProxyGuard)
|
|
export class ProxyController {
|
|
constructor(private readonly proxyService: ProxyService) {}
|
|
|
|
@Get('models')
|
|
getModels() {
|
|
return {
|
|
object: 'list',
|
|
data: [
|
|
// Gemini Native
|
|
{
|
|
id: 'gemini-2.5-flash-thinking',
|
|
object: 'model',
|
|
created: 1734336000,
|
|
owned_by: 'google',
|
|
},
|
|
{ id: 'gemini-2.5-flash', object: 'model', created: 1734336000, owned_by: 'google' },
|
|
{ id: 'gemini-2.5-pro', object: 'model', created: 1734336000, owned_by: 'google' },
|
|
{ id: 'gemini-3-flash', object: 'model', created: 1734336000, owned_by: 'google' },
|
|
|
|
// Claude Native (Mapped)
|
|
{ id: 'claude-sonnet-4-5', object: 'model', created: 1734336000, owned_by: 'anthropic' },
|
|
{
|
|
id: 'claude-sonnet-4-5-thinking',
|
|
object: 'model',
|
|
created: 1734336000,
|
|
owned_by: 'anthropic',
|
|
},
|
|
|
|
// Image Models
|
|
{ id: 'gemini-3-pro-image', object: 'model', created: 1734336000, owned_by: 'google' },
|
|
],
|
|
};
|
|
}
|
|
|
|
@Post('chat/completions')
|
|
async chatCompletions(@Body() body: OpenAIChatRequest, @Res() res: FastifyReply) {
|
|
try {
|
|
const result = await this.proxyService.handleChatCompletions(body);
|
|
|
|
if (body.stream && result instanceof Observable) {
|
|
res.header('Content-Type', 'text/event-stream');
|
|
res.header('Cache-Control', 'no-cache');
|
|
res.header('Connection', 'keep-alive');
|
|
res.send(result);
|
|
} else {
|
|
res.status(HttpStatus.OK).send(result);
|
|
}
|
|
} catch (error) {
|
|
const message = error instanceof Error ? error.message : 'Internal Server Error';
|
|
res.status(HttpStatus.INTERNAL_SERVER_ERROR).send({
|
|
error: {
|
|
message: message,
|
|
type: 'server_error',
|
|
},
|
|
});
|
|
}
|
|
}
|
|
|
|
@Post('messages')
|
|
async anthropicMessages(@Body() body: AnthropicChatRequest, @Res() res: FastifyReply) {
|
|
try {
|
|
const result = await this.proxyService.handleAnthropicMessages(body);
|
|
|
|
if (body.stream && result instanceof Observable) {
|
|
res.header('Content-Type', 'text/event-stream');
|
|
res.header('Cache-Control', 'no-cache');
|
|
res.header('Connection', 'keep-alive');
|
|
res.send(result);
|
|
} else {
|
|
res.status(HttpStatus.OK).send(result);
|
|
}
|
|
} catch (error) {
|
|
const message = error instanceof Error ? error.message : 'Internal Server Error';
|
|
res.status(HttpStatus.INTERNAL_SERVER_ERROR).send({
|
|
type: 'error',
|
|
error: {
|
|
type: 'api_error',
|
|
message: message,
|
|
},
|
|
});
|
|
}
|
|
}
|
|
}
|