diff --git a/ltx_director.py b/ltx_director.py index f861426..cae4653 100644 --- a/ltx_director.py +++ b/ltx_director.py @@ -438,9 +438,10 @@ _PROVIDER_DEFAULTS = { } _ANALYZE_PROMPT = ( - "Describe the character's physical appearance in two concise sentences. " - "Specify their hair color/style, face details, and their clothing type/color. " - "Keep the entire response very brief." + "Describe only the visible character in exactly two complete sentences. " + "Sentence 1 must cover hair, face, age impression, and any standout physical traits. " + "Sentence 2 must cover clothing, accessories, and overall silhouette. " + "Do not start with fragments like 'The'. Do not mention image quality, background, framing, or emotions." ) @@ -468,6 +469,17 @@ def _extract_ollama_generated_text(resp_json: dict) -> str: if text: return text return "" + + +def _analysis_text_is_usable(text: str) -> bool: + text = (text or "").strip() + if not text: + return False + if len(text) < 24: + return False + if len(text.split()) < 6: + return False + return True def _resolve_provider(data): @@ -515,8 +527,15 @@ async def analyze_character_endpoint(request): async with aiohttp.ClientSession() as session: if provider == "ollama": payload = { - "model": model_name, "prompt": _ANALYZE_PROMPT, - "images": cleaned_b64_list, "stream": False, "keep_alive": 0, + "model": model_name, + "prompt": _ANALYZE_PROMPT, + "images": cleaned_b64_list, + "stream": False, + "keep_alive": 0, + "options": { + "temperature": 0.2, + "num_predict": 120, + }, } async with session.post(f"{base_url}/api/generate", json=payload, timeout=300) as response: if response.status != 200: @@ -525,9 +544,9 @@ async def analyze_character_endpoint(request): resp_json = await response.json() generated_text = _extract_ollama_generated_text(resp_json) - # Some Ollama model variants return an empty `response` from `/api/generate` - # even though the same request succeeds via the chat endpoint. - if not generated_text: + # Some Ollama model variants return an empty or truncated response from + # `/api/generate` even though the same request succeeds via the chat endpoint. + if not _analysis_text_is_usable(generated_text): chat_payload = { "model": model_name, "messages": [{ @@ -537,6 +556,10 @@ async def analyze_character_endpoint(request): }], "stream": False, "keep_alive": 0, + "options": { + "temperature": 0.2, + "num_predict": 120, + }, } async with session.post(f"{base_url}/api/chat", json=chat_payload, timeout=300) as response: if response.status == 200: @@ -574,10 +597,10 @@ async def analyze_character_endpoint(request): if "" in generated_text: generated_text = generated_text.split("")[-1].strip() - if not generated_text: + if not _analysis_text_is_usable(generated_text): return web.json_response({ "status": "error", - "message": f"{provider} returned an empty analysis response.", + "message": f"{provider} returned an empty or truncated analysis response.", }) log.info("[LTXDirector] Analysis complete: %s", generated_text)