Compact UI: condensed plan, collapsible code, minimal results
Browse filesChanges:
- Plan: Show only overview + files list (not full implementation details)
- Code: Collapsible sections with <details> tags, shows line count
- Results: Compact table with cost inline in header
New output format:
## Plan Summary
[1-2 sentence overview]
Files: file1.py, file2.md
## Generated Code
βΆ file1.py (15 lines) - Click to expand
βΆ file2.md (20 lines) - Click to expand
## β
Success | Cost: $0.08
| Step | Status |
|------|--------|
| Plan | β
|
| Code | β
2 files |
| Review | β
Approved |
- Dockerfile +1 -1
- chainlit_app.py +79 -34
Dockerfile
CHANGED
|
@@ -1,5 +1,5 @@
|
|
| 1 |
# HuggingFace Spaces Dockerfile for CodePilot
|
| 2 |
-
# BUILD_VERSION:
|
| 3 |
FROM python:3.11-slim
|
| 4 |
|
| 5 |
# Set working directory
|
|
|
|
| 1 |
# HuggingFace Spaces Dockerfile for CodePilot
|
| 2 |
+
# BUILD_VERSION: 20 (v3.5.0 compact-ui - condensed plan, collapsible code, compact results)
|
| 3 |
FROM python:3.11-slim
|
| 4 |
|
| 5 |
# Set working directory
|
chainlit_app.py
CHANGED
|
@@ -22,8 +22,8 @@ from concurrent.futures import ThreadPoolExecutor
|
|
| 22 |
# ============================================================
|
| 23 |
# STARTUP VERSION CHECK - Change this to detect if rebuild worked
|
| 24 |
# ============================================================
|
| 25 |
-
APP_VERSION = "3.
|
| 26 |
-
BUILD_ID = "2024-12-20-
|
| 27 |
print("=" * 60)
|
| 28 |
print(f"[STARTUP] CodePilot Chainlit App")
|
| 29 |
print(f"[STARTUP] APP_VERSION: {APP_VERSION}")
|
|
@@ -76,7 +76,7 @@ def get_file_extension(file_path: str) -> str:
|
|
| 76 |
|
| 77 |
|
| 78 |
def format_code_output(code_changes: dict) -> str:
|
| 79 |
-
"""Format code changes as
|
| 80 |
if not code_changes:
|
| 81 |
return "No code changes."
|
| 82 |
|
|
@@ -85,12 +85,17 @@ def format_code_output(code_changes: dict) -> str:
|
|
| 85 |
# Get just the filename for display
|
| 86 |
filename = os.path.basename(file_path)
|
| 87 |
lang = get_file_extension(file_path)
|
|
|
|
| 88 |
|
| 89 |
-
|
| 90 |
-
output.append(f"
|
|
|
|
|
|
|
|
|
|
| 91 |
output.append(f"```{lang}")
|
| 92 |
output.append(content)
|
| 93 |
output.append("```")
|
|
|
|
| 94 |
output.append("")
|
| 95 |
|
| 96 |
return "\n".join(output)
|
|
@@ -184,56 +189,96 @@ def format_progress_display(status: dict, total_cost: float) -> str:
|
|
| 184 |
|
| 185 |
|
| 186 |
def format_final_result(result: dict, total_cost: float) -> str:
|
| 187 |
-
"""Format the final result with test table
|
| 188 |
lines = []
|
| 189 |
|
| 190 |
-
# Status header
|
| 191 |
success = result.get('success', False)
|
| 192 |
status_icon = "β
" if success else "β"
|
| 193 |
-
lines.append(f"##
|
| 194 |
|
| 195 |
-
#
|
| 196 |
-
lines.append("
|
| 197 |
-
lines.append("
|
| 198 |
-
lines.append("|-------|--------|")
|
| 199 |
|
| 200 |
-
|
| 201 |
-
|
| 202 |
-
else:
|
| 203 |
-
lines.append("| Plan Created | β Fail |")
|
| 204 |
|
|
|
|
| 205 |
if result.get('code_changes'):
|
| 206 |
-
lines.append(f"| Code
|
| 207 |
else:
|
| 208 |
-
lines.append("| Code
|
| 209 |
|
|
|
|
| 210 |
if result.get('review_feedback'):
|
| 211 |
-
if success
|
| 212 |
-
lines.append("| Code Review | β
Approved |")
|
| 213 |
-
else:
|
| 214 |
-
lines.append("| Code Review | β Rejected |")
|
| 215 |
else:
|
| 216 |
-
lines.append("|
|
| 217 |
-
|
| 218 |
-
lines.append("")
|
| 219 |
-
|
| 220 |
-
# Cost summary
|
| 221 |
-
lines.append("### Cost Summary\n")
|
| 222 |
-
lines.append(f"**Total Cost:** ${total_cost:.4f}")
|
| 223 |
-
lines.append(f"**Iterations:** {result.get('iterations', 'N/A')}")
|
| 224 |
|
| 225 |
return "\n".join(lines)
|
| 226 |
|
| 227 |
|
| 228 |
def format_plan_display(plan: str) -> str:
|
| 229 |
-
"""Format the implementation plan
|
| 230 |
if not plan:
|
| 231 |
return ""
|
| 232 |
|
| 233 |
-
lines = ["##
|
| 234 |
-
|
| 235 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 236 |
|
|
|
|
| 237 |
return "\n".join(lines)
|
| 238 |
|
| 239 |
|
|
|
|
| 22 |
# ============================================================
|
| 23 |
# STARTUP VERSION CHECK - Change this to detect if rebuild worked
|
| 24 |
# ============================================================
|
| 25 |
+
APP_VERSION = "3.5.0-compact-ui"
|
| 26 |
+
BUILD_ID = "2024-12-20-v4"
|
| 27 |
print("=" * 60)
|
| 28 |
print(f"[STARTUP] CodePilot Chainlit App")
|
| 29 |
print(f"[STARTUP] APP_VERSION: {APP_VERSION}")
|
|
|
|
| 76 |
|
| 77 |
|
| 78 |
def format_code_output(code_changes: dict) -> str:
|
| 79 |
+
"""Format code changes as collapsible markdown code blocks."""
|
| 80 |
if not code_changes:
|
| 81 |
return "No code changes."
|
| 82 |
|
|
|
|
| 85 |
# Get just the filename for display
|
| 86 |
filename = os.path.basename(file_path)
|
| 87 |
lang = get_file_extension(file_path)
|
| 88 |
+
line_count = len(content.split('\n'))
|
| 89 |
|
| 90 |
+
# Use collapsible details/summary
|
| 91 |
+
output.append(f"<details>")
|
| 92 |
+
output.append(f"<summary><strong>{filename}</strong> ({line_count} lines) - Click to expand</summary>")
|
| 93 |
+
output.append(f"")
|
| 94 |
+
output.append(f"**Path:** `{file_path}`")
|
| 95 |
output.append(f"```{lang}")
|
| 96 |
output.append(content)
|
| 97 |
output.append("```")
|
| 98 |
+
output.append(f"</details>")
|
| 99 |
output.append("")
|
| 100 |
|
| 101 |
return "\n".join(output)
|
|
|
|
| 189 |
|
| 190 |
|
| 191 |
def format_final_result(result: dict, total_cost: float) -> str:
|
| 192 |
+
"""Format the final result with compact test table."""
|
| 193 |
lines = []
|
| 194 |
|
| 195 |
+
# Status header with cost inline
|
| 196 |
success = result.get('success', False)
|
| 197 |
status_icon = "β
" if success else "β"
|
| 198 |
+
lines.append(f"## {status_icon} {'Success' if success else 'Failed'} | Cost: ${total_cost:.4f}\n")
|
| 199 |
|
| 200 |
+
# Compact results table
|
| 201 |
+
lines.append("| Step | Status |")
|
| 202 |
+
lines.append("|------|--------|")
|
|
|
|
| 203 |
|
| 204 |
+
# Plan
|
| 205 |
+
lines.append(f"| Plan | {'β
' if result.get('plan') else 'β'} |")
|
|
|
|
|
|
|
| 206 |
|
| 207 |
+
# Code
|
| 208 |
if result.get('code_changes'):
|
| 209 |
+
lines.append(f"| Code | β
{len(result['code_changes'])} files |")
|
| 210 |
else:
|
| 211 |
+
lines.append("| Code | β |")
|
| 212 |
|
| 213 |
+
# Review
|
| 214 |
if result.get('review_feedback'):
|
| 215 |
+
lines.append(f"| Review | {'β
Approved' if success else 'β Rejected'} |")
|
|
|
|
|
|
|
|
|
|
| 216 |
else:
|
| 217 |
+
lines.append("| Review | β¬ |")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 218 |
|
| 219 |
return "\n".join(lines)
|
| 220 |
|
| 221 |
|
| 222 |
def format_plan_display(plan: str) -> str:
|
| 223 |
+
"""Format a condensed version of the implementation plan."""
|
| 224 |
if not plan:
|
| 225 |
return ""
|
| 226 |
|
| 227 |
+
lines = ["## Plan Summary\n"]
|
| 228 |
+
|
| 229 |
+
# Extract just the overview and files from the plan
|
| 230 |
+
plan_lines = plan.split('\n')
|
| 231 |
+
in_overview = False
|
| 232 |
+
in_files = False
|
| 233 |
+
overview_text = []
|
| 234 |
+
files_list = []
|
| 235 |
+
|
| 236 |
+
for line in plan_lines:
|
| 237 |
+
line_lower = line.lower().strip()
|
| 238 |
+
|
| 239 |
+
# Detect sections
|
| 240 |
+
if 'overview' in line_lower and ('#' in line or line_lower.startswith('overview')):
|
| 241 |
+
in_overview = True
|
| 242 |
+
in_files = False
|
| 243 |
+
continue
|
| 244 |
+
elif 'files to' in line_lower or 'files:' in line_lower:
|
| 245 |
+
in_overview = False
|
| 246 |
+
in_files = True
|
| 247 |
+
continue
|
| 248 |
+
elif line.startswith('#') or line.startswith('==='):
|
| 249 |
+
in_overview = False
|
| 250 |
+
in_files = False
|
| 251 |
+
continue
|
| 252 |
+
|
| 253 |
+
# Collect content
|
| 254 |
+
if in_overview and line.strip():
|
| 255 |
+
overview_text.append(line.strip())
|
| 256 |
+
elif in_files and line.strip():
|
| 257 |
+
# Extract file paths or names
|
| 258 |
+
if '/' in line or '.py' in line or '.md' in line or '.html' in line:
|
| 259 |
+
# Clean up the line to get just the filename
|
| 260 |
+
clean_line = line.strip().lstrip('-').lstrip('*').lstrip('1234567890.').strip()
|
| 261 |
+
if clean_line:
|
| 262 |
+
files_list.append(clean_line)
|
| 263 |
+
|
| 264 |
+
# Build condensed output
|
| 265 |
+
if overview_text:
|
| 266 |
+
lines.append(' '.join(overview_text[:2])) # First 2 sentences max
|
| 267 |
+
lines.append("")
|
| 268 |
+
|
| 269 |
+
if files_list:
|
| 270 |
+
lines.append("**Files to create/modify:**")
|
| 271 |
+
for f in files_list[:5]: # Max 5 files
|
| 272 |
+
# Extract just filename from path
|
| 273 |
+
filename = os.path.basename(f.split()[0]) if f else f
|
| 274 |
+
lines.append(f"- `{filename}`")
|
| 275 |
+
if len(files_list) > 5:
|
| 276 |
+
lines.append(f"- ... and {len(files_list) - 5} more")
|
| 277 |
+
else:
|
| 278 |
+
# Fallback: just show first 3 lines of plan
|
| 279 |
+
lines.append(plan_lines[0] if plan_lines else "Plan created.")
|
| 280 |
|
| 281 |
+
lines.append("")
|
| 282 |
return "\n".join(lines)
|
| 283 |
|
| 284 |
|