Major Features Implemented: - Full Vue.js 3 admin interface with Vite build system - OpenAI Chat Completions API integration (replaced deprecated Assistants API) - PostgreSQL database with Sequelize ORM - Complete conversation management system - User authentication system (admin@oliver.agency, user@oliver.agency) - AI-powered conversation title generation - Server-Sent Events for streaming responses - Conversation soft delete functionality - Rate limiting middleware with development bypass Backend Infrastructure: - Node.js/Express server with comprehensive error handling - Database models: User, Assistant, Conversation, Message - Chat API endpoints with full conversation history context - Conversation CRUD operations with soft delete - Migration and seeding scripts - Environment-based configuration Frontend Features: - Responsive Vue.js interface with router - Real-time chat with streaming responses - Conversation sidebar with delete functionality - Agent selection dropdown - Persistent user sessions with hash-based user IDs - Conversation history loading and continuity - Login system with user role management - Prominent logout functionality Technical Improvements: - Fixed conversation continuity by loading full message history - Implemented conversation title generation using GPT-4o-mini - Added conversation persistence mechanisms (periodic refresh, window focus) - Enhanced error handling and rate limiting - Proper environment variable management - Clean project structure with separated concerns 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
135 lines
No EOL
3.9 KiB
JavaScript
135 lines
No EOL
3.9 KiB
JavaScript
const OpenAI = require('openai');
|
|
|
|
const openai = new OpenAI({
|
|
apiKey: process.env.OPENAI_API_KEY,
|
|
organization: process.env.OPENAI_ORG_ID,
|
|
});
|
|
|
|
class OpenAIService {
|
|
constructor() {
|
|
if (!process.env.OPENAI_API_KEY || process.env.OPENAI_API_KEY.includes('your-actual')) {
|
|
console.warn('⚠️ OpenAI API key not configured properly');
|
|
}
|
|
}
|
|
|
|
async createResponse(messages, assistantConfig = {}) {
|
|
try {
|
|
const {
|
|
model = 'gpt-4o',
|
|
temperature = 0.7,
|
|
maxTokens = 4000,
|
|
stream = false,
|
|
} = assistantConfig;
|
|
|
|
const response = await openai.chat.completions.create({
|
|
model,
|
|
messages,
|
|
temperature,
|
|
max_tokens: maxTokens,
|
|
stream,
|
|
});
|
|
|
|
return response;
|
|
} catch (error) {
|
|
console.error('OpenAI Responses API Error:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async createStreamingResponse(messages, assistantConfig = {}) {
|
|
try {
|
|
const {
|
|
model = 'gpt-4o',
|
|
temperature = 0.7,
|
|
maxTokens = 4000,
|
|
} = assistantConfig;
|
|
|
|
const stream = await openai.chat.completions.create({
|
|
model,
|
|
messages,
|
|
temperature,
|
|
max_tokens: maxTokens,
|
|
stream: true,
|
|
});
|
|
|
|
return stream;
|
|
} catch (error) {
|
|
console.error('OpenAI Streaming Responses API Error:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
formatMessagesForAPI(messages) {
|
|
return messages.map(msg => ({
|
|
role: msg.role,
|
|
content: msg.content,
|
|
}));
|
|
}
|
|
|
|
buildSystemMessage(systemPrompt) {
|
|
return {
|
|
role: 'system',
|
|
content: systemPrompt,
|
|
};
|
|
}
|
|
|
|
async generateConversationTitle(userMessage, assistantResponse, agentName) {
|
|
try {
|
|
if (!process.env.ENABLE_TITLE_GENERATION || process.env.ENABLE_TITLE_GENERATION !== 'true') {
|
|
console.log('Title generation disabled, using fallback');
|
|
return `Chat with ${agentName}`;
|
|
}
|
|
|
|
const titlePrompt = `Based on this conversation between a user and an AI assistant called "${agentName}", generate a short, descriptive title (3-6 words) that captures what the user is asking about or discussing. Be specific and concise.
|
|
|
|
User message: "${userMessage}"
|
|
Assistant response: "${assistantResponse}"
|
|
|
|
Generate only the title, nothing else. Examples:
|
|
- "Marketing Campaign Ideas"
|
|
- "JavaScript Function Help"
|
|
- "Travel Planning Advice"
|
|
- "Budget Analysis Discussion"`;
|
|
|
|
const response = await openai.chat.completions.create({
|
|
model: 'gpt-4o-mini', // Use cheaper model for title generation
|
|
messages: [
|
|
{ role: 'user', content: titlePrompt }
|
|
],
|
|
temperature: 0.3, // Lower temperature for more consistent titles
|
|
max_tokens: 20, // Short titles only
|
|
});
|
|
|
|
const title = response.choices[0]?.message?.content?.trim();
|
|
if (!title) {
|
|
console.warn('No title generated, using fallback');
|
|
return `Chat with ${agentName}`;
|
|
}
|
|
|
|
// Clean up the title - remove quotes if present
|
|
const cleanTitle = title.replace(/^["']|["']$/g, '');
|
|
console.log(`Generated title: "${cleanTitle}"`);
|
|
return cleanTitle;
|
|
|
|
} catch (error) {
|
|
console.error('Error generating conversation title:', error);
|
|
return `Chat with ${agentName}`; // Fallback title
|
|
}
|
|
}
|
|
|
|
async testConnection() {
|
|
try {
|
|
const response = await this.createResponse([
|
|
{ role: 'user', content: 'Hello, this is a test message.' }
|
|
], { maxTokens: 50 });
|
|
|
|
console.log('✅ OpenAI Responses API connection test successful');
|
|
return { success: true, response };
|
|
} catch (error) {
|
|
console.error('❌ OpenAI Responses API connection test failed:', error.message);
|
|
return { success: false, error: error.message };
|
|
}
|
|
}
|
|
}
|
|
|
|
module.exports = new OpenAIService(); |