Spaces:
Sleeping
Sleeping
| """ | |
| Context Builder: assembles compact, high-signal repository context for IBM Bob. | |
| """ | |
| from __future__ import annotations | |
| import re | |
| MAX_CONTEXT_CHARS = 6000 | |
| def build_architecture_context(repo_data: dict) -> str: | |
| structure = repo_data["structure"] | |
| technologies = repo_data["technologies"] | |
| file_contents = repo_data.get("file_contents", {}) | |
| important_files = _get_important_files(file_contents) | |
| ctx = f"""REPOSITORY: {repo_data['github_url']} | |
| TOTAL FILES: {structure['total_files']} | TOTAL LINES: {structure['total_lines']} | |
| LANGUAGES: {[l['name'] for l in technologies.get('languages', [])[:5]]} | |
| FRAMEWORKS: {technologies.get('frameworks', [])} | |
| DATABASES: {technologies.get('databases', [])} | |
| DEVOPS: {technologies.get('devops', [])} | |
| API STYLE: {technologies.get('apis', [])} | |
| FILE TREE (key files): | |
| {_format_file_tree(_rank_files(structure['files'])[:100])} | |
| KEY FILE CONTENTS: | |
| {important_files}""" | |
| return ctx[:MAX_CONTEXT_CHARS] | |
| def build_qa_context(repo_data: dict, question: str) -> str: | |
| file_contents = repo_data.get("file_contents", {}) | |
| technologies = repo_data["technologies"] | |
| relevant_files = _find_relevant_files(file_contents, question) | |
| ctx = f"""TECH STACK: {technologies.get('frameworks', [])} | {technologies.get('databases', [])} | |
| LANGUAGES: {[l['name'] for l in technologies.get('languages', [])[:3]]} | |
| RELEVANT CODE CONTEXT: | |
| {relevant_files}""" | |
| return ctx[:MAX_CONTEXT_CHARS] | |
| def build_impact_context(repo_data: dict, target_file: str) -> str: | |
| file_contents = repo_data.get("file_contents", {}) | |
| structure = repo_data["structure"] | |
| target_content = file_contents.get(target_file, "File content not available") | |
| importers = _find_importers(file_contents, target_file) | |
| ctx = f"""REPOSITORY STATS: {structure['total_files']} files | |
| TARGET FILE: {target_file} | |
| TARGET FILE CONTENT: | |
| ``` | |
| {target_content[:2500]} | |
| ``` | |
| FILES THAT IMPORT/USE THIS: | |
| {importers[:2200]} | |
| ALL FILES IN REPO: | |
| {_format_file_tree(_rank_files(structure['files'])[:80])}""" | |
| return ctx[:MAX_CONTEXT_CHARS] | |
| def build_docs_context(repo_data: dict) -> str: | |
| """Build a compact docs context so live Bob generation returns quickly.""" | |
| structure = repo_data["structure"] | |
| technologies = repo_data["technologies"] | |
| deps = repo_data.get("dependencies", {}) | |
| ranked_files = _rank_files(structure["files"]) | |
| ctx = f"""REPOSITORY: {repo_data['github_url']} | |
| TOTAL FILES: {structure['total_files']} | TOTAL LINES: {structure['total_lines']} | |
| LANGUAGES: {[l['name'] for l in technologies.get('languages', [])[:5]]} | |
| FRAMEWORKS: {technologies.get('frameworks', [])} | |
| DATABASES: {technologies.get('databases', [])} | |
| DEVOPS: {technologies.get('devops', [])} | |
| API STYLE: {technologies.get('apis', [])} | |
| IMPORTANT FILES: | |
| {_format_file_tree(ranked_files[:55])} | |
| DEPENDENCIES: | |
| NPM: {deps.get('npm', [])[:20]} | |
| PIP: {deps.get('pip', [])[:20]} | |
| GO: {deps.get('go', [])[:12]} | |
| CARGO: {deps.get('cargo', [])[:12]}""" | |
| return ctx[:3500] | |
| def _rank_files(files: list[dict]) -> list[dict]: | |
| important_tokens = ("main", "app", "server", "router", "route", "model", "schema", "auth", "security", "config", "package", "requirements") | |
| def score(file_info: dict) -> tuple[int, int]: | |
| path = file_info.get("path", "").lower() | |
| token_score = sum(5 for token in important_tokens if token in path) | |
| depth_score = max(0, 4 - path.count("/")) | |
| return (token_score + depth_score, -len(path)) | |
| return sorted(files, key=score, reverse=True) | |
| def _get_important_files(file_contents: dict) -> str: | |
| priority_patterns = [ | |
| "main.py", | |
| "app.py", | |
| "index.js", | |
| "server.js", | |
| "app.js", | |
| "main.ts", | |
| "main.jsx", | |
| "index.ts", | |
| "package.json", | |
| "requirements.txt", | |
| "App.jsx", | |
| "App.tsx", | |
| "routes.py", | |
| "models.py", | |
| "schema.prisma", | |
| "pyproject.toml", | |
| ] | |
| result = "" | |
| for name in priority_patterns: | |
| for path, content in file_contents.items(): | |
| if path.endswith(name) and len(result) < 3600: | |
| result += f"\n--- {path} ---\n{content[:700]}\n" | |
| return result | |
| def _format_file_tree(files: list[dict]) -> str: | |
| return "\n".join(file_info.get("path", "") for file_info in files) | |
| def _find_relevant_files(file_contents: dict, question: str) -> str: | |
| keywords = [token for token in re.split(r"\W+", question.lower()) if len(token) >= 3] | |
| scored = [] | |
| for path, content in file_contents.items(): | |
| combined = f"{path}\n{content}".lower() | |
| score = sum(1 for keyword in keywords if keyword in combined) | |
| if score: | |
| scored.append((score, path, content)) | |
| scored.sort(key=lambda item: (item[0], -len(item[1])), reverse=True) | |
| result = "" | |
| for _, path, content in scored[:5]: | |
| result += f"\n--- {path} ---\n{content[:800]}\n" | |
| return result or _get_important_files(file_contents) | |
| def _find_importers(file_contents: dict, target_file: str) -> str: | |
| filename = target_file.split("/")[-1] | |
| stem = filename.rsplit(".", 1)[0] | |
| module_guess = target_file.rsplit(".", 1)[0].replace("/", ".") | |
| result = "" | |
| for path, content in file_contents.items(): | |
| if path == target_file: | |
| continue | |
| if target_file in content or filename in content or stem in content or module_guess in content: | |
| result += f"\n--- {path} (references target) ---\n{content[:450]}\n" | |
| return result or "No direct textual importers found in scanned content." | |