vidhanm commited on
Commit
7d56bcc
·
1 Parent(s): f2f290e

adding print statements in logs

Browse files
Files changed (1) hide show
  1. app.py +108 -74
app.py CHANGED
@@ -5,134 +5,167 @@ import tempfile # For handling temporary image files
5
  from typing import Optional
6
  from PIL import Image as PILImage
7
  import gradio as gr
 
8
 
9
- # Add the cloned nanoVLM directory to Python's system path (generate.py might need this too if it imports from 'models')
10
  NANOVLM_REPO_PATH = "/app/nanoVLM"
11
  if NANOVLM_REPO_PATH not in sys.path:
12
  print(f"DEBUG: Adding {NANOVLM_REPO_PATH} to sys.path")
13
  sys.path.insert(0, NANOVLM_REPO_PATH)
14
 
15
  print(f"DEBUG: Python sys.path: {sys.path}")
 
16
 
17
- # Path to the generate.py script within our Docker container
18
  GENERATE_SCRIPT_PATH = "/app/nanoVLM/generate.py"
19
- MODEL_REPO_ID = "lusxvr/nanoVLM-222M" # Model ID for generate.py
20
 
21
  print(f"DEBUG: Using generate.py script at: {GENERATE_SCRIPT_PATH}")
22
  print(f"DEBUG: Using model repo ID: {MODEL_REPO_ID}")
23
 
24
-
25
  def call_generate_script(image_path: str, prompt_text: str) -> str:
26
- """
27
- Calls the generate.py script as a subprocess and returns its output.
28
- """
29
- print(f"DEBUG (call_generate_script): Calling with image_path='{image_path}', prompt='{prompt_text}'")
30
 
31
- # Arguments for generate.py (ensure they match its expected format)
32
- # From previous success: --hf_model, --image, --prompt, --generations, --max_new_tokens
33
  cmd_args = [
34
- "python", "-u", GENERATE_SCRIPT_PATH,
35
  "--hf_model", MODEL_REPO_ID,
36
- "--image", image_path,
37
  "--prompt", prompt_text,
38
- "--generations", "1", # Get one generation for the UI
39
- "--max_new_tokens", "20" # Adjust as needed
40
- # --device is handled by generate.py internally
 
 
 
41
  ]
42
 
43
- print(f"DEBUG (call_generate_script): Executing command: {' '.join(cmd_args)}")
 
 
 
 
 
44
 
 
45
  try:
46
- # Execute the command
47
- # capture_output=True, text=True are for Python 3.7+
48
- # For Python 3.9 (as in your Dockerfile base), this is fine.
49
  process = subprocess.run(
50
  cmd_args,
51
  capture_output=True,
52
  text=True,
53
- check=True, # Raise an exception for non-zero exit codes
54
- timeout=2400 # Add a timeout (e.g., 2 minutes)
55
  )
 
 
 
 
 
56
 
57
- stdout = process.stdout
58
- stderr = process.stderr
59
-
60
- print(f"DEBUG (call_generate_script): generate.py STDOUT:\n{stdout}")
61
- if stderr:
62
- print(f"DEBUG (call_generate_script): generate.py STDERR:\n{stderr}")
63
 
64
- # --- Parse the output from generate.py ---
65
- # The generate.py script prints:
 
 
 
 
 
 
 
 
 
 
66
  # Outputs:
67
- # >> Generation 1: Actual generated text here.
68
- # We need to extract "Actual generated text here."
69
-
70
  output_lines = stdout.splitlines()
71
- generated_text = "Error: Could not parse output from generate.py script." # Default
72
 
73
- parsing_output = False
74
- for line in output_lines:
75
- if "Outputs:" in line:
76
- parsing_output = True
77
- continue
78
- if parsing_output and line.strip().startswith(">> Generation 1:"):
79
- # Extract text after ">> Generation 1: " (note the two spaces)
80
- generated_text = line.split(">> Generation 1: ", 1)[-1].strip()
81
- break # Found the first generation
 
 
 
 
 
 
82
 
83
- print(f"DEBUG (call_generate_script): Parsed generated text: '{generated_text}'")
 
 
 
 
 
 
84
  return generated_text
85
 
86
- except subprocess.CalledProcessError as e:
87
- print(f"ERROR (call_generate_script): generate.py exited with error code {e.returncode}")
88
- print(f"ERROR (call_generate_script): STDOUT: {e.stdout}")
89
- print(f"ERROR (call_generate_script): STDERR: {e.stderr}")
90
- return f"Error executing generation script (Code {e.returncode}). Check logs."
91
- except subprocess.TimeoutExpired:
92
- print("ERROR (call_generate_script): generate.py timed out.")
93
- return "Error: Generation script timed out."
94
  except Exception as e:
95
- print(f"ERROR (call_generate_script): An unexpected error occurred: {e}")
96
- import traceback
97
- traceback.print_exc()
98
- return f"An unexpected error occurred while calling generation script: {str(e)}"
 
 
99
 
100
 
101
  def gradio_interface_fn(image_input_pil: Optional[PILImage.Image], prompt_input_str: Optional[str]) -> str:
102
- print(f"DEBUG (gradio_interface_fn): Received prompt: '{prompt_input_str}'")
 
 
103
  if image_input_pil is None:
104
  return "Please upload an image."
105
- if not prompt_input_str:
106
- return "Please provide a prompt."
 
 
107
 
108
- # Save the uploaded PIL image to a temporary file
109
- # tempfile.NamedTemporaryFile creates a file that is deleted when closed.
110
- # We need to ensure it has a .jpg extension for some image libraries if they are picky.
111
- # The 'delete=False' allows us to close it, pass its name, and then delete it manually.
112
  try:
 
 
 
 
113
  with tempfile.NamedTemporaryFile(suffix=".jpg", delete=False) as tmp_image_file:
114
  image_input_pil.save(tmp_image_file, format="JPEG")
115
  tmp_image_path = tmp_image_file.name
116
 
117
- print(f"DEBUG (gradio_interface_fn): Temporary image saved to: {tmp_image_path}")
118
 
119
- # Call the generate.py script with the path to the temporary image
120
- result_text = call_generate_script(tmp_image_path, prompt_input_str)
121
 
 
122
  return result_text
123
 
124
  except Exception as e:
125
- print(f"ERROR (gradio_interface_fn): Error processing image or calling script: {e}")
126
  import traceback; traceback.print_exc()
127
- return f"An error occurred: {str(e)}"
128
  finally:
129
- # Clean up the temporary image file
130
- if 'tmp_image_path' in locals() and os.path.exists(tmp_image_path):
131
  try:
132
  os.remove(tmp_image_path)
133
- print(f"DEBUG (gradio_interface_fn): Temporary image {tmp_image_path} removed.")
134
  except Exception as e_remove:
135
- print(f"WARN (gradio_interface_fn): Could not remove temporary image {tmp_image_path}: {e_remove}")
 
136
 
137
 
138
  # --- Gradio Interface Definition ---
@@ -140,6 +173,7 @@ description_md = """
140
  ## nanoVLM-222M Interactive Demo (via generate.py)
141
  Upload an image and type a prompt. This interface calls the `generate.py` script from
142
  `huggingface/nanoVLM` under the hood to perform inference.
 
143
  """
144
 
145
  print("DEBUG: Defining Gradio interface...")
@@ -151,7 +185,7 @@ try:
151
  gr.Image(type="pil", label="Upload Image"),
152
  gr.Textbox(label="Your Prompt / Question", info="e.g., 'describe this image in detail'")
153
  ],
154
- outputs=gr.Textbox(label="Generated Text", show_copy_button=True),
155
  title="nanoVLM-222M Demo (via Script)",
156
  description=description_md,
157
  allow_flagging="never"
@@ -166,13 +200,13 @@ if __name__ == "__main__":
166
  print("DEBUG: Entered __main__ block for Gradio launch.")
167
  if not os.path.exists(GENERATE_SCRIPT_PATH):
168
  print(f"CRITICAL ERROR: The script {GENERATE_SCRIPT_PATH} was not found. Cannot launch app.")
169
- iface = None # Prevent launch
170
 
171
  if iface is not None:
172
  print("DEBUG: Attempting to launch Gradio interface...")
173
  try:
174
  iface.launch(server_name="0.0.0.0", server_port=7860)
175
- print("DEBUG: Gradio launch command issued.")
176
  except Exception as e:
177
  print(f"CRITICAL ERROR launching Gradio interface: {e}")
178
  import traceback; traceback.print_exc()
 
5
  from typing import Optional
6
  from PIL import Image as PILImage
7
  import gradio as gr
8
+ import time # For timing
9
 
10
+ # Add the cloned nanoVLM directory to Python's system path
11
  NANOVLM_REPO_PATH = "/app/nanoVLM"
12
  if NANOVLM_REPO_PATH not in sys.path:
13
  print(f"DEBUG: Adding {NANOVLM_REPO_PATH} to sys.path")
14
  sys.path.insert(0, NANOVLM_REPO_PATH)
15
 
16
  print(f"DEBUG: Python sys.path: {sys.path}")
17
+ print(f"DEBUG: Gradio version: {gr.__version__}") # Log Gradio version
18
 
 
19
  GENERATE_SCRIPT_PATH = "/app/nanoVLM/generate.py"
20
+ MODEL_REPO_ID = "lusxvr/nanoVLM-222M"
21
 
22
  print(f"DEBUG: Using generate.py script at: {GENERATE_SCRIPT_PATH}")
23
  print(f"DEBUG: Using model repo ID: {MODEL_REPO_ID}")
24
 
 
25
  def call_generate_script(image_path: str, prompt_text: str) -> str:
26
+ print(f"\n--- DEBUG (call_generate_script) ---")
27
+ print(f"Timestamp: {time.strftime('%Y-%m-%d %H:%M:%S')}")
28
+ print(f"Calling with image_path='{image_path}', prompt='{prompt_text}'")
 
29
 
30
+ # Arguments for nanoVLM's generate.py
31
+ # Using low max_new_tokens for CPU testing.
32
  cmd_args = [
33
+ "python", "-u", GENERATE_SCRIPT_PATH, # -u for unbuffered output
34
  "--hf_model", MODEL_REPO_ID,
35
+ "--image_path", image_path, # Corrected: nanoVLM generate.py uses --image_path
36
  "--prompt", prompt_text,
37
+ "--num_samples", "1", # Corrected: Corresponds to --generations
38
+ "--max_new_tokens", "30", # Keep it low for testing
39
+ "--device", "cpu" # Explicitly set device for generate.py
40
+ # Optional args for generate.py:
41
+ # "--temperature", "0.7",
42
+ # "--top_k", "50"
43
  ]
44
 
45
+ print(f"Executing command: {' '.join(cmd_args)}")
46
+
47
+ # Realistic timeout for the subprocess. HF Spaces free tier usually times out requests around 60s.
48
+ # Set this shorter to catch issues within app.py.
49
+ SCRIPT_TIMEOUT_SECONDS = 55
50
+ start_time = time.time()
51
 
52
+ process_details = "Process details not available." # Placeholder
53
  try:
 
 
 
54
  process = subprocess.run(
55
  cmd_args,
56
  capture_output=True,
57
  text=True,
58
+ check=False, # Set to False to manually check returncode and log output
59
+ timeout=SCRIPT_TIMEOUT_SECONDS
60
  )
61
+ process_details = f"PID {process.pid if hasattr(process, 'pid') else 'N/A'}"
62
+
63
+ duration = time.time() - start_time
64
+ print(f"Subprocess ({process_details}) finished in {duration:.2f} seconds.")
65
+ print(f"generate.py RETURN CODE: {process.returncode}")
66
 
67
+ stdout = process.stdout.strip() if process.stdout else "[No STDOUT from generate.py]"
68
+ stderr = process.stderr.strip() if process.stderr else "[No STDERR from generate.py]"
 
 
 
 
69
 
70
+ print(f"---------- generate.py STDOUT ({process_details}) START ----------\n{stdout}\n---------- generate.py STDOUT ({process_details}) END ----------")
71
+ if stderr or process.returncode != 0:
72
+ print(f"---------- generate.py STDERR ({process_details}) START ----------\n{stderr}\n---------- generate.py STDERR ({process_details}) END ----------")
73
+
74
+ if process.returncode != 0:
75
+ error_message = f"Error: Generation script failed (code {process.returncode})."
76
+ if "out of memory" in stderr.lower(): error_message += " Potential OOM in script."
77
+ print(error_message) # Log it before returning
78
+ return error_message + f" See Space logs for full STDOUT/STDERR from script ({process_details})."
79
+
80
+ # --- Parse the output from nanoVLM's generate.py ---
81
+ # Expected format:
82
  # Outputs:
83
+ # > Sample 1: <generated text>
 
 
84
  output_lines = stdout.splitlines()
85
+ generated_text = "[No parsable output from generate.py]" # Default
86
 
87
+ found_output_line = False
88
+ for line_idx, line in enumerate(output_lines):
89
+ stripped_line = line.strip()
90
+ # print(f"Parsing STDOUT line {line_idx}: '{stripped_line}'") # Can be very verbose
91
+ if stripped_line.startswith("> Sample 1:") or stripped_line.startswith(">> Generation 1:"):
92
+ prefix_to_remove = ""
93
+ if stripped_line.startswith("> Sample 1:"): prefix_to_remove = "> Sample 1:"
94
+ elif stripped_line.startswith(">> Generation 1: "): prefix_to_remove = ">> Generation 1: " # Note double space
95
+ elif stripped_line.startswith(">> Generation 1: "): prefix_to_remove = ">> Generation 1: " # Note single space
96
+
97
+ if prefix_to_remove:
98
+ generated_text = stripped_line.replace(prefix_to_remove, "", 1).strip()
99
+ found_output_line = True
100
+ print(f"Parsed generated text: '{generated_text}'")
101
+ break
102
 
103
+ if not found_output_line:
104
+ print(f"Could not find 'Sample 1' or 'Generation 1' line in generate.py output.")
105
+ # Return a snippet of STDOUT if parsing fails, to help debug output format
106
+ generated_text = f"[Parsing failed] STDOUT (first 200 chars): {stdout[:200]}"
107
+
108
+
109
+ print(f"Returning parsed text: '{generated_text}'")
110
  return generated_text
111
 
112
+ except subprocess.TimeoutExpired as e:
113
+ duration = time.time() - start_time
114
+ print(f"ERROR: generate.py ({process_details}) timed out after {duration:.2f} seconds (limit: {SCRIPT_TIMEOUT_SECONDS}s).")
115
+ stdout_on_timeout = e.stdout.strip() if e.stdout else "[No STDOUT on timeout]"
116
+ stderr_on_timeout = e.stderr.strip() if e.stderr else "[No STDERR on timeout]"
117
+ print(f"STDOUT on timeout:\n{stdout_on_timeout}")
118
+ print(f"STDERR on timeout:\n{stderr_on_timeout}")
119
+ return f"Error: Generation script timed out after {SCRIPT_TIMEOUT_SECONDS}s. Model loading and generation may be too slow for CPU."
120
  except Exception as e:
121
+ duration = time.time() - start_time
122
+ print(f"ERROR: An unexpected error occurred ({process_details}) after {duration:.2f}s: {type(e).__name__} - {e}")
123
+ import traceback; traceback.print_exc()
124
+ return f"Unexpected error calling script: {str(e)}"
125
+ finally:
126
+ print(f"--- END (call_generate_script) ---")
127
 
128
 
129
  def gradio_interface_fn(image_input_pil: Optional[PILImage.Image], prompt_input_str: Optional[str]) -> str:
130
+ print(f"\nDEBUG (gradio_interface_fn): Timestamp: {time.strftime('%Y-%m-%d %H:%M:%S')}")
131
+ print(f"Received prompt: '{prompt_input_str}', Image type: {type(image_input_pil)}")
132
+
133
  if image_input_pil is None:
134
  return "Please upload an image."
135
+
136
+ cleaned_prompt = prompt_input_str.strip() if prompt_input_str else ""
137
+ if not cleaned_prompt:
138
+ return "Please provide a non-empty prompt."
139
 
140
+ tmp_image_path = None
 
 
 
141
  try:
142
+ if image_input_pil.mode != "RGB":
143
+ print(f"Converting image from {image_input_pil.mode} to RGB.")
144
+ image_input_pil = image_input_pil.convert("RGB")
145
+
146
  with tempfile.NamedTemporaryFile(suffix=".jpg", delete=False) as tmp_image_file:
147
  image_input_pil.save(tmp_image_file, format="JPEG")
148
  tmp_image_path = tmp_image_file.name
149
 
150
+ print(f"Temporary image saved to: {tmp_image_path}")
151
 
152
+ result_text = call_generate_script(tmp_image_path, cleaned_prompt)
 
153
 
154
+ print(f"Result from call_generate_script: '{result_text}'")
155
  return result_text
156
 
157
  except Exception as e:
158
+ print(f"ERROR (gradio_interface_fn): Error processing image or calling script: {type(e).__name__} - {e}")
159
  import traceback; traceback.print_exc()
160
+ return f"An error occurred in Gradio interface function: {str(e)}"
161
  finally:
162
+ if tmp_image_path and os.path.exists(tmp_image_path):
 
163
  try:
164
  os.remove(tmp_image_path)
165
+ print(f"Temporary image {tmp_image_path} removed.")
166
  except Exception as e_remove:
167
+ print(f"WARN: Could not remove temporary image {tmp_image_path}: {e_remove}")
168
+ print(f"DEBUG (gradio_interface_fn): Exiting.")
169
 
170
 
171
  # --- Gradio Interface Definition ---
 
173
  ## nanoVLM-222M Interactive Demo (via generate.py)
174
  Upload an image and type a prompt. This interface calls the `generate.py` script from
175
  `huggingface/nanoVLM` under the hood to perform inference.
176
+ **Note:** Each request re-loads the model via the script, so it might be slow on CPU.
177
  """
178
 
179
  print("DEBUG: Defining Gradio interface...")
 
185
  gr.Image(type="pil", label="Upload Image"),
186
  gr.Textbox(label="Your Prompt / Question", info="e.g., 'describe this image in detail'")
187
  ],
188
+ outputs=gr.Textbox(label="Generated Text", show_copy_button=True, lines=5),
189
  title="nanoVLM-222M Demo (via Script)",
190
  description=description_md,
191
  allow_flagging="never"
 
200
  print("DEBUG: Entered __main__ block for Gradio launch.")
201
  if not os.path.exists(GENERATE_SCRIPT_PATH):
202
  print(f"CRITICAL ERROR: The script {GENERATE_SCRIPT_PATH} was not found. Cannot launch app.")
203
+ iface = None
204
 
205
  if iface is not None:
206
  print("DEBUG: Attempting to launch Gradio interface...")
207
  try:
208
  iface.launch(server_name="0.0.0.0", server_port=7860)
209
+ print("DEBUG: Gradio launch command issued. UI should be accessible.")
210
  except Exception as e:
211
  print(f"CRITICAL ERROR launching Gradio interface: {e}")
212
  import traceback; traceback.print_exc()