Skip to content

Commit f58a4d1

Browse files
author
Aaron J Clifft
committed
added write to file button
1 parent 57e7271 commit f58a4d1

File tree

2 files changed

+93
-16
lines changed

2 files changed

+93
-16
lines changed

gui/astral_nexus_drafter.html

Lines changed: 57 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,13 @@ <h1 class="text-2xl font-bold text-white">Astral Drafter</h1>
9999
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
100100
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
101101
</svg>
102-
<span>Generate & Save Prose</span>
102+
<span>Generate Prose</span>
103103
</button>
104+
105+
<button id="save-button" class="mt-2 w-full bg-green-600 text-white font-bold py-3 px-4 rounded-md hover:bg-green-700 disabled:bg-green-800 disabled:cursor-not-allowed transition" disabled>
106+
<span>Save to File</span>
107+
</button>
108+
104109
<div id="error-message" class="mt-3 text-center text-red-400 text-sm"></div>
105110
</div>
106111
</div>
@@ -128,6 +133,7 @@ <h1 class="text-2xl font-bold text-white">Astral Drafter</h1>
128133
<script>
129134
// --- Element Selectors ---
130135
const generateButton = document.getElementById('generate-button');
136+
const saveButton = document.getElementById('save-button');
131137
const newSceneButton = document.getElementById('new-scene-button');
132138
const spinner = document.getElementById('spinner');
133139
const prevSceneInput = document.getElementById('prev-scene-summary');
@@ -161,6 +167,7 @@ <h1 class="text-2xl font-bold text-white">Astral Drafter</h1>
161167
outlineInput.addEventListener('input', updateContextUsage);
162168
characterInput.addEventListener('input', updateContextUsage);
163169
generateButton.addEventListener('click', generateProse);
170+
saveButton.addEventListener('click', saveProseToFile);
164171
newSceneButton.addEventListener('click', resetInterface);
165172
sendButton.addEventListener('click', sendChatMessage);
166173
chatInput.addEventListener('keypress', (e) => {
@@ -180,9 +187,10 @@ <h1 class="text-2xl font-bold text-white">Astral Drafter</h1>
180187
conversationHistory = [];
181188
currentOutputPath = '';
182189
lastGeneratedContent = '';
183-
chatInput.value = '';
190+
chatInput.value = true;
184191
chatInput.disabled = true;
185192
sendButton.disabled = true;
193+
saveButton.disabled = true;
186194
updateContextUsage();
187195
}
188196

@@ -211,6 +219,47 @@ <h1 class="text-2xl font-bold text-white">Astral Drafter</h1>
211219
}
212220
}
213221

222+
async function saveProseToFile() {
223+
if (!lastGeneratedContent || !currentOutputPath) {
224+
errorMessage.textContent = "No content to save or output path is missing.";
225+
return;
226+
}
227+
228+
saveButton.disabled = true;
229+
errorMessage.textContent = '';
230+
231+
try {
232+
const response = await fetch(MCP_SERVER_URL, {
233+
method: 'POST',
234+
headers: { 'Content-Type': 'application/json' },
235+
body: JSON.stringify({
236+
save_content: lastGeneratedContent,
237+
output_path: currentOutputPath
238+
})
239+
});
240+
241+
if (!response.ok) {
242+
const errorData = await response.json();
243+
throw new Error(errorData.error || `Save request failed: ${response.status}`);
244+
}
245+
246+
const result = await response.json();
247+
// You can add a success message here if you want
248+
console.log(result.message);
249+
// Maybe flash the button green or show a small confirmation message
250+
const originalText = saveButton.textContent;
251+
saveButton.textContent = 'Saved!';
252+
setTimeout(() => { saveButton.textContent = originalText; }, 2000);
253+
254+
255+
} catch (error) {
256+
console.error("Error saving file:", error);
257+
errorMessage.textContent = `Error saving file: ${error.message}`;
258+
} finally {
259+
saveButton.disabled = false;
260+
}
261+
}
262+
214263
async function generateProse() {
215264
const prevScene = prevSceneInput.value.trim();
216265
const outline = outlineInput.value.trim();
@@ -268,6 +317,7 @@ <h1 class="text-2xl font-bold text-white">Astral Drafter</h1>
268317
generateButton.disabled = true;
269318
sendButton.disabled = true;
270319
chatInput.disabled = true;
320+
saveButton.disabled = true;
271321
spinner.classList.remove('hidden');
272322

273323
const aiResponseContainer = addAiMessageContainer();
@@ -280,7 +330,6 @@ <h1 class="text-2xl font-bold text-white">Astral Drafter</h1>
280330
body: JSON.stringify({
281331
conversation_history: conversationHistory,
282332
stream: true,
283-
output_path: currentOutputPath
284333
})
285334
});
286335

@@ -318,8 +367,8 @@ <h1 class="text-2xl font-bold text-white">Astral Drafter</h1>
318367
});
319368

320369
addCopyToClipboardButton(aiResponseContainer, fullResponse);
321-
addSaveConfirmation(aiResponseContainer, currentOutputPath);
322-
370+
saveButton.disabled = false;
371+
323372
} catch (error) {
324373
console.error("Error querying Bridge server:", error);
325374
aiResponseContent.innerText = `Error connecting to Bridge server. Make sure it's running at ${MCP_SERVER_URL}.\n\nDetails: ${error.message}`;
@@ -409,7 +458,9 @@ <h1 class="text-2xl font-bold text-white">Astral Drafter</h1>
409458
container.appendChild(confirmation);
410459
}
411460

412-
resetInterface();
461+
function resetInterface() {
462+
saveButton.disabled = true;
463+
};
413464
</script>
414465
</body>
415466
</html>

llama_cpp_server_bridge.py

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,31 +15,57 @@ def do_POST(self):
1515
post_data = self.rfile.read(content_length)
1616
data = json.loads(post_data)
1717

18-
conversation_history = data.get('conversation_history', [])
19-
output_path = data.get('output_path')
20-
21-
if not conversation_history or not output_path:
22-
self._send_error("Missing 'conversation_history' or 'output_path'.", 400)
23-
return
18+
# NEW: Check if this is a save request or a generation request
19+
if 'save_content' in data:
20+
self._handle_save_request(data)
21+
else:
22+
self._handle_generation_request(data)
2423

2524
except (json.JSONDecodeError, TypeError, KeyError) as e:
2625
self._send_error(f"Invalid JSON request: {e}", 400)
2726
return
2827

28+
# NEW: Function to handle saving the file
29+
def _handle_save_request(self, data):
30+
content = data.get('save_content')
31+
output_path = data.get('output_path')
32+
33+
if not content or not output_path:
34+
self._send_error("Missing 'save_content' or 'output_path' for save request.", 400)
35+
return
36+
2937
try:
3038
output_dir = os.path.dirname(output_path)
3139
if output_dir:
3240
os.makedirs(output_dir, exist_ok=True)
3341

42+
# Write the final content to the file
3443
with open(output_path, 'w', encoding='utf-8') as outfile:
35-
self._stream_to_llama_cpp(conversation_history, outfile)
44+
outfile.write(content)
45+
46+
self.send_response(200)
47+
self.send_header('Content-Type', 'application/json')
48+
self.send_header('Access-Control-Allow-Origin', '*')
49+
self.end_headers()
50+
response = json.dumps({'message': f'Successfully saved to {output_path}'})
51+
self.wfile.write(response.encode('utf-8'))
3652

3753
except IOError as e:
3854
self._send_error(f"Could not write to file: {e}", 500)
3955
except Exception as e:
4056
self._send_error(f"An unexpected server error occurred: {e}", 500)
41-
42-
def _stream_to_llama_cpp(self, conversation_history, outfile):
57+
58+
# MODIFIED: This function now only handles generation and streaming
59+
def _handle_generation_request(self, data):
60+
conversation_history = data.get('conversation_history', [])
61+
if not conversation_history:
62+
self._send_error("Missing 'conversation_history' for generation request.", 400)
63+
return
64+
65+
self._stream_to_llama_cpp(conversation_history)
66+
67+
# MODIFIED: This function no longer writes to a file
68+
def _stream_to_llama_cpp(self, conversation_history):
4369
try:
4470
llama_cpp_payload = {
4571
"messages": conversation_history,
@@ -64,7 +90,7 @@ def _stream_to_llama_cpp(self, conversation_history, outfile):
6490
chunk = json.loads(line)
6591
content = chunk.get('choices', [{}])[0].get('delta', {}).get('content', '')
6692
if content:
67-
outfile.write(content)
93+
# REMOVED: outfile.write(content)
6894
gui_response = json.dumps({"response": content})
6995
self.wfile.write(gui_response.encode('utf-8') + b'\n')
7096
self.wfile.flush()

0 commit comments

Comments
 (0)