changes
This commit is contained in:
@@ -60,37 +60,6 @@ class AIService:
|
||||
|
||||
return None
|
||||
|
||||
def generate_single_rule(self, folder_name: str, folder_type: str = 'destination', rule_text: str ='') -> Tuple[Optional[str], Optional[Dict]]:
|
||||
"""Generate a single email organization rule using AI."""
|
||||
prompt = self._build_single_rule_prompt(folder_name, folder_type, rule_text)
|
||||
|
||||
payload = {
|
||||
'model': self.model,
|
||||
'messages': [
|
||||
{'role': 'system', 'content': 'You are an expert email organizer assistant.'},
|
||||
{'role': 'user', 'content': prompt}
|
||||
],
|
||||
'max_tokens': 800,
|
||||
'temperature': 0.7
|
||||
}
|
||||
|
||||
result = self._make_request('chat/completions', payload)
|
||||
|
||||
if not result or 'choices' not in result or not result['choices']:
|
||||
return None, {'error': 'No response from AI service'}
|
||||
|
||||
try:
|
||||
rule_text = result['choices'][0]['message']['content'].strip()
|
||||
quality_score = self._assess_rule_quality(rule_text, folder_name, folder_type)
|
||||
|
||||
return rule_text, {
|
||||
'quality_score': quality_score,
|
||||
'model_used': self.model,
|
||||
'generated_at': datetime.utcnow().isoformat()
|
||||
}
|
||||
except (KeyError, IndexError) as e:
|
||||
return None, {'error': f'Failed to parse AI response: {str(e)}'}
|
||||
|
||||
def generate_multiple_rules(self, folder_name: str, folder_type: str = 'destination', rule_text:str = '', count: int = 3) -> Tuple[Optional[List[Dict]], Optional[Dict]]:
|
||||
"""Generate multiple email organization rule options using AI."""
|
||||
prompt = self._build_multiple_rules_prompt(folder_name, folder_type, rule_text, count)
|
||||
|
||||
@@ -27,7 +27,9 @@ def index():
|
||||
@login_required
|
||||
def new_folder_modal():
|
||||
"""Return the add folder modal."""
|
||||
response = make_response(render_template('partials/folder_modal.html'))
|
||||
response = make_response(render_template('partials/folder_modal.html', folder_data={'rule_text': folder.rule_text,
|
||||
'show_ai_rules': True,
|
||||
'errors': None }))
|
||||
response.headers['HX-Trigger'] = 'open-modal'
|
||||
return response
|
||||
|
||||
@@ -59,7 +61,10 @@ def add_folder():
|
||||
|
||||
# If there are validation errors, return the modal with errors
|
||||
if errors:
|
||||
response = make_response(render_template('partials/folder_modal.html', errors=errors, name=name, rule_text=rule_text, priority=priority))
|
||||
response = make_response(render_template('partials/folder_modal.html', errors=errors, name=name, rule_text=rule_text, priority=priority,
|
||||
folder_data={'rule_text': '',
|
||||
'show_ai_rules': True,
|
||||
'errors': None }))
|
||||
response.headers['HX-Retarget'] = '#folder-modal'
|
||||
response.headers['HX-Reswap'] = 'outerHTML'
|
||||
return response
|
||||
@@ -235,7 +240,10 @@ def update_folder(folder_id):
|
||||
|
||||
# If there are validation errors, return the modal with errors
|
||||
if errors:
|
||||
response = make_response(render_template('partials/folder_modal.html', folder=folder, errors=errors, name=name, rule_text=rule_text, priority=priority))
|
||||
response = make_response(render_template('partials/folder_modal.html', folder=folder, errors=errors, name=name, rule_text=rule_text, priority=priority,
|
||||
folder_data={'rule_text': folder.rule_text,
|
||||
'show_ai_rules': True,
|
||||
'errors': None }))
|
||||
return response
|
||||
|
||||
# Update folder
|
||||
@@ -263,7 +271,10 @@ def update_folder(folder_id):
|
||||
db.session.rollback()
|
||||
# Return error in modal
|
||||
errors = {'general': 'An unexpected error occurred. Please try again.'}
|
||||
response = make_response(render_template('partials/folder_modal.html', folder=folder, errors=errors, name=name, rule_text=rule_text, priority=priority))
|
||||
response = make_response(render_template('partials/folder_modal.html', folder=folder, errors=errors, name=name, rule_text=rule_text, priority=priority,
|
||||
folder_data={'rule_text': folder.rule_text,
|
||||
'show_ai_rules': True,
|
||||
'errors': None }))
|
||||
response.headers['HX-Retarget'] = '#folder-modal'
|
||||
response.headers['HX-Reswap'] = 'outerHTML'
|
||||
return response
|
||||
@@ -365,79 +376,41 @@ def generate_rule():
|
||||
return render_template('partials/ai_rule_result.html', result=result)
|
||||
|
||||
# Generate new rule using AI service
|
||||
if rule_type == 'single':
|
||||
rule_text, metadata = ai_service.generate_single_rule(folder_name, folder_type, rule_text)
|
||||
|
||||
if rule_text is None:
|
||||
# AI service failed, return fallback
|
||||
fallback_rule = ai_service.get_fallback_rule(folder_name, folder_type)
|
||||
result = {
|
||||
'success': True,
|
||||
'fallback': True,
|
||||
'rule': fallback_rule,
|
||||
'quality_score': 50,
|
||||
'message': 'AI service unavailable, using fallback rule'
|
||||
}
|
||||
return render_template('partials/ai_rule_result.html', result=result)
|
||||
|
||||
# Cache the result
|
||||
expires_at = datetime.utcnow() + timedelta(hours=1) # Cache for 1 hour
|
||||
cache_entry = AIRuleCache(
|
||||
user_id=current_user.id,
|
||||
folder_name=folder_name,
|
||||
folder_type=folder_type,
|
||||
rule_text=rule_text,
|
||||
rule_metadata=metadata,
|
||||
cache_key=cache_key,
|
||||
expires_at=expires_at
|
||||
)
|
||||
db.session.add(cache_entry)
|
||||
|
||||
db.session.commit()
|
||||
|
||||
# Only support multiple rules now
|
||||
rules, metadata = ai_service.generate_multiple_rules(folder_name, folder_type, rule_text)
|
||||
|
||||
if rules is None:
|
||||
# AI service failed, return fallback
|
||||
fallback_rule = ai_service.get_fallback_rule(folder_name, folder_type)
|
||||
result = {
|
||||
'success': True,
|
||||
'rule': rule_text,
|
||||
'metadata': metadata,
|
||||
'quality_score': metadata.get('quality_score', 0)
|
||||
'fallback': True,
|
||||
'rules': [{'text': fallback_rule, 'quality_score': 50}],
|
||||
'message': 'AI service unavailable, using fallback rule'
|
||||
}
|
||||
return render_template('partials/ai_rule_result.html', result=result)
|
||||
|
||||
else: # multiple rules
|
||||
rules, metadata = ai_service.generate_multiple_rules(folder_name, folder_type, rule_text)
|
||||
|
||||
if rules is None:
|
||||
# AI service failed, return fallback
|
||||
fallback_rule = ai_service.get_fallback_rule(folder_name, folder_type)
|
||||
result = {
|
||||
'success': True,
|
||||
'fallback': True,
|
||||
'rules': [{'text': fallback_rule, 'quality_score': 50}],
|
||||
'message': 'AI service unavailable, using fallback rule'
|
||||
}
|
||||
return render_template('partials/ai_rule_result.html', result=result)
|
||||
|
||||
# Cache the first rule as representative
|
||||
expires_at = datetime.utcnow() + timedelta(hours=1)
|
||||
cache_entry = AIRuleCache(
|
||||
user_id=current_user.id,
|
||||
folder_name=folder_name,
|
||||
folder_type=folder_type,
|
||||
rule_text=rules[0]['text'] if rules else '',
|
||||
rule_metadata=metadata,
|
||||
cache_key=cache_key,
|
||||
expires_at=expires_at
|
||||
)
|
||||
db.session.add(cache_entry)
|
||||
|
||||
db.session.commit()
|
||||
|
||||
result = {
|
||||
'success': True,
|
||||
'rules': rules,
|
||||
'metadata': metadata
|
||||
}
|
||||
return render_template('partials/ai_rule_result.html', result=result)
|
||||
# Cache the first rule as representative
|
||||
expires_at = datetime.utcnow() + timedelta(hours=1)
|
||||
cache_entry = AIRuleCache(
|
||||
user_id=current_user.id,
|
||||
folder_name=folder_name,
|
||||
folder_type=folder_type,
|
||||
rule_text=rules[0]['text'] if rules else '',
|
||||
rule_metadata=metadata,
|
||||
cache_key=cache_key,
|
||||
expires_at=expires_at
|
||||
)
|
||||
db.session.add(cache_entry)
|
||||
|
||||
db.session.commit()
|
||||
|
||||
result = {
|
||||
'success': True,
|
||||
'rules': rules,
|
||||
'metadata': metadata
|
||||
}
|
||||
return render_template('partials/ai_rule_result.html', result=result)
|
||||
|
||||
except Exception as e:
|
||||
# Print unhandled exceptions to the console as required
|
||||
|
||||
@@ -63,7 +63,7 @@ x-data='{{ folder_data|tojson }}'
|
||||
placeholder="e.g., Move emails from 'newsletter@company.com' to this folder"
|
||||
required
|
||||
x-model="rule_text"
|
||||
>{% if rule_text is defined %}{{ rule_text }}{% elif folder %}{{ folder.rule_text }}{% endif %}</textarea>
|
||||
></textarea>
|
||||
{% if errors and errors.rule_text %}
|
||||
<div class="text-error text-sm mt-1">{{ errors.rule_text }}</div>
|
||||
{% endif %}
|
||||
|
||||
Reference in New Issue
Block a user