Skip to content

Commit dd27993

Browse files
CopilotMte90
andcommitted
Add project UI support and example client
Co-authored-by: Mte90 <403283+Mte90@users.noreply.github.com>
1 parent 831edd5 commit dd27993

File tree

4 files changed

+276
-1
lines changed

4 files changed

+276
-1
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,5 @@ codebase.*
44
picocode.egg-info
55
uv.lock
66
__pycache__
7+
# Per-project databases
8+
.picocode/

example_client.py

Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Example script demonstrating PicoCode API usage.
4+
This shows how to integrate PicoCode with a PyCharm plugin or other IDE.
5+
"""
6+
import requests
7+
import json
8+
import time
9+
from typing import Optional, Dict, Any
10+
11+
class PicoCodeClient:
12+
"""Client for interacting with PicoCode API."""
13+
14+
def __init__(self, base_url: str = "http://127.0.0.1:8000"):
15+
self.base_url = base_url
16+
self.api_base = f"{base_url}/api"
17+
18+
def health_check(self) -> Dict[str, Any]:
19+
"""Check if the server is running and healthy."""
20+
response = requests.get(f"{self.api_base}/health")
21+
response.raise_for_status()
22+
return response.json()
23+
24+
def create_project(self, path: str, name: Optional[str] = None) -> Dict[str, Any]:
25+
"""Create or get a project."""
26+
response = requests.post(
27+
f"{self.api_base}/projects",
28+
json={"path": path, "name": name}
29+
)
30+
response.raise_for_status()
31+
return response.json()
32+
33+
def list_projects(self) -> list:
34+
"""List all projects."""
35+
response = requests.get(f"{self.api_base}/projects")
36+
response.raise_for_status()
37+
return response.json()
38+
39+
def get_project(self, project_id: str) -> Dict[str, Any]:
40+
"""Get project details."""
41+
response = requests.get(f"{self.api_base}/projects/{project_id}")
42+
response.raise_for_status()
43+
return response.json()
44+
45+
def delete_project(self, project_id: str) -> Dict[str, Any]:
46+
"""Delete a project."""
47+
response = requests.delete(f"{self.api_base}/projects/{project_id}")
48+
response.raise_for_status()
49+
return response.json()
50+
51+
def index_project(self, project_id: str) -> Dict[str, Any]:
52+
"""Start indexing a project."""
53+
response = requests.post(
54+
f"{self.api_base}/projects/index",
55+
json={"project_id": project_id}
56+
)
57+
response.raise_for_status()
58+
return response.json()
59+
60+
def query(self, project_id: str, query: str, top_k: int = 5) -> Dict[str, Any]:
61+
"""Perform semantic search."""
62+
response = requests.post(
63+
f"{self.api_base}/query",
64+
json={
65+
"project_id": project_id,
66+
"query": query,
67+
"top_k": top_k
68+
}
69+
)
70+
response.raise_for_status()
71+
return response.json()
72+
73+
def get_code_suggestion(
74+
self,
75+
project_id: str,
76+
prompt: str,
77+
context: str = "",
78+
use_rag: bool = True,
79+
top_k: int = 5
80+
) -> Dict[str, Any]:
81+
"""Get code suggestions using RAG + LLM."""
82+
response = requests.post(
83+
f"{self.api_base}/code",
84+
json={
85+
"project_id": project_id,
86+
"prompt": prompt,
87+
"context": context,
88+
"use_rag": use_rag,
89+
"top_k": top_k
90+
}
91+
)
92+
response.raise_for_status()
93+
return response.json()
94+
95+
96+
def example_workflow():
97+
"""Example workflow for IDE integration."""
98+
client = PicoCodeClient()
99+
100+
print("=" * 60)
101+
print("PicoCode API Example Workflow")
102+
print("=" * 60)
103+
104+
# 1. Health check
105+
print("\n1. Checking server health...")
106+
try:
107+
health = client.health_check()
108+
print(f" ✓ Server is healthy: {health}")
109+
except Exception as e:
110+
print(f" ✗ Server is not running: {e}")
111+
print(" Please start the server with: python main.py")
112+
return
113+
114+
# 2. Create a project
115+
print("\n2. Creating/getting project...")
116+
project_path = "/tmp/example_project"
117+
try:
118+
project = client.create_project(project_path, "Example Project")
119+
project_id = project["id"]
120+
print(f" ✓ Project ID: {project_id}")
121+
print(f" ✓ Status: {project['status']}")
122+
except Exception as e:
123+
print(f" ✗ Failed to create project: {e}")
124+
return
125+
126+
# 3. List all projects
127+
print("\n3. Listing all projects...")
128+
try:
129+
projects = client.list_projects()
130+
print(f" ✓ Found {len(projects)} project(s)")
131+
for p in projects[:3]: # Show first 3
132+
print(f" - {p['name']}: {p['path']} ({p['status']})")
133+
except Exception as e:
134+
print(f" ✗ Failed to list projects: {e}")
135+
136+
# 4. Index the project (this would take time in real use)
137+
print("\n4. Starting project indexing...")
138+
print(" Note: This starts background indexing.")
139+
print(" In a real project, you would poll for completion.")
140+
try:
141+
index_result = client.index_project(project_id)
142+
print(f" ✓ Indexing started: {index_result}")
143+
except Exception as e:
144+
print(f" ✗ Failed to start indexing: {e}")
145+
146+
# 5. Query example (would fail if not indexed yet)
147+
print("\n5. Semantic search example...")
148+
print(" Note: This requires the project to be indexed first.")
149+
print(" Skipping in this demo as indexing takes time.")
150+
151+
# 6. Code suggestion example (would fail if not indexed yet)
152+
print("\n6. Code suggestion example...")
153+
print(" Note: This requires the project to be indexed first.")
154+
print(" Skipping in this demo as indexing takes time.")
155+
156+
print("\n" + "=" * 60)
157+
print("Example workflow completed!")
158+
print("=" * 60)
159+
print("\nFor full functionality:")
160+
print("1. Start the server: python main.py")
161+
print("2. Create a project with a real codebase path")
162+
print("3. Index the project: POST /api/projects/index")
163+
print("4. Wait for indexing to complete (poll /api/projects/{id})")
164+
print("5. Use /api/query and /api/code for RAG queries")
165+
166+
167+
def print_api_reference():
168+
"""Print API reference."""
169+
print("\n" + "=" * 60)
170+
print("PicoCode API Reference")
171+
print("=" * 60)
172+
print("""
173+
Base URL: http://127.0.0.1:8000/api
174+
175+
Endpoints:
176+
177+
1. Health Check
178+
GET /api/health
179+
Returns: {"status": "ok", "version": "0.2.0", ...}
180+
181+
2. Create/Get Project
182+
POST /api/projects
183+
Body: {"path": "/path/to/project", "name": "Optional Name"}
184+
Returns: Project object
185+
186+
3. List Projects
187+
GET /api/projects
188+
Returns: Array of project objects
189+
190+
4. Get Project
191+
GET /api/projects/{project_id}
192+
Returns: Project object
193+
194+
5. Delete Project
195+
DELETE /api/projects/{project_id}
196+
Returns: {"success": true}
197+
198+
6. Index Project
199+
POST /api/projects/index
200+
Body: {"project_id": "..."}
201+
Returns: {"status": "indexing", ...}
202+
203+
7. Semantic Search
204+
POST /api/query
205+
Body: {"project_id": "...", "query": "...", "top_k": 5}
206+
Returns: {"results": [...], ...}
207+
208+
8. Code Suggestions
209+
POST /api/code
210+
Body: {"project_id": "...", "prompt": "...", "use_rag": true}
211+
Returns: {"response": "...", "used_context": [...], ...}
212+
213+
For more details, see PYCHARM_INTEGRATION.md
214+
""")
215+
216+
217+
if __name__ == "__main__":
218+
import sys
219+
220+
if len(sys.argv) > 1 and sys.argv[1] == "--help":
221+
print_api_reference()
222+
else:
223+
example_workflow()

main.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,13 @@ def api_health():
230230
@app.get("/", response_class=HTMLResponse)
231231
def index(request: Request):
232232
analyses = list_analyses(DATABASE)
233-
return templates.TemplateResponse("index.html", {"request": request, "analyses": analyses, "config": CFG})
233+
projects_list = list_projects()
234+
return templates.TemplateResponse("index.html", {
235+
"request": request,
236+
"analyses": analyses,
237+
"projects": projects_list,
238+
"config": CFG
239+
})
234240

235241

236242
@app.get("/analyses/status")

templates/index.html

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,44 @@ <h5 class="card-title">Server / Configuration</h5>
5151
</div>
5252
</div>
5353

54+
<div class="card mt-3">
55+
<div class="card-body">
56+
<h5 class="card-title">Projects (v0.2)</h5>
57+
<p class="text-muted small">Per-project databases for isolation</p>
58+
{% if projects %}
59+
<ul class="list-group list-group-flush">
60+
{% for p in projects %}
61+
<li class="list-group-item project-item" data-project-id="{{ p.id }}">
62+
<div class="d-flex justify-content-between align-items-start">
63+
<div>
64+
<div class="fw-bold">{{ p.name }}</div>
65+
<div class="small text-muted">{{ p.path }}</div>
66+
<div class="small mt-1">
67+
{% if p.status == 'indexing' %}
68+
<span class="badge bg-warning text-dark">indexing</span>
69+
{% elif p.status == 'ready' %}
70+
<span class="badge bg-success">ready</span>
71+
{% elif p.status == 'error' %}
72+
<span class="badge bg-danger">error</span>
73+
{% else %}
74+
<span class="badge bg-secondary">{{ p.status }}</span>
75+
{% endif %}
76+
{% if p.last_indexed_at %}
77+
<span class="text-muted ms-2">Last indexed: {{ p.last_indexed_at }}</span>
78+
{% endif %}
79+
</div>
80+
</div>
81+
<button class="btn btn-sm btn-outline-primary" onclick="useProject('{{ p.id }}')">Use</button>
82+
</div>
83+
</li>
84+
{% endfor %}
85+
</ul>
86+
{% else %}
87+
<p class="mb-0 text-muted">No projects yet. Use API to create.</p>
88+
{% endif %}
89+
</div>
90+
</div>
91+
5492
<div class="card mt-3">
5593
<div class="card-body">
5694
<h5 class="card-title">Analyses</h5>
@@ -511,6 +549,12 @@ <h5 class="card-title mb-0">Chat</h5>
511549
}
512550
}
513551

552+
// Project management functions
553+
function useProject(projectId) {
554+
// For now, just show a message
555+
alert("Project selected: " + projectId + "\n\nUse the API endpoints to interact with this project:\n- POST /api/projects/index with project_id\n- POST /api/query with project_id and query\n- POST /api/code with project_id and prompt");
556+
}
557+
514558
// Wire up event handlers after DOM loaded
515559
window.addEventListener("load", () => {
516560
document.getElementById("sendBtn").addEventListener("click", sendMessage);

0 commit comments

Comments
 (0)