05/31 Phase 5

This commit is contained in:
2026-05-31 16:49:18 -04:00
parent 9c846159ef
commit b3d495e57c
9 changed files with 793 additions and 2 deletions
+65
View File
@@ -0,0 +1,65 @@
from flask import Blueprint, render_template, request, Response, stream_with_context, jsonify
from flask_login import login_required
from app.models.ai_insight import AiInsight
from app.services.ai_service import stream_chat, get_latest_daily_insight, generate_daily_insight
ai_bp = Blueprint('ai', __name__, url_prefix='/ai')
@ai_bp.route('/')
@login_required
def index():
latest_insight = get_latest_daily_insight()
recent_chats = AiInsight.query\
.filter_by(insight_type='chat_response')\
.order_by(AiInsight.created_at.desc())\
.limit(20).all()
return render_template('ai/index.html',
latest_insight=latest_insight,
recent_chats=recent_chats)
@ai_bp.route('/stream')
@login_required
def stream():
"""SSE endpoint — streams Groq response chunk by chunk."""
message = request.args.get('message', '').strip()
if not message:
def empty():
yield 'data: Please enter a message.\n\n'
yield 'data: [DONE]\n\n'
return Response(stream_with_context(empty()),
mimetype='text/event-stream',
headers={
'Cache-Control': 'no-cache',
'X-Accel-Buffering': 'no',
})
return Response(
stream_with_context(stream_chat(message)),
mimetype='text/event-stream',
headers={
'Cache-Control': 'no-cache',
'X-Accel-Buffering': 'no',
}
)
@ai_bp.route('/generate-insight', methods=['POST'])
@login_required
def trigger_insight():
"""Manually trigger a daily insight generation."""
content = generate_daily_insight()
if content:
return jsonify({'status': 'ok', 'content': content})
return jsonify({'status': 'error', 'message': 'Failed to generate insight'}), 500
@ai_bp.route('/history')
@login_required
def history():
page = request.args.get('page', 1, type=int)
insights = AiInsight.query\
.order_by(AiInsight.created_at.desc())\
.paginate(page=page, per_page=20, error_out=False)
return render_template('ai/history.html', insights=insights)
+6 -1
View File
@@ -6,6 +6,7 @@ from app.models.account import Account
from app.models.transaction import Transaction
from app.models.category import Category
from app.services.fx_service import get_today_rate, get_rate_history
from app.services.ai_service import get_latest_daily_insight
from app.services.account_service import get_total_assets, get_total_liabilities
from datetime import date, datetime, timedelta
import calendar
@@ -127,6 +128,9 @@ def index():
'rates': [float(r.usd_to_vnd) for r in fx_history],
}
# ── AI insight ──────────────────────────────────────
ai_insight = get_latest_daily_insight()
return render_template('dashboard/index.html',
period=period,
period_label=period_label,
@@ -145,7 +149,8 @@ def index():
chart_expense=chart_expense,
recent_txns=recent_txns,
fx=fx,
fx_history_data=fx_history_data)
fx_history_data=fx_history_data,
ai_insight=ai_insight)
@dashboard_bp.route('/api/fx-history')