diff --git a/app.py b/app.py index a76c2d5..fb4a44e 100644 --- a/app.py +++ b/app.py @@ -10,9 +10,12 @@ # Business logic, recommendation scoring, and data loading all live in # the utils/ and routes/ packages, not here. +import os + from flask import Flask, render_template from routes.main_routes import main + app = Flask(__name__) # Register all routes defined in the main Blueprint diff --git a/data/projects.json b/data/projects.json index a0ac29e..04c1f82 100644 --- a/data/projects.json +++ b/data/projects.json @@ -461,3 +461,5 @@ + + diff --git a/routes/main_routes.py b/routes/main_routes.py index 658553e..22ed450 100644 --- a/routes/main_routes.py +++ b/routes/main_routes.py @@ -3,12 +3,19 @@ # Each route is kept thin: it validates input, calls a utility function, # and returns a response. No business logic lives here. -from flask import Blueprint, render_template, request, jsonify, send_from_directory, abort, make_response +import json + +from flask import Blueprint, render_template, request, jsonify, send_from_directory, abort from utils.recommender import get_recommendations, validate_recommendation_inputs from utils.data_loader import find_project_by_id, load_all_projects, get_project_stats from utils.file_server import read_starter_code, resolve_starter_file, get_starter_code_dir import os +from groq import Groq +from dotenv import load_dotenv + +load_dotenv() +groq_client = Groq(api_key=os.environ["GROQ_API_KEY"]) # Interest categories that currently have no project recommendations available NO_PROJECT_INTERESTS = { @@ -44,52 +51,52 @@ def health_check(): }), 200 + @main.route("/api/recommend", methods=["POST"]) def recommend(): - """ - Accept a JSON body with user inputs and return matching project recommendations. - - Expected JSON fields: - skills (str) - comma-separated list of skills - level (str) - Beginner | Intermediate | Advanced - interest (str) - Web | Data | Education | Automation | Games - time (str) - Low | Medium | High - """ - payload = request.get_json() - - if not payload: - return jsonify({"error": "Request body must be valid JSON."}), 400 - - skills = payload.get("skills", "").strip() - level = payload.get("level", "").strip() - interest = payload.get("interest", "").strip() - time_availability = payload.get("time", "").strip() - - # Validate before running the recommendation engine - errors = validate_recommendation_inputs(skills, level, interest, time_availability) - if errors: - # Return only the first error to keep the UI message clean - return jsonify({"error": errors[0]}), 400 - - if interest_has_no_projects(interest): + try: + data = request.json or {} + skills = data.get("skills", "") + level = data.get("level", "") + interest = data.get("interest", "") + time = data.get("time", "") + + prompt = f"""Generate 3 UNIQUE coding projects. +Return ONLY a raw JSON array like this: +[ + {{ + "id": 1, + "title": "Project name", + "description": "What it does", + "skills": ["skill1", "skill2"], + "level": "{level}", + "time": "{time}" + }} +] + +Skills: {skills} +Level: {level} +Interest: {interest} +Time: {time}""" + + response = groq_client.chat.completions.create( + model="llama-3.3-70b-versatile", # ye use karo + messages=[{"role": "user", "content": prompt}] + ) + raw = response.choices[0].message.content.strip() + raw = raw.replace("```json", "").replace("```", "").strip() + projects = json.loads(raw) + + return jsonify({"projects": projects, "source": "ai"}) + + except Exception as e: + results = get_recommendations(skills, level, interest, time) return jsonify({ - "projects": [], - "message": "No projects are currently available for this interest area. Please check back later." - }), 200 - - results = get_recommendations(skills, level, interest, time_availability) - - if not results: - return jsonify({ - "projects": [], - "message": ( - "No projects matched your inputs. " - "Try different skills or broaden your interest area." - ) - }), 200 - - return jsonify({"projects": results}), 200 - + "projects": results, + "source": "stored", + "error": str(e) + }) + @main.route("/project/") def project_detail(project_id): diff --git a/static/script.js b/static/script.js index f97e5a0..25abbf6 100644 --- a/static/script.js +++ b/static/script.js @@ -652,6 +652,11 @@ if (clearFiltersBtn) { link.href = "/project/" + project.id; //each project has a unique id footer.appendChild(link); + + +// Add starter code block +var codeBlock = document.createElement("pre"); +codeBlock.textContent = project.code || ""; // Assemble the card in order card.appendChild(title);