refactor: Migrate file-based data storage to database

This commit is contained in:
2026-02-22 10:23:40 -05:00
parent b4058f9f1f
commit 51b98c9399
9 changed files with 108 additions and 80 deletions

View File

@@ -8,17 +8,27 @@ def _empty_state():
return {"active_threads": [], "immediate_handoff": "", "resolved_threads": [], "chapter": 0}
def load_story_state(folder):
"""Load structured story state from story_state.json, or return empty state."""
def load_story_state(folder, project_id=None):
"""Load structured story state from DB (if project_id given) or story_state.json fallback."""
if project_id is not None:
try:
from web.db import StoryState
record = StoryState.query.filter_by(project_id=project_id).first()
if record and record.state_json:
return json.loads(record.state_json) or _empty_state()
except Exception:
pass # Fall through to file-based load if DB unavailable (e.g. CLI context)
path = os.path.join(folder, "story_state.json")
if os.path.exists(path):
return utils.load_json(path) or _empty_state()
return _empty_state()
def update_story_state(chapter_text, chapter_num, current_state, folder):
def update_story_state(chapter_text, chapter_num, current_state, folder, project_id=None):
"""Use model_logic to extract structured story threads from the new chapter
and save the updated state to story_state.json. Returns the new state."""
and save the updated state to the StoryState DB table and/or story_state.json.
Returns the new state."""
utils.log("STATE", f"Updating story state after Ch {chapter_num}...")
prompt = f"""
ROLE: Story State Tracker
@@ -54,9 +64,28 @@ def update_story_state(chapter_text, chapter_num, current_state, folder):
utils.log_usage(folder, ai_models.model_logic.name, response.usage_metadata)
new_state = json.loads(utils.clean_json(response.text))
new_state['chapter'] = chapter_num
# Write to DB if project_id is available
if project_id is not None:
try:
from web.db import db, StoryState
from datetime import datetime
record = StoryState.query.filter_by(project_id=project_id).first()
if record:
record.state_json = json.dumps(new_state)
record.updated_at = datetime.utcnow()
else:
record = StoryState(project_id=project_id, state_json=json.dumps(new_state))
db.session.add(record)
db.session.commit()
except Exception as db_err:
utils.log("STATE", f" -> DB write failed: {db_err}. Falling back to file.")
# Always write to file for backward compat with CLI
path = os.path.join(folder, "story_state.json")
with open(path, 'w') as f:
json.dump(new_state, f, indent=2)
utils.log("STATE", f" -> Story state saved. Active threads: {len(new_state.get('active_threads', []))}")
return new_state
except Exception as e:

View File

@@ -157,10 +157,12 @@ def update_persona_sample(bp, folder):
author_name = meta.get('author', 'Unknown Author')
# Use a local file mirror for the engine context (runs outside Flask app context)
_personas_file = os.path.join(config.PERSONAS_DIR, "personas.json")
personas = {}
if os.path.exists(config.PERSONAS_FILE):
if os.path.exists(_personas_file):
try:
with open(config.PERSONAS_FILE, 'r') as f: personas = json.load(f)
with open(_personas_file, 'r') as f: personas = json.load(f)
except: pass
if author_name not in personas:
@@ -189,4 +191,4 @@ def update_persona_sample(bp, folder):
if filename not in personas[author_name]['sample_files']:
personas[author_name]['sample_files'].append(filename)
with open(config.PERSONAS_FILE, 'w') as f: json.dump(personas, f, indent=2)
with open(_personas_file, 'w') as f: json.dump(personas, f, indent=2)