Spaces:
Sleeping
Sleeping
| import gradio as gr | |
| import chromadb | |
| import os | |
| import uuid | |
| import time | |
| import requests | |
| from dotenv import load_dotenv | |
| # ================================================== | |
| # ENV SETUP | |
| # ================================================== | |
| load_dotenv() | |
| OPENROUTER_API_KEY = os.getenv("OPENROUTER_API_KEY") | |
| GITHUB_TOKEN = os.getenv("GITHUB_TOKEN") | |
| if not OPENROUTER_API_KEY: | |
| raise RuntimeError("β OPENROUTER_API_KEY not found in environment") | |
| # ================================================== | |
| # CHROMADB SETUP | |
| # ================================================== | |
| BASE_DIR = os.path.dirname(os.path.abspath(__file__)) | |
| DB_PATH = os.path.join(BASE_DIR, "roadmap_db") | |
| chroma_client = chromadb.PersistentClient(path=DB_PATH) | |
| collection = chroma_client.get_or_create_collection(name="project_roadmaps") | |
| print(f"β ChromaDB initialized at: {DB_PATH}") | |
| # ================================================== | |
| # OPENROUTER LLM (FREE MODEL) | |
| # ================================================== | |
| def generate_with_openrouter(prompt: str) -> str: | |
| url = "https://openrouter.ai/api/v1/chat/completions" | |
| headers = { | |
| "Authorization": f"Bearer {OPENROUTER_API_KEY}" | |
| } | |
| payload = { | |
| "model": "meta-llama/llama-3.3-70b-instruct:free", | |
| "messages": [ | |
| { | |
| "role": "system", | |
| "content": "You are an expert AI Tech Mentor and Career Analyst." | |
| }, | |
| { | |
| "role": "user", | |
| "content": prompt | |
| } | |
| ], | |
| "temperature": 0.7, | |
| "max_tokens": 1800 | |
| } | |
| response = requests.post(url, headers=headers, json=payload, timeout=60) | |
| if response.status_code != 200: | |
| return f"β OpenRouter Error {response.status_code}\n{response.text}" | |
| return response.json()["choices"][0]["message"]["content"] | |
| # ================================================== | |
| # GITHUB ANALYSIS | |
| # ================================================== | |
| def analyze_github_profile(url: str) -> str: | |
| if not url or "github.com" not in url: | |
| return "No valid GitHub URL provided." | |
| if not GITHUB_TOKEN: | |
| return "GitHub token not provided. Skipping GitHub analysis." | |
| try: | |
| username = url.rstrip("/").split("/")[-1] | |
| headers = { | |
| "Authorization": f"token {GITHUB_TOKEN}", | |
| "Accept": "application/vnd.github.v3+json" | |
| } | |
| api_url = f"https://api.github.com/users/{username}/repos?per_page=5&sort=updated" | |
| response = requests.get(api_url, headers=headers, timeout=20) | |
| if response.status_code != 200: | |
| return "Failed to fetch GitHub repositories." | |
| repos = response.json() | |
| languages = set() | |
| summaries = [] | |
| for repo in repos: | |
| lang = repo.get("language") | |
| if lang: | |
| languages.add(lang) | |
| summaries.append( | |
| f"- {repo['name']} ({lang}): {repo.get('description', 'No description')}" | |
| ) | |
| return ( | |
| f"GitHub User: {username}\n" | |
| f"Primary Languages: {', '.join(languages)}\n" | |
| f"Recent Repositories:\n" + "\n".join(summaries) | |
| ) | |
| except Exception as e: | |
| return f"GitHub analysis error: {str(e)}" | |
| # ================================================== | |
| # MARKET CONTEXT | |
| # ================================================== | |
| def get_market_context(goal: str) -> str: | |
| return ( | |
| f"The market for {goal} strongly favors scalable systems, " | |
| f"cloud-native deployment, automation, and real-world impact." | |
| ) | |
| # ================================================== | |
| # MAIN ROADMAP FUNCTION | |
| # ================================================== | |
| def generate_roadmap_endpoint(github_url, career_goal, preferred_stack): | |
| print("π₯ Received request for strategic roadmap") | |
| if not career_goal: | |
| return "β Career goal is required." | |
| cache_key = f"{career_goal}|{preferred_stack}" | |
| # ---- Cache lookup ---- | |
| try: | |
| cached = collection.query(query_texts=[cache_key], n_results=1) | |
| if cached["documents"] and cached["documents"][0]: | |
| if cached["distances"][0][0] < 0.2: | |
| print("β Loaded from cache") | |
| return "**[Loaded from Cache]**\n\n" + cached["documents"][0][0] | |
| except Exception: | |
| pass | |
| github_data = analyze_github_profile(github_url) | |
| market_context = get_market_context(career_goal) | |
| prompt = f""" | |
| Situation: | |
| You are an expert AI Tech Mentor. | |
| Rules: | |
| - Derive project scope strictly from the career goal | |
| - Prioritize preferred tech stack | |
| - Use GitHub info only for enhancement | |
| - Never suggest career or roadmap tools | |
| - Output plain text only | |
| GitHub Analysis: | |
| {github_data} | |
| Career Goal: | |
| {career_goal} | |
| Preferred Tech Stack: | |
| {preferred_stack if preferred_stack else "Not specified"} | |
| Market Context: | |
| {market_context} | |
| Output Format: | |
| Title: | |
| Project Scope: | |
| Existing Methodology: | |
| - Current Approach: | |
| - Limitations: | |
| Tech Stack: | |
| - Core Logic: | |
| - Infrastructure: | |
| - Testing / Deployment: | |
| Innovative Enhancements: | |
| - Technological Improvement: | |
| - Unique Value Proposition: | |
| Learning Roadmap: | |
| - Step 1: | |
| - Step 2: | |
| - Step 3: | |
| - Step 4: | |
| Enhancements Over Existing Methodology: | |
| - Enhancement 1 | |
| - Enhancement 2 | |
| - Enhancement 3 | |
| """ | |
| print("π€ Generating roadmap via OpenRouter (LLaMA 3.3 70B FREE)...") | |
| result_text = generate_with_openrouter(prompt) | |
| # ---- Save to cache ---- | |
| try: | |
| collection.add( | |
| documents=[result_text], | |
| metadatas=[{ | |
| "career_goal": career_goal, | |
| "stack": preferred_stack, | |
| "timestamp": str(time.time()) | |
| }], | |
| ids=[str(uuid.uuid4())] | |
| ) | |
| print("β Roadmap saved to ChromaDB") | |
| except Exception: | |
| pass | |
| return result_text | |
| # ================================================== | |
| # GRADIO UI | |
| # ================================================== | |
| with gr.Blocks(theme=gr.themes.Soft(primary_hue="cyan")) as demo: | |
| gr.Markdown( | |
| "# π AI Project Roadmap Generator\n" | |
| "Turn your career goal into a portfolio-ready project." | |
| ) | |
| github_input = gr.Textbox(label="GitHub Profile URL") | |
| career_input = gr.Textbox(label="Career Goal") | |
| stack_input = gr.Textbox(label="Preferred Tech Stack (optional)") | |
| submit_btn = gr.Button("Generate Roadmap", variant="primary") | |
| output = gr.Markdown() | |
| submit_btn.click( | |
| fn=generate_roadmap_endpoint, | |
| inputs=[github_input, career_input, stack_input], | |
| outputs=output | |
| ) | |
| if __name__ == "__main__": | |
| demo.launch(debug=True) | |