Flow improvements.
This commit is contained in:
@@ -373,7 +373,7 @@ def update_tracking(folder, chapter_num, chapter_text, current_tracking):
|
|||||||
utils.log("TRACKER", f"Failed to update tracking: {e}")
|
utils.log("TRACKER", f"Failed to update tracking: {e}")
|
||||||
return current_tracking
|
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()
|
guidelines = get_style_guidelines()
|
||||||
ai_isms = "', '".join(guidelines['ai_isms'])
|
ai_isms = "', '".join(guidelines['ai_isms'])
|
||||||
fw_examples = ", ".join([f"'He {w}'" for w in guidelines['filter_words'][:5]])
|
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"""
|
prompt = f"""
|
||||||
Act as a World-Class Literary Editor (e.g., Maxwell Perkins). Analyze this chapter draft with extreme scrutiny.
|
Act as a World-Class Literary Editor (e.g., Maxwell Perkins). Analyze this chapter draft with extreme scrutiny.
|
||||||
CHAPTER TITLE: {chapter_title}
|
CHAPTER TITLE: {chapter_title}
|
||||||
|
GENRE: {genre}
|
||||||
|
|
||||||
STRICT PROHIBITIONS (Automatic deduction):
|
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).
|
- 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.
|
- 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.
|
- 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']
|
ls = bp['length_settings']
|
||||||
meta = bp.get('book_metadata', {})
|
meta = bp.get('book_metadata', {})
|
||||||
style = meta.get('style', {})
|
style = meta.get('style', {})
|
||||||
|
genre = meta.get('genre', 'Fiction')
|
||||||
|
|
||||||
pov_char = chap.get('pov_character', '')
|
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"""
|
prompt = f"""
|
||||||
Write Chapter {chap['chapter_number']}: {chap['title']}
|
Write Chapter {chap['chapter_number']}: {chap['title']}
|
||||||
|
GENRE: {genre}
|
||||||
|
|
||||||
PACING GUIDE:
|
PACING GUIDE:
|
||||||
- Format: {ls.get('label', 'Story')}
|
- 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):
|
for attempt in range(1, max_attempts + 1):
|
||||||
utils.log("WRITER", f" -> Evaluating Ch {chap['chapter_number']} (Attempt {attempt}/{max_attempts})...")
|
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}")
|
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)
|
history_str = "\n".join(past_critiques)
|
||||||
|
|
||||||
refine_prompt = f"""
|
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 TO ADDRESS (MANDATORY):
|
||||||
{critique}
|
{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')}.
|
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.
|
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.
|
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:
|
STORY SO FAR:
|
||||||
{prev_sum}
|
{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.
|
Return the polished, final version of the chapter in Markdown.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
resp_refine = ai.model_writer.generate_content(refine_prompt)
|
# Use Logic model (Pro) for refinement to ensure higher quality prose
|
||||||
utils.log_usage(folder, "writer-flash", resp_refine.usage_metadata)
|
resp_refine = ai.model_logic.generate_content(refine_prompt)
|
||||||
|
utils.log_usage(folder, "logic-pro", resp_refine.usage_metadata)
|
||||||
current_text = resp_refine.text
|
current_text = resp_refine.text
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
utils.log("WRITER", f"Refinement failed: {e}")
|
utils.log("WRITER", f"Refinement failed: {e}")
|
||||||
|
|||||||
@@ -977,7 +977,13 @@ def run_status(id):
|
|||||||
if os.path.exists(temp_log):
|
if os.path.exists(temp_log):
|
||||||
with open(temp_log, 'r') as f: log_content = f.read()
|
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:
|
if last_log:
|
||||||
response["progress"] = {
|
response["progress"] = {
|
||||||
|
|||||||
@@ -109,7 +109,7 @@
|
|||||||
<strong class="text-primary" id="statusPhase">Initializing...</strong>
|
<strong class="text-primary" id="statusPhase">Initializing...</strong>
|
||||||
</div>
|
</div>
|
||||||
<h5 class="card-title mb-3" id="statusMessage">Preparing environment...</h5>
|
<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 id="progressBar" class="progress-bar progress-bar-striped progress-bar-animated bg-success" role="progressbar" style="width: 0%"></div>
|
||||||
</div>
|
</div>
|
||||||
<small class="text-muted mt-2 d-block" id="statusTime"></small>
|
<small class="text-muted mt-2 d-block" id="statusTime"></small>
|
||||||
@@ -164,8 +164,8 @@
|
|||||||
</td>
|
</td>
|
||||||
<td>${{ "%.4f"|format(r.cost) }}</td>
|
<td>${{ "%.4f"|format(r.cost) }}</td>
|
||||||
<td>
|
<td>
|
||||||
<a href="/project/{{ project.id }}/run/{{ r.id }}" class="btn btn-sm btn-outline-primary">
|
<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 else 'View' }}
|
{{ 'View Active' if active_run and r.id == active_run.id and active_run.status in ['running', 'queued'] else 'View' }}
|
||||||
</a>
|
</a>
|
||||||
{% if r.status in ['failed', 'cancelled', 'interrupted'] %}
|
{% if r.status in ['failed', 'cancelled', 'interrupted'] %}
|
||||||
<form action="/run/{{ r.id }}/restart" method="POST" class="d-inline ms-1">
|
<form action="/run/{{ r.id }}/restart" method="POST" class="d-inline ms-1">
|
||||||
@@ -562,6 +562,18 @@
|
|||||||
const progBar = document.getElementById('progressBar');
|
const progBar = document.getElementById('progressBar');
|
||||||
if (progBar && data.percent !== undefined) {
|
if (progBar && data.percent !== undefined) {
|
||||||
progBar.style.width = data.percent + "%";
|
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
|
// Update Status Bar
|
||||||
|
|||||||
@@ -324,7 +324,18 @@
|
|||||||
if (data.status === 'running' || data.status === 'queued') {
|
if (data.status === 'running' || data.status === 'queued') {
|
||||||
statusBar.className = "progress-bar progress-bar-striped progress-bar-animated";
|
statusBar.className = "progress-bar progress-bar-striped progress-bar-animated";
|
||||||
statusBar.style.width = (data.percent || 5) + "%";
|
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') {
|
} else if (data.status === 'failed') {
|
||||||
statusBar.className = "progress-bar bg-danger";
|
statusBar.className = "progress-bar bg-danger";
|
||||||
statusBar.style.width = "100%";
|
statusBar.style.width = "100%";
|
||||||
|
|||||||
Reference in New Issue
Block a user