Files
microfish/backend/app/api/template.py
Kunthawat Greethong 166ef73ad2 Phase 4: Template system with auto-select and pre-fill
Backend:
- Add templates.json with 5 template definitions (news, policy, business, fiction, social)
- Add template API (/api/template/list, /api/template/auto-select, /api/template/:id/filter-rules)
- Register template blueprint in Flask app

Frontend:
- Add template API client (frontend/src/api/template.js)
- Add template selector UI in Home.vue (chip buttons + auto-select button)
- Add template state management and auto-select logic

Locale:
- Add template keys for th/en/zh

Entity filter rules in templates.json for context-aware filtering in Step 1.
2026-06-26 11:44:55 +07:00

148 lines
4.7 KiB
Python

"""
Template Auto-Selection API
Analyze seed data and recommend the best simulation template
"""
import json
import os
from flask import Blueprint, request, jsonify
from ..utils.llm_client import LLMClient
from ..utils.locale import t, get_locale, get_language_instruction
from ..utils.logger import get_logger
logger = get_logger('crowdsight.template')
template_bp = Blueprint('template', __name__)
# Load templates
_templates_path = os.path.join(os.path.dirname(__file__), '..', 'templates.json')
with open(_templates_path, 'r', encoding='utf-8') as f:
_templates_data = json.load(f)
_templates = _templates_data['templates']
@template_bp.route('/list', methods=['GET'])
def list_templates():
"""Return all available templates"""
locale = get_locale()
lang_key = f'prompt_{locale}' if locale in ('th', 'en', 'zh') else 'prompt_en'
result = []
for tmpl in _templates:
result.append({
'id': tmpl['id'],
'icon': tmpl['icon'],
'category': tmpl['category'],
'prompt': tmpl.get(lang_key, tmpl['prompt_en']),
'placeholders': tmpl['placeholders'],
'name': t(f'templates.{tmpl["id"]}'),
})
return jsonify({'success': True, 'templates': result})
@template_bp.route('/auto-select', methods=['POST'])
def auto_select_template():
"""
Analyze seed data and recommend the best template + pre-fill prompt.
Request JSON:
{
"text": "extracted text from uploaded documents",
"simulation_requirement": "optional user requirement"
}
Response JSON:
{
"success": true,
"template_id": "news_event",
"prompt": "pre-filled prompt with actual values",
"confidence": 0.85,
"reasoning": "why this template was selected"
}
"""
try:
data = request.get_json() or {}
text = data.get('text', '')[:5000] # Limit to 5000 chars
simulation_requirement = data.get('simulation_requirement', '')
if not text:
return jsonify({'success': False, 'error': 'No text provided'}), 400
locale = get_locale()
lang_instruction = get_language_instruction()
# Build template descriptions for the LLM
template_desc = []
lang_key = f'prompt_{locale}' if locale in ('th', 'en', 'zh') else 'prompt_en'
for tmpl in _templates:
template_desc.append(f"- {tmpl['id']}: {tmpl.get(lang_key, tmpl['prompt_en'])}")
templates_list = '\n'.join(template_desc)
system_prompt = f"""You are a smart assistant that analyzes document content and recommends the best simulation template.
Available templates:
{templates_list}
Your task:
1. Analyze the document content
2. Select the MOST appropriate template
3. Fill in the template placeholders with actual values from the document
4. Return the result in JSON format
{lang_instruction}"""
user_prompt = f"""Document content:
{text[:3000]}
{f'User requirement: {simulation_requirement}' if simulation_requirement else ''}
Return JSON:
{{
"template_id": "best_template_id",
"prompt": "the template with placeholders filled in with actual values from the document",
"confidence": 0.0-1.0,
"reasoning": "brief explanation of why this template was chosen"
}}"""
llm = LLMClient()
result = llm.chat_json(
messages=[
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_prompt}
],
temperature=0.3
)
# Validate template_id
valid_ids = [t['id'] for t in _templates]
if result.get('template_id') not in valid_ids:
result['template_id'] = 'news_event' # Default fallback
return jsonify({
'success': True,
'template_id': result.get('template_id', 'news_event'),
'prompt': result.get('prompt', ''),
'confidence': result.get('confidence', 0.5),
'reasoning': result.get('reasoning', ''),
})
except Exception as e:
logger.error(f"Template auto-select failed: {e}")
return jsonify({'success': False, 'error': str(e)}), 500
@template_bp.route('/<template_id>/filter-rules', methods=['GET'])
def get_filter_rules(template_id):
"""Return entity filter rules for a template (used by Step 1)"""
for tmpl in _templates:
if tmpl['id'] == template_id:
return jsonify({
'success': True,
'template_id': template_id,
'filter_rules': tmpl.get('entity_filter', {})
})
return jsonify({'success': False, 'error': 'Template not found'}), 404