mirror of
https://github.com/dgtlmoon/changedetection.io.git
synced 2026-08-23 14:46:59 +00:00
feature: allow a watch or group to append to the inherited AI Change Summary prompt (#4294)
Build and push containers / metadata (push) Canceled after 0s
Build and push containers / build-push-containers (push) Canceled after 0s
Publish Python 🐍distribution 📦 to PyPI and TestPyPI / Build distribution 📦 (push) Canceled after 0s
ChangeDetection.io Container Build Test / Build linux/amd64 (alpine) (push) Canceled after 0s
ChangeDetection.io Container Build Test / Build linux/arm64 (alpine) (push) Canceled after 0s
ChangeDetection.io Container Build Test / Build linux/amd64 (main) (push) Canceled after 0s
ChangeDetection.io Container Build Test / Build linux/arm/v7 (main) (push) Canceled after 0s
ChangeDetection.io Container Build Test / Build linux/arm/v8 (main) (push) Canceled after 0s
ChangeDetection.io Container Build Test / Build linux/arm64 (main) (push) Canceled after 0s
ChangeDetection.io App Test / lint-code (push) Canceled after 0s
ChangeDetection.io App Test / lint-translations (push) Canceled after 0s
ChangeDetection.io App Test / lint-template-i18n (push) Canceled after 0s
Publish Python 🐍distribution 📦 to PyPI and TestPyPI / Test the built package works basically. (push) Canceled after 0s
Publish Python 🐍distribution 📦 to PyPI and TestPyPI / Publish Python 🐍 distribution 📦 to PyPI (push) Canceled after 0s
ChangeDetection.io App Test / test-application-3-10 (push) Canceled after 0s
ChangeDetection.io App Test / test-application-3-11 (push) Canceled after 0s
ChangeDetection.io App Test / test-application-3-12 (push) Canceled after 0s
ChangeDetection.io App Test / test-application-3-13 (push) Canceled after 0s
ChangeDetection.io App Test / test-application-3-14 (push) Canceled after 0s
Build and push containers / metadata (push) Canceled after 0s
Build and push containers / build-push-containers (push) Canceled after 0s
Publish Python 🐍distribution 📦 to PyPI and TestPyPI / Build distribution 📦 (push) Canceled after 0s
ChangeDetection.io Container Build Test / Build linux/amd64 (alpine) (push) Canceled after 0s
ChangeDetection.io Container Build Test / Build linux/arm64 (alpine) (push) Canceled after 0s
ChangeDetection.io Container Build Test / Build linux/amd64 (main) (push) Canceled after 0s
ChangeDetection.io Container Build Test / Build linux/arm/v7 (main) (push) Canceled after 0s
ChangeDetection.io Container Build Test / Build linux/arm/v8 (main) (push) Canceled after 0s
ChangeDetection.io Container Build Test / Build linux/arm64 (main) (push) Canceled after 0s
ChangeDetection.io App Test / lint-code (push) Canceled after 0s
ChangeDetection.io App Test / lint-translations (push) Canceled after 0s
ChangeDetection.io App Test / lint-template-i18n (push) Canceled after 0s
Publish Python 🐍distribution 📦 to PyPI and TestPyPI / Test the built package works basically. (push) Canceled after 0s
Publish Python 🐍distribution 📦 to PyPI and TestPyPI / Publish Python 🐍 distribution 📦 to PyPI (push) Canceled after 0s
ChangeDetection.io App Test / test-application-3-10 (push) Canceled after 0s
ChangeDetection.io App Test / test-application-3-11 (push) Canceled after 0s
ChangeDetection.io App Test / test-application-3-12 (push) Canceled after 0s
ChangeDetection.io App Test / test-application-3-13 (push) Canceled after 0s
ChangeDetection.io App Test / test-application-3-14 (push) Canceled after 0s
Co-authored-by: snowyukitty <270071858+snowyukitty@users.noreply.github.com> Co-authored-by: dgtlmoon <dgtlmoon@gmail.com>
This commit is contained in:
co-authored by
snowyukitty
dgtlmoon
parent
6b9040256a
commit
01cf56c8fb
@@ -1,5 +1,6 @@
|
||||
from wtforms import (
|
||||
Form,
|
||||
RadioField,
|
||||
StringField,
|
||||
SubmitField,
|
||||
TextAreaField,
|
||||
@@ -10,7 +11,11 @@ from flask_babel import lazy_gettext as _l
|
||||
|
||||
from changedetectionio.processors.restock_diff.forms import processor_settings_form as restock_settings_form
|
||||
from changedetectionio.llm.ui_strings import LLM_INTENT_TAG_PLACEHOLDER
|
||||
from changedetectionio.llm.evaluator import DEFAULT_CHANGE_SUMMARY_PROMPT
|
||||
from changedetectionio.llm.evaluator import (
|
||||
DEFAULT_CHANGE_SUMMARY_PROMPT,
|
||||
LLM_PROMPT_MODE_APPEND,
|
||||
LLM_PROMPT_MODE_REPLACE,
|
||||
)
|
||||
|
||||
class group_restock_settings_form(restock_settings_form):
|
||||
overrides_watch = BooleanField(_l('Activate for individual watches in this tag/group?'), default=False)
|
||||
@@ -26,6 +31,15 @@ class group_restock_settings_form(restock_settings_form):
|
||||
render_kw={"rows": "5", "placeholder": DEFAULT_CHANGE_SUMMARY_PROMPT},
|
||||
default='')
|
||||
|
||||
llm_change_summary_mode = RadioField(
|
||||
_l('How this prompt combines with the inherited one'),
|
||||
choices=[
|
||||
(LLM_PROMPT_MODE_REPLACE, _l('Replace the inherited prompt')),
|
||||
(LLM_PROMPT_MODE_APPEND, _l('Append to the inherited prompt')),
|
||||
],
|
||||
default=LLM_PROMPT_MODE_REPLACE,
|
||||
)
|
||||
|
||||
class SingleTag(Form):
|
||||
|
||||
name = StringField(_l('Tag name'), [validators.InputRequired()], render_kw={"placeholder": _l("Name")})
|
||||
|
||||
@@ -6,7 +6,13 @@ from flask_babel import lazy_gettext as _l, gettext
|
||||
|
||||
from changedetectionio.blueprint.rss import RSS_FORMAT_TYPES, RSS_TEMPLATE_TYPE_OPTIONS, RSS_TEMPLATE_HTML_DEFAULT
|
||||
from changedetectionio.llm.ui_strings import LLM_INTENT_WATCH_PLACEHOLDER
|
||||
from changedetectionio.llm.evaluator import DEFAULT_CHANGE_SUMMARY_PROMPT, LLM_DEFAULT_MAX_SUMMARY_TOKENS, LLM_DEFAULT_THINKING_BUDGET
|
||||
from changedetectionio.llm.evaluator import (
|
||||
DEFAULT_CHANGE_SUMMARY_PROMPT,
|
||||
LLM_DEFAULT_MAX_SUMMARY_TOKENS,
|
||||
LLM_DEFAULT_THINKING_BUDGET,
|
||||
LLM_PROMPT_MODE_APPEND,
|
||||
LLM_PROMPT_MODE_REPLACE,
|
||||
)
|
||||
from changedetectionio.conditions.form import ConditionFormRow
|
||||
from changedetectionio.notification_service import NotificationContextData
|
||||
from changedetectionio.strtobool import strtobool
|
||||
@@ -886,6 +892,15 @@ class processor_text_json_diff_form(commonSettingsForm):
|
||||
render_kw={"rows": "5", "placeholder": DEFAULT_CHANGE_SUMMARY_PROMPT},
|
||||
default='')
|
||||
|
||||
llm_change_summary_mode = RadioField(
|
||||
_l('How this prompt combines with the inherited one'),
|
||||
choices=[
|
||||
(LLM_PROMPT_MODE_REPLACE, _l('Replace the inherited prompt')),
|
||||
(LLM_PROMPT_MODE_APPEND, _l('Append to the inherited prompt')),
|
||||
],
|
||||
default=LLM_PROMPT_MODE_REPLACE,
|
||||
)
|
||||
|
||||
include_filters = StringListField(_l('CSS/JSONPath/JQ/XPath Filters'), [ValidateCSSJSONXPATHInput()], default='')
|
||||
|
||||
subtractive_selectors = StringListField(_l('Remove elements'), [ValidateCSSJSONXPATHInput(allow_json=False)])
|
||||
|
||||
@@ -149,6 +149,13 @@ DEFAULT_CHANGE_SUMMARY_PROMPT = (
|
||||
"Do not give partial listings such as 'Examples include:', always be thorough."
|
||||
)
|
||||
|
||||
# How a watch's or tag's llm_change_summary combines with the prompt it inherits.
|
||||
# 'replace' is the default and the historical behaviour; 'append' lets a watch add a line
|
||||
# or two to the inherited prompt instead of holding a full private copy of it, so later
|
||||
# edits to the global prompt still reach that watch. Re #4251.
|
||||
LLM_PROMPT_MODE_REPLACE = 'replace'
|
||||
LLM_PROMPT_MODE_APPEND = 'append'
|
||||
|
||||
|
||||
def _summary_max_tokens(diff: str, max_cap: int = LLM_DEFAULT_MAX_SUMMARY_TOKENS) -> int:
|
||||
"""Scale completion tokens to diff size: floor 400, ~1 token per 4 chars, ceiling max_cap."""
|
||||
@@ -539,16 +546,54 @@ def run_setup(watch, datastore, snapshot_text: str) -> None:
|
||||
# AI Change Summary — human-readable description of what changed
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def _first_tag_with_field(watch, datastore, field: str):
|
||||
"""Return (value, tag) for the first linked tag with a non-empty `field`, else ('', None).
|
||||
|
||||
Same first-match-wins order as resolve_llm_field(); this variant also hands back the
|
||||
tag itself so the caller can read sibling keys such as the prompt mode.
|
||||
"""
|
||||
for tag_uuid in watch.get('tags', []):
|
||||
tag = datastore.data['settings']['application'].get('tags', {}).get(tag_uuid)
|
||||
if tag:
|
||||
value = (tag.get(field) or '').strip()
|
||||
if value:
|
||||
return value, tag
|
||||
return '', None
|
||||
|
||||
|
||||
def _apply_prompt_layer(inherited: str, value: str, mode: str) -> str:
|
||||
"""Fold one cascade level's prompt onto what it inherited.
|
||||
|
||||
'append' keeps the inherited prompt and adds `value` after it, so a watch can add a
|
||||
sentence or two without pinning a private copy of the prompt above it (see #4251).
|
||||
Anything else replaces, which is the historical behaviour and stays the default.
|
||||
"""
|
||||
if not value:
|
||||
return inherited
|
||||
if mode == LLM_PROMPT_MODE_APPEND and inherited:
|
||||
return f"{inherited}\n\n{value}"
|
||||
return value
|
||||
|
||||
|
||||
def get_effective_summary_prompt(watch, datastore) -> str:
|
||||
"""Return the prompt that summarise_change will use.
|
||||
|
||||
Cascade: watch → tag → global settings default → hardcoded fallback.
|
||||
Cascade: hardcoded fallback → global settings default → tag → watch. Each level with a
|
||||
value either replaces what it inherited or appends to it, per its own
|
||||
`llm_change_summary_mode`. With every level left on the default 'replace' this reduces
|
||||
to the original watch → tag → global → hardcoded first-non-empty-wins behaviour.
|
||||
"""
|
||||
prompt, _ = resolve_llm_field(watch, datastore, 'llm_change_summary')
|
||||
if prompt:
|
||||
return prompt
|
||||
global_default = get_llm_settings(datastore).change_summary_default.strip()
|
||||
return global_default or DEFAULT_CHANGE_SUMMARY_PROMPT
|
||||
prompt = get_llm_settings(datastore).change_summary_default.strip() or DEFAULT_CHANGE_SUMMARY_PROMPT
|
||||
|
||||
tag_value, tag = _first_tag_with_field(watch, datastore, 'llm_change_summary')
|
||||
if tag_value:
|
||||
prompt = _apply_prompt_layer(prompt, tag_value, tag.get('llm_change_summary_mode'))
|
||||
|
||||
watch_value = (watch.get('llm_change_summary') or '').strip()
|
||||
if watch_value:
|
||||
prompt = _apply_prompt_layer(prompt, watch_value, watch.get('llm_change_summary_mode'))
|
||||
|
||||
return prompt
|
||||
|
||||
|
||||
def compute_summary_cache_key(diff_text: str, prompt: str) -> str:
|
||||
|
||||
@@ -191,6 +191,7 @@ class watch_base(dict):
|
||||
# LLM intent-based evaluation
|
||||
'llm_intent': '', # Plain-English description of what the user cares about (change filter)
|
||||
'llm_change_summary': '', # Prompt for AI Change Summary — replaces {{ diff }} in notifications
|
||||
'llm_change_summary_mode': 'replace', # 'replace' the inherited prompt, or 'append' to it
|
||||
'llm_prefilter': None, # CSS selector derived at setup time (semantic only, e.g. "footer")
|
||||
'llm_evaluation_cache': {}, # {sha256(intent+diff): {important, summary}} - evaluated once, cached
|
||||
'fetch_backend': 'system', # plaintext, playwright etc
|
||||
|
||||
@@ -97,6 +97,23 @@
|
||||
<div style="margin-top: 0.3em;">
|
||||
<a href="#" class="pure-button button-xsmall" onclick="var t=document.getElementById('llm_change_summary'); if(!t.value&&t.placeholder) t.value=t.placeholder; return false;">{{ _('Modify default prompt') }}</a>
|
||||
</div>
|
||||
<div class="pure-control-group" style="margin-top: 0.6em;">
|
||||
<label>{{ form.llm_change_summary_mode.label.text }}</label>
|
||||
<div>
|
||||
{% for subfield in form.llm_change_summary_mode %}
|
||||
<label class="pure-radio" style="display:block; font-weight:normal; margin-bottom:0.3em;">
|
||||
{{ subfield() }} {{ subfield.label.text }}
|
||||
</label>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<span class="pure-form-message-inline">
|
||||
{% if watch is defined and watch %}
|
||||
{{ _('Appending keeps the prompt inherited from the group or from global settings and adds your text after it, so later edits to that prompt still reach this watch.') }}
|
||||
{% else %}
|
||||
{{ _('Appending keeps the prompt inherited from global settings and adds your text after it, so later edits to that prompt still reach this group.') }}
|
||||
{% endif %}
|
||||
</span>
|
||||
</div>
|
||||
{% if watch is defined and watch %}
|
||||
<div class="pure-form-message-inline">
|
||||
<strong>{{ _('Examples:') }}</strong>
|
||||
|
||||
@@ -556,3 +556,87 @@ class TestSummaryCacheKey:
|
||||
ds = _make_datastore(tags={'t1': tag})
|
||||
watch = _make_watch(llm_change_summary='', tags=['t1'])
|
||||
assert get_effective_summary_prompt(watch, ds) == 'tag-level prompt'
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# llm_change_summary_mode — append vs replace (#4251)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
class TestSummaryPromptAppendMode:
|
||||
"""A watch/tag may add to the prompt it inherits instead of holding a private copy.
|
||||
|
||||
Everything here must leave the legacy 'replace' path byte-identical — that is what
|
||||
the TestSummaryCacheKey cases above pin.
|
||||
"""
|
||||
|
||||
def test_global_default_used_as_base_when_nothing_else_set(self):
|
||||
from changedetectionio.llm.evaluator import get_effective_summary_prompt
|
||||
ds = _make_datastore(llm_cfg={'change_summary_default': 'GLOBAL'})
|
||||
assert get_effective_summary_prompt(_make_watch(), ds) == 'GLOBAL'
|
||||
|
||||
def test_watch_appends_to_global_default(self):
|
||||
from changedetectionio.llm.evaluator import get_effective_summary_prompt
|
||||
ds = _make_datastore(llm_cfg={'change_summary_default': 'GLOBAL'})
|
||||
watch = _make_watch(llm_change_summary='Also mention the SKU.')
|
||||
watch['llm_change_summary_mode'] = 'append'
|
||||
assert get_effective_summary_prompt(watch, ds) == 'GLOBAL\n\nAlso mention the SKU.'
|
||||
|
||||
def test_watch_appends_to_hardcoded_default_when_no_global_set(self):
|
||||
from changedetectionio.llm.evaluator import get_effective_summary_prompt, DEFAULT_CHANGE_SUMMARY_PROMPT
|
||||
ds = _make_datastore()
|
||||
watch = _make_watch(llm_change_summary='Also mention the SKU.')
|
||||
watch['llm_change_summary_mode'] = 'append'
|
||||
result = get_effective_summary_prompt(watch, ds)
|
||||
assert result == f'{DEFAULT_CHANGE_SUMMARY_PROMPT}\n\nAlso mention the SKU.'
|
||||
|
||||
def test_watch_append_targets_the_tag_prompt_when_a_tag_supplies_one(self):
|
||||
"""The watch appends to what it would otherwise have inherited — here the tag."""
|
||||
from changedetectionio.llm.evaluator import get_effective_summary_prompt
|
||||
tag = {'title': 'grp', 'llm_change_summary': 'TAG'}
|
||||
ds = _make_datastore(llm_cfg={'change_summary_default': 'GLOBAL'}, tags={'t1': tag})
|
||||
watch = _make_watch(llm_change_summary='WATCH', tags=['t1'])
|
||||
watch['llm_change_summary_mode'] = 'append'
|
||||
assert get_effective_summary_prompt(watch, ds) == 'TAG\n\nWATCH'
|
||||
|
||||
def test_tag_and_watch_can_both_append_forming_a_chain(self):
|
||||
from changedetectionio.llm.evaluator import get_effective_summary_prompt
|
||||
tag = {'title': 'grp', 'llm_change_summary': 'TAG', 'llm_change_summary_mode': 'append'}
|
||||
ds = _make_datastore(llm_cfg={'change_summary_default': 'GLOBAL'}, tags={'t1': tag})
|
||||
watch = _make_watch(llm_change_summary='WATCH', tags=['t1'])
|
||||
watch['llm_change_summary_mode'] = 'append'
|
||||
assert get_effective_summary_prompt(watch, ds) == 'GLOBAL\n\nTAG\n\nWATCH'
|
||||
|
||||
def test_tag_appends_while_watch_replaces(self):
|
||||
from changedetectionio.llm.evaluator import get_effective_summary_prompt
|
||||
tag = {'title': 'grp', 'llm_change_summary': 'TAG', 'llm_change_summary_mode': 'append'}
|
||||
ds = _make_datastore(llm_cfg={'change_summary_default': 'GLOBAL'}, tags={'t1': tag})
|
||||
watch = _make_watch(llm_change_summary='WATCH', tags=['t1'])
|
||||
assert get_effective_summary_prompt(watch, ds) == 'WATCH'
|
||||
|
||||
def test_append_mode_with_empty_text_changes_nothing(self):
|
||||
from changedetectionio.llm.evaluator import get_effective_summary_prompt
|
||||
ds = _make_datastore(llm_cfg={'change_summary_default': 'GLOBAL'})
|
||||
watch = _make_watch(llm_change_summary='')
|
||||
watch['llm_change_summary_mode'] = 'append'
|
||||
assert get_effective_summary_prompt(watch, ds) == 'GLOBAL'
|
||||
|
||||
def test_missing_mode_key_behaves_as_replace(self):
|
||||
"""Watches stored before this feature have no mode key at all."""
|
||||
from changedetectionio.llm.evaluator import get_effective_summary_prompt
|
||||
ds = _make_datastore(llm_cfg={'change_summary_default': 'GLOBAL'})
|
||||
watch = _make_watch(llm_change_summary='WATCH')
|
||||
assert 'llm_change_summary_mode' not in watch
|
||||
assert get_effective_summary_prompt(watch, ds) == 'WATCH'
|
||||
|
||||
def test_append_changes_the_cache_key(self):
|
||||
"""Toggling the mode must invalidate cached summaries, not silently reuse them."""
|
||||
from changedetectionio.llm.evaluator import get_effective_summary_prompt, compute_summary_cache_key
|
||||
ds = _make_datastore(llm_cfg={'change_summary_default': 'GLOBAL'})
|
||||
|
||||
replacing = _make_watch(llm_change_summary='WATCH')
|
||||
appending = _make_watch(llm_change_summary='WATCH')
|
||||
appending['llm_change_summary_mode'] = 'append'
|
||||
|
||||
key_replace = compute_summary_cache_key('diff', get_effective_summary_prompt(replacing, ds))
|
||||
key_append = compute_summary_cache_key('diff', get_effective_summary_prompt(appending, ds))
|
||||
assert key_replace != key_append
|
||||
|
||||
@@ -319,6 +319,99 @@ def test_watch_prompt_overrides_tag_and_global(
|
||||
delete_all_watches(client)
|
||||
|
||||
|
||||
def test_append_mode_saved_via_edit_form_and_applied(
|
||||
client, live_server, measure_memory_usage, datastore_path):
|
||||
"""
|
||||
Choosing "add to the end of the inherited prompt" in the watch edit form persists,
|
||||
and the watch's text is then appended to the global default rather than replacing it.
|
||||
Re #4251.
|
||||
"""
|
||||
from changedetectionio.llm.evaluator import get_effective_summary_prompt
|
||||
|
||||
_set_response(datastore_path, HTML_V1)
|
||||
_configure_llm(client)
|
||||
ds = client.application.config.get('DATASTORE')
|
||||
_set_global_default(ds, 'Global: summarise as one sentence.')
|
||||
|
||||
test_url = url_for('test_endpoint', _external=True)
|
||||
uuid = ds.add_watch(url=test_url)
|
||||
|
||||
res = client.post(
|
||||
url_for("ui.ui_edit.edit_page", uuid=uuid),
|
||||
data={
|
||||
"url": test_url,
|
||||
"fetch_backend": "html_requests",
|
||||
"time_between_check_use_default": "y",
|
||||
"llm_change_summary": "Also flag anything mentioning a recall.",
|
||||
"llm_change_summary_mode": "append",
|
||||
},
|
||||
follow_redirects=True,
|
||||
)
|
||||
assert b"Updated watch." in res.data
|
||||
|
||||
watch = ds.data['watching'][uuid]
|
||||
assert watch.get('llm_change_summary_mode') == 'append'
|
||||
assert get_effective_summary_prompt(watch, ds) == (
|
||||
'Global: summarise as one sentence.\n\nAlso flag anything mentioning a recall.'
|
||||
)
|
||||
|
||||
delete_all_watches(client)
|
||||
|
||||
|
||||
def test_edit_form_defaults_to_replace_preserving_old_behaviour(
|
||||
client, live_server, measure_memory_usage, datastore_path):
|
||||
"""
|
||||
A form submitted without the mode field (the pre-#4251 shape) must still replace,
|
||||
so upgrading does not silently change what existing watches send to the LLM.
|
||||
"""
|
||||
from changedetectionio.llm.evaluator import get_effective_summary_prompt
|
||||
|
||||
_set_response(datastore_path, HTML_V1)
|
||||
_configure_llm(client)
|
||||
ds = client.application.config.get('DATASTORE')
|
||||
_set_global_default(ds, 'Global: summarise as one sentence.')
|
||||
|
||||
test_url = url_for('test_endpoint', _external=True)
|
||||
uuid = ds.add_watch(url=test_url)
|
||||
|
||||
res = client.post(
|
||||
url_for("ui.ui_edit.edit_page", uuid=uuid),
|
||||
data={
|
||||
"url": test_url,
|
||||
"fetch_backend": "html_requests",
|
||||
"time_between_check_use_default": "y",
|
||||
"llm_change_summary": "Only tell me the new price.",
|
||||
},
|
||||
follow_redirects=True,
|
||||
)
|
||||
assert b"Updated watch." in res.data
|
||||
|
||||
watch = ds.data['watching'][uuid]
|
||||
assert get_effective_summary_prompt(watch, ds) == 'Only tell me the new price.'
|
||||
|
||||
delete_all_watches(client)
|
||||
|
||||
|
||||
def test_edit_page_renders_the_prompt_mode_radio(
|
||||
client, live_server, measure_memory_usage, datastore_path):
|
||||
"""Both radio options must be present on the watch edit page."""
|
||||
_set_response(datastore_path, HTML_V1)
|
||||
_configure_llm(client)
|
||||
ds = client.application.config.get('DATASTORE')
|
||||
|
||||
test_url = url_for('test_endpoint', _external=True)
|
||||
uuid = ds.add_watch(url=test_url)
|
||||
|
||||
res = client.get(url_for("ui.ui_edit.edit_page", uuid=uuid))
|
||||
body = res.data.decode('utf-8', errors='replace')
|
||||
|
||||
assert 'name="llm_change_summary_mode"' in body
|
||||
assert 'value="replace"' in body
|
||||
assert 'value="append"' in body
|
||||
|
||||
delete_all_watches(client)
|
||||
|
||||
|
||||
def test_hardcoded_fallback_when_nothing_set(
|
||||
client, live_server, measure_memory_usage, datastore_path):
|
||||
"""
|
||||
|
||||
@@ -382,3 +382,49 @@ def test_tag_edit_page_shows_ai_section(
|
||||
f"{field} must not be readonly in tag edit context; snippet: {snippet!r}"
|
||||
|
||||
delete_all_watches(client)
|
||||
|
||||
|
||||
def test_tag_edit_page_shows_prompt_mode_radio(
|
||||
client, live_server, measure_memory_usage, datastore_path):
|
||||
"""
|
||||
A group must also be able to append to the global prompt rather than replace it,
|
||||
so the mode radio has to render on the tag edit page too. Re #4251.
|
||||
"""
|
||||
ds = client.application.config.get('DATASTORE')
|
||||
_configure_llm(ds)
|
||||
|
||||
tag_uuid = ds.add_tag('Append Group')
|
||||
|
||||
res = client.get(url_for('tags.form_tag_edit', uuid=tag_uuid))
|
||||
assert res.status_code == 200
|
||||
body = res.data.decode('utf-8', errors='replace')
|
||||
|
||||
assert 'name="llm_change_summary_mode"' in body, \
|
||||
"prompt mode radio missing from tag edit page"
|
||||
assert 'value="replace"' in body
|
||||
assert 'value="append"' in body
|
||||
|
||||
delete_all_watches(client)
|
||||
|
||||
|
||||
def test_tag_append_mode_persists_and_applies(
|
||||
client, live_server, measure_memory_usage, datastore_path):
|
||||
"""A group set to append adds its text to the global prompt for its watches."""
|
||||
from changedetectionio.llm.evaluator import get_effective_summary_prompt
|
||||
|
||||
ds = client.application.config.get('DATASTORE')
|
||||
_configure_llm(ds)
|
||||
ds.data['settings']['application']['llm']['change_summary_default'] = 'GLOBAL RULES'
|
||||
|
||||
api_token = _api_token(client)
|
||||
test_url = url_for('test_endpoint', _external=True)
|
||||
watch_uuid = _create_watch(client, test_url, api_token)
|
||||
|
||||
tag_uuid = _add_tag_with_llm(ds, 'Append Group', llm_change_summary='Group extra line.')
|
||||
ds.data['settings']['application']['tags'][tag_uuid]['llm_change_summary_mode'] = 'append'
|
||||
_link_watch_to_tag(ds, watch_uuid, tag_uuid)
|
||||
|
||||
watch = ds.data['watching'][watch_uuid]
|
||||
assert get_effective_summary_prompt(watch, ds) == 'GLOBAL RULES\n\nGroup extra line.'
|
||||
|
||||
delete_all_watches(client)
|
||||
|
||||
@@ -3162,6 +3162,18 @@ msgstr "AI záměr změny"
|
||||
msgid "AI Change Summary"
|
||||
msgstr "AI souhrn změny"
|
||||
|
||||
#: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py
|
||||
msgid "How this prompt combines with the inherited one"
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py
|
||||
msgid "Replace the inherited prompt"
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py
|
||||
msgid "Append to the inherited prompt"
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/forms.py
|
||||
msgid "CSS/JSONPath/JQ/XPath Filters"
|
||||
msgstr "CSS/JSONPath/JQ/xPath filtry"
|
||||
@@ -4555,6 +4567,18 @@ msgstr ""
|
||||
msgid "Describe how changes should be summarised in notifications for all watches in this group."
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/templates/edit/include_llm_intent.html
|
||||
msgid ""
|
||||
"Appending keeps the prompt inherited from the group or from global settings and adds your text after it, so later "
|
||||
"edits to that prompt still reach this watch."
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/templates/edit/include_llm_intent.html
|
||||
msgid ""
|
||||
"Appending keeps the prompt inherited from global settings and adds your text after it, so later edits to that prompt "
|
||||
"still reach this group."
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/templates/edit/include_llm_intent.html
|
||||
msgid "List each new item added with its name and price. Translate to English."
|
||||
msgstr ""
|
||||
|
||||
@@ -3211,6 +3211,18 @@ msgstr ""
|
||||
msgid "AI Change Summary"
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py
|
||||
msgid "How this prompt combines with the inherited one"
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py
|
||||
msgid "Replace the inherited prompt"
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py
|
||||
msgid "Append to the inherited prompt"
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/forms.py
|
||||
msgid "CSS/JSONPath/JQ/XPath Filters"
|
||||
msgstr "CSS/xPath-Filter"
|
||||
@@ -4609,6 +4621,18 @@ msgstr ""
|
||||
msgid "Describe how changes should be summarised in notifications for all watches in this group."
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/templates/edit/include_llm_intent.html
|
||||
msgid ""
|
||||
"Appending keeps the prompt inherited from the group or from global settings and adds your text after it, so later "
|
||||
"edits to that prompt still reach this watch."
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/templates/edit/include_llm_intent.html
|
||||
msgid ""
|
||||
"Appending keeps the prompt inherited from global settings and adds your text after it, so later edits to that prompt "
|
||||
"still reach this group."
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/templates/edit/include_llm_intent.html
|
||||
msgid "List each new item added with its name and price. Translate to English."
|
||||
msgstr ""
|
||||
|
||||
@@ -3154,6 +3154,18 @@ msgstr ""
|
||||
msgid "AI Change Summary"
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py
|
||||
msgid "How this prompt combines with the inherited one"
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py
|
||||
msgid "Replace the inherited prompt"
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py
|
||||
msgid "Append to the inherited prompt"
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/forms.py
|
||||
msgid "CSS/JSONPath/JQ/XPath Filters"
|
||||
msgstr ""
|
||||
@@ -4547,6 +4559,18 @@ msgstr ""
|
||||
msgid "Describe how changes should be summarised in notifications for all watches in this group."
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/templates/edit/include_llm_intent.html
|
||||
msgid ""
|
||||
"Appending keeps the prompt inherited from the group or from global settings and adds your text after it, so later "
|
||||
"edits to that prompt still reach this watch."
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/templates/edit/include_llm_intent.html
|
||||
msgid ""
|
||||
"Appending keeps the prompt inherited from global settings and adds your text after it, so later edits to that prompt "
|
||||
"still reach this group."
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/templates/edit/include_llm_intent.html
|
||||
msgid "List each new item added with its name and price. Translate to English."
|
||||
msgstr ""
|
||||
|
||||
@@ -3154,6 +3154,18 @@ msgstr ""
|
||||
msgid "AI Change Summary"
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py
|
||||
msgid "How this prompt combines with the inherited one"
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py
|
||||
msgid "Replace the inherited prompt"
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py
|
||||
msgid "Append to the inherited prompt"
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/forms.py
|
||||
msgid "CSS/JSONPath/JQ/XPath Filters"
|
||||
msgstr ""
|
||||
@@ -4547,6 +4559,18 @@ msgstr ""
|
||||
msgid "Describe how changes should be summarised in notifications for all watches in this group."
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/templates/edit/include_llm_intent.html
|
||||
msgid ""
|
||||
"Appending keeps the prompt inherited from the group or from global settings and adds your text after it, so later "
|
||||
"edits to that prompt still reach this watch."
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/templates/edit/include_llm_intent.html
|
||||
msgid ""
|
||||
"Appending keeps the prompt inherited from global settings and adds your text after it, so later edits to that prompt "
|
||||
"still reach this group."
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/templates/edit/include_llm_intent.html
|
||||
msgid "List each new item added with its name and price. Translate to English."
|
||||
msgstr ""
|
||||
|
||||
@@ -3227,6 +3227,18 @@ msgstr ""
|
||||
msgid "AI Change Summary"
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py
|
||||
msgid "How this prompt combines with the inherited one"
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py
|
||||
msgid "Replace the inherited prompt"
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py
|
||||
msgid "Append to the inherited prompt"
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/forms.py
|
||||
msgid "CSS/JSONPath/JQ/XPath Filters"
|
||||
msgstr "Filtros CSS/JSONPath/JQ/XPath"
|
||||
@@ -4624,6 +4636,18 @@ msgstr ""
|
||||
msgid "Describe how changes should be summarised in notifications for all watches in this group."
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/templates/edit/include_llm_intent.html
|
||||
msgid ""
|
||||
"Appending keeps the prompt inherited from the group or from global settings and adds your text after it, so later "
|
||||
"edits to that prompt still reach this watch."
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/templates/edit/include_llm_intent.html
|
||||
msgid ""
|
||||
"Appending keeps the prompt inherited from global settings and adds your text after it, so later edits to that prompt "
|
||||
"still reach this group."
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/templates/edit/include_llm_intent.html
|
||||
msgid "List each new item added with its name and price. Translate to English."
|
||||
msgstr ""
|
||||
|
||||
@@ -3167,6 +3167,18 @@ msgstr ""
|
||||
msgid "AI Change Summary"
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py
|
||||
msgid "How this prompt combines with the inherited one"
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py
|
||||
msgid "Replace the inherited prompt"
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py
|
||||
msgid "Append to the inherited prompt"
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/forms.py
|
||||
msgid "CSS/JSONPath/JQ/XPath Filters"
|
||||
msgstr "Filtre CSS/JSONPath/JQ/XPath"
|
||||
@@ -4562,6 +4574,18 @@ msgstr ""
|
||||
msgid "Describe how changes should be summarised in notifications for all watches in this group."
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/templates/edit/include_llm_intent.html
|
||||
msgid ""
|
||||
"Appending keeps the prompt inherited from the group or from global settings and adds your text after it, so later "
|
||||
"edits to that prompt still reach this watch."
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/templates/edit/include_llm_intent.html
|
||||
msgid ""
|
||||
"Appending keeps the prompt inherited from global settings and adds your text after it, so later edits to that prompt "
|
||||
"still reach this group."
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/templates/edit/include_llm_intent.html
|
||||
msgid "List each new item added with its name and price. Translate to English."
|
||||
msgstr ""
|
||||
|
||||
@@ -3156,6 +3156,18 @@ msgstr ""
|
||||
msgid "AI Change Summary"
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py
|
||||
msgid "How this prompt combines with the inherited one"
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py
|
||||
msgid "Replace the inherited prompt"
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py
|
||||
msgid "Append to the inherited prompt"
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/forms.py
|
||||
msgid "CSS/JSONPath/JQ/XPath Filters"
|
||||
msgstr "Filtri CSS/JSONPath/JQ/XPath"
|
||||
@@ -4549,6 +4561,18 @@ msgstr ""
|
||||
msgid "Describe how changes should be summarised in notifications for all watches in this group."
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/templates/edit/include_llm_intent.html
|
||||
msgid ""
|
||||
"Appending keeps the prompt inherited from the group or from global settings and adds your text after it, so later "
|
||||
"edits to that prompt still reach this watch."
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/templates/edit/include_llm_intent.html
|
||||
msgid ""
|
||||
"Appending keeps the prompt inherited from global settings and adds your text after it, so later edits to that prompt "
|
||||
"still reach this group."
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/templates/edit/include_llm_intent.html
|
||||
msgid "List each new item added with its name and price. Translate to English."
|
||||
msgstr ""
|
||||
|
||||
@@ -3173,6 +3173,18 @@ msgstr ""
|
||||
msgid "AI Change Summary"
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py
|
||||
msgid "How this prompt combines with the inherited one"
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py
|
||||
msgid "Replace the inherited prompt"
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py
|
||||
msgid "Append to the inherited prompt"
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/forms.py
|
||||
msgid "CSS/JSONPath/JQ/XPath Filters"
|
||||
msgstr "CSS/JSONPath/JQ/XPath フィルタ"
|
||||
@@ -4580,6 +4592,18 @@ msgstr ""
|
||||
msgid "Describe how changes should be summarised in notifications for all watches in this group."
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/templates/edit/include_llm_intent.html
|
||||
msgid ""
|
||||
"Appending keeps the prompt inherited from the group or from global settings and adds your text after it, so later "
|
||||
"edits to that prompt still reach this watch."
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/templates/edit/include_llm_intent.html
|
||||
msgid ""
|
||||
"Appending keeps the prompt inherited from global settings and adds your text after it, so later edits to that prompt "
|
||||
"still reach this group."
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/templates/edit/include_llm_intent.html
|
||||
msgid "List each new item added with its name and price. Translate to English."
|
||||
msgstr ""
|
||||
|
||||
@@ -3164,6 +3164,18 @@ msgstr "AI 판단 기준"
|
||||
msgid "AI Change Summary"
|
||||
msgstr "AI 변경 요약"
|
||||
|
||||
#: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py
|
||||
msgid "How this prompt combines with the inherited one"
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py
|
||||
msgid "Replace the inherited prompt"
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py
|
||||
msgid "Append to the inherited prompt"
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/forms.py
|
||||
msgid "CSS/JSONPath/JQ/XPath Filters"
|
||||
msgstr "CSS/JSONPath/JQ/XPath 필터"
|
||||
@@ -4557,6 +4569,18 @@ msgstr "변경이 감지되면 AI가 지시에 따라 이를 설명하고 알림
|
||||
msgid "Describe how changes should be summarised in notifications for all watches in this group."
|
||||
msgstr "이 그룹의 모든 모니터링 알림에서 변경 사항을 어떻게 요약할지 설명하세요."
|
||||
|
||||
#: changedetectionio/templates/edit/include_llm_intent.html
|
||||
msgid ""
|
||||
"Appending keeps the prompt inherited from the group or from global settings and adds your text after it, so later "
|
||||
"edits to that prompt still reach this watch."
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/templates/edit/include_llm_intent.html
|
||||
msgid ""
|
||||
"Appending keeps the prompt inherited from global settings and adds your text after it, so later edits to that prompt "
|
||||
"still reach this group."
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/templates/edit/include_llm_intent.html
|
||||
msgid "List each new item added with its name and price. Translate to English."
|
||||
msgstr "추가된 각 새 항목을 이름과 가격과 함께 나열하세요. 영어로 번역하세요."
|
||||
|
||||
@@ -3153,6 +3153,18 @@ msgstr ""
|
||||
msgid "AI Change Summary"
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py
|
||||
msgid "How this prompt combines with the inherited one"
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py
|
||||
msgid "Replace the inherited prompt"
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py
|
||||
msgid "Append to the inherited prompt"
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/forms.py
|
||||
msgid "CSS/JSONPath/JQ/XPath Filters"
|
||||
msgstr ""
|
||||
@@ -4546,6 +4558,18 @@ msgstr ""
|
||||
msgid "Describe how changes should be summarised in notifications for all watches in this group."
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/templates/edit/include_llm_intent.html
|
||||
msgid ""
|
||||
"Appending keeps the prompt inherited from the group or from global settings and adds your text after it, so later "
|
||||
"edits to that prompt still reach this watch."
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/templates/edit/include_llm_intent.html
|
||||
msgid ""
|
||||
"Appending keeps the prompt inherited from global settings and adds your text after it, so later edits to that prompt "
|
||||
"still reach this group."
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/templates/edit/include_llm_intent.html
|
||||
msgid "List each new item added with its name and price. Translate to English."
|
||||
msgstr ""
|
||||
|
||||
@@ -3204,6 +3204,18 @@ msgstr ""
|
||||
msgid "AI Change Summary"
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py
|
||||
msgid "How this prompt combines with the inherited one"
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py
|
||||
msgid "Replace the inherited prompt"
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py
|
||||
msgid "Append to the inherited prompt"
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/forms.py
|
||||
msgid "CSS/JSONPath/JQ/XPath Filters"
|
||||
msgstr "Filtros CSS/JSONPath/JQ/XPath"
|
||||
@@ -4599,6 +4611,18 @@ msgstr ""
|
||||
msgid "Describe how changes should be summarised in notifications for all watches in this group."
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/templates/edit/include_llm_intent.html
|
||||
msgid ""
|
||||
"Appending keeps the prompt inherited from the group or from global settings and adds your text after it, so later "
|
||||
"edits to that prompt still reach this watch."
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/templates/edit/include_llm_intent.html
|
||||
msgid ""
|
||||
"Appending keeps the prompt inherited from global settings and adds your text after it, so later edits to that prompt "
|
||||
"still reach this group."
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/templates/edit/include_llm_intent.html
|
||||
msgid "List each new item added with its name and price. Translate to English."
|
||||
msgstr ""
|
||||
|
||||
@@ -3272,6 +3272,18 @@ msgstr "Изменение намерения ИИ"
|
||||
msgid "AI Change Summary"
|
||||
msgstr "Обзор изменений ИИ"
|
||||
|
||||
#: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py
|
||||
msgid "How this prompt combines with the inherited one"
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py
|
||||
msgid "Replace the inherited prompt"
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py
|
||||
msgid "Append to the inherited prompt"
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/forms.py
|
||||
msgid "CSS/JSONPath/JQ/XPath Filters"
|
||||
msgstr "Фильтры CSS/JSONPath/JQ/XPath"
|
||||
@@ -4687,6 +4699,18 @@ msgstr ""
|
||||
msgid "Describe how changes should be summarised in notifications for all watches in this group."
|
||||
msgstr "Опишите, как изменения должны отражаться в уведомлениях для всех часов в этой группе."
|
||||
|
||||
#: changedetectionio/templates/edit/include_llm_intent.html
|
||||
msgid ""
|
||||
"Appending keeps the prompt inherited from the group or from global settings and adds your text after it, so later "
|
||||
"edits to that prompt still reach this watch."
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/templates/edit/include_llm_intent.html
|
||||
msgid ""
|
||||
"Appending keeps the prompt inherited from global settings and adds your text after it, so later edits to that prompt "
|
||||
"still reach this group."
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/templates/edit/include_llm_intent.html
|
||||
msgid "List each new item added with its name and price. Translate to English."
|
||||
msgstr "Перечислите каждый новый добавленный товар с его названием и ценой. Перевести на английский."
|
||||
|
||||
@@ -3207,6 +3207,18 @@ msgstr ""
|
||||
msgid "AI Change Summary"
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py
|
||||
msgid "How this prompt combines with the inherited one"
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py
|
||||
msgid "Replace the inherited prompt"
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py
|
||||
msgid "Append to the inherited prompt"
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/forms.py
|
||||
msgid "CSS/JSONPath/JQ/XPath Filters"
|
||||
msgstr "CSS/JSONPath/JQ/XPath Filtreleri"
|
||||
@@ -4604,6 +4616,18 @@ msgstr ""
|
||||
msgid "Describe how changes should be summarised in notifications for all watches in this group."
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/templates/edit/include_llm_intent.html
|
||||
msgid ""
|
||||
"Appending keeps the prompt inherited from the group or from global settings and adds your text after it, so later "
|
||||
"edits to that prompt still reach this watch."
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/templates/edit/include_llm_intent.html
|
||||
msgid ""
|
||||
"Appending keeps the prompt inherited from global settings and adds your text after it, so later edits to that prompt "
|
||||
"still reach this group."
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/templates/edit/include_llm_intent.html
|
||||
msgid "List each new item added with its name and price. Translate to English."
|
||||
msgstr ""
|
||||
|
||||
@@ -3186,6 +3186,18 @@ msgstr ""
|
||||
msgid "AI Change Summary"
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py
|
||||
msgid "How this prompt combines with the inherited one"
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py
|
||||
msgid "Replace the inherited prompt"
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py
|
||||
msgid "Append to the inherited prompt"
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/forms.py
|
||||
msgid "CSS/JSONPath/JQ/XPath Filters"
|
||||
msgstr "Фільтри CSS/JSONPath/JQ/XPath"
|
||||
@@ -4581,6 +4593,18 @@ msgstr ""
|
||||
msgid "Describe how changes should be summarised in notifications for all watches in this group."
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/templates/edit/include_llm_intent.html
|
||||
msgid ""
|
||||
"Appending keeps the prompt inherited from the group or from global settings and adds your text after it, so later "
|
||||
"edits to that prompt still reach this watch."
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/templates/edit/include_llm_intent.html
|
||||
msgid ""
|
||||
"Appending keeps the prompt inherited from global settings and adds your text after it, so later edits to that prompt "
|
||||
"still reach this group."
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/templates/edit/include_llm_intent.html
|
||||
msgid "List each new item added with its name and price. Translate to English."
|
||||
msgstr ""
|
||||
|
||||
@@ -3160,6 +3160,18 @@ msgstr ""
|
||||
msgid "AI Change Summary"
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py
|
||||
msgid "How this prompt combines with the inherited one"
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py
|
||||
msgid "Replace the inherited prompt"
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py
|
||||
msgid "Append to the inherited prompt"
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/forms.py
|
||||
msgid "CSS/JSONPath/JQ/XPath Filters"
|
||||
msgstr "CSS/JSONPath/JQ/XPath 过滤器"
|
||||
@@ -4555,6 +4567,18 @@ msgstr ""
|
||||
msgid "Describe how changes should be summarised in notifications for all watches in this group."
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/templates/edit/include_llm_intent.html
|
||||
msgid ""
|
||||
"Appending keeps the prompt inherited from the group or from global settings and adds your text after it, so later "
|
||||
"edits to that prompt still reach this watch."
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/templates/edit/include_llm_intent.html
|
||||
msgid ""
|
||||
"Appending keeps the prompt inherited from global settings and adds your text after it, so later edits to that prompt "
|
||||
"still reach this group."
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/templates/edit/include_llm_intent.html
|
||||
msgid "List each new item added with its name and price. Translate to English."
|
||||
msgstr ""
|
||||
|
||||
@@ -3160,6 +3160,18 @@ msgstr ""
|
||||
msgid "AI Change Summary"
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py
|
||||
msgid "How this prompt combines with the inherited one"
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py
|
||||
msgid "Replace the inherited prompt"
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py
|
||||
msgid "Append to the inherited prompt"
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/forms.py
|
||||
msgid "CSS/JSONPath/JQ/XPath Filters"
|
||||
msgstr "CSS / JSONPath / JQ / XPath 過濾器"
|
||||
@@ -4553,6 +4565,18 @@ msgstr ""
|
||||
msgid "Describe how changes should be summarised in notifications for all watches in this group."
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/templates/edit/include_llm_intent.html
|
||||
msgid ""
|
||||
"Appending keeps the prompt inherited from the group or from global settings and adds your text after it, so later "
|
||||
"edits to that prompt still reach this watch."
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/templates/edit/include_llm_intent.html
|
||||
msgid ""
|
||||
"Appending keeps the prompt inherited from global settings and adds your text after it, so later edits to that prompt "
|
||||
"still reach this group."
|
||||
msgstr ""
|
||||
|
||||
#: changedetectionio/templates/edit/include_llm_intent.html
|
||||
msgid "List each new item added with its name and price. Translate to English."
|
||||
msgstr ""
|
||||
|
||||
@@ -605,6 +605,11 @@ components:
|
||||
maxLength: 2000
|
||||
default: ''
|
||||
description: Instructions for the AI to summarise changes in notifications. When set, replaces {{diff}} with a human-readable description.
|
||||
llm_change_summary_mode:
|
||||
type: string
|
||||
enum: ['replace', 'append']
|
||||
default: 'replace'
|
||||
description: Whether llm_change_summary replaces the prompt inherited from the tag/global settings, or is appended to the end of it.
|
||||
llm_prefilter:
|
||||
type: [string, 'null']
|
||||
readOnly: true
|
||||
|
||||
Reference in New Issue
Block a user