feat: Market Intel Database & UI Polish
- market_db_manager.py: Created SQLite manager for saving/loading projects. - server.cjs: Added API routes for project management. - geminiService.ts: Added client-side DB functions. - StepInput.tsx: Added 'Past Runs' sidebar to load previous audits. - App.tsx: Added auto-save functionality and full state hydration logic. - StepOutreach.tsx: Improved UI layout by merging generated campaigns and suggestions into one list.
This commit is contained in:
105
market_db_manager.py
Normal file
105
market_db_manager.py
Normal file
@@ -0,0 +1,105 @@
|
||||
import sqlite3
|
||||
import json
|
||||
import os
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
|
||||
DB_PATH = "/app/market_intelligence.db"
|
||||
|
||||
def get_db_connection():
|
||||
conn = sqlite3.connect(DB_PATH)
|
||||
conn.row_factory = sqlite3.Row
|
||||
return conn
|
||||
|
||||
def init_db():
|
||||
conn = get_db_connection()
|
||||
# Flexible schema: We store almost everything in a 'data' JSON column
|
||||
conn.execute('''
|
||||
CREATE TABLE IF NOT EXISTS projects (
|
||||
id TEXT PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
data JSON NOT NULL
|
||||
)
|
||||
''')
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
def save_project(project_data):
|
||||
"""
|
||||
Saves a project. If 'id' exists in data, updates it. Otherwise creates new.
|
||||
"""
|
||||
conn = get_db_connection()
|
||||
try:
|
||||
project_id = project_data.get('id')
|
||||
|
||||
# Extract a name for the list view (e.g. from companyName or referenceUrl)
|
||||
# We assume the frontend passes a 'name' field, or we derive it.
|
||||
name = project_data.get('name') or project_data.get('companyName') or "Untitled Project"
|
||||
|
||||
if not project_id:
|
||||
# Create New
|
||||
project_id = str(uuid.uuid4())
|
||||
project_data['id'] = project_id
|
||||
|
||||
conn.execute(
|
||||
'INSERT INTO projects (id, name, data) VALUES (?, ?, ?)',
|
||||
(project_id, name, json.dumps(project_data))
|
||||
)
|
||||
else:
|
||||
# Update Existing
|
||||
conn.execute(
|
||||
'''UPDATE projects
|
||||
SET name = ?, data = ?, updated_at = CURRENT_TIMESTAMP
|
||||
WHERE id = ?''',
|
||||
(name, json.dumps(project_data), project_id)
|
||||
)
|
||||
|
||||
conn.commit()
|
||||
return {"id": project_id, "status": "saved"}
|
||||
|
||||
except Exception as e:
|
||||
return {"error": str(e)}
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
def get_all_projects():
|
||||
conn = get_db_connection()
|
||||
projects = conn.execute('SELECT id, name, created_at, updated_at FROM projects ORDER BY updated_at DESC').fetchall()
|
||||
conn.close()
|
||||
return [dict(ix) for ix in projects]
|
||||
|
||||
def load_project(project_id):
|
||||
conn = get_db_connection()
|
||||
project = conn.execute('SELECT data FROM projects WHERE id = ?', (project_id,)).fetchone()
|
||||
conn.close()
|
||||
if project:
|
||||
return json.loads(project['data'])
|
||||
return None
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
# Simple CLI for Node.js bridge
|
||||
# Usage: python market_db_manager.py [init|list|save|load] [args...]
|
||||
|
||||
mode = sys.argv[1]
|
||||
|
||||
if mode == "init":
|
||||
init_db()
|
||||
print(json.dumps({"status": "initialized"}))
|
||||
|
||||
elif mode == "list":
|
||||
print(json.dumps(get_all_projects()))
|
||||
|
||||
elif mode == "save":
|
||||
# Data is passed as a JSON string file path to avoid command line length limits
|
||||
data_file = sys.argv[2]
|
||||
with open(data_file, 'r') as f:
|
||||
data = json.load(f)
|
||||
print(json.dumps(save_project(data)))
|
||||
|
||||
elif mode == "load":
|
||||
p_id = sys.argv[2]
|
||||
result = load_project(p_id)
|
||||
print(json.dumps(result if result else {"error": "Project not found"}))
|
||||
Reference in New Issue
Block a user