Flow improvements.

This commit is contained in:
=
2026-02-04 22:57:38 -05:00
parent 346dbe3f64
commit 1cd62a75c9
4 changed files with 46 additions and 11 deletions

View File

@@ -373,7 +373,7 @@ def update_tracking(folder, chapter_num, chapter_text, current_tracking):
utils.log("TRACKER", f"Failed to update tracking: {e}")
return current_tracking
def evaluate_chapter_quality(text, chapter_title, model, folder):
def evaluate_chapter_quality(text, chapter_title, genre, model, folder):
guidelines = get_style_guidelines()
ai_isms = "', '".join(guidelines['ai_isms'])
fw_examples = ", ".join([f"'He {w}'" for w in guidelines['filter_words'][:5]])
@@ -381,9 +381,10 @@ def evaluate_chapter_quality(text, chapter_title, model, folder):
prompt = f"""
Act as a World-Class Literary Editor (e.g., Maxwell Perkins). Analyze this chapter draft with extreme scrutiny.
CHAPTER TITLE: {chapter_title}
GENRE: {genre}
STRICT PROHIBITIONS (Automatic deduction):
- "AI-isms": '{ai_isms}'.
- "AI-isms": '{ai_isms}'. (Evaluate in context of {genre}. Allow genre-appropriate tropes, but penalize robotic clichés).
- Filter Words: {fw_examples}, etc. (Show the sensation/action, don't state the internal process).
- Stilted Dialogue: Characters speaking in perfect paragraphs without interruptions, slang, or subtext.
- White Room Syndrome: Dialogue occurring in a void without interaction with the setting/props.
@@ -532,6 +533,7 @@ def write_chapter(chap, bp, folder, prev_sum, tracking=None, prev_content=None):
ls = bp['length_settings']
meta = bp.get('book_metadata', {})
style = meta.get('style', {})
genre = meta.get('genre', 'Fiction')
pov_char = chap.get('pov_character', '')
@@ -593,6 +595,7 @@ def write_chapter(chap, bp, folder, prev_sum, tracking=None, prev_content=None):
prompt = f"""
Write Chapter {chap['chapter_number']}: {chap['title']}
GENRE: {genre}
PACING GUIDE:
- Format: {ls.get('label', 'Story')}
@@ -651,7 +654,7 @@ def write_chapter(chap, bp, folder, prev_sum, tracking=None, prev_content=None):
for attempt in range(1, max_attempts + 1):
utils.log("WRITER", f" -> Evaluating Ch {chap['chapter_number']} (Attempt {attempt}/{max_attempts})...")
score, critique = evaluate_chapter_quality(current_text, chap['title'], ai.model_logic, folder)
score, critique = evaluate_chapter_quality(current_text, chap['title'], meta.get('genre', 'Fiction'), ai.model_logic, folder)
past_critiques.append(f"Attempt {attempt}: {critique}")
@@ -686,7 +689,7 @@ def write_chapter(chap, bp, folder, prev_sum, tracking=None, prev_content=None):
history_str = "\n".join(past_critiques)
refine_prompt = f"""
Act as a Senior Editor. Rewrite this chapter to fix the issues identified below.
Act as a Senior Editor. Rewrite this chapter to fix the issues identified below and ELEVATE the writing quality.
CRITIQUE TO ADDRESS (MANDATORY):
{critique}
@@ -701,6 +704,8 @@ def write_chapter(chap, bp, folder, prev_sum, tracking=None, prev_content=None):
4. GENRE CONSISTENCY: Ensure the tone matches {meta.get('genre', 'Fiction')}.
5. SETTING INTERACTION: Ensure characters interact with their environment (props, weather, lighting) during dialogue.
6. DRAMATIZE, DON'T SUMMARIZE: Expand summarized moments into full scenes with dialogue and action. Ensure the scene feels "full" and immersive.
7. STRONG VERBS: Avoid "was/were" constructions. Use active, specific verbs to drive the prose.
8. EMOTIONAL RESONANCE: Ensure the POV character's internal state is clear and drives the narrative.
STORY SO FAR:
{prev_sum}
@@ -712,8 +717,9 @@ def write_chapter(chap, bp, folder, prev_sum, tracking=None, prev_content=None):
Return the polished, final version of the chapter in Markdown.
"""
try:
resp_refine = ai.model_writer.generate_content(refine_prompt)
utils.log_usage(folder, "writer-flash", resp_refine.usage_metadata)
# Use Logic model (Pro) for refinement to ensure higher quality prose
resp_refine = ai.model_logic.generate_content(refine_prompt)
utils.log_usage(folder, "logic-pro", resp_refine.usage_metadata)
current_text = resp_refine.text
except Exception as e:
utils.log("WRITER", f"Refinement failed: {e}")

View File

@@ -977,7 +977,13 @@ def run_status(id):
if os.path.exists(temp_log):
with open(temp_log, 'r') as f: log_content = f.read()
response = {"status": run.status, "log": log_content, "cost": run.cost, "percent": run.progress}
response = {
"status": run.status,
"log": log_content,
"cost": run.cost,
"percent": run.progress,
"start_time": run.start_time.timestamp() if run.start_time else None
}
if last_log:
response["progress"] = {

View File

@@ -109,7 +109,7 @@
<strong class="text-primary" id="statusPhase">Initializing...</strong>
</div>
<h5 class="card-title mb-3" id="statusMessage">Preparing environment...</h5>
<div class="progress" style="height: 10px;">
<div class="progress" style="height: 20px;">
<div id="progressBar" class="progress-bar progress-bar-striped progress-bar-animated bg-success" role="progressbar" style="width: 0%"></div>
</div>
<small class="text-muted mt-2 d-block" id="statusTime"></small>
@@ -164,8 +164,8 @@
</td>
<td>${{ "%.4f"|format(r.cost) }}</td>
<td>
<a href="/project/{{ project.id }}/run/{{ r.id }}" class="btn btn-sm btn-outline-primary">
{{ 'View Active' if active_run and r.id == active_run.id else 'View' }}
<a href="{{ url_for('view_run', id=r.id) }}" class="btn btn-sm btn-outline-primary">
{{ 'View Active' if active_run and r.id == active_run.id and active_run.status in ['running', 'queued'] else 'View' }}
</a>
{% if r.status in ['failed', 'cancelled', 'interrupted'] %}
<form action="/run/{{ r.id }}/restart" method="POST" class="d-inline ms-1">
@@ -562,6 +562,18 @@
const progBar = document.getElementById('progressBar');
if (progBar && data.percent !== undefined) {
progBar.style.width = data.percent + "%";
let label = data.percent + "%";
if (data.status === 'running' && data.percent > 2 && data.start_time) {
const elapsed = (Date.now() / 1000) - data.start_time;
if (elapsed > 5) {
const remaining = (elapsed / (data.percent / 100)) - elapsed;
const m = Math.floor(remaining / 60);
const s = Math.floor(remaining % 60);
if (remaining > 0 && remaining < 86400) label += ` (~${m}m ${s}s)`;
}
}
progBar.innerText = label;
}
// Update Status Bar

View File

@@ -324,7 +324,18 @@
if (data.status === 'running' || data.status === 'queued') {
statusBar.className = "progress-bar progress-bar-striped progress-bar-animated";
statusBar.style.width = (data.percent || 5) + "%";
statusBar.innerText = (data.percent || 0) + "%";
let label = (data.percent || 0) + "%";
if (data.status === 'running' && data.percent > 2 && data.start_time) {
const elapsed = (Date.now() / 1000) - data.start_time;
if (elapsed > 5) {
const remaining = (elapsed / (data.percent / 100)) - elapsed;
const m = Math.floor(remaining / 60);
const s = Math.floor(remaining % 60);
if (remaining > 0 && remaining < 86400) label += ` (~${m}m ${s}s)`;
}
}
statusBar.innerText = label;
} else if (data.status === 'failed') {
statusBar.className = "progress-bar bg-danger";
statusBar.style.width = "100%";