mirror of
https://github.com/dgtlmoon/changedetection.io.git
synced 2026-08-25 15:46:54 +00:00
WIP
This commit is contained in:
@@ -127,15 +127,11 @@ def construct_blueprint(datastore: ChangeDetectionStore):
|
||||
# model_dump() — even though .attribute access reads the alias correctly.
|
||||
merged = LLMSettings.model_validate({**existing_llm.model_dump(by_alias=True), **llm_form_input})
|
||||
|
||||
# Clearing the model strips only the credential fields. User toggles
|
||||
# (llm_enabled, debug, override_diff_with_summary, …), the global summary
|
||||
# prompt, monthly budgets, and the system token counters all survive —
|
||||
# matches the /llm/clear endpoint's semantics.
|
||||
merged_dict = merged.model_dump()
|
||||
if not merged.model.strip():
|
||||
for key in ('model', 'api_key', 'api_base', 'provider_kind', 'local_token_multiplier'):
|
||||
merged_dict.pop(key, None)
|
||||
datastore.data['settings']['application']['llm'] = merged_dict
|
||||
# Clearing the model field strips only the provider-connection fields.
|
||||
# User toggles, budgets, the summary prompt, and system counters survive
|
||||
# (same semantics as /llm/clear).
|
||||
exclude = set(LLMSettings.CONNECTION_FIELDS) if not merged.model.strip() else None
|
||||
datastore.data['settings']['application']['llm'] = merged.model_dump(exclude=exclude)
|
||||
|
||||
# Handle dynamic worker count adjustment
|
||||
old_worker_count = datastore.data['settings']['requests'].get('workers', 1)
|
||||
|
||||
@@ -232,12 +232,11 @@ def construct_llm_blueprint(datastore: ChangeDetectionStore):
|
||||
@llm_blueprint.route("/clear", methods=['POST'])
|
||||
@login_optionally_required
|
||||
def llm_clear():
|
||||
from changedetectionio.model.LLMSettings import LLMSettings
|
||||
logger.debug("LLM configuration cleared by user")
|
||||
# Strip only the credential / connection fields — user-set toggles, the
|
||||
# global summary prompt, monthly budgets, and the system token counters
|
||||
# all survive a "clear credentials" action.
|
||||
# Strip provider-connection fields only. Toggles, prompts, budgets and counters survive.
|
||||
llm = datastore.data['settings']['application'].get('llm') or {}
|
||||
for key in ('model', 'api_key', 'api_base', 'provider_kind', 'local_token_multiplier'):
|
||||
for key in LLMSettings.CONNECTION_FIELDS:
|
||||
llm.pop(key, None)
|
||||
if llm:
|
||||
datastore.data['settings']['application']['llm'] = llm
|
||||
|
||||
@@ -1,16 +1,10 @@
|
||||
"""
|
||||
LLMSettings — validation/typing layer over the LLM config dict.
|
||||
Validation/typing layer for the LLM config dict stored at
|
||||
datastore.data['settings']['application']['llm']
|
||||
|
||||
Storage shape (after migration update_31): everything lives under
|
||||
datastore.data['settings']['application']['llm'] = { ... }
|
||||
|
||||
Field names are stripped (enabled, debug, model, …). WTForms field names are
|
||||
still llm_-prefixed (llm_enabled, llm_debug, …) and Pydantic Field aliases
|
||||
bridge both sides, so callers don't repeat the rename.
|
||||
|
||||
The store stays a plain dict (orjson-serialized) — this model is hydrated on
|
||||
read (model_validate) and dumped on write (model_dump). Pydantic instances
|
||||
are never held in datastore.data.
|
||||
Storage stays a plain dict (orjson-serialized). This model is hydrated on read
|
||||
(model_validate) and dumped on write (model_dump). Form-side WTForms field names
|
||||
keep the llm_-prefix; Field aliases bridge them to the stripped storage names.
|
||||
"""
|
||||
from typing import ClassVar, Tuple
|
||||
|
||||
@@ -25,10 +19,7 @@ LLM_DEFAULT_BUDGET_ACTION = 'skip_llm'
|
||||
|
||||
|
||||
class LLMSettings(BaseModel):
|
||||
model_config = ConfigDict(
|
||||
populate_by_name=True,
|
||||
extra='allow',
|
||||
)
|
||||
model_config = ConfigDict(populate_by_name=True, extra='allow')
|
||||
|
||||
enabled: bool = Field(default=True, alias='llm_enabled')
|
||||
debug: bool = Field(default=False, alias='llm_debug')
|
||||
@@ -38,14 +29,14 @@ class LLMSettings(BaseModel):
|
||||
max_summary_tokens: int = Field(default=LLM_DEFAULT_MAX_SUMMARY_TOKENS, alias='llm_max_summary_tokens')
|
||||
budget_action: str = Field(default=LLM_DEFAULT_BUDGET_ACTION, alias='llm_budget_action')
|
||||
change_summary_default: str = Field(default='', alias='llm_change_summary_default')
|
||||
token_budget_month: int = Field(default=0, alias='llm_token_budget_month')
|
||||
max_input_chars: int = Field(default=LLM_DEFAULT_MAX_INPUT_CHARS, alias='llm_max_input_chars')
|
||||
|
||||
model: str = Field(default='', alias='llm_model')
|
||||
api_key: str = Field(default='', alias='llm_api_key')
|
||||
api_base: str = Field(default='', alias='llm_api_base')
|
||||
provider_kind: str = Field(default='', alias='llm_provider_kind')
|
||||
local_token_multiplier: int = Field(default=LLM_DEFAULT_LOCAL_TOKEN_MULTIPLIER, alias='llm_local_token_multiplier')
|
||||
token_budget_month: int = Field(default=0, alias='llm_token_budget_month')
|
||||
max_input_chars: int = Field(default=LLM_DEFAULT_MAX_INPUT_CHARS, alias='llm_max_input_chars')
|
||||
|
||||
tokens_total_cumulative: int = 0
|
||||
tokens_this_month: int = 0
|
||||
@@ -53,12 +44,12 @@ class LLMSettings(BaseModel):
|
||||
cost_usd_total_cumulative: float = 0.0
|
||||
cost_usd_this_month: float = 0.0
|
||||
|
||||
# Runtime-managed counters that must survive form submissions. The settings
|
||||
# POST handler strips these from form input before applying the merge.
|
||||
# Provider-connection fields wiped on /llm/clear and when the model is emptied.
|
||||
CONNECTION_FIELDS: ClassVar[Tuple[str, ...]] = (
|
||||
'model', 'api_key', 'api_base', 'provider_kind', 'local_token_multiplier',
|
||||
)
|
||||
# Runtime-managed counters — form submissions must never overwrite these.
|
||||
PROTECTED_FIELDS: ClassVar[Tuple[str, ...]] = (
|
||||
'tokens_total_cumulative',
|
||||
'tokens_this_month',
|
||||
'tokens_month_key',
|
||||
'cost_usd_total_cumulative',
|
||||
'cost_usd_this_month',
|
||||
'tokens_total_cumulative', 'tokens_this_month', 'tokens_month_key',
|
||||
'cost_usd_total_cumulative', 'cost_usd_this_month',
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user