File size: 5,526 Bytes
ba72f62
 
 
 
 
 
 
504df0f
d8acd61
504df0f
 
 
 
 
 
d8acd61
504df0f
 
 
 
 
5d095b2
 
 
 
 
 
 
 
d8acd61
 
 
 
 
 
5d095b2
d8acd61
 
 
 
 
 
 
 
 
 
 
5d095b2
d8acd61
5d095b2
 
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
 
227e456
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
import os

# Ensure Hugging Face writes cache to a safe writable location on Spaces
os.environ["HF_HOME"] = "/tmp/huggingface"
os.environ["TRANSFORMERS_CACHE"] = "/tmp/huggingface/transformers"
os.environ["HUGGINGFACE_HUB_CACHE"] = "/tmp/huggingface/hub"

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

# 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)

# Import and initialize DB
from backend.models.database import db, Job, Application, init_db
from backend.models.user import User
from backend.routes.auth import auth_bp
from backend.routes.interview_api import interview_api
from backend.models.resume_parser.resume_to_features import extract_resume_features


# 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

# Initialize DB with app
init_db(app)

# 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 blueprints
app.register_blueprint(auth_bp)
app.register_blueprint(interview_api, url_prefix="/api")



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=7860)