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:
salvacybersec
2025-11-10 21:13:58 +03:00
parent d41ff7671e
commit af0510e486
8 changed files with 1121 additions and 7 deletions

View 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);
}
};