Merge pull request #27 from EnricoLibutti/optimization/project-cleanup-improvements
Optimization/project cleanup improvements
This commit is contained in:
43
.gitignore
vendored
43
.gitignore
vendored
@@ -1,9 +1,26 @@
|
|||||||
# Python artifacts
|
# Python
|
||||||
__pycache__/
|
__pycache__/
|
||||||
*.py[cod]
|
*.py[cod]
|
||||||
*$py.class
|
*$py.class
|
||||||
*.so
|
*.so
|
||||||
.Python
|
.Python
|
||||||
|
build/
|
||||||
|
develop-eggs/
|
||||||
|
dist/
|
||||||
|
downloads/
|
||||||
|
eggs/
|
||||||
|
.eggs/
|
||||||
|
lib/
|
||||||
|
lib64/
|
||||||
|
parts/
|
||||||
|
sdist/
|
||||||
|
var/
|
||||||
|
wheels/
|
||||||
|
*.egg-info/
|
||||||
|
.installed.cfg
|
||||||
|
*.egg
|
||||||
|
|
||||||
|
# Virtual environments
|
||||||
.env
|
.env
|
||||||
.venv
|
.venv
|
||||||
env/
|
env/
|
||||||
@@ -12,22 +29,26 @@ ENV/
|
|||||||
env.bak/
|
env.bak/
|
||||||
venv.bak/
|
venv.bak/
|
||||||
|
|
||||||
# IDE artifacts
|
# IDE
|
||||||
.vscode/
|
.vscode/
|
||||||
.idea/
|
.idea/
|
||||||
*.swp
|
*.swp
|
||||||
*.swo
|
*.swo
|
||||||
*~
|
*~
|
||||||
|
|
||||||
# OS artifacts
|
# OS
|
||||||
.DS_Store
|
.DS_Store
|
||||||
.DS_Store?
|
|
||||||
._*
|
|
||||||
.Spotlight-V100
|
|
||||||
.Trashes
|
|
||||||
ehthumbs.db
|
|
||||||
Thumbs.db
|
Thumbs.db
|
||||||
|
|
||||||
|
# Application specific
|
||||||
|
database/workflows.db
|
||||||
|
database/workflows.db-*
|
||||||
|
*.log
|
||||||
|
|
||||||
|
# Temporary files
|
||||||
|
*.tmp
|
||||||
|
*.temp
|
||||||
|
|
||||||
# Development artifacts
|
# Development artifacts
|
||||||
*.log
|
*.log
|
||||||
*.tmp
|
*.tmp
|
||||||
@@ -53,7 +74,6 @@ workflow_backups/
|
|||||||
*.db
|
*.db
|
||||||
*.sqlite
|
*.sqlite
|
||||||
*.sqlite3
|
*.sqlite3
|
||||||
workflows.db
|
|
||||||
|
|
||||||
# Rename logs
|
# Rename logs
|
||||||
workflow_rename_log.json
|
workflow_rename_log.json
|
||||||
@@ -61,8 +81,3 @@ workflow_rename_log.json
|
|||||||
# Node.js artifacts (if using npm)
|
# Node.js artifacts (if using npm)
|
||||||
node_modules/
|
node_modules/
|
||||||
package-lock.json
|
package-lock.json
|
||||||
|
|
||||||
# Python package files
|
|
||||||
*.egg-info/
|
|
||||||
dist/
|
|
||||||
build/
|
|
||||||
376
README.md
376
README.md
@@ -12,21 +12,22 @@ A professionally organized collection of **2,053 n8n workflows** with a lightnin
|
|||||||
pip install -r requirements.txt
|
pip install -r requirements.txt
|
||||||
|
|
||||||
# Start the fast API server
|
# Start the fast API server
|
||||||
python3 api_server.py
|
python run.py
|
||||||
|
|
||||||
# Open in browser
|
# Open in browser
|
||||||
http://localhost:8000
|
http://localhost:8000
|
||||||
```
|
```
|
||||||
|
|
||||||
**Features:**
|
**Features:**
|
||||||
- ⚡ **Sub-100ms response times** (vs 10+ seconds before)
|
- ⚡ **Sub-100ms response times** with SQLite FTS5 search
|
||||||
- 🔍 **Instant full-text search** with ranking and filters
|
- 🔍 **Instant full-text search** with advanced filtering
|
||||||
- 📱 **Responsive design** - works perfectly on mobile
|
- 📱 **Responsive design** - works perfectly on mobile
|
||||||
- 🌙 **Dark/light themes** with system preference detection
|
- 🌙 **Dark/light themes** with system preference detection
|
||||||
- 📊 **Live statistics** and workflow insights
|
- 📊 **Live statistics** - 365 unique integrations, 29,445 total nodes
|
||||||
- 🎯 **Smart categorization** by trigger type and complexity
|
- 🎯 **Smart categorization** by trigger type and complexity
|
||||||
- 📄 **On-demand JSON viewing** and download
|
- 📄 **On-demand JSON viewing** and download
|
||||||
- 🔗 **Mermaid diagram generation** for workflow visualization
|
- 🔗 **Mermaid diagram generation** for workflow visualization
|
||||||
|
- 🔄 **Real-time workflow naming** with intelligent formatting
|
||||||
|
|
||||||
### Performance Comparison
|
### Performance Comparison
|
||||||
|
|
||||||
@@ -44,15 +45,16 @@ http://localhost:8000
|
|||||||
|
|
||||||
### Workflow Collection
|
### Workflow Collection
|
||||||
- **2,053 workflows** with meaningful, searchable names
|
- **2,053 workflows** with meaningful, searchable names
|
||||||
- **Professional naming convention** - `[ID]_[Service]_[Purpose]_[Trigger].json`
|
- **365 unique integrations** across popular platforms
|
||||||
- **Comprehensive coverage** - 100+ services and use cases
|
- **29,445 total nodes** with professional categorization
|
||||||
- **Quality assurance** - All workflows analyzed and categorized
|
- **Quality assurance** - All workflows analyzed and categorized
|
||||||
|
|
||||||
### Recent Improvements
|
### Advanced Naming System ✨
|
||||||
- ✅ **858 generic workflows renamed** from meaningless "workflow_XXX" patterns
|
Our intelligent naming system converts technical filenames into readable titles:
|
||||||
- ✅ **36 overly long names shortened** while preserving meaning
|
- **Before**: `2051_Telegram_Webhook_Automation_Webhook.json`
|
||||||
- ✅ **9 broken filenames fixed** with proper extensions
|
- **After**: `Telegram Webhook Automation`
|
||||||
- ✅ **100% success rate** with zero data loss during transformation
|
- **100% meaningful names** with smart capitalization
|
||||||
|
- **Automatic integration detection** from node analysis
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -60,109 +62,135 @@ http://localhost:8000
|
|||||||
|
|
||||||
### Option 1: Modern Fast System (Recommended)
|
### Option 1: Modern Fast System (Recommended)
|
||||||
```bash
|
```bash
|
||||||
|
# Clone repository
|
||||||
|
git clone <repo-url>
|
||||||
|
cd n8n-workflows
|
||||||
|
|
||||||
# Install Python dependencies
|
# Install Python dependencies
|
||||||
pip install fastapi uvicorn
|
pip install -r requirements.txt
|
||||||
|
|
||||||
# Start the documentation server
|
# Start the documentation server
|
||||||
python3 api_server.py
|
python run.py
|
||||||
|
|
||||||
# Browse workflows at http://localhost:8000
|
# Browse workflows at http://localhost:8000
|
||||||
# - Instant search and filtering
|
# - Instant search across 2,053 workflows
|
||||||
# - Professional responsive interface
|
# - Professional responsive interface
|
||||||
# - Real-time workflow statistics
|
# - Real-time workflow statistics
|
||||||
```
|
```
|
||||||
|
|
||||||
### Option 2: Legacy System (Deprecated)
|
### Option 2: Development Mode
|
||||||
```bash
|
```bash
|
||||||
# ⚠️ WARNING: Generates 71MB file, very slow
|
# Start with auto-reload for development
|
||||||
python3 generate_documentation.py
|
python run.py --dev
|
||||||
# Then open workflow-documentation.html
|
|
||||||
|
# Or specify custom host/port
|
||||||
|
python run.py --host 0.0.0.0 --port 3000
|
||||||
|
|
||||||
|
# Force database reindexing
|
||||||
|
python run.py --reindex
|
||||||
```
|
```
|
||||||
|
|
||||||
### Import Workflows into n8n
|
### Import Workflows into n8n
|
||||||
1. Open your [n8n Editor UI](https://docs.n8n.io/hosting/editor-ui/)
|
|
||||||
2. Click **menu** (☰) → `Import workflow`
|
|
||||||
3. Choose any `.json` file from the `workflows/` folder
|
|
||||||
4. Update credentials/webhook URLs before running
|
|
||||||
|
|
||||||
### Bulk Import All Workflows
|
|
||||||
```bash
|
```bash
|
||||||
./import-workflows.sh
|
# Use the Python importer (recommended)
|
||||||
|
python import_workflows.py
|
||||||
|
|
||||||
|
# Or manually import individual workflows:
|
||||||
|
# 1. Open your n8n Editor UI
|
||||||
|
# 2. Click menu (☰) → Import workflow
|
||||||
|
# 3. Choose any .json file from the workflows/ folder
|
||||||
|
# 4. Update credentials/webhook URLs before running
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 📊 Workflow Statistics
|
## 📊 Workflow Statistics
|
||||||
|
|
||||||
|
### Current Collection Stats
|
||||||
- **Total Workflows**: 2,053 automation workflows
|
- **Total Workflows**: 2,053 automation workflows
|
||||||
- **Naming Quality**: 100% meaningful names (improved from 58%)
|
- **Active Workflows**: 215 (10.5% active rate)
|
||||||
- **Categories**: Data sync, notifications, integrations, monitoring
|
- **Total Nodes**: 29,445 (avg 14.3 nodes per workflow)
|
||||||
- **Services**: 100+ platforms (Gmail, Slack, Notion, Stripe, etc.)
|
- **Unique Integrations**: 365 different services and APIs
|
||||||
- **Complexity Range**: Simple 2-node to complex 50+ node automations
|
- **Database**: SQLite with FTS5 full-text search
|
||||||
- **File Format**: Standard n8n-compatible JSON exports
|
|
||||||
|
|
||||||
### Trigger Distribution
|
### Trigger Distribution
|
||||||
- **Manual**: ~40% - User-initiated workflows
|
- **Complex**: 831 workflows (40.5%) - Multi-trigger systems
|
||||||
- **Webhook**: ~25% - API-triggered automations
|
- **Webhook**: 519 workflows (25.3%) - API-triggered automations
|
||||||
- **Scheduled**: ~20% - Time-based executions
|
- **Manual**: 477 workflows (23.2%) - User-initiated workflows
|
||||||
- **Complex**: ~15% - Multi-trigger systems
|
- **Scheduled**: 226 workflows (11.0%) - Time-based executions
|
||||||
|
|
||||||
### Complexity Levels
|
### Complexity Analysis
|
||||||
- **Low (≤5 nodes)**: ~45% - Simple automations
|
- **Low (≤5 nodes)**: ~35% - Simple automations
|
||||||
- **Medium (6-15 nodes)**: ~35% - Standard workflows
|
- **Medium (6-15 nodes)**: ~45% - Standard workflows
|
||||||
- **High (16+ nodes)**: ~20% - Complex systems
|
- **High (16+ nodes)**: ~20% - Complex enterprise systems
|
||||||
|
|
||||||
|
### Popular Integrations
|
||||||
|
Top services by usage frequency:
|
||||||
|
- **Communication**: Telegram, Discord, Slack, WhatsApp
|
||||||
|
- **Cloud Storage**: Google Drive, Google Sheets, Dropbox
|
||||||
|
- **Databases**: PostgreSQL, MySQL, MongoDB, Airtable
|
||||||
|
- **AI/ML**: OpenAI, Anthropic, Hugging Face
|
||||||
|
- **Development**: HTTP Request, Webhook, GraphQL
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 📋 Naming Convention
|
## 🔍 Advanced Search Features
|
||||||
|
|
||||||
### Standard Format
|
### Smart Search Categories
|
||||||
```
|
Our system automatically categorizes workflows into 12 service categories:
|
||||||
[ID]_[Service1]_[Service2]_[Purpose]_[Trigger].json
|
|
||||||
```
|
|
||||||
|
|
||||||
### Examples
|
#### Available Categories:
|
||||||
|
- **messaging**: Telegram, Discord, Slack, WhatsApp, Teams
|
||||||
|
- **ai_ml**: OpenAI, Anthropic, Hugging Face
|
||||||
|
- **database**: PostgreSQL, MySQL, MongoDB, Redis, Airtable
|
||||||
|
- **email**: Gmail, Mailjet, Outlook, SMTP/IMAP
|
||||||
|
- **cloud_storage**: Google Drive, Google Docs, Dropbox, OneDrive
|
||||||
|
- **project_management**: Jira, GitHub, GitLab, Trello, Asana
|
||||||
|
- **social_media**: LinkedIn, Twitter/X, Facebook, Instagram
|
||||||
|
- **ecommerce**: Shopify, Stripe, PayPal
|
||||||
|
- **analytics**: Google Analytics, Mixpanel
|
||||||
|
- **calendar_tasks**: Google Calendar, Cal.com, Calendly
|
||||||
|
- **forms**: Typeform, Google Forms, Form Triggers
|
||||||
|
- **development**: Webhook, HTTP Request, GraphQL, SSE
|
||||||
|
|
||||||
|
### API Usage Examples
|
||||||
```bash
|
```bash
|
||||||
# Good naming examples:
|
# Search workflows by text
|
||||||
100_Gmail_Slack_Notification_Webhook.json
|
curl "http://localhost:8000/api/workflows?q=telegram+automation"
|
||||||
250_Stripe_Hubspot_Invoice_Sync.json
|
|
||||||
375_Airtable_Data_Backup_Scheduled.json
|
|
||||||
|
|
||||||
# Service mappings:
|
# Filter by trigger type and complexity
|
||||||
n8n-nodes-base.gmail → Gmail
|
curl "http://localhost:8000/api/workflows?trigger=Webhook&complexity=high"
|
||||||
n8n-nodes-base.slack → Slack
|
|
||||||
n8n-nodes-base.webhook → Webhook
|
# Find all messaging workflows
|
||||||
|
curl "http://localhost:8000/api/workflows/category/messaging"
|
||||||
|
|
||||||
|
# Get database statistics
|
||||||
|
curl "http://localhost:8000/api/stats"
|
||||||
|
|
||||||
|
# Browse available categories
|
||||||
|
curl "http://localhost:8000/api/categories"
|
||||||
```
|
```
|
||||||
|
|
||||||
### Purpose Categories
|
|
||||||
- **Create** - Creating new records/content
|
|
||||||
- **Update** - Updating existing data
|
|
||||||
- **Sync** - Synchronizing between systems
|
|
||||||
- **Send** - Sending notifications/messages
|
|
||||||
- **Monitor** - Monitoring and alerting
|
|
||||||
- **Process** - Data processing/transformation
|
|
||||||
- **Import/Export** - Data migration tasks
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🏗 Technical Architecture
|
## 🏗 Technical Architecture
|
||||||
|
|
||||||
### Modern Stack (New System)
|
### Modern Stack
|
||||||
- **SQLite Database** - FTS5 full-text search, indexed metadata
|
- **SQLite Database** - FTS5 full-text search with 365 indexed integrations
|
||||||
- **FastAPI Backend** - REST API with automatic documentation
|
- **FastAPI Backend** - RESTful API with automatic OpenAPI documentation
|
||||||
- **Responsive Frontend** - Single-file HTML with embedded assets
|
- **Responsive Frontend** - Modern HTML5 with embedded CSS/JavaScript
|
||||||
- **Smart Analysis** - Automatic workflow categorization
|
- **Smart Analysis** - Automatic workflow categorization and naming
|
||||||
|
|
||||||
### Key Features
|
### Key Features
|
||||||
- **Change Detection** - Only reprocess modified workflows
|
- **Change Detection** - MD5 hashing for efficient re-indexing
|
||||||
- **Background Indexing** - Non-blocking workflow analysis
|
- **Background Processing** - Non-blocking workflow analysis
|
||||||
- **Compressed Responses** - Gzip middleware for speed
|
- **Compressed Responses** - Gzip middleware for optimal speed
|
||||||
- **Virtual Scrolling** - Handle thousands of workflows smoothly
|
- **Error Handling** - Graceful degradation and comprehensive logging
|
||||||
- **Lazy Loading** - Diagrams and JSON loaded on demand
|
- **Mobile Optimization** - Touch-friendly interface design
|
||||||
|
|
||||||
### Database Schema
|
### Database Performance
|
||||||
```sql
|
```sql
|
||||||
-- Optimized for search and filtering
|
-- Optimized schema for lightning-fast queries
|
||||||
CREATE TABLE workflows (
|
CREATE TABLE workflows (
|
||||||
id INTEGER PRIMARY KEY,
|
id INTEGER PRIMARY KEY,
|
||||||
filename TEXT UNIQUE,
|
filename TEXT UNIQUE,
|
||||||
@@ -171,14 +199,16 @@ CREATE TABLE workflows (
|
|||||||
trigger_type TEXT,
|
trigger_type TEXT,
|
||||||
complexity TEXT,
|
complexity TEXT,
|
||||||
node_count INTEGER,
|
node_count INTEGER,
|
||||||
integrations TEXT, -- JSON array
|
integrations TEXT, -- JSON array of 365 unique services
|
||||||
tags TEXT, -- JSON array
|
description TEXT,
|
||||||
file_hash TEXT -- For change detection
|
file_hash TEXT, -- MD5 for change detection
|
||||||
|
analyzed_at TIMESTAMP
|
||||||
);
|
);
|
||||||
|
|
||||||
-- Full-text search capability
|
-- Full-text search with ranking
|
||||||
CREATE VIRTUAL TABLE workflows_fts USING fts5(
|
CREATE VIRTUAL TABLE workflows_fts USING fts5(
|
||||||
filename, name, description, integrations, tags
|
filename, name, description, integrations, tags,
|
||||||
|
content='workflows', content_rowid='id'
|
||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -189,6 +219,7 @@ CREATE VIRTUAL TABLE workflows_fts USING fts5(
|
|||||||
### System Requirements
|
### System Requirements
|
||||||
- **Python 3.7+** - For running the documentation system
|
- **Python 3.7+** - For running the documentation system
|
||||||
- **Modern Browser** - Chrome, Firefox, Safari, Edge
|
- **Modern Browser** - Chrome, Firefox, Safari, Edge
|
||||||
|
- **50MB Storage** - For SQLite database and indexes
|
||||||
- **n8n Instance** - For importing and running workflows
|
- **n8n Instance** - For importing and running workflows
|
||||||
|
|
||||||
### Installation
|
### Installation
|
||||||
@@ -197,14 +228,13 @@ CREATE VIRTUAL TABLE workflows_fts USING fts5(
|
|||||||
git clone <repo-url>
|
git clone <repo-url>
|
||||||
cd n8n-workflows
|
cd n8n-workflows
|
||||||
|
|
||||||
# Install dependencies (for fast system)
|
# Install dependencies
|
||||||
pip install -r requirements.txt
|
pip install -r requirements.txt
|
||||||
|
|
||||||
# Start documentation server
|
# Start documentation server
|
||||||
python3 api_server.py --port 8000
|
python run.py
|
||||||
|
|
||||||
# Or use legacy system (not recommended)
|
# Access at http://localhost:8000
|
||||||
python3 generate_documentation.py
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Development Setup
|
### Development Setup
|
||||||
@@ -215,10 +245,75 @@ source .venv/bin/activate # Linux/Mac
|
|||||||
# or .venv\Scripts\activate # Windows
|
# or .venv\Scripts\activate # Windows
|
||||||
|
|
||||||
# Install dependencies
|
# Install dependencies
|
||||||
pip install fastapi uvicorn
|
pip install -r requirements.txt
|
||||||
|
|
||||||
# Run with auto-reload for development
|
# Run with auto-reload for development
|
||||||
python3 api_server.py --reload
|
python api_server.py --reload
|
||||||
|
|
||||||
|
# Force database reindexing
|
||||||
|
python workflow_db.py --index --force
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📋 Naming Convention
|
||||||
|
|
||||||
|
### Intelligent Formatting System
|
||||||
|
Our system automatically converts technical filenames to user-friendly names:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Automatic transformations:
|
||||||
|
2051_Telegram_Webhook_Automation_Webhook.json → "Telegram Webhook Automation"
|
||||||
|
0250_HTTP_Discord_Import_Scheduled.json → "HTTP Discord Import Scheduled"
|
||||||
|
0966_OpenAI_Data_Processing_Manual.json → "OpenAI Data Processing Manual"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Technical Format
|
||||||
|
```
|
||||||
|
[ID]_[Service1]_[Service2]_[Purpose]_[Trigger].json
|
||||||
|
```
|
||||||
|
|
||||||
|
### Smart Capitalization Rules
|
||||||
|
- **HTTP** → HTTP (not Http)
|
||||||
|
- **API** → API (not Api)
|
||||||
|
- **webhook** → Webhook
|
||||||
|
- **automation** → Automation
|
||||||
|
- **scheduled** → Scheduled
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚀 API Documentation
|
||||||
|
|
||||||
|
### Core Endpoints
|
||||||
|
- `GET /` - Main workflow browser interface
|
||||||
|
- `GET /api/stats` - Database statistics and metrics
|
||||||
|
- `GET /api/workflows` - Search with filters and pagination
|
||||||
|
- `GET /api/workflows/{filename}` - Detailed workflow information
|
||||||
|
- `GET /api/workflows/{filename}/download` - Download workflow JSON
|
||||||
|
- `GET /api/workflows/{filename}/diagram` - Generate Mermaid diagram
|
||||||
|
|
||||||
|
### Advanced Search
|
||||||
|
- `GET /api/workflows/category/{category}` - Search by service category
|
||||||
|
- `GET /api/categories` - List all available categories
|
||||||
|
- `GET /api/integrations` - Get integration statistics
|
||||||
|
- `POST /api/reindex` - Trigger background reindexing
|
||||||
|
|
||||||
|
### Response Examples
|
||||||
|
```json
|
||||||
|
// GET /api/stats
|
||||||
|
{
|
||||||
|
"total": 2053,
|
||||||
|
"active": 215,
|
||||||
|
"inactive": 1838,
|
||||||
|
"triggers": {
|
||||||
|
"Complex": 831,
|
||||||
|
"Webhook": 519,
|
||||||
|
"Manual": 477,
|
||||||
|
"Scheduled": 226
|
||||||
|
},
|
||||||
|
"total_nodes": 29445,
|
||||||
|
"unique_integrations": 365
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -227,100 +322,79 @@ python3 api_server.py --reload
|
|||||||
|
|
||||||
### Adding New Workflows
|
### Adding New Workflows
|
||||||
1. **Export workflow** as JSON from n8n
|
1. **Export workflow** as JSON from n8n
|
||||||
2. **Name descriptively** following the naming convention
|
2. **Name descriptively** following the established pattern
|
||||||
3. **Add to workflows/** directory
|
3. **Add to workflows/** directory
|
||||||
4. **Test the workflow** before contributing
|
4. **Remove sensitive data** (credentials, personal URLs)
|
||||||
5. **Remove sensitive data** (credentials, personal URLs)
|
5. **Run reindexing** to update the database
|
||||||
|
|
||||||
### Naming Guidelines
|
|
||||||
- Use clear, descriptive names
|
|
||||||
- Follow the established format: `[ID]_[Service]_[Purpose].json`
|
|
||||||
- Maximum 80 characters when possible
|
|
||||||
- Use underscores instead of spaces
|
|
||||||
|
|
||||||
### Quality Standards
|
### Quality Standards
|
||||||
- ✅ Workflow must be functional
|
- ✅ Workflow must be functional and tested
|
||||||
- ✅ Remove all credentials and sensitive data
|
- ✅ Remove all credentials and sensitive data
|
||||||
- ✅ Add meaningful description in workflow name
|
- ✅ Follow naming convention for consistency
|
||||||
- ✅ Test in clean n8n instance
|
- ✅ Verify compatibility with recent n8n versions
|
||||||
- ✅ Follow naming convention
|
- ✅ Include meaningful description or comments
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📚 Workflow Sources
|
|
||||||
|
|
||||||
This collection includes workflows from:
|
|
||||||
- **Official n8n.io** - Website and community forum
|
|
||||||
- **GitHub repositories** - Public community contributions
|
|
||||||
- **Blog posts & tutorials** - Real-world examples
|
|
||||||
- **User submissions** - Tested automation patterns
|
|
||||||
- **Documentation examples** - Official n8n guides
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## ⚠️ Important Notes
|
## ⚠️ Important Notes
|
||||||
|
|
||||||
### Security & Privacy
|
### Security & Privacy
|
||||||
- **Review before use** - All workflows shared as-is
|
- **Review before use** - All workflows shared as-is for educational purposes
|
||||||
- **Update credentials** - Remove/replace API keys and tokens
|
- **Update credentials** - Replace API keys, tokens, and webhooks
|
||||||
- **Test safely** - Verify in development environment first
|
- **Test safely** - Verify in development environment first
|
||||||
- **Check permissions** - Ensure proper access rights
|
- **Check permissions** - Ensure proper access rights for integrations
|
||||||
|
|
||||||
### Compatibility
|
### Compatibility
|
||||||
- **n8n Version** - Most workflows compatible with recent versions
|
- **n8n Version** - Compatible with n8n 1.0+ (most workflows)
|
||||||
- **Community Nodes** - Some may require additional node installations
|
- **Community Nodes** - Some workflows may require additional node installations
|
||||||
- **API Changes** - External services may have updated their APIs
|
- **API Changes** - External services may have updated their APIs since creation
|
||||||
- **Dependencies** - Check required integrations before importing
|
- **Dependencies** - Verify required integrations before importing
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🎯 Quick Start Guide
|
## 📚 Resources & References
|
||||||
|
|
||||||
1. **Clone Repository**
|
### Workflow Sources
|
||||||
```bash
|
This comprehensive collection includes workflows from:
|
||||||
git clone <repo-url>
|
- **Official n8n.io** - Documentation and community examples
|
||||||
cd n8n-workflows
|
- **GitHub repositories** - Open source community contributions
|
||||||
```
|
- **Blog posts & tutorials** - Real-world automation patterns
|
||||||
|
- **User submissions** - Tested and verified workflows
|
||||||
|
- **Enterprise use cases** - Business process automations
|
||||||
|
|
||||||
2. **Start Fast Documentation**
|
### Learn More
|
||||||
```bash
|
- [n8n Documentation](https://docs.n8n.io/) - Official documentation
|
||||||
pip install fastapi uvicorn
|
- [n8n Community](https://community.n8n.io/) - Community forum and support
|
||||||
python3 api_server.py
|
- [Workflow Templates](https://n8n.io/workflows/) - Official template library
|
||||||
```
|
- [Integration Docs](https://docs.n8n.io/integrations/) - Service-specific guides
|
||||||
|
|
||||||
3. **Browse Workflows**
|
|
||||||
- Open http://localhost:8000
|
|
||||||
- Use instant search and filters
|
|
||||||
- Explore workflow categories
|
|
||||||
|
|
||||||
4. **Import & Use**
|
|
||||||
- Find interesting workflows
|
|
||||||
- Download JSON files
|
|
||||||
- Import into your n8n instance
|
|
||||||
- Update credentials and test
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🏆 Project Achievements
|
## 🏆 Project Achievements
|
||||||
|
|
||||||
### Repository Transformation
|
### Repository Transformation
|
||||||
- **903 workflows renamed** with intelligent content analysis
|
- **2,053 workflows** professionally organized and named
|
||||||
- **100% meaningful names** (improved from 58% well-named)
|
- **365 unique integrations** automatically detected and categorized
|
||||||
- **Professional organization** with consistent standards
|
- **100% meaningful names** (improved from basic filename patterns)
|
||||||
- **Zero data loss** during renaming process
|
- **Zero data loss** during intelligent renaming process
|
||||||
|
- **Advanced search** with 12 service categories
|
||||||
|
|
||||||
### Performance Revolution
|
### Performance Revolution
|
||||||
- **71MB → <100KB** documentation size (700x improvement)
|
- **Sub-100ms search** with SQLite FTS5 full-text indexing
|
||||||
- **10+ seconds → <1 second** load time (10x faster)
|
- **Instant filtering** across 29,445 workflow nodes
|
||||||
- **Client-side → Server-side** search (infinite scalability)
|
- **Mobile-optimized** responsive design for all devices
|
||||||
- **Static → Dynamic** interface (modern user experience)
|
- **Real-time statistics** with live database queries
|
||||||
|
- **Professional interface** with modern UX principles
|
||||||
|
|
||||||
### Quality Improvements
|
### System Reliability
|
||||||
- **Intelligent categorization** - Automatic trigger and complexity detection
|
- **Robust error handling** with graceful degradation
|
||||||
- **Enhanced searchability** - Full-text search with ranking
|
- **Change detection** for efficient database updates
|
||||||
- **Mobile optimization** - Responsive design for all devices
|
- **Background processing** for non-blocking operations
|
||||||
- **Professional presentation** - Clean, modern interface
|
- **Comprehensive logging** for debugging and monitoring
|
||||||
|
- **Production-ready** with proper middleware and security
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
*This repository represents the most comprehensive and well-organized collection of n8n workflows available, with cutting-edge documentation technology that makes workflow discovery and usage a delightful experience.*
|
*This repository represents the most comprehensive and well-organized collection of n8n workflows available, featuring cutting-edge search technology and professional documentation that makes workflow discovery and usage a delightful experience.*
|
||||||
|
|
||||||
|
**🎯 Perfect for**: Developers, automation engineers, business analysts, and anyone looking to streamline their workflows with proven n8n automations.
|
||||||
@@ -1,217 +0,0 @@
|
|||||||
# 🧠 n8n 工作流程收藏集
|
|
||||||
|
|
||||||
本儲存庫包含從多個來源收集的 **n8n 工作流程**,包括:
|
|
||||||
|
|
||||||
* 從 [n8n.io](https://n8n.io) 網站和社群論壇匯出的工作流程
|
|
||||||
* 在網路上公開分享的範例(GitHub、部落格等)
|
|
||||||
|
|
||||||
目標是為您的 n8n 專案提供有用的靈感、學習和重複使用資源。
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📂 資料夾結構
|
|
||||||
|
|
||||||
* 每個 `.json` 檔案代表一個匯出的工作流程。
|
|
||||||
* 檔案根據原始標題或來源命名。
|
|
||||||
* 您可能還會發現一些已轉換為 `.json` 的 `.txt` 檔案(請參見下方說明)。
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🔄 TXT 轉 JSON 轉換
|
|
||||||
|
|
||||||
一些工作流程最初儲存為 `.txt` 檔案或從線上來源複製。使用腳本來:
|
|
||||||
|
|
||||||
* 偵測 `.txt` 檔案
|
|
||||||
* 嘗試將它們解析為 JSON 或結構化鍵值對
|
|
||||||
* 將它們轉換為有效的 `.json` 格式
|
|
||||||
|
|
||||||
如果您想自己執行轉換,請查看本儲存庫中包含的 `convert_txt_to_json.py`。
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🛠 使用說明
|
|
||||||
|
|
||||||
要將工作流程匯入您自己的 n8n 實例:
|
|
||||||
|
|
||||||
1. 開啟您的 [n8n 編輯器 UI](https://docs.n8n.io/hosting/editor-ui/)
|
|
||||||
2. 點擊右上角的**選單** (☰) → `匯入工作流程`
|
|
||||||
3. 從此資料夾選擇一個 `.json` 檔案
|
|
||||||
4. 點擊「匯入」來載入工作流程
|
|
||||||
|
|
||||||
在執行前,請確保檢查並修改所需的憑證或 webhook URL。
|
|
||||||
|
|
||||||
若要一次匯入所有工作流程,請執行下列命令:
|
|
||||||
|
|
||||||
`./import-workflows.sh`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📋 工作流程清單
|
|
||||||
|
|
||||||
以下是所有可用的工作流程,按類別分組:
|
|
||||||
|
|
||||||
### 🤖 AI 智能代理和聊天機器人
|
|
||||||
|
|
||||||
* [🤖 Telegram 文字/音訊/圖片訊息代理](workflows/🤖%20Telegram%20Messaging%20Agent%20for%20Text_Audio_Images.json) - 支援多媒體的 Telegram 智能代理
|
|
||||||
* [🤖🧑💻 n8n 創作者排行榜 AI 代理](workflows/🤖🧑_💻%20AI%20Agent%20for%20Top%20n8n%20Creators%20Leaderboard%20Reporting.json) - 頂級 n8n 創作者排行榜報告
|
|
||||||
* [🤖🧠 AI 聊天機器人 + 長期記憶 + 筆記儲存 + Telegram](workflows/🤖🧠%20AI%20Agent%20Chatbot%20+%20LONG%20TERM%20Memory%20+%20Note%20Storage%20+%20Telegram.json) - 具備長期記憶功能的聊天機器人
|
|
||||||
* [🐋🤖 DeepSeek AI 代理 + Telegram + 長期記憶 🧠](workflows/🐋🤖%20DeepSeek%20AI%20Agent%20+%20Telegram%20+%20LONG%20TERM%20Memory%20🧠.json) - 基於 DeepSeek 的智能代理
|
|
||||||
* [🔐🦙🤖 私人本地 Ollama 自主 AI 助理](workflows/🔐🦙🤖%20Private%20&%20Local%20Ollama%20Self-Hosted%20AI%20Assistant.json) - 本地部署的私人 AI 助理
|
|
||||||
* [🔥📈🤖 n8n 創作者排行榜 AI 代理 - 尋找熱門工作流程](workflows/🔥📈🤖%20AI%20Agent%20for%20n8n%20Creators%20Leaderboard%20-%20Find%20Popular%20Workflows.json) - 發現熱門工作流程
|
|
||||||
* [🚀 本地多 LLM 測試與效能追蹤器](workflows/🚀%20Local%20Multi-LLM%20Testing%20&%20Performance%20Tracker.json) - 多模型效能比較工具
|
|
||||||
* [HR & IT 服務台聊天機器人與音訊轉錄](workflows/zmgSshZ5xESr3ozl_HR_&_IT_Helpdesk_Chatbot_with_Audio_Transcription.json) - 企業服務台解決方案
|
|
||||||
* [旅遊助理代理](workflows/znRwva47HzXesOYk_Travel_AssistantAgent.json) - 智能旅遊規劃助手
|
|
||||||
* [🐋DeepSeek V3 聊天與 R1 推理快速開始](workflows/🐋DeepSeek%20V3%20Chat%20&%20R1%20Reasoning%20Quick%20Start.json) - DeepSeek V3 模型使用指南
|
|
||||||
* [使用 LangChain 和 Gemini 建構自訂 AI 代理(自主託管)](workflows/yCIEiv9QUHP8pNfR_Build_Custom_AI_Agent_with_LangChain_&_Gemini_(Self-Hosted).json) - 自訂 AI 代理建構指南
|
|
||||||
* [使用 Jina.ai 網頁爬蟲的 AI 代理聊天機器人](workflows/xEij0kj2I1DHbL3I_🌐🪛_AI_Agent_Chatbot_with_Jina.ai_Webpage_Scraper.json) - 網頁內容理解聊天機器人
|
|
||||||
* [WhatsApp 文字、語音、圖片和 PDF AI 聊天機器人](workflows/zMtPPjJ80JJznrJP_AI-Powered_WhatsApp_Chatbot_for_Text,_Voice,_Images_&_PDFs.json) - 全功能 WhatsApp 助手
|
|
||||||
* [Line 聊天機器人使用 Groq 和 Llama3 處理 AI 回應](workflows/xibc6WDU53isYN1o_Line_Chatbot_Handling_AI_Responses_with_Groq_and_Llama3.json) - Line 平台聊天機器人
|
|
||||||
* [Microsoft Outlook AI 電子郵件助理](workflows/reQhibpNwU63Y8sn_Microsoft_Outlook_AI_Email_Assistant.json) - 智能郵件處理助手
|
|
||||||
* [電子郵件 AI 自動回覆器。總結並發送電子郵件](workflows/q8IFGLeOCGSfoWZu_Email_AI_Auto-responder._Summerize_and_send_email.json) - 智能郵件自動回覆
|
|
||||||
* [Discord MCP 聊天代理](workflows/xRclXA5QzrT3c6U8_Discord_MCP_Chat_Agent.json) - Discord 聊天機器人
|
|
||||||
* [Hubspot 聊天助理使用 OpenAI 和 Airtable](workflows/vAssistant%20for%20Hubspot%20Chat%20using%20OpenAi%20and%20Airtable.json) - CRM 整合聊天助手
|
|
||||||
|
|
||||||
### 📊 內容創作與分析
|
|
||||||
|
|
||||||
* [📚 使用 GPT 和 Docsify 自動生成 n8n 工作流程文件](workflows/📚%20Auto-generate%20documentation%20for%20n8n%20workflows%20with%20GPT%20and%20Docsify.json) - 自動文件生成
|
|
||||||
* [🔍 Perplexity 研究轉 HTML:AI 驅動的內容創作](workflows/🔍%20Perplexity%20Research%20to%20HTML_%20AI-Powered%20Content%20Creation.json) - 研究內容轉換
|
|
||||||
* [⚡AI 驅動的 YouTube 影片摘要與分析](workflows/⚡AI-Powered%20YouTube%20Video%20Summarization%20&%20Analysis.json) - 影片內容分析
|
|
||||||
* [🎨 使用 FLUX.1 填充工具的互動式圖片編輯器](workflows/🎨%20Interactive%20Image%20Editor%20with%20FLUX.1%20Fill%20Tool%20for%20Inpainting.json) - AI 圖片編輯
|
|
||||||
* [將 YouTube 影片轉換為摘要、轉錄和視覺洞察](workflows/wZBgoWrBZveMmzYi_Turn_YouTube_Videos_into_Summaries,_Transcripts,_and_Visual_Insights.json) - 影片內容分析
|
|
||||||
* [YouTube 評論情感分析器](workflows/xaC6zL4bWBo14xyJ_YouTube_Comment_Sentiment_Analyzer.json) - 評論情感分析
|
|
||||||
* [WordPress 部落格文章 AI 自動標記](workflows/siXUnQhJpCJ9rHzu_Auto-Tag_Blog_Posts_in_WordPress_with_AI.json) - 內容標記自動化
|
|
||||||
* [🎦💌進階 YouTube RSS 訂閱好幫手](workflows/tHgDFmFyuj6DnP6l_🎦💌Advanced_YouTube_RSS_Feed_Buddy_for_Your_Favorite_Channels.json) - YouTube 內容追蹤
|
|
||||||
* [n8n 圖形設計團隊](workflows/tnRYt0kDGMO9BBFd_n8n_Graphic_Design_Team.json) - 設計工作流程
|
|
||||||
* [使用 Perplexity AI 搜尋新聞並發布到 X (Twitter)](workflows/v9K61fCQhrG6gt6Z_Search_news_using_Perplexity_AI_and_post_to_X_(Twitter).json) - 新聞分享自動化
|
|
||||||
* [社群媒體發布器](workflows/r1u4HOJu5j5sP27x_Social_Media_Publisher.json) - 多平台內容發布
|
|
||||||
* [發布到 X](workflows/plzObaqgoEvV4UU0_Post_on_X.json) - Twitter 自動發布
|
|
||||||
* [YouTube 自動化](workflows/wLbJ7rE6vQzizCp2_Youtube_Automation.json) - YouTube 內容管理
|
|
||||||
|
|
||||||
### 🌐 網頁爬蟲與資料擷取
|
|
||||||
|
|
||||||
* [✨ 視覺基礎 AI 代理爬蟲 - 搭配 Google Sheets、ScrapingBee 和 Gemini](workflows/✨%20Vision-Based%20AI%20Agent%20Scraper%20-%20with%20Google%20Sheets,%20ScrapingBee,%20and%20Gemini.json) - 視覺化網頁爬蟲
|
|
||||||
* [智能網頁查詢和語意重新排序流程](workflows/wa2uEnSIowqSrHoY_Intelligent_Web_Query_and_Semantic_Re-Ranking_Flow.json) - 智能搜尋排序
|
|
||||||
* [使用 Jina.ai 的重要多頁網站爬蟲](workflows/xEij0kj2I1DHbL3I_💡🌐_Essential_Multipage_Website_Scraper_with_Jina.ai.json) - 多頁面爬蟲
|
|
||||||
* [使用 DeepSeek 爬取 Trustpilot 評論,使用 OpenAI 分析情感](workflows/w434EiZ2z7klQAyp_Scrape_Trustpilot_Reviews_with_DeepSeek,_Analyze_Sentiment_with_OpenAI.json) - 評論情感分析
|
|
||||||
* [使用 Bright Data 和 Gemini AI 擷取和總結維基百科資料](workflows/sczRNO4u1HYc5YV7_Extract_&_Summarize_Wikipedia_Data_with_Bright_Data_and_Gemini_AI.json) - 維基百科內容處理
|
|
||||||
* [使用 Bright Data 和 Google Gemini 從 LinkedIn 生成公司故事](workflows/q1DorytEoEw1QLGj_Generate_Company_Stories_from_LinkedIn_with_Bright_Data_&_Google_Gemini.json) - LinkedIn 內容分析
|
|
||||||
* [使用 Bright Data 進行品牌內容擷取、總結和情感分析](workflows/wTI77cpLkbxsRQat_Brand_Content_Extract,_Summarize_&_Sentiment_Analysis_with_Bright_Data.json) - 品牌內容分析
|
|
||||||
* [新聞擷取](workflows/xM8Z5vZVNTNjCySL_News_Extraction.json) - 新聞內容爬蟲
|
|
||||||
|
|
||||||
### 📱 通訊與訊息處理
|
|
||||||
|
|
||||||
* [WhatsApp 入門工作流程](workflows/yxv7OYbDEnqsqfa9_WhatsApp_starter_workflow.json) - WhatsApp 基礎設定
|
|
||||||
* [📈 從 FT.com 接收每日市場新聞到 Microsoft Outlook 收件匣](workflows/📈%20Receive%20Daily%20Market%20News%20from%20FT.com%20to%20your%20Microsoft%20outlook%20inbox.json) - 市場新聞推送
|
|
||||||
|
|
||||||
### 🗃️ 資料管理與同步
|
|
||||||
|
|
||||||
* [📦 新電子郵件 ➔ 建立 Google 任務](workflows/z0C6H2kYSgML2dib_📦_New_Email_➔_Create_Google_Task.json) - 郵件任務轉換
|
|
||||||
* [同步 Google Sheets 與 Postgres](workflows/wDD4XugmHIvx3KMT_Synchronize_your_Google_Sheets_with_Postgres.json) - 資料庫同步
|
|
||||||
* [從 Google Drive 同步新檔案到 Airtable](workflows/uLHpFu2ndN6ZKClZ_Sync_New_Files_From_Google_Drive_with_Airtable.json) - 檔案管理同步
|
|
||||||
* [同步 YouTube 影片 URL 到 Google Sheets](workflows/rJNvM4vU6SLUeC1d_Sync_Youtube_Video_Urls_with_Google_Sheets.json) - 影片清單管理
|
|
||||||
* [從 URL 匯入 CSV 到 Excel](workflows/xcl8D1sukz9Rak69_Import_CSV_from_URL_to_Excel.json) - 資料匯入
|
|
||||||
* [自動將 CSV 檔案匯入 postgres](workflows/q8GNbRhjQDwDpXoo_How_to_automatically_import_CSV_files_into_postgres.json) - 資料庫匯入
|
|
||||||
* [從 Google Sheets 匯入多個製造商到 Shopware 6](workflows/xLjE4IkQXARXOCZy_Import_multiple_Manufacturers_from_Google_Sheets_to_Shopware_6.json) - 電商資料匯入
|
|
||||||
* [匯入多個 CSV 到 Google Sheet](workflows/zic2ZEHvxHR4UAYI_Import_multiple_CSV_to_GoogleSheet.json) - 批次資料匯入
|
|
||||||
* [透過 Excel 更新角色](workflows/xzKlhjcc6QEzA98Z_Update_Roles_by_Excel.json) - 權限管理
|
|
||||||
* [壓縮多個檔案](workflows/r3qHlCVCczqTw3pP_Zip_multiple_files.json) - 檔案打包
|
|
||||||
* [合併多個執行成一個](workflows/ynTqojfUnGpG2rBP_Merge_multiple_runs_into_one.json) - 執行結果合併
|
|
||||||
|
|
||||||
### 🏢 企業與 CRM 管理
|
|
||||||
|
|
||||||
* [LinkedIn 自動化](workflows/yF1HNe2ucaE81fNl_Linkedin_Automation.json) - LinkedIn 行銷自動化
|
|
||||||
* [使用 Icypeas 執行電子郵件搜尋(單次)](workflows/zAkPoRdcG5M5x4KT_Perform_an_email_search_with_Icypeas_(single).json) - 電子郵件查找
|
|
||||||
* [會議預訂 - 到通訊和 CRM](workflows/xe9sXQUc7yW8P8im_Meeting_booked_-_to_newsletter_and_CRM.json) - 會議管理整合
|
|
||||||
* [ICP 公司評分](workflows/xyLfWaqdIoZmbTfv_ICP_Company_Scoring.json) - 潛在客戶評分
|
|
||||||
* [ProspectLens 公司研究](workflows/wwvUsosYUyMfpGbB_ProspectLens_company_research.json) - 客戶研究
|
|
||||||
* [HR 重點自動化流程與 AI](workflows/t1P14FvfibKYCh3E_HR-focused_automation_pipeline_with_AI.json) - 人力資源自動化
|
|
||||||
* [CV 評估 - 錯誤處理](workflows/vnhhf9aNsw0kzdBV_CV_Evaluation_-_Error_Handling.json) - 履歷評估系統
|
|
||||||
* [使用 AI 發現職場歧視模式](workflows/vzU9QRZsHcyRsord_Spot_Workplace_Discrimination_Patterns_with_AI.json) - 職場分析工具
|
|
||||||
|
|
||||||
### 🔧 開發與維運工具
|
|
||||||
|
|
||||||
* [在 n8n 實例之間複製工作流程使用 n8n API](workflows/yOhH9SGiZgZTDUB4_Clone_n8n_Workflows_between_Instances_using_n8n_API.json) - 工作流程遷移
|
|
||||||
* [憑證轉移](workflows/tlnJNm9t5H3VLU5K_Credentials_Transfer.json) - 憑證管理
|
|
||||||
* [[OPS] 從 GitHub 恢復工作流程到 n8n](workflows/uoBZx3eMvLMxlHCS_[OPS]_Restore_workflows_from_GitHub_to_n8n.json) - 工作流程備份恢復
|
|
||||||
* [工作流程節點更新檢查範本的附加元件](workflows/xlMrGt0c1eFi4J1U_Addon_for_Workflow_Nodes_Update_Check_Template.json) - 更新檢查工具
|
|
||||||
* [尋找受影響表達式的參數助手](workflows/zlHbtHIcCZ9enKwg_v1_helper_-_Find_params_with_affected_expressions.json) - 除錯工具
|
|
||||||
* [在 n8n 中測試 Webhooks 而不更改 WEBHOOK URL](workflows/sB6dC0GZ7zZHuMGF_Test_Webhooks_in_n8n_Without_Changing_WEBHOOK_URL_(PostBin_&_BambooHR_Example).json) - Webhook 測試
|
|
||||||
* [失敗重試除了已知錯誤範本](workflows/qAzZekQuABuH8uho_Retry_on_fail_except_for_known_error_Template.json) - 錯誤處理
|
|
||||||
* [網頁伺服器監控](workflows/pcLi17oUJK9pSaee_Web_Server_Monitor..json) - 系統監控
|
|
||||||
* [可疑登入偵測](workflows/xQHiKDTkezDY5lFu_Suspicious_login_detection.json) - 安全監控
|
|
||||||
* [MAIA - 健康檢查](workflows/wng5xcxlYA6jFS6n_MAIA_-_Health_Check.json) - 系統健康監控
|
|
||||||
* [追蹤工作時間和休息](workflows/pdgNdag49lwoTxUP_Track_Working_Time_and_Pauses.json) - 時間管理
|
|
||||||
* [基於位置觸發的自動化工作考勤](workflows/x2kgOnBLtqAjqUVS_Automated_Work_Attendance_with_Location_Triggers.json) - 考勤系統
|
|
||||||
|
|
||||||
### 🔌 API 與整合服務
|
|
||||||
|
|
||||||
* [OIDC 客戶端工作流程](workflows/zeyTmqqmXaQIFWzV_OIDC_client_workflow.json) - 身份驗證整合
|
|
||||||
* [使用 HttpRequest 節點透過 XMLRPC 發布到 Wordpress.com](workflows/yPIST7l13huQEjY5_Use_XMLRPC_via_HttpRequest-node_to_post_on_Wordpress.com.json) - WordPress 整合
|
|
||||||
* [圖片生成 API](workflows/wDD4XugmHIvx3KMT_Image_Generation_API.json) - 圖片生成服務
|
|
||||||
* [使用 Kling API 為服裝生成 360° 虛擬試穿影片](workflows/xQ0xqhNzFeEdBpFK_Generate_360°_Virtual_Try-on_Videos_for_Clothing_with_Kling_API.json) - 虛擬試穿
|
|
||||||
* [使用 Google 腳本上傳影片到雲端硬碟](workflows/wGv0NPBA0QLp4rQ6_Upload_video_to_drive_via_google_script.json) - 檔案上傳
|
|
||||||
* [反應 PDFMonkey 回調](workflows/s6nTFZfg6xjWyJRX_React_to_PDFMonkey_Callback.json) - PDF 處理回調
|
|
||||||
* [上傳發布圖片](workflows/ra8MrqshnzXPy55O_upload-post_images.json) - 圖片上傳
|
|
||||||
* [Luma AI - Webhook 回應 v1 - AK](workflows/rYuhIChQyjpGNvuR_Luma_AI_-_Webhook_Response_v1_-_AK.json) - AI 服務整合
|
|
||||||
|
|
||||||
### 📈 分析與報告
|
|
||||||
|
|
||||||
* [OpenSea 分析代理工具](workflows/yRMCUm6oJEMknhbw_OpenSea_Analytics_Agent_Tool.json) - NFT 市場分析
|
|
||||||
* [OpenSea AI 驅動的 Telegram 洞察](workflows/wi2ZWKN9XPR0jkvn_OpenSea_AI-Powered_Insights_via_Telegram.json) - NFT 市場智能分析
|
|
||||||
* [SERPBear 分析範本](workflows/qmmXKcpJOCm9qaCk_SERPBear_analytics_template.json) - SEO 分析
|
|
||||||
* [Google Maps 完整版](workflows/qhZvZVCoV3HLjRkq_Google_Maps_FULL.json) - 地圖服務整合
|
|
||||||
* [擷取 Squarespace 部落格和活動集合到 Google Sheets](workflows/sUGieRWulZJ7scll_Fetch_Squarespace_Blog_&_Event_Collections_to_Google_Sheets__.json) - 內容分析
|
|
||||||
|
|
||||||
### 🎯 專業領域應用
|
|
||||||
|
|
||||||
* [使用 Gmail 和 Mailjet 將 Netflix 電子郵件轉發到多個電子郵件地址](workflows/pkw1vY5q1p2nNfNC_Forward_Netflix_emails_to_multiple_email_addresses_with_GMail_and_Mailjet.json) - 郵件轉發
|
|
||||||
* [Namesilo 批次域名可用性檢查 [範本]](workflows/phqg5Kk3YowxoMHQ_Namesilo_Bulk_Domain_Availability_[Template].json) - 域名檢查
|
|
||||||
* [HDW Lead Geländewagen](workflows/piapgd2e6zmzFxAq_HDW_Lead_Geländewagen.json) - 專業業務流程
|
|
||||||
* [n8n-農產品](workflows/ziJG3tgG91Gkbina_n8n-農產品.json) - 農業應用
|
|
||||||
* [一般 3D 簡報](workflows/vpZ1wpsniCvKYjCF_General_3D_Presentation.json) - 3D 內容處理
|
|
||||||
* [翻譯](workflows/vssVsRO0FW6InbaY_Translate.json) - 多語言翻譯
|
|
||||||
* [puq-docker-immich-deploy](workflows/qps97Q4NEet1Pkm4_puq-docker-immich-deploy.json) - 容器部署
|
|
||||||
* [InstaTest](workflows/qww129cm4TM9N8Ru_InstaTest.json) - 測試自動化
|
|
||||||
|
|
||||||
### 🔍 文件與資料處理
|
|
||||||
|
|
||||||
* [使用 AI 分析螢幕截圖](workflows/wDD4XugmHIvx3KMT_Analyze_Screenshots_with_AI.json) - 圖片分析
|
|
||||||
* [使用 Vertex AI (Gemini) 從 PDF 和圖片擷取文字到 CSV](workflows/sUIPemKdKqmUQFt6_Extract_text_from_PDF_and_image_using_Vertex_AI_(Gemini)_into_CSV.json) - 文件內容擷取
|
|
||||||
* [從 Splunk 警報建立唯一的 Jira 票證](workflows/uD31xU0VYjogxWoY_Create_Unique_Jira_tickets_from_Splunk_alerts.json) - 事件管理
|
|
||||||
|
|
||||||
### 🎮 其他實用工具
|
|
||||||
|
|
||||||
* [我的工作流程](workflows/yYjRbTWULZuNLXM0_My_workflow.json) - 個人工作流程範例
|
|
||||||
* [我的工作流程 6](workflows/rLoXUoKSZ4a9XUAv_My_workflow_6.json) - 個人工作流程範例 6
|
|
||||||
* [工作流程 x2VUvhqV1YTJCIN0](workflows/x2VUvhqV1YTJCIN0_workflow_x2VUvhqV1YTJCIN0.json) - 自訂工作流程範例
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🤝 貢獻
|
|
||||||
|
|
||||||
發現了有趣的工作流程或創建了自己的工作流程?
|
|
||||||
歡迎貢獻到這個收藏集!
|
|
||||||
|
|
||||||
請確保:
|
|
||||||
|
|
||||||
* 使用描述性的檔案名稱
|
|
||||||
* 如果適用,在頂部包含原始來源的簡短註釋
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ⚠️ 免責聲明
|
|
||||||
|
|
||||||
此處的所有工作流程都是**按原樣**分享。
|
|
||||||
在生產環境中使用之前,請務必在安全環境中檢查和測試它們。
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📊 統計資訊
|
|
||||||
|
|
||||||
* **總工作流程數量**:107 個
|
|
||||||
* **主要類別**:AI 智能代理、內容創作、資料管理、企業應用、開發工具
|
|
||||||
* **支援的服務**:Telegram、WhatsApp、OpenAI、Google Sheets、n8n API、WordPress 等
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
*最後更新:2024年12月*
|
|
||||||
@@ -39,6 +39,20 @@ app.add_middleware(
|
|||||||
# Initialize database
|
# Initialize database
|
||||||
db = WorkflowDatabase()
|
db = WorkflowDatabase()
|
||||||
|
|
||||||
|
# Startup function to verify database
|
||||||
|
@app.on_event("startup")
|
||||||
|
async def startup_event():
|
||||||
|
"""Verify database connectivity on startup."""
|
||||||
|
try:
|
||||||
|
stats = db.get_stats()
|
||||||
|
if stats['total'] == 0:
|
||||||
|
print("⚠️ Warning: No workflows found in database. Run indexing first.")
|
||||||
|
else:
|
||||||
|
print(f"✅ Database connected: {stats['total']} workflows indexed")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ Database connection failed: {e}")
|
||||||
|
raise
|
||||||
|
|
||||||
# Response models
|
# Response models
|
||||||
class WorkflowSummary(BaseModel):
|
class WorkflowSummary(BaseModel):
|
||||||
id: Optional[int] = None
|
id: Optional[int] = None
|
||||||
@@ -345,6 +359,68 @@ async def get_integrations():
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise HTTPException(status_code=500, detail=f"Error fetching integrations: {str(e)}")
|
raise HTTPException(status_code=500, detail=f"Error fetching integrations: {str(e)}")
|
||||||
|
|
||||||
|
@app.get("/api/categories")
|
||||||
|
async def get_categories():
|
||||||
|
"""Get available service categories for filtering."""
|
||||||
|
try:
|
||||||
|
categories = db.get_service_categories()
|
||||||
|
return {"categories": categories}
|
||||||
|
except Exception as e:
|
||||||
|
raise HTTPException(status_code=500, detail=f"Error fetching categories: {str(e)}")
|
||||||
|
|
||||||
|
@app.get("/api/workflows/category/{category}", response_model=SearchResponse)
|
||||||
|
async def search_workflows_by_category(
|
||||||
|
category: str,
|
||||||
|
page: int = Query(1, ge=1, description="Page number"),
|
||||||
|
per_page: int = Query(20, ge=1, le=100, description="Items per page")
|
||||||
|
):
|
||||||
|
"""Search workflows by service category (messaging, database, ai_ml, etc.)."""
|
||||||
|
try:
|
||||||
|
offset = (page - 1) * per_page
|
||||||
|
|
||||||
|
workflows, total = db.search_by_category(
|
||||||
|
category=category,
|
||||||
|
limit=per_page,
|
||||||
|
offset=offset
|
||||||
|
)
|
||||||
|
|
||||||
|
# Convert to Pydantic models with error handling
|
||||||
|
workflow_summaries = []
|
||||||
|
for workflow in workflows:
|
||||||
|
try:
|
||||||
|
clean_workflow = {
|
||||||
|
'id': workflow.get('id'),
|
||||||
|
'filename': workflow.get('filename', ''),
|
||||||
|
'name': workflow.get('name', ''),
|
||||||
|
'active': workflow.get('active', False),
|
||||||
|
'description': workflow.get('description', ''),
|
||||||
|
'trigger_type': workflow.get('trigger_type', 'Manual'),
|
||||||
|
'complexity': workflow.get('complexity', 'low'),
|
||||||
|
'node_count': workflow.get('node_count', 0),
|
||||||
|
'integrations': workflow.get('integrations', []),
|
||||||
|
'tags': workflow.get('tags', []),
|
||||||
|
'created_at': workflow.get('created_at'),
|
||||||
|
'updated_at': workflow.get('updated_at')
|
||||||
|
}
|
||||||
|
workflow_summaries.append(WorkflowSummary(**clean_workflow))
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error converting workflow {workflow.get('filename', 'unknown')}: {e}")
|
||||||
|
continue
|
||||||
|
|
||||||
|
pages = (total + per_page - 1) // per_page
|
||||||
|
|
||||||
|
return SearchResponse(
|
||||||
|
workflows=workflow_summaries,
|
||||||
|
total=total,
|
||||||
|
page=page,
|
||||||
|
per_page=per_page,
|
||||||
|
pages=pages,
|
||||||
|
query=f"category:{category}",
|
||||||
|
filters={"category": category}
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
raise HTTPException(status_code=500, detail=f"Error searching by category: {str(e)}")
|
||||||
|
|
||||||
# Custom exception handler for better error responses
|
# Custom exception handler for better error responses
|
||||||
@app.exception_handler(Exception)
|
@app.exception_handler(Exception)
|
||||||
async def global_exception_handler(request, exc):
|
async def global_exception_handler(request, exc):
|
||||||
|
|||||||
@@ -1,202 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
"""
|
|
||||||
Script to clean up the database by removing orphaned workflows
|
|
||||||
(workflows that exist in database but not on filesystem)
|
|
||||||
"""
|
|
||||||
|
|
||||||
import os
|
|
||||||
import sqlite3
|
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
def cleanup_orphaned_workflows():
|
|
||||||
"""Remove workflow entries from database that don't have corresponding files."""
|
|
||||||
|
|
||||||
# Connect to database
|
|
||||||
db_path = "workflows.db"
|
|
||||||
if not os.path.exists(db_path):
|
|
||||||
print("❌ Database not found. Run the API server first to create the database.")
|
|
||||||
return
|
|
||||||
|
|
||||||
conn = sqlite3.connect(db_path)
|
|
||||||
cursor = conn.cursor()
|
|
||||||
|
|
||||||
try:
|
|
||||||
# Get all workflow filenames from database
|
|
||||||
cursor.execute("SELECT filename FROM workflows")
|
|
||||||
db_workflows = [row[0] for row in cursor.fetchall()]
|
|
||||||
|
|
||||||
# Get all actual workflow files from filesystem
|
|
||||||
workflows_dir = Path("workflows")
|
|
||||||
if not workflows_dir.exists():
|
|
||||||
print("❌ Workflows directory not found.")
|
|
||||||
return
|
|
||||||
|
|
||||||
actual_files = set()
|
|
||||||
for file_path in workflows_dir.glob("*.json"):
|
|
||||||
actual_files.add(file_path.name)
|
|
||||||
|
|
||||||
# Find orphaned workflows (in database but not on filesystem)
|
|
||||||
orphaned = []
|
|
||||||
for db_filename in db_workflows:
|
|
||||||
if db_filename not in actual_files:
|
|
||||||
orphaned.append(db_filename)
|
|
||||||
|
|
||||||
if not orphaned:
|
|
||||||
print("✅ No orphaned workflows found. Database is clean!")
|
|
||||||
return
|
|
||||||
|
|
||||||
print(f"🧹 Found {len(orphaned)} orphaned workflows in database:")
|
|
||||||
for i, filename in enumerate(orphaned[:10], 1): # Show first 10
|
|
||||||
print(f" {i}. {filename}")
|
|
||||||
|
|
||||||
if len(orphaned) > 10:
|
|
||||||
print(f" ... and {len(orphaned) - 10} more")
|
|
||||||
|
|
||||||
# Ask for confirmation
|
|
||||||
response = input(f"\n❓ Remove {len(orphaned)} orphaned workflows from database? (y/N): ")
|
|
||||||
if response.lower() not in ['y', 'yes']:
|
|
||||||
print("❌ Operation cancelled.")
|
|
||||||
return
|
|
||||||
|
|
||||||
# Remove orphaned workflows
|
|
||||||
placeholders = ','.join(['?' for _ in orphaned])
|
|
||||||
cursor.execute(f"DELETE FROM workflows WHERE filename IN ({placeholders})", orphaned)
|
|
||||||
|
|
||||||
# Also remove from FTS table
|
|
||||||
cursor.execute(f"DELETE FROM workflows_fts WHERE filename IN ({placeholders})", orphaned)
|
|
||||||
|
|
||||||
conn.commit()
|
|
||||||
print(f"✅ Removed {len(orphaned)} orphaned workflows from database.")
|
|
||||||
|
|
||||||
# Show updated stats
|
|
||||||
cursor.execute("SELECT COUNT(*) FROM workflows")
|
|
||||||
total_count = cursor.fetchone()[0]
|
|
||||||
print(f"📊 Database now contains {total_count} workflows.")
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
print(f"❌ Error cleaning database: {e}")
|
|
||||||
conn.rollback()
|
|
||||||
finally:
|
|
||||||
conn.close()
|
|
||||||
|
|
||||||
def find_missing_workflows():
|
|
||||||
"""Find workflow files that exist on filesystem but not in database."""
|
|
||||||
|
|
||||||
db_path = "workflows.db"
|
|
||||||
if not os.path.exists(db_path):
|
|
||||||
print("❌ Database not found. Run the API server first to create the database.")
|
|
||||||
return
|
|
||||||
|
|
||||||
conn = sqlite3.connect(db_path)
|
|
||||||
cursor = conn.cursor()
|
|
||||||
|
|
||||||
try:
|
|
||||||
# Get all workflow filenames from database
|
|
||||||
cursor.execute("SELECT filename FROM workflows")
|
|
||||||
db_workflows = set(row[0] for row in cursor.fetchall())
|
|
||||||
|
|
||||||
# Get all actual workflow files from filesystem
|
|
||||||
workflows_dir = Path("workflows")
|
|
||||||
if not workflows_dir.exists():
|
|
||||||
print("❌ Workflows directory not found.")
|
|
||||||
return
|
|
||||||
|
|
||||||
actual_files = []
|
|
||||||
for file_path in workflows_dir.glob("*.json"):
|
|
||||||
actual_files.append(file_path.name)
|
|
||||||
|
|
||||||
# Find missing workflows (on filesystem but not in database)
|
|
||||||
missing = []
|
|
||||||
for filename in actual_files:
|
|
||||||
if filename not in db_workflows:
|
|
||||||
missing.append(filename)
|
|
||||||
|
|
||||||
if not missing:
|
|
||||||
print("✅ All workflow files are indexed in database!")
|
|
||||||
return
|
|
||||||
|
|
||||||
print(f"📁 Found {len(missing)} workflow files not in database:")
|
|
||||||
for i, filename in enumerate(missing[:10], 1): # Show first 10
|
|
||||||
print(f" {i}. {filename}")
|
|
||||||
|
|
||||||
if len(missing) > 10:
|
|
||||||
print(f" ... and {len(missing) - 10} more")
|
|
||||||
|
|
||||||
print(f"\n💡 Run 'curl -X POST http://localhost:8000/api/reindex?force=true' to reindex all workflows.")
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
print(f"❌ Error checking for missing workflows: {e}")
|
|
||||||
finally:
|
|
||||||
conn.close()
|
|
||||||
|
|
||||||
def show_database_stats():
|
|
||||||
"""Show current database statistics."""
|
|
||||||
|
|
||||||
db_path = "workflows.db"
|
|
||||||
if not os.path.exists(db_path):
|
|
||||||
print("❌ Database not found. Run the API server first to create the database.")
|
|
||||||
return
|
|
||||||
|
|
||||||
conn = sqlite3.connect(db_path)
|
|
||||||
cursor = conn.cursor()
|
|
||||||
|
|
||||||
try:
|
|
||||||
# Get total workflows
|
|
||||||
cursor.execute("SELECT COUNT(*) FROM workflows")
|
|
||||||
total = cursor.fetchone()[0]
|
|
||||||
|
|
||||||
# Get active/inactive counts
|
|
||||||
cursor.execute("SELECT COUNT(*) FROM workflows WHERE active = 1")
|
|
||||||
active = cursor.fetchone()[0]
|
|
||||||
inactive = total - active
|
|
||||||
|
|
||||||
# Get trigger type distribution
|
|
||||||
cursor.execute("SELECT trigger_type, COUNT(*) FROM workflows GROUP BY trigger_type ORDER BY COUNT(*) DESC")
|
|
||||||
triggers = cursor.fetchall()
|
|
||||||
|
|
||||||
# Show filesystem stats
|
|
||||||
workflows_dir = Path("workflows")
|
|
||||||
if workflows_dir.exists():
|
|
||||||
actual_files = len(list(workflows_dir.glob("*.json")))
|
|
||||||
else:
|
|
||||||
actual_files = 0
|
|
||||||
|
|
||||||
print("📊 Database Statistics:")
|
|
||||||
print(f" Total workflows in DB: {total}")
|
|
||||||
print(f" Active workflows: {active}")
|
|
||||||
print(f" Inactive workflows: {inactive}")
|
|
||||||
print(f" Files on filesystem: {actual_files}")
|
|
||||||
|
|
||||||
if total != actual_files:
|
|
||||||
print(f" ⚠️ Database/filesystem mismatch: {abs(total - actual_files)} difference")
|
|
||||||
|
|
||||||
print("\n🎯 Trigger Types:")
|
|
||||||
for trigger_type, count in triggers:
|
|
||||||
print(f" {trigger_type}: {count}")
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
print(f"❌ Error getting database stats: {e}")
|
|
||||||
finally:
|
|
||||||
conn.close()
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
import sys
|
|
||||||
|
|
||||||
if len(sys.argv) > 1:
|
|
||||||
command = sys.argv[1].lower()
|
|
||||||
if command == "cleanup":
|
|
||||||
cleanup_orphaned_workflows()
|
|
||||||
elif command == "missing":
|
|
||||||
find_missing_workflows()
|
|
||||||
elif command == "stats":
|
|
||||||
show_database_stats()
|
|
||||||
else:
|
|
||||||
print("❌ Unknown command. Use: cleanup, missing, or stats")
|
|
||||||
else:
|
|
||||||
print("🧹 Database Cleanup Tool")
|
|
||||||
print("\nAvailable commands:")
|
|
||||||
print(" python3 cleanup_database.py cleanup - Remove orphaned workflows from database")
|
|
||||||
print(" python3 cleanup_database.py missing - Find workflows missing from database")
|
|
||||||
print(" python3 cleanup_database.py stats - Show database statistics")
|
|
||||||
print("\nRunning stats by default...\n")
|
|
||||||
show_database_stats()
|
|
||||||
@@ -1,396 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
"""
|
|
||||||
Comprehensive N8N Workflow Renamer
|
|
||||||
Complete standardization of all 2053+ workflows with uniform naming convention.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import json
|
|
||||||
import os
|
|
||||||
import glob
|
|
||||||
import re
|
|
||||||
import shutil
|
|
||||||
from typing import Dict, List, Any, Optional, Tuple
|
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
class ComprehensiveWorkflowRenamer:
|
|
||||||
"""Renames ALL workflows to uniform 0001-9999 standard with intelligent analysis."""
|
|
||||||
|
|
||||||
def __init__(self, workflows_dir: str = "workflows"):
|
|
||||||
self.workflows_dir = workflows_dir
|
|
||||||
self.rename_log = []
|
|
||||||
self.errors = []
|
|
||||||
self.backup_dir = "workflow_backups"
|
|
||||||
|
|
||||||
def analyze_all_workflows(self) -> Dict[str, Any]:
|
|
||||||
"""Analyze all workflow files and generate comprehensive rename plan."""
|
|
||||||
if not os.path.exists(self.workflows_dir):
|
|
||||||
print(f"❌ Workflows directory '{self.workflows_dir}' not found.")
|
|
||||||
return {'workflows': [], 'total': 0, 'errors': []}
|
|
||||||
|
|
||||||
json_files = glob.glob(os.path.join(self.workflows_dir, "*.json"))
|
|
||||||
|
|
||||||
if not json_files:
|
|
||||||
print(f"❌ No JSON files found in '{self.workflows_dir}' directory.")
|
|
||||||
return {'workflows': [], 'total': 0, 'errors': []}
|
|
||||||
|
|
||||||
print(f"🔍 Analyzing {len(json_files)} workflow files...")
|
|
||||||
|
|
||||||
workflows = []
|
|
||||||
for file_path in json_files:
|
|
||||||
try:
|
|
||||||
workflow_data = self._analyze_workflow_file(file_path)
|
|
||||||
if workflow_data:
|
|
||||||
workflows.append(workflow_data)
|
|
||||||
except Exception as e:
|
|
||||||
error_msg = f"Error analyzing {file_path}: {str(e)}"
|
|
||||||
print(f"❌ {error_msg}")
|
|
||||||
self.errors.append(error_msg)
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Sort by current filename for consistent numbering
|
|
||||||
workflows.sort(key=lambda x: x['current_filename'])
|
|
||||||
|
|
||||||
# Assign new sequential numbers
|
|
||||||
for i, workflow in enumerate(workflows, 1):
|
|
||||||
workflow['new_number'] = f"{i:04d}"
|
|
||||||
workflow['new_filename'] = self._generate_new_filename(workflow, i)
|
|
||||||
|
|
||||||
return {
|
|
||||||
'workflows': workflows,
|
|
||||||
'total': len(workflows),
|
|
||||||
'errors': self.errors
|
|
||||||
}
|
|
||||||
|
|
||||||
def _analyze_workflow_file(self, file_path: str) -> Optional[Dict[str, Any]]:
|
|
||||||
"""Analyze a single workflow file and extract metadata for renaming."""
|
|
||||||
try:
|
|
||||||
with open(file_path, 'r', encoding='utf-8') as f:
|
|
||||||
data = json.load(f)
|
|
||||||
except (json.JSONDecodeError, UnicodeDecodeError) as e:
|
|
||||||
print(f"❌ Error reading {file_path}: {str(e)}")
|
|
||||||
return None
|
|
||||||
|
|
||||||
filename = os.path.basename(file_path)
|
|
||||||
|
|
||||||
# Extract workflow metadata
|
|
||||||
workflow = {
|
|
||||||
'current_filename': filename,
|
|
||||||
'current_path': file_path,
|
|
||||||
'name': data.get('name', filename.replace('.json', '')),
|
|
||||||
'workflow_id': data.get('id', ''),
|
|
||||||
'active': data.get('active', False),
|
|
||||||
'nodes': data.get('nodes', []),
|
|
||||||
'connections': data.get('connections', {}),
|
|
||||||
'tags': data.get('tags', []),
|
|
||||||
'created_at': data.get('createdAt', ''),
|
|
||||||
'updated_at': data.get('updatedAt', '')
|
|
||||||
}
|
|
||||||
|
|
||||||
# Analyze nodes for intelligent naming
|
|
||||||
node_count = len(workflow['nodes'])
|
|
||||||
workflow['node_count'] = node_count
|
|
||||||
|
|
||||||
# Determine complexity
|
|
||||||
if node_count <= 5:
|
|
||||||
complexity = 'Simple'
|
|
||||||
elif node_count <= 15:
|
|
||||||
complexity = 'Standard'
|
|
||||||
else:
|
|
||||||
complexity = 'Complex'
|
|
||||||
workflow['complexity'] = complexity
|
|
||||||
|
|
||||||
# Find services and trigger type
|
|
||||||
services, trigger_type = self._analyze_nodes(workflow['nodes'])
|
|
||||||
workflow['services'] = list(services)
|
|
||||||
workflow['trigger_type'] = trigger_type
|
|
||||||
|
|
||||||
# Determine purpose from name and nodes
|
|
||||||
workflow['purpose'] = self._determine_purpose(workflow['name'], workflow['nodes'])
|
|
||||||
|
|
||||||
return workflow
|
|
||||||
|
|
||||||
def _analyze_nodes(self, nodes: List[Dict]) -> Tuple[set, str]:
|
|
||||||
"""Analyze nodes to determine services and trigger type."""
|
|
||||||
services = set()
|
|
||||||
trigger_type = 'Manual'
|
|
||||||
|
|
||||||
for node in nodes:
|
|
||||||
node_type = node.get('type', '')
|
|
||||||
node_name = node.get('name', '')
|
|
||||||
|
|
||||||
# Determine trigger type
|
|
||||||
if any(x in node_type.lower() for x in ['webhook', 'http']):
|
|
||||||
trigger_type = 'Webhook'
|
|
||||||
elif any(x in node_type.lower() for x in ['cron', 'schedule', 'interval']):
|
|
||||||
trigger_type = 'Scheduled'
|
|
||||||
elif 'trigger' in node_type.lower() and trigger_type == 'Manual':
|
|
||||||
trigger_type = 'Triggered'
|
|
||||||
|
|
||||||
# Extract service names
|
|
||||||
if node_type.startswith('n8n-nodes-base.'):
|
|
||||||
service = node_type.replace('n8n-nodes-base.', '')
|
|
||||||
service = service.replace('Trigger', '').replace('trigger', '')
|
|
||||||
|
|
||||||
# Clean up service names
|
|
||||||
service_mapping = {
|
|
||||||
'webhook': 'Webhook',
|
|
||||||
'httpRequest': 'HTTP',
|
|
||||||
'cron': 'Cron',
|
|
||||||
'gmail': 'Gmail',
|
|
||||||
'slack': 'Slack',
|
|
||||||
'googleSheets': 'GoogleSheets',
|
|
||||||
'airtable': 'Airtable',
|
|
||||||
'notion': 'Notion',
|
|
||||||
'telegram': 'Telegram',
|
|
||||||
'discord': 'Discord',
|
|
||||||
'twitter': 'Twitter',
|
|
||||||
'github': 'GitHub',
|
|
||||||
'hubspot': 'HubSpot',
|
|
||||||
'salesforce': 'Salesforce',
|
|
||||||
'stripe': 'Stripe',
|
|
||||||
'shopify': 'Shopify',
|
|
||||||
'trello': 'Trello',
|
|
||||||
'asana': 'Asana',
|
|
||||||
'clickup': 'ClickUp',
|
|
||||||
'calendly': 'Calendly',
|
|
||||||
'zoom': 'Zoom',
|
|
||||||
'mattermost': 'Mattermost',
|
|
||||||
'microsoftTeams': 'Teams',
|
|
||||||
'googleCalendar': 'GoogleCalendar',
|
|
||||||
'googleDrive': 'GoogleDrive',
|
|
||||||
'dropbox': 'Dropbox',
|
|
||||||
'onedrive': 'OneDrive',
|
|
||||||
'aws': 'AWS',
|
|
||||||
'azure': 'Azure',
|
|
||||||
'googleCloud': 'GCP'
|
|
||||||
}
|
|
||||||
|
|
||||||
clean_service = service_mapping.get(service, service.title())
|
|
||||||
|
|
||||||
# Skip utility nodes
|
|
||||||
if clean_service not in ['Set', 'Function', 'If', 'Switch', 'Merge', 'StickyNote', 'NoOp']:
|
|
||||||
services.add(clean_service)
|
|
||||||
|
|
||||||
return services, trigger_type
|
|
||||||
|
|
||||||
def _determine_purpose(self, name: str, nodes: List[Dict]) -> str:
|
|
||||||
"""Determine workflow purpose from name and node analysis."""
|
|
||||||
name_lower = name.lower()
|
|
||||||
|
|
||||||
# Purpose keywords mapping
|
|
||||||
purpose_keywords = {
|
|
||||||
'create': ['create', 'add', 'new', 'generate', 'build'],
|
|
||||||
'update': ['update', 'modify', 'change', 'edit', 'patch'],
|
|
||||||
'sync': ['sync', 'synchronize', 'mirror', 'replicate'],
|
|
||||||
'send': ['send', 'email', 'message', 'notify', 'alert'],
|
|
||||||
'import': ['import', 'load', 'fetch', 'get', 'retrieve'],
|
|
||||||
'export': ['export', 'save', 'backup', 'archive'],
|
|
||||||
'monitor': ['monitor', 'check', 'watch', 'track', 'status'],
|
|
||||||
'process': ['process', 'transform', 'convert', 'parse'],
|
|
||||||
'automate': ['automate', 'workflow', 'bot', 'automation']
|
|
||||||
}
|
|
||||||
|
|
||||||
for purpose, keywords in purpose_keywords.items():
|
|
||||||
if any(keyword in name_lower for keyword in keywords):
|
|
||||||
return purpose.title()
|
|
||||||
|
|
||||||
# Default purpose based on node analysis
|
|
||||||
return 'Automation'
|
|
||||||
|
|
||||||
def _generate_new_filename(self, workflow: Dict, number: int) -> str:
|
|
||||||
"""Generate new standardized filename."""
|
|
||||||
# Format: 0001_Service1_Service2_Purpose_Trigger.json
|
|
||||||
|
|
||||||
services = workflow['services'][:2] # Max 2 services in filename
|
|
||||||
purpose = workflow['purpose']
|
|
||||||
trigger = workflow['trigger_type']
|
|
||||||
|
|
||||||
# Build filename components
|
|
||||||
parts = [f"{number:04d}"]
|
|
||||||
|
|
||||||
# Add services
|
|
||||||
if services:
|
|
||||||
parts.extend(services)
|
|
||||||
|
|
||||||
# Add purpose
|
|
||||||
parts.append(purpose)
|
|
||||||
|
|
||||||
# Add trigger if not Manual
|
|
||||||
if trigger != 'Manual':
|
|
||||||
parts.append(trigger)
|
|
||||||
|
|
||||||
# Join and clean filename
|
|
||||||
filename = '_'.join(parts)
|
|
||||||
filename = re.sub(r'[^\w\-_]', '', filename) # Remove special chars
|
|
||||||
filename = re.sub(r'_+', '_', filename) # Collapse multiple underscores
|
|
||||||
filename = filename.strip('_') # Remove leading/trailing underscores
|
|
||||||
|
|
||||||
return f"{filename}.json"
|
|
||||||
|
|
||||||
def create_backup(self) -> bool:
|
|
||||||
"""Create backup of current workflows directory."""
|
|
||||||
try:
|
|
||||||
if os.path.exists(self.backup_dir):
|
|
||||||
shutil.rmtree(self.backup_dir)
|
|
||||||
|
|
||||||
shutil.copytree(self.workflows_dir, self.backup_dir)
|
|
||||||
print(f"✅ Backup created at: {self.backup_dir}")
|
|
||||||
return True
|
|
||||||
except Exception as e:
|
|
||||||
print(f"❌ Failed to create backup: {e}")
|
|
||||||
return False
|
|
||||||
|
|
||||||
def execute_rename_plan(self, rename_plan: Dict[str, Any], dry_run: bool = True) -> bool:
|
|
||||||
"""Execute the comprehensive rename plan."""
|
|
||||||
if not rename_plan['workflows']:
|
|
||||||
print("❌ No workflows to rename.")
|
|
||||||
return False
|
|
||||||
|
|
||||||
print(f"\n{'🔍 DRY RUN - ' if dry_run else '🚀 EXECUTING - '}Renaming {rename_plan['total']} workflows")
|
|
||||||
|
|
||||||
if not dry_run:
|
|
||||||
if not self.create_backup():
|
|
||||||
print("❌ Cannot proceed without backup.")
|
|
||||||
return False
|
|
||||||
|
|
||||||
success_count = 0
|
|
||||||
|
|
||||||
for workflow in rename_plan['workflows']:
|
|
||||||
old_path = workflow['current_path']
|
|
||||||
new_filename = workflow['new_filename']
|
|
||||||
new_path = os.path.join(self.workflows_dir, new_filename)
|
|
||||||
|
|
||||||
# Check for filename conflicts
|
|
||||||
if os.path.exists(new_path) and old_path != new_path:
|
|
||||||
print(f"⚠️ Conflict: {new_filename} already exists")
|
|
||||||
continue
|
|
||||||
|
|
||||||
if dry_run:
|
|
||||||
print(f"📝 {workflow['current_filename']} → {new_filename}")
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
os.rename(old_path, new_path)
|
|
||||||
self.rename_log.append({
|
|
||||||
'old': workflow['current_filename'],
|
|
||||||
'new': new_filename,
|
|
||||||
'services': workflow['services'],
|
|
||||||
'purpose': workflow['purpose'],
|
|
||||||
'trigger': workflow['trigger_type']
|
|
||||||
})
|
|
||||||
success_count += 1
|
|
||||||
print(f"✅ {workflow['current_filename']} → {new_filename}")
|
|
||||||
except Exception as e:
|
|
||||||
error_msg = f"❌ Failed to rename {workflow['current_filename']}: {e}"
|
|
||||||
print(error_msg)
|
|
||||||
self.errors.append(error_msg)
|
|
||||||
|
|
||||||
if not dry_run:
|
|
||||||
print(f"\n🎉 Rename complete: {success_count}/{rename_plan['total']} workflows renamed")
|
|
||||||
self._save_rename_log()
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
def _save_rename_log(self):
|
|
||||||
"""Save detailed rename log to file."""
|
|
||||||
log_data = {
|
|
||||||
'timestamp': os.popen('date').read().strip(),
|
|
||||||
'total_renamed': len(self.rename_log),
|
|
||||||
'errors': self.errors,
|
|
||||||
'renames': self.rename_log
|
|
||||||
}
|
|
||||||
|
|
||||||
with open('workflow_rename_log.json', 'w', encoding='utf-8') as f:
|
|
||||||
json.dump(log_data, f, indent=2, ensure_ascii=False)
|
|
||||||
|
|
||||||
print(f"📄 Rename log saved to: workflow_rename_log.json")
|
|
||||||
|
|
||||||
def generate_report(self, rename_plan: Dict[str, Any]) -> str:
|
|
||||||
"""Generate comprehensive rename report."""
|
|
||||||
workflows = rename_plan['workflows']
|
|
||||||
total = rename_plan['total']
|
|
||||||
|
|
||||||
# Statistics
|
|
||||||
services_count = {}
|
|
||||||
purposes_count = {}
|
|
||||||
triggers_count = {}
|
|
||||||
|
|
||||||
for workflow in workflows:
|
|
||||||
for service in workflow['services']:
|
|
||||||
services_count[service] = services_count.get(service, 0) + 1
|
|
||||||
|
|
||||||
purposes_count[workflow['purpose']] = purposes_count.get(workflow['purpose'], 0) + 1
|
|
||||||
triggers_count[workflow['trigger_type']] = triggers_count.get(workflow['trigger_type'], 0) + 1
|
|
||||||
|
|
||||||
report = f"""
|
|
||||||
# 🎯 Comprehensive Workflow Rename Plan
|
|
||||||
|
|
||||||
## 📊 Overview
|
|
||||||
- **Total workflows**: {total}
|
|
||||||
- **Naming convention**: 0001-{total:04d}_Service1_Service2_Purpose_Trigger.json
|
|
||||||
- **Quality improvement**: 100% standardized naming
|
|
||||||
|
|
||||||
## 🏷️ Service Distribution
|
|
||||||
"""
|
|
||||||
|
|
||||||
for service, count in sorted(services_count.items(), key=lambda x: x[1], reverse=True)[:10]:
|
|
||||||
report += f"- **{service}**: {count} workflows\n"
|
|
||||||
|
|
||||||
report += f"\n## 🎯 Purpose Distribution\n"
|
|
||||||
for purpose, count in sorted(purposes_count.items(), key=lambda x: x[1], reverse=True):
|
|
||||||
report += f"- **{purpose}**: {count} workflows\n"
|
|
||||||
|
|
||||||
report += f"\n## ⚡ Trigger Distribution\n"
|
|
||||||
for trigger, count in sorted(triggers_count.items(), key=lambda x: x[1], reverse=True):
|
|
||||||
report += f"- **{trigger}**: {count} workflows\n"
|
|
||||||
|
|
||||||
report += f"""
|
|
||||||
## 📝 Naming Examples
|
|
||||||
"""
|
|
||||||
|
|
||||||
for i, workflow in enumerate(workflows[:10]):
|
|
||||||
report += f"- `{workflow['current_filename']}` → `{workflow['new_filename']}`\n"
|
|
||||||
|
|
||||||
if len(workflows) > 10:
|
|
||||||
report += f"... and {len(workflows) - 10} more workflows\n"
|
|
||||||
|
|
||||||
return report
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
"""Main execution function."""
|
|
||||||
import argparse
|
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(description='Comprehensive N8N Workflow Renamer')
|
|
||||||
parser.add_argument('--analyze', action='store_true', help='Analyze all workflows and create rename plan')
|
|
||||||
parser.add_argument('--execute', action='store_true', help='Execute the rename plan (requires --analyze first)')
|
|
||||||
parser.add_argument('--dry-run', action='store_true', help='Show rename plan without executing')
|
|
||||||
parser.add_argument('--report', action='store_true', help='Generate comprehensive report')
|
|
||||||
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
renamer = ComprehensiveWorkflowRenamer()
|
|
||||||
|
|
||||||
if args.analyze or args.dry_run or args.report:
|
|
||||||
print("🔍 Analyzing all workflows...")
|
|
||||||
rename_plan = renamer.analyze_all_workflows()
|
|
||||||
|
|
||||||
if args.report:
|
|
||||||
report = renamer.generate_report(rename_plan)
|
|
||||||
print(report)
|
|
||||||
|
|
||||||
if args.dry_run:
|
|
||||||
renamer.execute_rename_plan(rename_plan, dry_run=True)
|
|
||||||
|
|
||||||
if args.execute:
|
|
||||||
confirm = input(f"\n⚠️ This will rename {rename_plan['total']} workflows. Continue? (yes/no): ")
|
|
||||||
if confirm.lower() == 'yes':
|
|
||||||
renamer.execute_rename_plan(rename_plan, dry_run=False)
|
|
||||||
else:
|
|
||||||
print("❌ Rename cancelled.")
|
|
||||||
|
|
||||||
else:
|
|
||||||
parser.print_help()
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,10 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
WORKFLOW_DIR="./workflows"
|
|
||||||
|
|
||||||
for file in "$WORKFLOW_DIR"/*.json
|
|
||||||
do
|
|
||||||
echo "Importing $file..."
|
|
||||||
npx n8n import:workflow --input="$file"
|
|
||||||
done
|
|
||||||
|
|
||||||
162
import_workflows.py
Normal file
162
import_workflows.py
Normal file
@@ -0,0 +1,162 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
N8N Workflow Importer
|
||||||
|
Python replacement for import-workflows.sh with better error handling and progress tracking.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import json
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import List, Dict, Any
|
||||||
|
|
||||||
|
|
||||||
|
class WorkflowImporter:
|
||||||
|
"""Import n8n workflows with progress tracking and error handling."""
|
||||||
|
|
||||||
|
def __init__(self, workflows_dir: str = "workflows"):
|
||||||
|
self.workflows_dir = Path(workflows_dir)
|
||||||
|
self.imported_count = 0
|
||||||
|
self.failed_count = 0
|
||||||
|
self.errors = []
|
||||||
|
|
||||||
|
def validate_workflow(self, file_path: Path) -> bool:
|
||||||
|
"""Validate workflow JSON before import."""
|
||||||
|
try:
|
||||||
|
with open(file_path, 'r', encoding='utf-8') as f:
|
||||||
|
data = json.load(f)
|
||||||
|
|
||||||
|
# Basic validation
|
||||||
|
if not isinstance(data, dict):
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Check required fields
|
||||||
|
required_fields = ['nodes', 'connections']
|
||||||
|
for field in required_fields:
|
||||||
|
if field not in data:
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
except (json.JSONDecodeError, FileNotFoundError, PermissionError):
|
||||||
|
return False
|
||||||
|
|
||||||
|
def import_workflow(self, file_path: Path) -> bool:
|
||||||
|
"""Import a single workflow file."""
|
||||||
|
try:
|
||||||
|
# Validate first
|
||||||
|
if not self.validate_workflow(file_path):
|
||||||
|
self.errors.append(f"Invalid JSON: {file_path.name}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Run n8n import command
|
||||||
|
result = subprocess.run([
|
||||||
|
'npx', 'n8n', 'import:workflow',
|
||||||
|
f'--input={file_path}'
|
||||||
|
], capture_output=True, text=True, timeout=30)
|
||||||
|
|
||||||
|
if result.returncode == 0:
|
||||||
|
print(f"✅ Imported: {file_path.name}")
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
error_msg = result.stderr.strip() or result.stdout.strip()
|
||||||
|
self.errors.append(f"Import failed for {file_path.name}: {error_msg}")
|
||||||
|
print(f"❌ Failed: {file_path.name}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
except subprocess.TimeoutExpired:
|
||||||
|
self.errors.append(f"Timeout importing {file_path.name}")
|
||||||
|
print(f"⏰ Timeout: {file_path.name}")
|
||||||
|
return False
|
||||||
|
except Exception as e:
|
||||||
|
self.errors.append(f"Error importing {file_path.name}: {str(e)}")
|
||||||
|
print(f"❌ Error: {file_path.name} - {str(e)}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def get_workflow_files(self) -> List[Path]:
|
||||||
|
"""Get all workflow JSON files."""
|
||||||
|
if not self.workflows_dir.exists():
|
||||||
|
print(f"❌ Workflows directory not found: {self.workflows_dir}")
|
||||||
|
return []
|
||||||
|
|
||||||
|
json_files = list(self.workflows_dir.glob("*.json"))
|
||||||
|
if not json_files:
|
||||||
|
print(f"❌ No JSON files found in: {self.workflows_dir}")
|
||||||
|
return []
|
||||||
|
|
||||||
|
return sorted(json_files)
|
||||||
|
|
||||||
|
def import_all(self) -> Dict[str, Any]:
|
||||||
|
"""Import all workflow files."""
|
||||||
|
workflow_files = self.get_workflow_files()
|
||||||
|
total_files = len(workflow_files)
|
||||||
|
|
||||||
|
if total_files == 0:
|
||||||
|
return {"success": False, "message": "No workflow files found"}
|
||||||
|
|
||||||
|
print(f"🚀 Starting import of {total_files} workflows...")
|
||||||
|
print("-" * 50)
|
||||||
|
|
||||||
|
for i, file_path in enumerate(workflow_files, 1):
|
||||||
|
print(f"[{i}/{total_files}] Processing {file_path.name}...")
|
||||||
|
|
||||||
|
if self.import_workflow(file_path):
|
||||||
|
self.imported_count += 1
|
||||||
|
else:
|
||||||
|
self.failed_count += 1
|
||||||
|
|
||||||
|
# Summary
|
||||||
|
print("\n" + "=" * 50)
|
||||||
|
print(f"📊 Import Summary:")
|
||||||
|
print(f"✅ Successfully imported: {self.imported_count}")
|
||||||
|
print(f"❌ Failed imports: {self.failed_count}")
|
||||||
|
print(f"📁 Total files: {total_files}")
|
||||||
|
|
||||||
|
if self.errors:
|
||||||
|
print(f"\n❌ Errors encountered:")
|
||||||
|
for error in self.errors[:10]: # Show first 10 errors
|
||||||
|
print(f" • {error}")
|
||||||
|
if len(self.errors) > 10:
|
||||||
|
print(f" ... and {len(self.errors) - 10} more errors")
|
||||||
|
|
||||||
|
return {
|
||||||
|
"success": self.failed_count == 0,
|
||||||
|
"imported": self.imported_count,
|
||||||
|
"failed": self.failed_count,
|
||||||
|
"total": total_files,
|
||||||
|
"errors": self.errors
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def check_n8n_available() -> bool:
|
||||||
|
"""Check if n8n CLI is available."""
|
||||||
|
try:
|
||||||
|
result = subprocess.run(
|
||||||
|
['npx', 'n8n', '--version'],
|
||||||
|
capture_output=True, text=True, timeout=10
|
||||||
|
)
|
||||||
|
return result.returncode == 0
|
||||||
|
except (subprocess.TimeoutExpired, FileNotFoundError):
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""Main entry point."""
|
||||||
|
print("🔧 N8N Workflow Importer")
|
||||||
|
print("=" * 40)
|
||||||
|
|
||||||
|
# Check if n8n is available
|
||||||
|
if not check_n8n_available():
|
||||||
|
print("❌ n8n CLI not found. Please install n8n first:")
|
||||||
|
print(" npm install -g n8n")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Create importer and run
|
||||||
|
importer = WorkflowImporter()
|
||||||
|
result = importer.import_all()
|
||||||
|
|
||||||
|
# Exit with appropriate code
|
||||||
|
sys.exit(0 if result["success"] else 1)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
fastapi==0.104.1
|
# N8N Workflows API Dependencies
|
||||||
uvicorn[standard]==0.24.0
|
# Core API Framework
|
||||||
pydantic==2.5.0
|
fastapi>=0.104.0,<1.0.0
|
||||||
|
uvicorn[standard]>=0.24.0,<1.0.0
|
||||||
|
pydantic>=2.4.0,<3.0.0
|
||||||
176
run.py
Executable file
176
run.py
Executable file
@@ -0,0 +1,176 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
🚀 N8N Workflows Search Engine Launcher
|
||||||
|
Start the advanced search system with optimized performance.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import argparse
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
def print_banner():
|
||||||
|
"""Print application banner."""
|
||||||
|
print("🚀 n8n-workflows Advanced Search Engine")
|
||||||
|
print("=" * 50)
|
||||||
|
|
||||||
|
|
||||||
|
def check_requirements() -> bool:
|
||||||
|
"""Check if required dependencies are installed."""
|
||||||
|
missing_deps = []
|
||||||
|
|
||||||
|
try:
|
||||||
|
import sqlite3
|
||||||
|
except ImportError:
|
||||||
|
missing_deps.append("sqlite3")
|
||||||
|
|
||||||
|
try:
|
||||||
|
import uvicorn
|
||||||
|
except ImportError:
|
||||||
|
missing_deps.append("uvicorn")
|
||||||
|
|
||||||
|
try:
|
||||||
|
import fastapi
|
||||||
|
except ImportError:
|
||||||
|
missing_deps.append("fastapi")
|
||||||
|
|
||||||
|
if missing_deps:
|
||||||
|
print(f"❌ Missing dependencies: {', '.join(missing_deps)}")
|
||||||
|
print("💡 Install with: pip install -r requirements.txt")
|
||||||
|
return False
|
||||||
|
|
||||||
|
print("✅ Dependencies verified")
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def setup_directories():
|
||||||
|
"""Create necessary directories."""
|
||||||
|
directories = ["database", "static", "workflows"]
|
||||||
|
|
||||||
|
for directory in directories:
|
||||||
|
os.makedirs(directory, exist_ok=True)
|
||||||
|
|
||||||
|
print("✅ Directories verified")
|
||||||
|
|
||||||
|
|
||||||
|
def setup_database(force_reindex: bool = False) -> str:
|
||||||
|
"""Setup and initialize the database."""
|
||||||
|
from workflow_db import WorkflowDatabase
|
||||||
|
|
||||||
|
db_path = "database/workflows.db"
|
||||||
|
|
||||||
|
print(f"🔄 Setting up database: {db_path}")
|
||||||
|
db = WorkflowDatabase(db_path)
|
||||||
|
|
||||||
|
# Check if database has data or force reindex
|
||||||
|
stats = db.get_stats()
|
||||||
|
if stats['total'] == 0 or force_reindex:
|
||||||
|
print("📚 Indexing workflows...")
|
||||||
|
index_stats = db.index_all_workflows(force_reindex=True)
|
||||||
|
print(f"✅ Indexed {index_stats['processed']} workflows")
|
||||||
|
|
||||||
|
# Show final stats
|
||||||
|
final_stats = db.get_stats()
|
||||||
|
print(f"📊 Database contains {final_stats['total']} workflows")
|
||||||
|
else:
|
||||||
|
print(f"✅ Database ready: {stats['total']} workflows")
|
||||||
|
|
||||||
|
return db_path
|
||||||
|
|
||||||
|
|
||||||
|
def start_server(host: str = "127.0.0.1", port: int = 8000, reload: bool = False):
|
||||||
|
"""Start the FastAPI server."""
|
||||||
|
print(f"🌐 Starting server at http://{host}:{port}")
|
||||||
|
print(f"📊 API Documentation: http://{host}:{port}/docs")
|
||||||
|
print(f"🔍 Workflow Search: http://{host}:{port}/api/workflows")
|
||||||
|
print()
|
||||||
|
print("Press Ctrl+C to stop the server")
|
||||||
|
print("-" * 50)
|
||||||
|
|
||||||
|
# Configure database path
|
||||||
|
os.environ['WORKFLOW_DB_PATH'] = "database/workflows.db"
|
||||||
|
|
||||||
|
# Start uvicorn with better configuration
|
||||||
|
import uvicorn
|
||||||
|
uvicorn.run(
|
||||||
|
"api_server:app",
|
||||||
|
host=host,
|
||||||
|
port=port,
|
||||||
|
reload=reload,
|
||||||
|
log_level="info",
|
||||||
|
access_log=False # Reduce log noise
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""Main entry point with command line arguments."""
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description="N8N Workflows Search Engine",
|
||||||
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||||
|
epilog="""
|
||||||
|
Examples:
|
||||||
|
python run.py # Start with default settings
|
||||||
|
python run.py --port 3000 # Start on port 3000
|
||||||
|
python run.py --host 0.0.0.0 # Accept external connections
|
||||||
|
python run.py --reindex # Force database reindexing
|
||||||
|
python run.py --dev # Development mode with auto-reload
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
"--host",
|
||||||
|
default="127.0.0.1",
|
||||||
|
help="Host to bind to (default: 127.0.0.1)"
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--port",
|
||||||
|
type=int,
|
||||||
|
default=8000,
|
||||||
|
help="Port to bind to (default: 8000)"
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--reindex",
|
||||||
|
action="store_true",
|
||||||
|
help="Force database reindexing"
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--dev",
|
||||||
|
action="store_true",
|
||||||
|
help="Development mode with auto-reload"
|
||||||
|
)
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
print_banner()
|
||||||
|
|
||||||
|
# Check dependencies
|
||||||
|
if not check_requirements():
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Setup directories
|
||||||
|
setup_directories()
|
||||||
|
|
||||||
|
# Setup database
|
||||||
|
try:
|
||||||
|
setup_database(force_reindex=args.reindex)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ Database setup error: {e}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Start server
|
||||||
|
try:
|
||||||
|
start_server(
|
||||||
|
host=args.host,
|
||||||
|
port=args.port,
|
||||||
|
reload=args.dev
|
||||||
|
)
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
print("\n👋 Server stopped!")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ Server error: {e}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
"""
|
|
||||||
Setup script for the new fast N8N workflow documentation system.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import subprocess
|
|
||||||
import sys
|
|
||||||
import os
|
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
def run_command(command, description):
|
|
||||||
"""Run a shell command and handle errors."""
|
|
||||||
print(f"🔄 {description}...")
|
|
||||||
try:
|
|
||||||
result = subprocess.run(command, shell=True, check=True, capture_output=True, text=True)
|
|
||||||
print(f"✅ {description} completed successfully")
|
|
||||||
return result.stdout
|
|
||||||
except subprocess.CalledProcessError as e:
|
|
||||||
print(f"❌ {description} failed: {e.stderr}")
|
|
||||||
return None
|
|
||||||
|
|
||||||
def install_dependencies():
|
|
||||||
"""Install Python dependencies."""
|
|
||||||
return run_command(
|
|
||||||
f"{sys.executable} -m pip install -r requirements.txt",
|
|
||||||
"Installing Python dependencies"
|
|
||||||
)
|
|
||||||
|
|
||||||
def index_workflows():
|
|
||||||
"""Index all workflows into the database."""
|
|
||||||
return run_command(
|
|
||||||
f"{sys.executable} workflow_db.py --index",
|
|
||||||
"Indexing workflow files into database"
|
|
||||||
)
|
|
||||||
|
|
||||||
def main():
|
|
||||||
print("🚀 Setting up N8N Fast Workflow Documentation System")
|
|
||||||
print("=" * 60)
|
|
||||||
|
|
||||||
# Check if we're in the right directory
|
|
||||||
if not os.path.exists("workflows"):
|
|
||||||
print("❌ Error: 'workflows' directory not found. Please run this script from the repository root.")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
# Install dependencies
|
|
||||||
if install_dependencies() is None:
|
|
||||||
print("❌ Failed to install dependencies. Please install manually:")
|
|
||||||
print(" pip install fastapi uvicorn pydantic")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
# Index workflows
|
|
||||||
if index_workflows() is None:
|
|
||||||
print("⚠️ Warning: Failed to index workflows. You can do this manually later:")
|
|
||||||
print(" python workflow_db.py --index")
|
|
||||||
|
|
||||||
print("\n🎉 Setup completed successfully!")
|
|
||||||
print("\n📊 Performance Comparison:")
|
|
||||||
print(" Old system: 71MB HTML file, 10s+ load time")
|
|
||||||
print(" New system: <100KB initial load, <100ms search")
|
|
||||||
print("\n🚀 To start the fast documentation server:")
|
|
||||||
print(" python api_server.py")
|
|
||||||
print("\n🌐 Then open: http://localhost:8000")
|
|
||||||
print("\n💡 Features:")
|
|
||||||
print(" • Instant search with <100ms response times")
|
|
||||||
print(" • Virtual scrolling for smooth browsing")
|
|
||||||
print(" • Real-time filtering and pagination")
|
|
||||||
print(" • Lazy-loaded diagrams and JSON viewing")
|
|
||||||
print(" • Dark/light theme support")
|
|
||||||
print(" • Mobile-responsive design")
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
||||||
283
workflow_db.py
283
workflow_db.py
@@ -16,7 +16,10 @@ from pathlib import Path
|
|||||||
class WorkflowDatabase:
|
class WorkflowDatabase:
|
||||||
"""High-performance SQLite database for workflow metadata and search."""
|
"""High-performance SQLite database for workflow metadata and search."""
|
||||||
|
|
||||||
def __init__(self, db_path: str = "workflows.db"):
|
def __init__(self, db_path: str = None):
|
||||||
|
# Use environment variable if no path provided
|
||||||
|
if db_path is None:
|
||||||
|
db_path = os.environ.get('WORKFLOW_DB_PATH', 'workflows.db')
|
||||||
self.db_path = db_path
|
self.db_path = db_path
|
||||||
self.workflows_dir = "workflows"
|
self.workflows_dir = "workflows"
|
||||||
self.init_database()
|
self.init_database()
|
||||||
@@ -106,6 +109,44 @@ class WorkflowDatabase:
|
|||||||
hash_md5.update(chunk)
|
hash_md5.update(chunk)
|
||||||
return hash_md5.hexdigest()
|
return hash_md5.hexdigest()
|
||||||
|
|
||||||
|
def format_workflow_name(self, filename: str) -> str:
|
||||||
|
"""Convert filename to readable workflow name."""
|
||||||
|
# Remove .json extension
|
||||||
|
name = filename.replace('.json', '')
|
||||||
|
|
||||||
|
# Split by underscores
|
||||||
|
parts = name.split('_')
|
||||||
|
|
||||||
|
# Skip the first part if it's just a number
|
||||||
|
if len(parts) > 1 and parts[0].isdigit():
|
||||||
|
parts = parts[1:]
|
||||||
|
|
||||||
|
# Convert parts to title case and join with spaces
|
||||||
|
readable_parts = []
|
||||||
|
for part in parts:
|
||||||
|
# Special handling for common terms
|
||||||
|
if part.lower() == 'http':
|
||||||
|
readable_parts.append('HTTP')
|
||||||
|
elif part.lower() == 'api':
|
||||||
|
readable_parts.append('API')
|
||||||
|
elif part.lower() == 'webhook':
|
||||||
|
readable_parts.append('Webhook')
|
||||||
|
elif part.lower() == 'automation':
|
||||||
|
readable_parts.append('Automation')
|
||||||
|
elif part.lower() == 'automate':
|
||||||
|
readable_parts.append('Automate')
|
||||||
|
elif part.lower() == 'scheduled':
|
||||||
|
readable_parts.append('Scheduled')
|
||||||
|
elif part.lower() == 'triggered':
|
||||||
|
readable_parts.append('Triggered')
|
||||||
|
elif part.lower() == 'manual':
|
||||||
|
readable_parts.append('Manual')
|
||||||
|
else:
|
||||||
|
# Capitalize first letter
|
||||||
|
readable_parts.append(part.capitalize())
|
||||||
|
|
||||||
|
return ' '.join(readable_parts)
|
||||||
|
|
||||||
def analyze_workflow_file(self, file_path: str) -> Optional[Dict[str, Any]]:
|
def analyze_workflow_file(self, file_path: str) -> Optional[Dict[str, Any]]:
|
||||||
"""Analyze a single workflow file and extract metadata."""
|
"""Analyze a single workflow file and extract metadata."""
|
||||||
try:
|
try:
|
||||||
@@ -122,7 +163,7 @@ class WorkflowDatabase:
|
|||||||
# Extract basic metadata
|
# Extract basic metadata
|
||||||
workflow = {
|
workflow = {
|
||||||
'filename': filename,
|
'filename': filename,
|
||||||
'name': data.get('name', filename.replace('.json', '')),
|
'name': self.format_workflow_name(filename),
|
||||||
'workflow_id': data.get('id', ''),
|
'workflow_id': data.get('id', ''),
|
||||||
'active': data.get('active', False),
|
'active': data.get('active', False),
|
||||||
'nodes': data.get('nodes', []),
|
'nodes': data.get('nodes', []),
|
||||||
@@ -134,6 +175,12 @@ class WorkflowDatabase:
|
|||||||
'file_size': file_size
|
'file_size': file_size
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Use JSON name if available and meaningful, otherwise use formatted filename
|
||||||
|
json_name = data.get('name', '').strip()
|
||||||
|
if json_name and json_name != filename.replace('.json', '') and not json_name.startswith('My workflow'):
|
||||||
|
workflow['name'] = json_name
|
||||||
|
# If no meaningful JSON name, use formatted filename (already set above)
|
||||||
|
|
||||||
# Analyze nodes
|
# Analyze nodes
|
||||||
node_count = len(workflow['nodes'])
|
node_count = len(workflow['nodes'])
|
||||||
workflow['node_count'] = node_count
|
workflow['node_count'] = node_count
|
||||||
@@ -162,12 +209,127 @@ class WorkflowDatabase:
|
|||||||
trigger_type = 'Manual'
|
trigger_type = 'Manual'
|
||||||
integrations = set()
|
integrations = set()
|
||||||
|
|
||||||
|
# Enhanced service mapping for better recognition
|
||||||
|
service_mappings = {
|
||||||
|
# Messaging & Communication
|
||||||
|
'telegram': 'Telegram',
|
||||||
|
'telegramTrigger': 'Telegram',
|
||||||
|
'discord': 'Discord',
|
||||||
|
'slack': 'Slack',
|
||||||
|
'whatsapp': 'WhatsApp',
|
||||||
|
'mattermost': 'Mattermost',
|
||||||
|
'teams': 'Microsoft Teams',
|
||||||
|
'rocketchat': 'Rocket.Chat',
|
||||||
|
|
||||||
|
# Email
|
||||||
|
'gmail': 'Gmail',
|
||||||
|
'mailjet': 'Mailjet',
|
||||||
|
'emailreadimap': 'Email (IMAP)',
|
||||||
|
'emailsendsmt': 'Email (SMTP)',
|
||||||
|
'outlook': 'Outlook',
|
||||||
|
|
||||||
|
# Cloud Storage
|
||||||
|
'googledrive': 'Google Drive',
|
||||||
|
'googledocs': 'Google Docs',
|
||||||
|
'googlesheets': 'Google Sheets',
|
||||||
|
'dropbox': 'Dropbox',
|
||||||
|
'onedrive': 'OneDrive',
|
||||||
|
'box': 'Box',
|
||||||
|
|
||||||
|
# Databases
|
||||||
|
'postgres': 'PostgreSQL',
|
||||||
|
'mysql': 'MySQL',
|
||||||
|
'mongodb': 'MongoDB',
|
||||||
|
'redis': 'Redis',
|
||||||
|
'airtable': 'Airtable',
|
||||||
|
'notion': 'Notion',
|
||||||
|
|
||||||
|
# Project Management
|
||||||
|
'jira': 'Jira',
|
||||||
|
'github': 'GitHub',
|
||||||
|
'gitlab': 'GitLab',
|
||||||
|
'trello': 'Trello',
|
||||||
|
'asana': 'Asana',
|
||||||
|
'mondaycom': 'Monday.com',
|
||||||
|
|
||||||
|
# AI/ML Services
|
||||||
|
'openai': 'OpenAI',
|
||||||
|
'anthropic': 'Anthropic',
|
||||||
|
'huggingface': 'Hugging Face',
|
||||||
|
|
||||||
|
# Social Media
|
||||||
|
'linkedin': 'LinkedIn',
|
||||||
|
'twitter': 'Twitter/X',
|
||||||
|
'facebook': 'Facebook',
|
||||||
|
'instagram': 'Instagram',
|
||||||
|
|
||||||
|
# E-commerce
|
||||||
|
'shopify': 'Shopify',
|
||||||
|
'stripe': 'Stripe',
|
||||||
|
'paypal': 'PayPal',
|
||||||
|
|
||||||
|
# Analytics
|
||||||
|
'googleanalytics': 'Google Analytics',
|
||||||
|
'mixpanel': 'Mixpanel',
|
||||||
|
|
||||||
|
# Calendar & Tasks
|
||||||
|
'googlecalendar': 'Google Calendar',
|
||||||
|
'googletasks': 'Google Tasks',
|
||||||
|
'cal': 'Cal.com',
|
||||||
|
'calendly': 'Calendly',
|
||||||
|
|
||||||
|
# Forms & Surveys
|
||||||
|
'typeform': 'Typeform',
|
||||||
|
'googleforms': 'Google Forms',
|
||||||
|
'form': 'Form Trigger',
|
||||||
|
|
||||||
|
# Development Tools
|
||||||
|
'webhook': 'Webhook',
|
||||||
|
'httpRequest': 'HTTP Request',
|
||||||
|
'graphql': 'GraphQL',
|
||||||
|
'sse': 'Server-Sent Events',
|
||||||
|
|
||||||
|
# Utility nodes (exclude from integrations)
|
||||||
|
'set': None,
|
||||||
|
'function': None,
|
||||||
|
'code': None,
|
||||||
|
'if': None,
|
||||||
|
'switch': None,
|
||||||
|
'merge': None,
|
||||||
|
'split': None,
|
||||||
|
'stickynote': None,
|
||||||
|
'stickyNote': None,
|
||||||
|
'wait': None,
|
||||||
|
'schedule': None,
|
||||||
|
'cron': None,
|
||||||
|
'manual': None,
|
||||||
|
'stopanderror': None,
|
||||||
|
'noop': None,
|
||||||
|
'noOp': None,
|
||||||
|
'error': None,
|
||||||
|
'limit': None,
|
||||||
|
'aggregate': None,
|
||||||
|
'summarize': None,
|
||||||
|
'filter': None,
|
||||||
|
'sort': None,
|
||||||
|
'removeDuplicates': None,
|
||||||
|
'dateTime': None,
|
||||||
|
'extractFromFile': None,
|
||||||
|
'convertToFile': None,
|
||||||
|
'readBinaryFile': None,
|
||||||
|
'readBinaryFiles': None,
|
||||||
|
'executionData': None,
|
||||||
|
'executeWorkflow': None,
|
||||||
|
'executeCommand': None,
|
||||||
|
'respondToWebhook': None,
|
||||||
|
}
|
||||||
|
|
||||||
for node in nodes:
|
for node in nodes:
|
||||||
node_type = node.get('type', '')
|
node_type = node.get('type', '')
|
||||||
node_name = node.get('name', '')
|
node_name = node.get('name', '').lower()
|
||||||
|
|
||||||
# Determine trigger type
|
# Determine trigger type
|
||||||
if 'webhook' in node_type.lower() or 'webhook' in node_name.lower():
|
if 'webhook' in node_type.lower() or 'webhook' in node_name:
|
||||||
trigger_type = 'Webhook'
|
trigger_type = 'Webhook'
|
||||||
elif 'cron' in node_type.lower() or 'schedule' in node_type.lower():
|
elif 'cron' in node_type.lower() or 'schedule' in node_type.lower():
|
||||||
trigger_type = 'Scheduled'
|
trigger_type = 'Scheduled'
|
||||||
@@ -175,12 +337,45 @@ class WorkflowDatabase:
|
|||||||
if 'manual' not in node_type.lower():
|
if 'manual' not in node_type.lower():
|
||||||
trigger_type = 'Webhook'
|
trigger_type = 'Webhook'
|
||||||
|
|
||||||
# Extract integrations
|
# Extract integrations with enhanced mapping
|
||||||
|
service_name = None
|
||||||
|
|
||||||
|
# Handle n8n-nodes-base nodes
|
||||||
if node_type.startswith('n8n-nodes-base.'):
|
if node_type.startswith('n8n-nodes-base.'):
|
||||||
service = node_type.replace('n8n-nodes-base.', '')
|
raw_service = node_type.replace('n8n-nodes-base.', '').lower()
|
||||||
service = service.replace('Trigger', '').replace('trigger', '')
|
raw_service = raw_service.replace('trigger', '')
|
||||||
if service and service not in ['set', 'function', 'if', 'switch', 'merge', 'stickyNote']:
|
service_name = service_mappings.get(raw_service, raw_service.title() if raw_service else None)
|
||||||
integrations.add(service.title())
|
|
||||||
|
# Handle @n8n/ namespaced nodes
|
||||||
|
elif node_type.startswith('@n8n/'):
|
||||||
|
raw_service = node_type.split('.')[-1].lower() if '.' in node_type else node_type.lower()
|
||||||
|
raw_service = raw_service.replace('trigger', '')
|
||||||
|
service_name = service_mappings.get(raw_service, raw_service.title() if raw_service else None)
|
||||||
|
|
||||||
|
# Handle custom nodes
|
||||||
|
elif '-' in node_type:
|
||||||
|
# Try to extract service name from custom node names like "n8n-nodes-youtube-transcription-kasha.youtubeTranscripter"
|
||||||
|
parts = node_type.lower().split('.')
|
||||||
|
for part in parts:
|
||||||
|
if 'youtube' in part:
|
||||||
|
service_name = 'YouTube'
|
||||||
|
break
|
||||||
|
elif 'telegram' in part:
|
||||||
|
service_name = 'Telegram'
|
||||||
|
break
|
||||||
|
elif 'discord' in part:
|
||||||
|
service_name = 'Discord'
|
||||||
|
break
|
||||||
|
|
||||||
|
# Also check node names for service hints
|
||||||
|
for service_key, service_value in service_mappings.items():
|
||||||
|
if service_key in node_name and service_value:
|
||||||
|
service_name = service_value
|
||||||
|
break
|
||||||
|
|
||||||
|
# Add to integrations if valid service found
|
||||||
|
if service_name and service_name not in ['None', None]:
|
||||||
|
integrations.add(service_name)
|
||||||
|
|
||||||
# Determine if complex based on node variety and count
|
# Determine if complex based on node variety and count
|
||||||
if len(nodes) > 10 and len(integrations) > 3:
|
if len(nodes) > 10 and len(integrations) > 3:
|
||||||
@@ -445,6 +640,76 @@ class WorkflowDatabase:
|
|||||||
'last_indexed': datetime.datetime.now().isoformat()
|
'last_indexed': datetime.datetime.now().isoformat()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def get_service_categories(self) -> Dict[str, List[str]]:
|
||||||
|
"""Get service categories for enhanced filtering."""
|
||||||
|
return {
|
||||||
|
'messaging': ['Telegram', 'Discord', 'Slack', 'WhatsApp', 'Mattermost', 'Microsoft Teams', 'Rocket.Chat'],
|
||||||
|
'email': ['Gmail', 'Mailjet', 'Email (IMAP)', 'Email (SMTP)', 'Outlook'],
|
||||||
|
'cloud_storage': ['Google Drive', 'Google Docs', 'Google Sheets', 'Dropbox', 'OneDrive', 'Box'],
|
||||||
|
'database': ['PostgreSQL', 'MySQL', 'MongoDB', 'Redis', 'Airtable', 'Notion'],
|
||||||
|
'project_management': ['Jira', 'GitHub', 'GitLab', 'Trello', 'Asana', 'Monday.com'],
|
||||||
|
'ai_ml': ['OpenAI', 'Anthropic', 'Hugging Face'],
|
||||||
|
'social_media': ['LinkedIn', 'Twitter/X', 'Facebook', 'Instagram'],
|
||||||
|
'ecommerce': ['Shopify', 'Stripe', 'PayPal'],
|
||||||
|
'analytics': ['Google Analytics', 'Mixpanel'],
|
||||||
|
'calendar_tasks': ['Google Calendar', 'Google Tasks', 'Cal.com', 'Calendly'],
|
||||||
|
'forms': ['Typeform', 'Google Forms', 'Form Trigger'],
|
||||||
|
'development': ['Webhook', 'HTTP Request', 'GraphQL', 'Server-Sent Events', 'YouTube']
|
||||||
|
}
|
||||||
|
|
||||||
|
def search_by_category(self, category: str, limit: int = 50, offset: int = 0) -> Tuple[List[Dict], int]:
|
||||||
|
"""Search workflows by service category."""
|
||||||
|
categories = self.get_service_categories()
|
||||||
|
if category not in categories:
|
||||||
|
return [], 0
|
||||||
|
|
||||||
|
services = categories[category]
|
||||||
|
conn = sqlite3.connect(self.db_path)
|
||||||
|
conn.row_factory = sqlite3.Row
|
||||||
|
|
||||||
|
# Build OR conditions for all services in category
|
||||||
|
service_conditions = []
|
||||||
|
params = []
|
||||||
|
for service in services:
|
||||||
|
service_conditions.append("integrations LIKE ?")
|
||||||
|
params.append(f'%"{service}"%')
|
||||||
|
|
||||||
|
where_clause = " OR ".join(service_conditions)
|
||||||
|
|
||||||
|
# Count total results
|
||||||
|
count_query = f"SELECT COUNT(*) as total FROM workflows WHERE {where_clause}"
|
||||||
|
cursor = conn.execute(count_query, params)
|
||||||
|
total = cursor.fetchone()['total']
|
||||||
|
|
||||||
|
# Get paginated results
|
||||||
|
query = f"""
|
||||||
|
SELECT * FROM workflows
|
||||||
|
WHERE {where_clause}
|
||||||
|
ORDER BY analyzed_at DESC
|
||||||
|
LIMIT {limit} OFFSET {offset}
|
||||||
|
"""
|
||||||
|
|
||||||
|
cursor = conn.execute(query, params)
|
||||||
|
rows = cursor.fetchall()
|
||||||
|
|
||||||
|
# Convert to dictionaries and parse JSON fields
|
||||||
|
results = []
|
||||||
|
for row in rows:
|
||||||
|
workflow = dict(row)
|
||||||
|
workflow['integrations'] = json.loads(workflow['integrations'] or '[]')
|
||||||
|
raw_tags = json.loads(workflow['tags'] or '[]')
|
||||||
|
clean_tags = []
|
||||||
|
for tag in raw_tags:
|
||||||
|
if isinstance(tag, dict):
|
||||||
|
clean_tags.append(tag.get('name', str(tag.get('id', 'tag'))))
|
||||||
|
else:
|
||||||
|
clean_tags.append(str(tag))
|
||||||
|
workflow['tags'] = clean_tags
|
||||||
|
results.append(workflow)
|
||||||
|
|
||||||
|
conn.close()
|
||||||
|
return results, total
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
"""Command-line interface for workflow database."""
|
"""Command-line interface for workflow database."""
|
||||||
|
|||||||
BIN
workflows.db
BIN
workflows.db
Binary file not shown.
Reference in New Issue
Block a user