fix: address AI review feedback for disinto-chat (#705)
This commit is contained in:
parent
eada673493
commit
938cd319aa
5 changed files with 25 additions and 46 deletions
5
.gitignore
vendored
5
.gitignore
vendored
|
|
@ -32,3 +32,8 @@ docker/agents/bin/
|
|||
# Generated docker-compose.yml (run 'bin/disinto init' to regenerate)
|
||||
# Note: This file is now committed to track volume mount configuration
|
||||
# docker-compose.yml
|
||||
|
||||
# Python bytecode
|
||||
__pycache__/
|
||||
*.pyc
|
||||
*.pyo
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
# disinto-chat — minimal HTTP+WebSocket backend for Claude chat UI
|
||||
# disinto-chat — minimal HTTP backend for Claude chat UI
|
||||
#
|
||||
# Small Debian slim base with Python runtime and websockets library.
|
||||
# Chosen for simplicity and small image size (~100MB vs ~150MB for Go).
|
||||
# Small Debian slim base with Python runtime.
|
||||
# Chosen for simplicity and small image size (~100MB).
|
||||
#
|
||||
# Image size: ~100MB (well under the 200MB ceiling)
|
||||
#
|
||||
|
|
@ -10,11 +10,9 @@
|
|||
|
||||
FROM debian:bookworm-slim
|
||||
|
||||
# Install Python and websockets (no build-time network access needed)
|
||||
# Install Python (no build-time network access needed)
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
python3 \
|
||||
python3-pip \
|
||||
&& pip3 install --break-system-packages websockets \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Non-root user
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -165,35 +165,21 @@ class ChatHandler(BaseHTTPRequestHandler):
|
|||
return
|
||||
|
||||
try:
|
||||
# Spawn claude --print with streaming output
|
||||
# Using stream-json format for structured parsing capability
|
||||
# Spawn claude --print with text output format
|
||||
proc = subprocess.Popen(
|
||||
[CLAUDE_BIN, "--print", message, "--output-format", "stream-json"],
|
||||
[CLAUDE_BIN, "--print", message],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
text=False,
|
||||
bufsize=0, # Unbuffered for streaming
|
||||
text=True,
|
||||
)
|
||||
|
||||
# Read and stream response
|
||||
response_parts = []
|
||||
error_parts = []
|
||||
|
||||
# Read stdout in chunks
|
||||
while True:
|
||||
chunk = proc.stdout.read(4096)
|
||||
if not chunk:
|
||||
break
|
||||
try:
|
||||
response_parts.append(chunk.decode("utf-8"))
|
||||
except UnicodeDecodeError:
|
||||
response_parts.append(chunk.decode("utf-8", errors="replace"))
|
||||
# Read response as text (Claude outputs plain text when not using stream-json)
|
||||
response = proc.stdout.read()
|
||||
|
||||
# Read stderr (should be minimal, mostly for debugging)
|
||||
if proc.stderr:
|
||||
error_output = proc.stderr.read()
|
||||
if error_output:
|
||||
error_parts.append(error_output.decode("utf-8", errors="replace"))
|
||||
print(f"Claude stderr: {error_output}", file=sys.stderr)
|
||||
|
||||
# Wait for process to complete
|
||||
proc.wait()
|
||||
|
|
@ -202,12 +188,6 @@ class ChatHandler(BaseHTTPRequestHandler):
|
|||
if proc.returncode != 0:
|
||||
self.send_error(500, f"Claude CLI failed with exit code {proc.returncode}")
|
||||
return
|
||||
|
||||
# Combine response parts
|
||||
response = "".join(response_parts)
|
||||
|
||||
# If using stream-json, we could parse and reformat here.
|
||||
# For now, return as-is (HTMX will display it in the UI).
|
||||
self.send_response(200)
|
||||
self.send_header("Content-Type", "text/plain; charset=utf-8")
|
||||
self.send_header("Content-Length", len(response.encode("utf-8")))
|
||||
|
|
|
|||
|
|
@ -132,7 +132,7 @@
|
|||
<div class="content">Welcome to disinto-chat. Type a message to start chatting with Claude.</div>
|
||||
</div>
|
||||
</div>
|
||||
<form class="input-area" hx-post="/chat" hx-swap="none" hx-target="#messages">
|
||||
<form class="input-area">
|
||||
<textarea name="message" placeholder="Type your message..." required></textarea>
|
||||
<button type="submit" id="send-btn">Send</button>
|
||||
</form>
|
||||
|
|
@ -161,13 +161,6 @@
|
|||
return div.innerHTML.replace(/\n/g, '<br>');
|
||||
}
|
||||
|
||||
// Handle HTMX swap for streaming responses
|
||||
document.body.addEventListener('htmx:afterSwap', function(event) {
|
||||
const newContent = event.detail.xhr.responseText;
|
||||
// HTMX will handle the swap; we just need to scroll to bottom
|
||||
messagesDiv.scrollTop = messagesDiv.scrollHeight;
|
||||
});
|
||||
|
||||
// Send message handler
|
||||
sendBtn.addEventListener('click', async () => {
|
||||
const message = textarea.value.trim();
|
||||
|
|
@ -183,13 +176,16 @@
|
|||
textarea.value = '';
|
||||
|
||||
try {
|
||||
// Use fetch for better control over streaming
|
||||
const formData = new FormData();
|
||||
formData.append('message', message);
|
||||
// Use fetch with URLSearchParams for application/x-www-form-urlencoded
|
||||
const params = new URLSearchParams();
|
||||
params.append('message', message);
|
||||
|
||||
const response = await fetch('/chat', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
},
|
||||
body: params
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue