← all conversations

Ollama timeout fix

2025-07-266 turns22,888 charsgpt-4o
ollamapythondebugging

Summary

User was debugging a Python script that was timing out when connecting to Ollama for text embeddings.

Messages

(venv) danielkliewer@Daniels-MacBook-Pro red-persona-01 % python3 personafy.py 🔍 Loading markdown content... 📝 Loaded 2521 text samples 📐 Embedding texts... /Users/danielkliewer/red-persona-01/venv/lib/python3.13/site-packages/torch/nn/modules/module.py:1762: FutureWarning: `encoder_attention_mask` is deprecated and will be removed in version 4.55.0 for `BertSdpaSelfAttention.forward`. return forward_call(*args, **kwargs) 🧠 Clustering into personas... huggingface/tokenizers: The current process just got forked, after parallelism has already been used. Disabling parallelism to avoid deadlocks... To disable this warning, you can either: - Avoid using `tokenizers` before the fork if possible - Explicitly set the environment variable TOKENIZERS_PARALLELISM=(true | false) huggingface/tokenizers: The current process just got forked, after parallelism has already been used. Disabling parallelism to avoid deadlocks... To disable this warning, you can either: - Avoid using `tokenizers` before the fork if possible - Explicitly set the environment variable TOKENIZERS_PARALLELISM=(true | false) huggingface/tokenizers: The current process just got forked, after parallelism has already been used. Disabling parallelism to avoid deadlocks... To disable this warning, you can either: - Avoid using `tokenizers` before the fork if possible - Explicitly set the environment variable TOKENIZERS_PARALLELISM=(true | false) huggingface/tokenizers: The current process just got forked, after parallelism has already been used. Disabling parallelism to avoid deadlocks... To disable this warning, you can either: - Avoid using `tokenizers` before the fork if possible - Explicitly set the environment variable TOKENIZERS_PARALLELISM=(true | false) huggingface/tokenizers: The current process just got forked, after parallelism has already been used. Disabling parallelism to avoid deadlocks... To disable this warning, you can either: - Avoid using `tokenizers` before the fork if possible - Explicitly set the environment variable TOKENIZERS_PARALLELISM=(true | false) huggingface/tokenizers: The current process just got forked, after parallelism has already been used. Disabling parallelism to avoid deadlocks... To disable this warning, you can either: - Avoid using `tokenizers` before the fork if possible - Explicitly set the environment variable TOKENIZERS_PARALLELISM=(true | false) Traceback (most recent call last): File "/Users/danielkliewer/red-persona-01/personafy.py", line 252, in <module> main() ~~~~^^ File "/Users/danielkliewer/red-persona-01/personafy.py", line 244, in main personas = generate_personas(texts, embeddings, NUM_CLUSTERS) File "/Users/danielkliewer/red-persona-01/personafy.py", line 186, in generate_personas summary_text = summarize_persona_local(short_samples) File "/Users/danielkliewer/red-persona-01/personafy.py", line 165, in summarize_persona_local result = subprocess.run( ["ollama", "run", OLLAMA_MODEL], ...<3 lines>... timeout=60 ) File "/opt/homebrew/Cellar/python@3.13/3.13.5/Frameworks/Python.framework/Versions/3.13/lib/python3.13/subprocess.py", line 556, in run stdout, stderr = process.communicate(input, timeout=timeout) ~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^ File "/opt/homebrew/Cellar/python@3.13/3.13.5/Frameworks/Python.framework/Versions/3.13/lib/python3.13/subprocess.py", line 1222, in communicate stdout, stderr = self._communicate(input, endtime, timeout) ~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^ File "/opt/homebrew/Cellar/python@3.13/3.13.5/Frameworks/Python.framework/Versions/3.13/lib/python3.13/subprocess.py", line 2129, in _communicate self._check_timeout(endtime, orig_timeout, stdout, stderr) ~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/opt/homebrew/Cellar/python@3.13/3.13.5/Frameworks/Python.framework/Versions/3.13/lib/python3.13/subprocess.py", line 1269, in _check_timeout raise TimeoutExpired( ...<2 lines>... stderr=b''.join(stderr_seq) if stderr_seq else None) subprocess.TimeoutExpired: Command '['ollama', 'run', 'mistral']' timed out after 60 seconds
The error message you're seeing indicates that the `subprocess.run()` call to the command: ```bash ollama run mistral ``` is timing out after 60 seconds, leading to this exception: ``` subprocess.TimeoutExpired: Command '['ollama', 'run', 'mistral']' timed out after 60 seconds ``` ### ✅ TL;DR Fix: Increase the timeout or handle the subprocess more gracefully. You can modify `personafy.py` to raise the timeout or stream the process. --- ### ✅ Solution Options #### **1. Increase the Timeout (Quick Fix)** Find this in your script: ```python result = subprocess.run( ["ollama", "run", OLLAMA_MODEL], input=prompt.encode("utf-8"), capture_output=True, timeout=60 ) ``` Change `timeout=60` to something like `timeout=300`: ```python timeout=300 # Give it 5 minutes to respond ``` --- #### **2. Use `subprocess.Popen()` for Streaming Output (More Robust)** If the model takes longer than expected or if it streams responses slowly, use `Popen` instead: ```python import subprocess def run_ollama_stream(prompt): process = subprocess.Popen( ["ollama", "run", OLLAMA_MODEL], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True ) try: stdout, stderr = process.communicate(prompt, timeout=300) return stdout except subprocess.TimeoutExpired: process.kill() print("❌ Timeout from Ollama model") return None ``` Replace your `subprocess.run(...)` with: ```python result = run_ollama_stream(prompt) if result is None: raise RuntimeError("Model timed out.") ``` --- ### ✅ Optional: Avoid Deadlocks with Tokenizer Parallelism Warning You're also seeing repeated messages about `huggingface/tokenizers`: ```text huggingface/tokenizers: The current process just got forked... ``` To silence this warning, add this to the top of your script (before tokenization begins): ```python import os os.environ["TOKENIZERS_PARALLELISM"] = "false" ``` --- ### ✅ Summary 1. **Timeout fix**: Increase the timeout to `300`. 2. **Better subprocess control**: Use `Popen` to handle longer or streaming outputs. 3. **Silence tokenizer warnings**: `os.environ["TOKENIZERS_PARALLELISM"] = "false"` Let me know if you want help rewriting your `summarize_persona_local()` function with `Popen`.
gpt-4o
python3 personafy.py 🔍 Loading markdown content... 📝 Loaded 2521 text samples 📐 Embedding texts... /Users/danielkliewer/red-persona-01/venv/lib/python3.13/site-packages/torch/nn/ modules/module.py:1762: FutureWarning: `encoder_attention_mask` is deprecated and will be removed in version 4.55.0 for `BertSdpaSelfAttention.forward`. return forward_call(*args, **kwargs) 🧠 Clustering into personas... Traceback (most recent call last): File "/Users/danielkliewer/red-persona-01/personafy.py", line 252, in <module > main() ~~~~^^ File "/Users/danielkliewer/red-persona-01/personafy.py", line 244, in main personas = generate_personas(texts, embeddings, NUM_CLUSTERS) File "/Users/danielkliewer/red-persona-01/personafy.py", line 186, in generat e_personas summary_text = summarize_persona_local(short_samples) File "/Users/danielkliewer/red-persona-01/personafy.py", line 165, in summari ze_persona_local result = subprocess.run( ["ollama", "run", OLLAMA_MODEL], ...<3 lines>... timeout=300 ) File "/opt/homebrew/Cellar/python@3.13/3.13.5/Frameworks/Python.framework/Ver sions/3.13/lib/python3.13/subprocess.py", line 556, in run stdout, stderr = process.communicate(input, timeout=timeout) ~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^ File "/opt/homebrew/Cellar/python@3.13/3.13.5/Frameworks/Python.framework/Ver sions/3.13/lib/python3.13/subprocess.py", line 1222, in communicate stdout, stderr = self._communicate(input, endtime, timeout) ~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^ File "/opt/homebrew/Cellar/python@3.13/3.13.5/Frameworks/Python.framework/Ver sions/3.13/lib/python3.13/subprocess.py", line 2129, in _communicate self._check_timeout(endtime, orig_timeout, stdout, stderr) ~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/opt/homebrew/Cellar/python@3.13/3.13.5/Frameworks/Python.framework/Ver sions/3.13/lib/python3.13/subprocess.py", line 1269, in _check_timeout raise TimeoutExpired( ...<2 lines>... stderr=b''.join(stderr_seq) if stderr_seq else None) subprocess.TimeoutExpired: Command '['ollama', 'run', 'mistral']' timed out aft er 300 seconds
You're still getting a `TimeoutExpired` error, even after increasing the timeout to 300 seconds: ``` subprocess.TimeoutExpired: Command '['ollama', 'run', 'mistral']' timed out after 300 seconds ``` This means the `ollama run mistral` call is either **stalling**, **waiting for input**, or **taking too long to generate output**. Here's how to fix or debug this reliably: --- ### ✅ Fix Step-by-Step #### 1. **Test the `ollama run` call outside Python** Run this from your terminal: ```bash echo "Summarize this sample text." | ollama run mistral ``` If it hangs or asks for more input, then Ollama may not be receiving the prompt correctly from your script. If it works normally, then we know the model is fine. --- #### 2. **Check if Your Prompt is Too Long** Print the prompt before passing it to subprocess: ```python print(prompt) print(f"Prompt length: {len(prompt)} characters") ``` If it's over ~8000 tokens (depending on the model), it might be silently failing. --- #### 3. **Switch to `Popen` to Stream Output Safely** Replace your `subprocess.run(...)` call with the safer `Popen` version. Here's a full working replacement for `summarize_persona_local`: ```python import subprocess def summarize_persona_local(samples): prompt = "Summarize the following writing samples into a personality description:\n\n" prompt += "\n\n".join(samples) process = subprocess.Popen( ["ollama", "run", OLLAMA_MODEL], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True ) try: stdout, stderr = process.communicate(input=prompt, timeout=600) if stderr: print("⚠️ stderr:", stderr) if process.returncode != 0: raise RuntimeError(f"Model failed: {stderr}") return stdout.strip() except subprocess.TimeoutExpired: process.kill() print("❌ Ollama model timed out.") return "Timeout: Could not generate persona." ``` --- ### ✅ Optional Enhancements #### Avoid tokenizer warnings: At the top of your script, add: ```python import os os.environ["TOKENIZERS_PARALLELISM"] = "false" ``` #### Log failures: Add logging or write failed prompts to disk for reprocessing: ```python with open("failed_prompt.txt", "w") as f: f.write(prompt) ``` --- ### 🔍 Summary - You’re hitting a **timeout**, most likely from a **long or malformed prompt**. - Use `subprocess.Popen()` to stream input/output and improve reliability. - Test `ollama run` from the shell to verify model functionality. - Log prompt lengths and contents to help debug. Would you like help modifying the full `generate_personas()` or `summarize_persona_local()` function to include retry logic and debugging output?
gpt-4o
import os import json import random import subprocess from glob import glob from collections import defaultdict import numpy as np from sentence_transformers import SentenceTransformer from sklearn.cluster import KMeans # ========== CONFIG ========== BASE_DIR = "./reddit_data/KonradFreeman" NUM_CLUSTERS = 10 OUTPUT_DIR = "./personas" OLLAMA_MODEL = "mistral-small3.2" # your local LLM model RANDOM_SEED = 42 # ============================ os.environ["TOKENIZERS_PARALLELISM"] = "false" def load_markdown_texts(base_dir): files = glob(os.path.join(base_dir, "**/*.md"), recursive=True) texts = [] for file in files: with open(file, 'r', encoding='utf-8') as f: content = f.read() if len(content.strip()) > 50: texts.append((file, content.strip())) return texts def embed_texts(texts): model = SentenceTransformer('all-MiniLM-L6-v2') contents = [text for _, text in texts] embeddings = model.encode(contents) return embeddings def cluster_texts(embeddings, num_clusters): kmeans = KMeans(n_clusters=num_clusters, random_state=RANDOM_SEED) labels = kmeans.fit_predict(embeddings) return labels def summarize_persona_local(text_samples): joined_samples = "\n\n".join(text_samples) prompt = f""" You are analyzing a Reddit user's writing style and personality based on 5 sample posts/comments. For each of the following 50 traits, rate how strongly that trait is expressed in these samples on a scale from 0.0 to 1.0, where 0.0 means "not present at all" and 1.0 means "strongly present and dominant". Please output the results as a JSON object with keys as the trait names and values as floating point numbers between 0 and 1, inclusive. The traits and what they measure: 1. openness: curiosity and creativity in ideas. 2. conscientiousness: carefulness and discipline. 3. extraversion: sociability and expressiveness. 4. agreeableness: kindness and cooperativeness. 5. neuroticism: emotional instability or sensitivity. 6. optimism: hopeful and positive tone. 7. skepticism: questioning and critical thinking. 8. humor: presence of irony, wit, or jokes. 9. formality: use of formal language and structure. 10. emotionality: expression of feelings and passion. 11. analytical: logical reasoning and argumentation. 12. narrative: storytelling and personal anecdotes. 13. philosophical: discussion of abstract ideas. 14. political: engagement with political topics. 15. technical: use of technical or domain-specific language. 16. empathy: understanding others' feelings. 17. assertiveness: confident and direct expression. 18. humility: modesty and openness to other views. 19. creativity: original and novel expressions. 20. negativity: presence of criticism or complaints. 21. curiosity: eagerness to explore and learn. 22. frustration: signs of irritation or dissatisfaction. 23. supportiveness: encouraging and helpful tone. 24. introspection: self-reflection and personal insight. 25. irony: use of sarcasm or indirect humor. 26. self-deprecation: making fun of oneself. 27. rebelliousness: resistance to authority or norms. 28. clarity: how clear and understandable the writing is. 29. verbosity: tendency to use many words. 30. conciseness: brevity and efficiency in expression. 31. abstraction: use of conceptual, vague, or intangible ideas. 32. concreteness: use of tangible and specific examples. 33. poeticness: lyrical or artistic expression. 34. intensity: forcefulness or emotional strength. 35. dry_humor: understated and deadpan comedic tone. 36. wit: clever and quick verbal humor. 37. playfulness: light, spontaneous tone or wordplay. 38. moralizing: emphasis on right and wrong. 39. storytelling_depth: complexity and layers in narratives. 40. irony_detection: ability to recognize and deploy irony. 41. cultural_reference: use of shared cultural, media, or historic touchpoints. 42. emotional_regulation: control over emotional expression. 43. antagonism: tendency toward conflict or provocation. 44. warmth: friendliness and emotional accessibility. 45. idealism: belief in or striving for perfection or betterment. 46. realism: grounded and practical perspective. 47. sarcasm: biting or mocking form of humor. 48. absurdism: surreal or illogical humor and concepts. 49. urgency: immediacy or emotional pressure in tone. 50. rhythm: sense of pacing and flow in the writing. Analyze these samples carefully and output the JSON exactly like this example (with different values): {{ "openness": 0.75, "conscientiousness": 0.55, "extraversion": 0.10, "agreeableness": 0.60, "neuroticism": 0.20, "optimism": 0.50, "skepticism": 0.85, "humor": 0.15, "formality": 0.30, "emotionality": 0.70, "analytical": 0.80, "narrative": 0.45, "philosophical": 0.65, "political": 0.40, "technical": 0.25, "empathy": 0.55, "assertiveness": 0.35, "humility": 0.50, "creativity": 0.60, "negativity": 0.10, "curiosity": 0.70, "frustration": 0.05, "supportiveness": 0.40, "introspection": 0.75, "irony": 0.30, "self_deprecation": 0.20, "rebelliousness": 0.65, "clarity": 0.90, "verbosity": 0.80, "conciseness": 0.40, "abstraction": 0.55, "concreteness": 0.60, "poeticness": 0.25, "intensity": 0.75, "dry_humor": 0.50, "wit": 0.70, "playfulness": 0.65, "moralizing": 0.35, "storytelling_depth": 0.60, "irony_detection": 0.45, "cultural_reference": 0.50, "emotional_regulation": 0.55, "antagonism": 0.20, "warmth": 0.60, "idealism": 0.45, "realism": 0.50, "sarcasm": 0.55, "absurdism": 0.40, "urgency": 0.35, "rhythm": 0.80 }} {joined_samples} """ result = subprocess.run( ["ollama", "run", OLLAMA_MODEL], input=prompt, capture_output=True, text=True, timeout=300 ) return result.stdout.strip() # <- Return raw string, no parsing def generate_personas(texts, embeddings, num_clusters): labels = cluster_texts(embeddings, num_clusters) clusters = defaultdict(list) for (filename, content), label in zip(texts, labels): clusters[label].append(content) personas = [] for label, samples in clusters.items(): short_samples = random.sample(samples, min(5, len(samples))) summary_text = summarize_persona_local(short_samples) persona = { "id": label, "summary": summary_text, "samples": short_samples } personas.append(persona) return personas def convert_numpy(obj): if isinstance(obj, dict): return {k: convert_numpy(v) for k, v in obj.items()} elif isinstance(obj, list): return [convert_numpy(i) for i in obj] elif isinstance(obj, (np.integer,)): return int(obj) elif isinstance(obj, (np.floating,)): return float(obj) else: return obj def save_personas(personas, output_dir): os.makedirs(output_dir, exist_ok=True) for i, persona in enumerate(personas): with open(f"{output_dir}/persona_{i}.json", "w") as f: # If any values are NumPy or other types, convert to plain Python types cleaned = { k: float(v) if hasattr(v, 'item') else v for k, v in persona.items() } json.dump(cleaned, f, indent=2) def convert_to_serializable(obj): if isinstance(obj, dict): return {k: convert_to_serializable(v) for k, v in obj.items()} elif isinstance(obj, list): return [convert_to_serializable(i) for i in obj] elif isinstance(obj, (np.integer, np.floating)): return obj.item() # Convert to native Python int/float else: return obj def main(): print("🔍 Loading markdown content...") texts = load_markdown_texts(BASE_DIR) print(f"📝 Loaded {len(texts)} text samples") print("📐 Embedding texts...") embeddings = embed_texts(texts) print("🧠 Clustering into personas...") personas = generate_personas(texts, embeddings, NUM_CLUSTERS) print("💾 Saving personas...") save_personas(personas, OUTPUT_DIR) print("✅ Done. Personas saved to", OUTPUT_DIR) if __name__ == "__main__": main()
Thanks for sharing the full code — it's solid and well-structured, but the issue is clearly with how `subprocess.run()` interacts with `ollama` when generating responses. Since `ollama run mistral-small3.2` is still timing out (even after 300s), let's make it *resilient* by switching to `Popen` to stream and control the output more safely. --- ### ✅ Here's a Fixed Version of `summarize_persona_local()` Using `subprocess.Popen`: Replace your existing `summarize_persona_local()` function with this version: ```python def summarize_persona_local(text_samples): joined_samples = "\n\n".join(text_samples) prompt = f""" You are analyzing a Reddit user's writing style and personality based on 5 sample posts/comments. For each of the following 50 traits, rate how strongly that trait is expressed in these samples on a scale from 0.0 to 1.0... [TRUNCATED FOR BREVITY IN THIS RESPONSE — KEEP FULL PROMPT IN YOUR CODE] {joined_samples} """ try: process = subprocess.Popen( ["ollama", "run", OLLAMA_MODEL], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True ) stdout, stderr = process.communicate(input=prompt, timeout=600) # bump to 10 min just in case if stderr: print("⚠️ Ollama stderr:", stderr) if process.returncode != 0: print("❌ Ollama returned non-zero exit code") return "{}" return stdout.strip() except subprocess.TimeoutExpired: process.kill() print("❌ Ollama timed out while summarizing persona.") return "{}" ``` --- ### 🔍 Explanation - `subprocess.run()` is **blocking** and assumes the command will finish quickly. It's brittle when the model: - Needs more than 5 minutes - Hangs on partial input - Writes a lot to `stdout` or `stderr` - `subprocess.Popen()` gives you more control, especially: - Killing the process if it hangs - Capturing both `stdout` and `stderr` - Streaming input --- ### 🛠 Optional Debugging Helpers Add this just before returning in `summarize_persona_local()` to debug a stuck response: ```python print("🧾 Raw Ollama Output:") print(stdout[:500]) # print first 500 characters of model output ``` And if you want to write failed prompts to a file: ```python if process.returncode != 0 or not stdout.strip().startswith("{"): with open("failed_prompt_debug.txt", "w") as f: f.write(prompt) ``` --- ### ✅ Final Notes Once you update to use `Popen`, this should: - Fix your `TimeoutExpired` issue. - Improve fault tolerance. - Make debugging easier. Let me know if you'd like to parallelize this with `multiprocessing` next or cache outputs to avoid reprocessing the same clusters.
gpt-4o