diff --git a/conditioning.py b/conditioning.py index 678600c6..fb75206e 100644 --- a/conditioning.py +++ b/conditioning.py @@ -11333,138 +11333,6 @@ class FunPackVideoRefinerV2(FunPackVideoRefiner): return current_prompt, f"Advisor: no change. {analysis}".strip(), analysis, False, "" return advised, f"Advisor: applied repair. {analysis}".strip(), analysis, True, advised - def _v2_negative_advisor_prompt( - self, - positive_prompt, - negative_prompt, - intent_prompt, - previous_run=None, - feedback_prompt="", - feedback_history="", - ): - has_feedback = bool(str(feedback_prompt or "").strip()) - previous_run = previous_run if isinstance(previous_run, dict) else {} - previous_prompt = self._v2_prompt_key(previous_run.get("encoded_prompt", "") or previous_run.get("prompt", "")) - neg_rules = ( - "Additional rules for negative prompt repair:\n" - "- Add only concise suppression tags for things that were wrong or harmful.\n" - "- Never suppress requested subjects, actions, or visual intent.\n" - "- Preserve useful existing tags.\n" - "Output exactly two lines:\n" - "DIAGNOSTIC: one short sentence explaining the change or why none is needed.\n" - "NEGATIVE_PROMPT: comma-separated tags, or the current negative prompt unchanged." - ) - user_lines = [] - if has_feedback: - user_lines.append(f"User feedback: {str(feedback_prompt).strip()}") - user_lines += [ - f"User intent: {self._v2_prompt_key(intent_prompt) or 'same as suggested prompt'}", - f"Suggested prompt: {self._v2_prompt_key(positive_prompt)}", - f"Current negative: {self._v2_prompt_key(negative_prompt) or 'empty'}", - ] - if previous_prompt: - user_lines.append(f"Previous prompt (what caused the feedback): {previous_prompt}") - if feedback_history: - user_lines.append(f"Past feedback (most recent first):\n{feedback_history}") - if has_feedback: - user_lines.append("Task: apply the user feedback to the negative prompt.") - else: - user_lines.append("Task: repair the negative prompt to suppress what went wrong.") - return ( - V2_PROMPT_ADVISOR_SYSTEM_PROMPT.strip() + "\n" + neg_rules - + ("\n" + V2_PROMPT_ADVISOR_FEEDBACK_OVERRIDE.strip() if has_feedback else "") - + "\n\n" + "\n".join(user_lines) - ) - - def _v2_validate_advisor_negative_prompt( - self, - advised_negative, - current_positive, - intent_prompt, - intent_phrases=None, - intent_family_slot=None, - ): - advised = self._v2_prompt_key(advised_negative) - if not advised: - return True, "empty" - if self._prompt_looks_like_refusal(advised): - return False, "refusal text" - if len(advised) > 1200: - return False, "too long" - for phrase in self._ordered_prompt_phrases(advised)[:32]: - text = phrase.get("text", "") - if not text: - continue - if self._v2_negative_text_conflicts_with_request( - text, - current_prompt=current_positive, - intent_prompt=intent_prompt, - intent_phrases=intent_phrases or [], - family_slot=intent_family_slot, - ): - return False, f"conflicts with requested text: {text}" - return True, "validated" - - def _v2_negative_prompt_advisor( - self, - clip, - mode, - positive_prompt, - negative_prompt, - intent_prompt, - rating_profile, - axis_feedback, - previous_run=None, - intent_phrases=None, - intent_family_slot=None, - allow_prompt_change=False, - seed=0, - image=None, - thinking=True, - feedback_prompt="", - feedback_history="", - max_length=800, - ): - mode = self._v2_advisor_mode(mode) - rating_profile = rating_profile if isinstance(rating_profile, dict) else {} - if mode == "Off": - return negative_prompt, "Negative advisor: off.", "", False - reward = float(rating_profile.get("reward", 0.0)) - is_perfect = rating_profile.get("key") == "like" - repair_signal = bool(axis_feedback.get("wrong_axes")) or rating_profile.get("key") == "awful" or reward < -0.30 - if mode in {"Only prompt", "Full"} and not repair_signal and not str(feedback_prompt or "").strip(): - return negative_prompt, "Negative advisor: skipped; no wrong/awful signal and no user feedback.", "", False - advisor_prompt_text = self._v2_negative_advisor_prompt( - positive_prompt, - negative_prompt, - intent_prompt, - previous_run=previous_run, - feedback_prompt=feedback_prompt, - feedback_history=feedback_history, - ) - raw, gen_status = self._v2_generate_advisor_text( - clip, advisor_prompt_text, seed=seed, image=image, thinking=thinking, max_length=max_length - ) - if not raw: - return negative_prompt, gen_status.replace("Advisor:", "Negative advisor:", 1), "", False - diagnostic, advised = self._v2_parse_advisor_response(raw, prompt_labels=("NEGATIVE_PROMPT", "PROMPT")) - if mode == "Only diagnostics" or not allow_prompt_change or is_perfect: - reason = "diagnostics only" if mode == "Only diagnostics" else ("perfect rating — analysis only" if is_perfect else "prompt changes disabled") - return negative_prompt, f"Negative advisor: {reason}. {diagnostic or advised or 'No diagnostic returned.'}", diagnostic or advised, False - valid, reason = self._v2_validate_advisor_negative_prompt( - advised, - positive_prompt, - intent_prompt, - intent_phrases=intent_phrases or [], - intent_family_slot=intent_family_slot, - ) - if not valid: - return negative_prompt, f"Negative advisor: rejected ({reason}). {diagnostic}".strip(), diagnostic, False - advised = self._v2_prompt_key(advised) - if advised == self._v2_prompt_key(negative_prompt): - return negative_prompt, f"Negative advisor: no change. {diagnostic}".strip(), diagnostic, False - return advised, f"Negative advisor: applied. {diagnostic}".strip(), diagnostic, True - def _v2_encoded_prompts_output(self, positive_prompt, advisor_diagnostic="", pre_advisor_prompt="", advisor_suggested=""): parts = [f"Positive prompt: {str(positive_prompt or '').strip()}"] positive_key = self._v2_prompt_key(positive_prompt) diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md new file mode 100644 index 00000000..485d2dd8 --- /dev/null +++ b/docs/ROADMAP.md @@ -0,0 +1,27 @@ +# Roadmap + +Planned work, in no particular order. Items move to the CHANGELOG when they ship. + +## Advisor multitool + +Turn the prompt advisor into a general-purpose assistant surface rather than a +prompt-repair step: a picker wheel of operations that act on whatever the user points it at. + +Intended operations: +- **Describe image** — look at the selected image, return text the user can copy or paste + straight into any prompt field. +- **Enhance prompt** — rewrite or extend the current prompt. +- **Write** — longer-form story text for multi-scene timelines. +- **Change settings** — act on Engine Settings by request rather than by navigation. + +The shape is an assistant that reaches into FunPack's own state, not a text box that returns a +string. + +## Family-aware settings + +Detect the model family when the loader state is saved, and hide controls the loaded model +cannot use, instead of reporting per run that they do not apply. Owning the loaders makes the +family known before generation starts. + +Replaces the "this model has no cross-attention, feature X is skipped" class of log line: what +is not wired does not appear.