File size: 5,585 Bytes
504df0f
d8acd61
504df0f
 
 
 
 
 
2ae57cb
 
 
d8acd61
504df0f
 
 
 
 
d8acd61
 
 
 
 
 
 
 
2ae57cb
d8acd61
 
 
 
 
504df0f
d8acd61
504df0f
d8acd61
504df0f
d8acd61
504df0f
 
d8acd61
504df0f
d8acd61
 
 
 
 
 
 
2ae57cb
d8acd61
 
 
 
2ae57cb
d8acd61
 
 
 
 
 
 
 
 
 
 
 
504df0f
d8acd61
 
 
 
504df0f
d8acd61
 
504df0f
d8acd61
 
 
 
504df0f
 
2ae57cb
504df0f
 
 
 
 
2ae57cb
504df0f
 
 
 
 
2ae57cb
504df0f
 
 
 
 
2ae57cb
504df0f
d8acd61
504df0f
 
 
2ae57cb
 
 
d8acd61
2ae57cb
 
 
d8acd61
504df0f
 
2ae57cb
 
 
 
504df0f
 
 
 
 
 
 
 
2ae57cb
 
 
 
 
 
 
 
 
 
504df0f
 
 
2ae57cb
d8acd61
 
504df0f
d8acd61
 
 
504df0f
d8acd61
 
 
 
 
 
 
 
 
2ae57cb
 
 
d8acd61
 
504df0f
2ae57cb
 
 
 
 
 
 
 
 
 
 
 
504df0f
 
 
 
d8acd61
 
2ae57cb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
from flask import Flask, render_template, redirect, url_for, flash, request
from flask_login import LoginManager, login_required, current_user
from werkzeug.utils import secure_filename
import os
import sys
import json
from datetime import datetime

from backend.routes.interview_api import interview_api
app.register_blueprint(interview_api, url_prefix="/api")

# Adjust sys.path for import flexibility
current_dir = os.path.dirname(os.path.abspath(__file__))
parent_dir = os.path.dirname(current_dir)
sys.path.append(parent_dir)
sys.path.append(current_dir)

# Initialize Flask app
app = Flask(__name__)
app.config['SECRET_KEY'] = 'your-secret-key'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///codingo.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

# Import and initialize DB
from backend.models.database import db, Job, Application, init_db

init_db(app)

# Import models/routes AFTER initializing the DB
from backend.models.user import User
from backend.routes.auth import auth_bp

# Import other modules
try:
    from backend.form.JobApplicationForm import JobApplicationForm
except ImportError:
    from form.JobApplicationForm import JobApplicationForm

try:
    from backend.models.resume_parser.resume_to_features import extract_resume_features
except ImportError:
    from models.resume_parser.resume_to_features import extract_resume_features

# Flask-Login setup
login_manager = LoginManager()
login_manager.login_view = 'auth.login'
login_manager.init_app(app)


@login_manager.user_loader
def load_user(user_id):
    return db.session.get(User, int(user_id))


# Register auth blueprint
app.register_blueprint(auth_bp)


def handle_resume_upload(file):
    """
    Save uploaded file temporarily, extract features, then clean up.
    Returns (features_dict, error_message, filename)
    """
    if not file or file.filename == '':
        return None, "No file uploaded", None

    try:
        filename = secure_filename(file.filename)
        filepath = os.path.join(current_dir, 'temp', filename)
        os.makedirs(os.path.dirname(filepath), exist_ok=True)
        file.save(filepath)

        features = extract_resume_features(filepath)
        os.remove(filepath)  # Clean up after parsing

        return features, None, filename
    except Exception as e:
        print(f"Error in handle_resume_upload: {e}")
        return None, str(e), None



# Routes
@app.route('/')
def index():
    return render_template('index.html')


@app.route('/jobs')
def jobs():
    all_jobs = Job.query.order_by(Job.date_posted.desc()).all()
    return render_template('jobs.html', jobs=all_jobs)


@app.route('/job/<int:job_id>')
def job_detail(job_id):
    job = Job.query.get_or_404(job_id)
    return render_template('job_detail.html', job=job)


@app.route('/apply/<int:job_id>', methods=['GET', 'POST'])
@login_required
def apply(job_id):
    job = Job.query.get_or_404(job_id)

    if request.method == 'POST':
        file = request.files.get('resume')
        features, error, _ = handle_resume_upload(file)

        if error or not features:
            flash("Resume parsing failed. Please try again.", "danger")
            return render_template('apply.html', job=job)

        application = Application(
            job_id=job_id,
            user_id=current_user.id,
            name=current_user.username,
            email=current_user.email,
            extracted_features=json.dumps(features)
        )

        db.session.add(application)
        db.session.commit()

        flash('Your application has been submitted successfully!', 'success')
        return redirect(url_for('jobs'))

    return render_template('apply.html', job=job)


@app.route('/my_applications')
@login_required
def my_applications():
    """View user's applications"""
    applications = Application.query.filter_by(user_id=current_user.id).order_by(Application.date_applied.desc()).all()
    return render_template('my_applications.html', applications=applications)


@app.route('/parse_resume', methods=['POST'])
def parse_resume():
    """API endpoint for parsing resume and returning features"""
    file = request.files.get('resume')
    features, error, _ = handle_resume_upload(file)

    if error:
        print(f"[Resume Error] {error}")
        return {"error": "Error parsing resume. Please try again."}, 400

    if not features:
        print("[Resume Error] No features extracted.")
        return {"error": "Failed to extract resume details."}, 400

    response = {
        "name": features.get('name', ''),
        "email": features.get('email', ''),
        "mobile_number": features.get('mobile_number', ''),
        "skills": features.get('skills', []),
        "experience": features.get('experience', []),
        "education": features.get('education', []),
        "summary": features.get('summary', '')
    }
    return response, 200

@app.route("/interview/<int:job_id>")
@login_required
def interview_page(job_id):
    job = Job.query.get_or_404(job_id)
    application = Application.query.filter_by(user_id=current_user.id, job_id=job_id).first()

    if not application or not application.extracted_features:
        flash("Please apply for this job and upload your resume first.", "warning")
        return redirect(url_for('job_detail', job_id=job_id))

    cv_data = json.loads(application.extracted_features)
    return render_template("interview.html", job=job, cv=cv_data)


if __name__ == '__main__':
    print("Starting Codingo application...")
    with app.app_context():
        db.create_all()
    app.run(debug=True, port=5001)