review-copilot
Version:
ReviewCopilot - AI-powered code review assistant with customizable prompts
183 lines (182 loc) • 9.13 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.OpenAIProvider = void 0;
const base_provider_1 = require("./base-provider");
const util_1 = __importDefault(require("util"));
const ai_messages_1 = require("../constants/ai-messages");
const logger_1 = require("../utils/logger");
class OpenAIProvider extends base_provider_1.BaseProvider {
constructor(config) {
super(config);
}
async review(prompt, content) {
try {
logger_1.Logger.info('\n=== OpenAI Review Request ===');
logger_1.Logger.gray('Model: ' + this.config.model);
logger_1.Logger.gray('BaseURL: ' + this.config.baseURL);
logger_1.Logger.gray('API Key: ***[REDACTED]***');
logger_1.Logger.gray('Prompt: ' + prompt);
logger_1.Logger.gray('Content Length: ' + content.length);
logger_1.Logger.gray('Content Preview: ' + content.slice(0, 100) + '...');
if (!content.trim()) {
logger_1.Logger.warning('Warning: Empty content provided');
return 'No content to review.';
}
const messages = [
{
role: 'system',
content: ai_messages_1.SYSTEM_MESSAGES.CODE_REVIEW(this.config.reviewLanguage),
},
{
role: 'user',
content: `${prompt}\n\nContent to review:\n${content}`,
},
];
const requestBody = {
model: this.config.model,
messages,
temperature: 0.7,
stream: false,
};
logger_1.Logger.info('\n=== Request Details ===');
logger_1.Logger.gray('Request Body: ' +
util_1.default.inspect({
...requestBody,
messages: requestBody.messages.map((msg) => ({
...msg,
content: msg.content
? msg.content.length > 100
? msg.content.slice(0, 100) + '...'
: msg.content
: '[NO CONTENT]',
})),
}, {
colors: true,
depth: 2,
maxArrayLength: 2,
}));
logger_1.Logger.info('\n=== Making API Call ===');
logger_1.Logger.gray('Request Config: ' +
JSON.stringify({
baseURL: this.config.baseURL,
model: requestBody.model,
}));
let response;
try {
response = await this.client.chat.completions.create(requestBody);
}
catch (apiError) {
logger_1.Logger.error('\n=== API Call Failed ===');
if (apiError.response) {
logger_1.Logger.gray('Response Type: ' +
(apiError.response.headers?.['content-type'] || 'unknown'));
logger_1.Logger.gray('Response Status: ' + apiError.response.status);
logger_1.Logger.gray('Response Headers: ' + util_1.default.inspect(apiError.response.headers));
logger_1.Logger.gray('Response Body: ' + util_1.default.inspect(apiError.response.data));
if (typeof apiError.response.data === 'string' &&
apiError.response.data.includes('<!DOCTYPE html>')) {
logger_1.Logger.error('\nReceived HTML response instead of JSON. This usually indicates:');
logger_1.Logger.warning('1. The baseURL might be incorrect or pointing to a web interface');
logger_1.Logger.warning('2. The proxy server might be returning an auth/error page');
logger_1.Logger.warning('3. The API endpoint might not be properly configured');
logger_1.Logger.warning('\nPlease verify:');
logger_1.Logger.warning('- The baseURL is a direct API endpoint (should end with /v1)');
logger_1.Logger.warning('- Your API key is correctly set and has proper permissions');
logger_1.Logger.warning("- If using a proxy, ensure it's correctly forwarding API requests");
}
}
throw apiError;
}
logger_1.Logger.info('\n=== Response Details ===');
logger_1.Logger.gray('Response Object: ' +
util_1.default.inspect(response, {
colors: true,
depth: null,
maxArrayLength: null,
}));
let parsedResponse;
if (typeof response === 'string') {
try {
parsedResponse = JSON.parse(response);
logger_1.Logger.info('\n=== Parsed Response ===');
logger_1.Logger.gray('Parsed Response: ' +
util_1.default.inspect(parsedResponse, {
colors: true,
depth: null,
maxArrayLength: null,
}));
}
catch (parseError) {
logger_1.Logger.error('\nError: Failed to parse response string');
logger_1.Logger.gray('Parse Error: ' + util_1.default.inspect(parseError));
throw new Error('Failed to parse OpenAI API response');
}
}
else {
parsedResponse = response;
}
if (!parsedResponse ||
!parsedResponse.choices ||
parsedResponse.choices.length === 0) {
logger_1.Logger.error('\nError: Invalid Response Format');
logger_1.Logger.gray('Response: ' +
util_1.default.inspect(parsedResponse, { colors: true, depth: null }));
throw new Error('Invalid response format from OpenAI API');
}
const result = parsedResponse.choices[0]?.message?.content;
if (!result) {
logger_1.Logger.error('\nError: Empty Response Content');
logger_1.Logger.gray('Choice Object: ' +
util_1.default.inspect(parsedResponse.choices[0], {
colors: true,
depth: null,
}));
throw new Error('Empty response content from OpenAI API');
}
logger_1.Logger.success('\n=== Success ===');
logger_1.Logger.gray('Response Content: ' + result);
return result;
}
catch (error) {
logger_1.Logger.error('\n=== Error Details ===');
logger_1.Logger.error('Type: ' +
(error instanceof Error ? error.constructor.name : typeof error));
if (error instanceof Error) {
logger_1.Logger.error('Name: ' + error.name);
logger_1.Logger.error('Message: ' + error.message);
logger_1.Logger.error('Stack: ' + error.stack);
const errorMessage = error.message;
if (errorMessage.includes('401')) {
throw new Error('OpenAI API authentication failed. Please check your API key and ensure it has the correct permissions.');
}
else if (errorMessage.includes('404')) {
throw new Error('OpenAI API endpoint not found. Please verify the baseURL configuration.');
}
else if (errorMessage.includes('429')) {
throw new Error('OpenAI API rate limit exceeded. Please check your API quota and try again later.');
}
else if (errorMessage.includes('500')) {
throw new Error('OpenAI API internal server error. Please try again later or contact support if the issue persists.');
}
// Log any additional error properties
const errorObj = error;
if (errorObj.response) {
logger_1.Logger.error('\nAPI Response Error:');
logger_1.Logger.gray('Status: ' + errorObj.response.status);
logger_1.Logger.gray('Status Text: ' + errorObj.response.statusText);
logger_1.Logger.gray('Headers: ' + util_1.default.inspect(errorObj.response.headers));
logger_1.Logger.gray('Data: ' +
util_1.default.inspect(errorObj.response.data, {
colors: true,
depth: null,
}));
}
}
throw error;
}
}
}
exports.OpenAIProvider = OpenAIProvider;