Skip to content

Commit 7ef6a5b

Browse files
committed
feat(upload): first working version
1 parent 88b9593 commit 7ef6a5b

File tree

2 files changed

+42
-10
lines changed

2 files changed

+42
-10
lines changed

README.md

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,18 +29,20 @@ First step: Example .env (copy `.env.example` -> `.env` and edit)
2929
- Follow Astral uv installation instructions first: https://docs.astral.sh/uv/
3030
- Typical flow (after `uv` is installed and you are in the project directory):
3131

32-
# create and install dependencies from pyproject.toml using uv
32+
```
3333
3434
uv pip install -r pyproject.toml
3535
3636
uv run python ./main.py
37+
```
3738

3839
Notes:
3940
- The exact `uv` subcommands depend on the uv version/configuration. Check the Astral uv docs for the exact syntax for your uv CLI release. The analyzer only needs a Python executable in the venv to run `python -m pip list --format=json`; `uv` typically provides or creates that venv.
4041

4142
### Using plain virtualenv / pip (fallback)
42-
- Create a virtual environment and install dependencies listed in `pyproject.toml` with your preferred tool.
4343

44+
- Create a virtual environment and install dependencies listed in `pyproject.toml` with your preferred tool.
45+
```
4446
# create venv
4547
python -m venv .venv
4648
@@ -54,10 +56,11 @@ Notes:
5456
5557
# run the server
5658
python ./main.py
59+
```
5760

5861
### Using Poetry
5962

60-
- If your workflow is Poetry-based:
61-
63+
```
6264
poetry install
6365
poetry run uvicorn main:app --reload
66+
```

templates/index.html

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,11 @@ <h5 class="card-title mb-0">Chat</h5>
187187
const spinner = document.createElement("div");
188188
spinner.className = "spinner-small ms-2";
189189
rightMeta.appendChild(spinner);
190+
} else if(msg.status === "deleted"){
191+
const delTag = document.createElement("span");
192+
delTag.className = "text-muted small ms-2";
193+
delTag.textContent = "deleted";
194+
rightMeta.appendChild(delTag);
190195
} else if(msg.status === "error"){
191196
const err = document.createElement("span");
192197
err.className = "text-danger small ms-2";
@@ -200,11 +205,17 @@ <h5 class="card-title mb-0">Chat</h5>
200205
regenBtn.title = "Regenerate";
201206
regenBtn.textContent = "Regenerate";
202207
regenBtn.addEventListener("click", ()=>regenerateMessage(msg.id));
208+
203209
const delBtn = document.createElement("button");
204210
delBtn.className = "btn btn-outline-danger btn-sm btn-sm-icon";
205-
delBtn.title = "Delete";
206-
delBtn.textContent = "Delete";
207-
delBtn.addEventListener("click", ()=>deleteMessage(msg.id));
211+
delBtn.title = msg.status === "deleted" ? "Remove permanently" : "Delete";
212+
delBtn.textContent = msg.status === "deleted" ? "Remove" : "Delete";
213+
// soft-delete versus permanent removal
214+
if(msg.status === "deleted"){
215+
delBtn.addEventListener("click", ()=>permanentDeleteMessage(msg.id));
216+
} else {
217+
delBtn.addEventListener("click", ()=>softDeleteMessage(msg.id));
218+
}
208219
actions.appendChild(regenBtn);
209220
actions.appendChild(delBtn);
210221
rightMeta.appendChild(actions);
@@ -216,8 +227,13 @@ <h5 class="card-title mb-0">Chat</h5>
216227
const content = document.createElement("div");
217228
content.className = "content";
218229
if(msg.role === "assistant"){
219-
const md = typeof msg.text === "string" ? msg.text : JSON.stringify(msg.text, null, 2);
220-
content.innerHTML = renderMarkdown(md);
230+
if(msg.status === "deleted"){
231+
content.textContent = "(deleted)";
232+
content.className = "content text-muted fst-italic";
233+
} else {
234+
const md = typeof msg.text === "string" ? msg.text : JSON.stringify(msg.text, null, 2);
235+
content.innerHTML = renderMarkdown(md);
236+
}
221237
} else {
222238
content.textContent = msg.text || "";
223239
}
@@ -325,16 +341,29 @@ <h5 class="card-title mb-0">Chat</h5>
325341
if(!msg) return;
326342
const userMsg = arr.find(m=>m.id===msg.replyTo);
327343
if(!userMsg) return;
344+
// mark pending and clear previous used_context
328345
updateMessage(assistantId, { status: "pending", text: "", used_context: [] });
329346
await callModel(userMsg, assistantId);
330347
}
331348

332-
function deleteMessage(assistantId){
349+
// Soft-delete: keep message so regeneration can still find replyTo and id.
350+
function softDeleteMessage(assistantId){
351+
updateMessage(assistantId, { status: "deleted", text: "", used_context: [] });
352+
}
353+
354+
// Permanent removal from history
355+
function permanentDeleteMessage(assistantId){
333356
const arr = loadHistory().filter(m=>m.id!==assistantId);
334357
saveHistory(arr);
335358
renderChat();
336359
}
337360

361+
// Backwards compatibility: keep function name if something else calls deleteMessage
362+
function deleteMessage(assistantId){
363+
// default to soft-delete to preserve regenerate behavior
364+
softDeleteMessage(assistantId);
365+
}
366+
338367
function clearHistory(){
339368
if(!confirm("Clear entire chat history?")) return;
340369
localStorage.removeItem(STORAGE_KEY);

0 commit comments

Comments
 (0)