feat: Add Ollama AI integration for automatic mail template generation
✨ New Features: - 🤖 AI-powered mail template generation with Ollama - 📧 Test mail sending with preview - 🔧 Ollama server and model management - 🎨 Beautiful AI generation dialog in Templates page - ⚙️ Ollama settings panel with connection test Backend: - Add ollama.service.js - Ollama API integration - Add ollama.controller.js - Template generation endpoint - Add ollama.routes.js - /api/ollama/* routes - Support for multiple Ollama models (llama3.2, mistral, gemma) - JSON-formatted AI responses with subject + HTML body - Configurable server URL and model selection Frontend: - Settings: Ollama configuration panel - Server URL input - Model selection - Connection test with model listing - Templates: AI generation dialog - Company name, scenario, employee info inputs - Custom prompt for AI instructions - Auto-save to database - Test mail sending functionality Documentation: - OLLAMA_SETUP.md - Comprehensive setup guide - Installation instructions - Model recommendations - Usage examples - Troubleshooting Tech Stack: - Ollama API integration (REST) - Axios HTTP client - React dialogs with MUI - Self-hosted AI (privacy-friendly) - Zero external API dependencies Example Usage: Company: Garanti Bankası Scenario: Account security warning → AI generates professional phishing test mail in seconds!
This commit is contained in:
188
backend/src/controllers/ollama.controller.js
Normal file
188
backend/src/controllers/ollama.controller.js
Normal file
@@ -0,0 +1,188 @@
|
||||
const ollamaService = require('../services/ollama.service');
|
||||
const { Settings, MailTemplate } = require('../models');
|
||||
const logger = require('../utils/logger');
|
||||
|
||||
/**
|
||||
* Test Ollama connection
|
||||
*/
|
||||
exports.testConnection = async (req, res, next) => {
|
||||
try {
|
||||
const result = await ollamaService.testConnection();
|
||||
res.json({
|
||||
success: result.success,
|
||||
message: result.message,
|
||||
data: {
|
||||
models: result.models,
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* List available Ollama models
|
||||
*/
|
||||
exports.listModels = async (req, res, next) => {
|
||||
try {
|
||||
const models = await ollamaService.listModels();
|
||||
res.json({
|
||||
success: true,
|
||||
data: models,
|
||||
});
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Update Ollama settings
|
||||
*/
|
||||
exports.updateSettings = async (req, res, next) => {
|
||||
try {
|
||||
const { ollama_server_url, ollama_model } = req.body;
|
||||
|
||||
if (ollama_server_url !== undefined) {
|
||||
if (ollama_server_url) {
|
||||
// Validate URL format
|
||||
const cleanUrl = ollama_server_url.trim().replace(/\/$/, '');
|
||||
try {
|
||||
new URL(cleanUrl);
|
||||
} catch (e) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
error: 'Geçersiz Ollama URL formatı. Örnek: http://localhost:11434',
|
||||
});
|
||||
}
|
||||
|
||||
await Settings.upsert({
|
||||
key: 'ollama_server_url',
|
||||
value: cleanUrl,
|
||||
is_encrypted: false,
|
||||
description: 'Ollama server URL',
|
||||
});
|
||||
} else {
|
||||
await Settings.destroy({ where: { key: 'ollama_server_url' } });
|
||||
}
|
||||
}
|
||||
|
||||
if (ollama_model !== undefined) {
|
||||
if (ollama_model) {
|
||||
await Settings.upsert({
|
||||
key: 'ollama_model',
|
||||
value: ollama_model,
|
||||
is_encrypted: false,
|
||||
description: 'Ollama model name',
|
||||
});
|
||||
} else {
|
||||
await Settings.destroy({ where: { key: 'ollama_model' } });
|
||||
}
|
||||
}
|
||||
|
||||
// Reinitialize service with new settings
|
||||
await ollamaService.initialize();
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: 'Ollama ayarları güncellendi',
|
||||
});
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Generate mail template with AI
|
||||
*/
|
||||
exports.generateTemplate = async (req, res, next) => {
|
||||
try {
|
||||
const { company_name, scenario, employee_info, custom_prompt, template_name, template_type } = req.body;
|
||||
|
||||
// Validation
|
||||
if (!company_name || !scenario) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
error: 'company_name ve scenario zorunludur',
|
||||
});
|
||||
}
|
||||
|
||||
logger.info(`AI template generation requested for: ${company_name} - ${scenario}`);
|
||||
|
||||
// Generate template using Ollama
|
||||
const templateData = await ollamaService.generateMailTemplate({
|
||||
company_name,
|
||||
scenario,
|
||||
employee_info,
|
||||
custom_prompt,
|
||||
});
|
||||
|
||||
// Save to database if template_name is provided
|
||||
let savedTemplate = null;
|
||||
if (template_name && template_type) {
|
||||
savedTemplate = await MailTemplate.create({
|
||||
name: template_name,
|
||||
type: template_type,
|
||||
subject_template: templateData.subject_template,
|
||||
body_template: templateData.body_template,
|
||||
description: `AI tarafından oluşturuldu - ${scenario}`,
|
||||
});
|
||||
|
||||
logger.info(`AI-generated template saved: ${template_name}`);
|
||||
}
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: savedTemplate
|
||||
? 'Template başarıyla oluşturuldu ve kaydedildi'
|
||||
: 'Template başarıyla oluşturuldu',
|
||||
data: {
|
||||
template: savedTemplate || templateData,
|
||||
generated_by: templateData.model,
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error('AI template generation failed:', error);
|
||||
next(error);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Send test mail with generated template
|
||||
*/
|
||||
exports.sendTestMail = async (req, res, next) => {
|
||||
try {
|
||||
const { test_email, subject, body, company_name, employee_name } = req.body;
|
||||
|
||||
if (!test_email || !subject || !body) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
error: 'test_email, subject ve body zorunludur',
|
||||
});
|
||||
}
|
||||
|
||||
const mailService = require('../services/mail.service');
|
||||
|
||||
// Replace placeholders
|
||||
const finalSubject = subject
|
||||
.replace(/\{\{company_name\}\}/g, company_name || 'Test Şirketi')
|
||||
.replace(/\{\{employee_name\}\}/g, employee_name || 'Test Kullanıcı');
|
||||
|
||||
const finalBody = body
|
||||
.replace(/\{\{company_name\}\}/g, company_name || 'Test Şirketi')
|
||||
.replace(/\{\{employee_name\}\}/g, employee_name || 'Test Kullanıcı')
|
||||
.replace(/\{\{tracking_url\}\}/g, 'http://example.com/test-tracking-link');
|
||||
|
||||
await mailService.sendMail(test_email, finalSubject, finalBody);
|
||||
|
||||
logger.info(`Test mail sent to: ${test_email}`);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: 'Test maili başarıyla gönderildi',
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error('Test mail sending failed:', error);
|
||||
next(error);
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user