
# Create remaining utility and database modules

# 15. database/db_manager.py
files_content['database/db_manager.py'] = """\"\"\"Database manager for tracking applications\"\"\"

import sqlite3
import json
from datetime import datetime
from pathlib import Path
from utils.logger import get_logger

class DatabaseManager:
    \"\"\"Manages job and application databases\"\"\"
    
    def __init__(self, db_path='data/jobs.db'):
        self.db_path = db_path
        self.logger = get_logger(__name__)
        self._init_database()
    
    def _init_database(self):
        \"\"\"Initialize database schema\"\"\"
        Path(self.db_path).parent.mkdir(parents=True, exist_ok=True)
        
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        
        # Create jobs table
        cursor.execute('''
            CREATE TABLE IF NOT EXISTS jobs (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                title TEXT NOT NULL,
                company TEXT NOT NULL,
                location TEXT,
                url TEXT UNIQUE NOT NULL,
                platform TEXT NOT NULL,
                scraped_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
            )
        ''')
        
        # Create applications table
        cursor.execute('''
            CREATE TABLE IF NOT EXISTS applications (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                job_id INTEGER,
                job_url TEXT NOT NULL,
                status TEXT DEFAULT 'applied',
                applied_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                notes TEXT,
                FOREIGN KEY (job_id) REFERENCES jobs (id)
            )
        ''')
        
        conn.commit()
        conn.close()
        self.logger.info("Database initialized")
    
    def save_job(self, job_data):
        \"\"\"Save job to database\"\"\"
        try:
            conn = sqlite3.connect(self.db_path)
            cursor = conn.cursor()
            
            cursor.execute('''
                INSERT OR IGNORE INTO jobs (title, company, location, url, platform)
                VALUES (?, ?, ?, ?, ?)
            ''', (
                job_data['title'],
                job_data['company'],
                job_data.get('location', ''),
                job_data['url'],
                job_data['platform']
            ))
            
            conn.commit()
            job_id = cursor.lastrowid
            conn.close()
            
            return job_id
            
        except Exception as e:
            self.logger.error(f"Failed to save job: {str(e)}")
            return None
    
    def record_application(self, job_data, notes=''):
        \"\"\"Record a job application\"\"\"
        try:
            # First save the job
            job_id = self.save_job(job_data)
            
            # Then record application
            conn = sqlite3.connect(self.db_path)
            cursor = conn.cursor()
            
            cursor.execute('''
                INSERT INTO applications (job_id, job_url, notes)
                VALUES (?, ?, ?)
            ''', (job_id, job_data['url'], notes))
            
            conn.commit()
            conn.close()
            
            self.logger.info(f"Application recorded: {job_data['title']}")
            return True
            
        except Exception as e:
            self.logger.error(f"Failed to record application: {str(e)}")
            return False
    
    def is_already_applied(self, job_url):
        \"\"\"Check if already applied to this job\"\"\"
        try:
            conn = sqlite3.connect(self.db_path)
            cursor = conn.cursor()
            
            cursor.execute('SELECT COUNT(*) FROM applications WHERE job_url = ?', (job_url,))
            count = cursor.fetchone()[0]
            
            conn.close()
            return count > 0
            
        except Exception as e:
            self.logger.error(f"Database check failed: {str(e)}")
            return False
    
    def get_applications_count(self, days=1):
        \"\"\"Get count of applications in last N days\"\"\"
        try:
            conn = sqlite3.connect(self.db_path)
            cursor = conn.cursor()
            
            cursor.execute('''
                SELECT COUNT(*) FROM applications 
                WHERE applied_at >= datetime('now', '-' || ? || ' days')
            ''', (days,))
            
            count = cursor.fetchone()[0]
            conn.close()
            
            return count
            
        except Exception as e:
            self.logger.error(f"Failed to get applications count: {str(e)}")
            return 0
"""

# 16. utils/logger.py
files_content['utils/logger.py'] = """\"\"\"Logging configuration\"\"\"

import logging
import sys
from pathlib import Path
from colorama import Fore, Style

# Create logs directory
Path('data/logs').mkdir(parents=True, exist_ok=True)

class ColoredFormatter(logging.Formatter):
    \"\"\"Custom formatter with colors\"\"\"
    
    COLORS = {
        'DEBUG': Fore.CYAN,
        'INFO': Fore.GREEN,
        'WARNING': Fore.YELLOW,
        'ERROR': Fore.RED,
        'CRITICAL': Fore.RED + Style.BRIGHT
    }
    
    def format(self, record):
        color = self.COLORS.get(record.levelname, '')
        record.levelname = f"{color}{record.levelname}{Style.RESET_ALL}"
        return super().format(record)

def setup_logger(name='job_agent', level=logging.INFO):
    \"\"\"Setup application logger\"\"\"
    logger = logging.getLogger(name)
    logger.setLevel(level)
    
    # Console handler
    console_handler = logging.StreamHandler(sys.stdout)
    console_handler.setLevel(level)
    console_formatter = ColoredFormatter(
        '%(asctime)s - %(name)s - %(levelname)s - %(message)s',
        datefmt='%Y-%m-%d %H:%M:%S'
    )
    console_handler.setFormatter(console_formatter)
    
    # File handler
    file_handler = logging.FileHandler('data/logs/app.log')
    file_handler.setLevel(logging.DEBUG)
    file_formatter = logging.Formatter(
        '%(asctime)s - %(name)s - %(levelname)s - %(message)s',
        datefmt='%Y-%m-%d %H:%M:%S'
    )
    file_handler.setFormatter(file_formatter)
    
    # Add handlers
    logger.addHandler(console_handler)
    logger.addHandler(file_handler)
    
    return logger

def get_logger(name):
    \"\"\"Get logger instance\"\"\"
    return logging.getLogger(name)
"""

# 17. utils/helpers.py
files_content['utils/helpers.py'] = """\"\"\"Utility helper functions\"\"\"

import re
import time
from datetime import datetime

def clean_text(text):
    \"\"\"Clean and normalize text\"\"\"
    if not text:
        return ''
    text = re.sub(r'\\s+', ' ', text)
    return text.strip()

def extract_salary(text):
    \"\"\"Extract salary from text\"\"\"
    if not text:
        return None
    
    # Look for patterns like "10-15 LPA" or "₹10,00,000"
    patterns = [
        r'(\\d+)\\s*-\\s*(\\d+)\\s*LPA',
        r'₹\\s*(\\d+,?\\d*)',
        r'(\\d+)\\s*lakhs'
    ]
    
    for pattern in patterns:
        match = re.search(pattern, text, re.IGNORECASE)
        if match:
            return match.group(0)
    
    return None

def is_relevant_job(job_title, keywords):
    \"\"\"Check if job title matches keywords\"\"\"
    job_title_lower = job_title.lower()
    return any(keyword.lower() in job_title_lower for keyword in keywords)

def format_timestamp():
    \"\"\"Get formatted timestamp\"\"\"
    return datetime.now().strftime('%Y-%m-%d %H:%M:%S')

def wait_with_message(seconds, message="Waiting"):
    \"\"\"Wait with progress message\"\"\"
    print(f"{message}...", end='', flush=True)
    time.sleep(seconds)
    print(" Done!")
"""

# 18. README.md
files_content['README.md'] = """# AI Job Application Agent

An intelligent automation agent that automatically searches for job openings on multiple platforms and applies on your behalf.

## 🎯 Features

- **Multi-Platform Support**: LinkedIn, Naukri, Hirist, and Remote job boards
- **Intelligent Job Matching**: Filters jobs based on your preferences
- **Auto-Fill Applications**: Automatically fills application forms
- **AI-Powered Q&A**: Answers application questions intelligently (optional)
- **Application Tracking**: Maintains database of applied jobs
- **Duplicate Prevention**: Avoids applying to the same job twice
- **Stealth Mode**: Human-like behavior to avoid detection

## 📋 Supported Platforms

1. **LinkedIn** - Easy Apply jobs
2. **Naukri.com** - Instant Apply jobs
3. **Hirist.com** - Tech jobs
4. **Remote Job Boards** - Himalayas, Remotive, etc.

## 🚀 Installation

### Prerequisites

- Python 3.9 or higher
- Google Chrome browser
- ChromeDriver (automatically managed)

### Step 1: Clone or Download

```bash
# If you have the zip file, extract it
unzip AI_Job_Agent.zip
cd AI_Job_Agent
```

### Step 2: Create Virtual Environment (Recommended)

```bash
# Windows
python -m venv venv
venv\\Scripts\\activate

# Linux/Mac
python3 -m venv venv
source venv/bin/activate
```

### Step 3: Install Dependencies

```bash
pip install -r requirements.txt
```

### Step 4: Configure Environment Variables

```bash
# Copy the example env file
cp .env.example .env

# Edit .env file and add your credentials
# Use any text editor (notepad, vim, nano, etc.)
```

### Step 5: Configure Your Profile

```bash
# Edit config.yaml file with your details:
# - Personal information
# - Work experience
# - Skills
# - Job preferences
# - Resume path
```

## ⚙️ Configuration

### 1. User Profile (config.yaml)

Edit `config.yaml` and update:

- Personal details (name, email, phone)
- Work experience
- Skills
- Resume path
- Job preferences (titles, locations, salary)

### 2. Platform Credentials (.env)

Add your login credentials in `.env`:

```
LINKEDIN_EMAIL=your.email@example.com
LINKEDIN_PASSWORD=your_password

NAUKRI_EMAIL=your.email@example.com
NAUKRI_PASSWORD=your_password
```

### 3. AI Integration (Optional)

To enable AI-powered question answering:

1. Get API key from OpenAI or Google Gemini
2. Add to `.env`:
```
GEMINI_API_KEY=your_api_key
```
3. Enable in `config.yaml`:
```yaml
ai_settings:
  enabled: true
  provider: "gemini"
```

## 📖 Usage

### Basic Usage

Apply to jobs on all platforms:

```bash
python main.py
```

### Platform-Specific

Apply only on LinkedIn:

```bash
python main.py --platform linkedin
```

Apply on specific platform:

```bash
python main.py --platform naukri
python main.py --platform hirist
python main.py --platform remote
```

### Limit Applications

Apply to maximum 20 jobs:

```bash
python main.py --max-apps 20
```

### Dry Run (Test Mode)

Test without actually applying:

```bash
python main.py --dry-run
```

### Configure Profile Interactively

```bash
python main.py --config
```

## 📁 Project Structure

```
AI_Job_Agent/
├── main.py                 # Entry point
├── requirements.txt        # Dependencies
├── config.yaml            # Configuration
├── .env                   # Credentials (DO NOT SHARE)
├── README.md              # This file
├── config/
│   ├── settings.py        # Settings manager
│   ├── user_profile.py    # Profile configuration
│   └── qa_bank.py         # Question-answer bank
├── scrapers/
│   ├── base_scraper.py    # Base scraper class
│   ├── linkedin_scraper.py
│   ├── naukri_scraper.py
│   ├── hirist_scraper.py
│   └── remote_jobs_scraper.py
├── automation/
│   ├── form_filler.py     # Form auto-fill
│   ├── login_handler.py   # Login automation
│   └── application_submitter.py
├── ai/
│   ├── question_answerer.py  # AI Q&A
│   └── resume_tailor.py      # Resume customization
├── database/
│   ├── db_manager.py      # Database operations
│   └── models.py          # Data models
├── utils/
│   ├── logger.py          # Logging
│   └── helpers.py         # Utility functions
├── data/
│   ├── jobs.db            # SQLite database
│   └── logs/              # Log files
└── resumes/
    └── default_resume.pdf  # Your resume
```

## ⚠️ Important Considerations

### Legal & Ethical

1. **Terms of Service**: Using automation may violate platform ToS
2. **Rate Limiting**: Respect platform limits to avoid bans
3. **Accuracy**: Review auto-filled information for accuracy
4. **Authenticity**: Be prepared to discuss all applications

### Best Practices

1. **Start Slow**: Begin with 10-20 applications per day
2. **Review Settings**: Double-check configuration before running
3. **Monitor Logs**: Check `data/logs/app.log` for issues
4. **Update Resume**: Keep your resume current
5. **Customize Answers**: Review and update Q&A responses

### Security

1. **Never Share .env**: Keep credentials private
2. **Use Strong Passwords**: Secure your accounts
3. **Regular Updates**: Keep dependencies updated
4. **Secure Storage**: Protect database files

## 🛠️ Troubleshooting

### Issue: ChromeDriver Error

**Solution**: The package auto-downloads ChromeDriver, but if issues occur:
```bash
pip install --upgrade undetected-chromedriver
```

### Issue: Login Fails

**Solutions**:
1. Check credentials in `.env`
2. Disable 2-factor authentication temporarily
3. Try manual login first to verify
4. Check for CAPTCHA requirements

### Issue: No Jobs Found

**Solutions**:
1. Verify job search criteria in `config.yaml`
2. Broaden search locations or titles
3. Check platform availability
4. Review logs for errors

### Issue: Application Fails

**Solutions**:
1. Run in non-headless mode (`headless: false` in config)
2. Check screenshot in `data/screenshots/`
3. Review error logs
4. Slow down automation (increase delays)

## 📊 Viewing Results

### Check Applied Jobs

```bash
# View database
sqlite3 data/jobs.db "SELECT * FROM applications ORDER BY applied_at DESC LIMIT 10;"
```

### Application Statistics

```python
from database.db_manager import DatabaseManager

db = DatabaseManager()
count = db.get_applications_count(days=1)
print(f"Applications today: {count}")
```

## 🔄 Updates and Maintenance

### Update Dependencies

```bash
pip install --upgrade -r requirements.txt
```

### Backup Data

```bash
# Backup database
cp data/jobs.db data/jobs_backup_$(date +%Y%m%d).db
```

## 🤝 Support

For issues or questions:

1. Check troubleshooting section
2. Review logs in `data/logs/`
3. Check configuration files
4. Test with `--dry-run` flag

## ⚖️ Disclaimer

This tool is for educational purposes. Users are responsible for:

1. Complying with platform Terms of Service
2. Ensuring accuracy of applications
3. Following local employment laws
4. Maintaining professional conduct

The authors are not responsible for:
- Account suspensions
- Application rejections  
- Legal issues
- Data privacy violations

## 📝 License

This project is provided as-is for personal use only.

## 🎓 Learning Resources

- [Selenium Documentation](https://selenium-python.readthedocs.io/)
- [Web Scraping Best Practices](https://www.scraperapi.com/blog/web-scraping-best-practices/)
- [Job Search Strategies](https://www.linkedin.com/pulse/job-search-strategies-2024/)

---

**Version**: 1.0.0  
**Last Updated**: November 2025

**Happy Job Hunting! 🎯**
"""

print("Created database, utilities, and README")
print("Total files:", len(files_content))
