Hug0endob commited on
Commit
58e5fdf
·
verified ·
1 Parent(s): e4bf697

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +84 -57
app.py CHANGED
@@ -14,27 +14,26 @@ except Exception as e:
14
  raise RuntimeError("llama-cpp-python import failed: " + str(e))
15
 
16
  MODEL_DIR = "model"
17
- EXPECTED_TARGET = os.path.join(MODEL_DIR, "llama-joycaption-q4_k_m.gguf")
 
18
 
19
  # Candidate direct-download URLs (try in order)
20
  CANDIDATES = [
21
- # Jasaga7818 copy (often a direct GGUF)
22
  ("https://huggingface.co/Jasaga7818/llama-joycaption-beta-one-hf-llava-Q4_K_M-GGUF/resolve/main/llama-joycaption-beta-one-hf-llava-q4_k_m.gguf",
23
- EXPECTED_TARGET),
24
- # mradermacher (alternate host)
25
  ("https://huggingface.co/mradermacher/llama-joycaption-beta-one-hf-llava-GGUF/resolve/main/llama-joycaption-beta-one-hf-llava-q4_k_m.gguf",
26
- EXPECTED_TARGET),
27
- # Fallback to Q4_K_S (Jasaga)
28
- ("https://huggingface.co/Jasaga7818/llama-joycaption-beta-one-hf-llava-Q4_K_M-GGUF/resolve/main/llama-joycaption-beta-one-hf-llava-q4_k_s.gguf",
29
- os.path.join(MODEL_DIR, "llama-joycaption-q4_k_s.gguf")),
30
  ("https://huggingface.co/mradermacher/llama-joycaption-beta-one-hf-llava-GGUF/resolve/main/llama-joycaption-beta-one-hf-llava-q4_k_s.gguf",
31
- os.path.join(MODEL_DIR, "llama-joycaption-q4_k_s.gguf")),
 
 
32
  ]
33
 
34
  def download_curl(url: str, path: str) -> bool:
35
  os.makedirs(os.path.dirname(path), exist_ok=True)
36
  try:
37
- # Use curl for resume support and progress in logs
38
  subprocess.check_call(["curl", "-L", "-C", "-", "-o", path, url])
39
  return True
40
  except Exception:
@@ -46,8 +45,6 @@ def download_curl(url: str, path: str) -> bool:
46
  return False
47
 
48
  def is_valid_gguf(path: str) -> bool:
49
- # GGUF files start with "GGUF" in ASCII at offset 0 (0x47 0x47 0x55 0x46).
50
- # Some converted uploads may be HTML pages or redirects; check header.
51
  try:
52
  with open(path, "rb") as f:
53
  head = f.read(8)
@@ -55,50 +52,85 @@ def is_valid_gguf(path: str) -> bool:
55
  except Exception:
56
  return False
57
 
58
- def ensure_model() -> str:
59
- # If already present (and valid), use it.
60
- if os.path.exists(EXPECTED_TARGET) and is_valid_gguf(EXPECTED_TARGET):
61
- sys.stderr.write(f"Model already present and valid at {EXPECTED_TARGET}\n")
62
- return EXPECTED_TARGET
63
-
64
- sys.stderr.write("Model not found locally or invalid, attempting download (several GB)...\n")
 
 
 
 
65
  for url, dest in CANDIDATES:
66
- sys.stderr.write(f"Attempting download: {url} -> {dest}\n")
67
- if download_curl(url, dest):
68
- sys.stderr.write(f"Downloaded candidate to {dest}; verifying header...\n")
69
- if is_valid_gguf(dest):
70
- # If candidate wasn't the expected filename, create symlink so rest of code can use EXPECTED_TARGET.
71
- if os.path.abspath(dest) != os.path.abspath(EXPECTED_TARGET):
72
- try:
73
- if os.path.exists(EXPECTED_TARGET):
74
- os.remove(EXPECTED_TARGET)
75
- os.symlink(os.path.basename(dest), EXPECTED_TARGET)
76
- sys.stderr.write(f"Created symlink {EXPECTED_TARGET} -> {os.path.basename(dest)}\n")
77
- except Exception:
78
- # fallback: copy
79
- try:
80
- import shutil
81
- shutil.copyfile(dest, EXPECTED_TARGET)
82
- sys.stderr.write(f"Copied {dest} to {EXPECTED_TARGET}\n")
83
- except Exception:
84
- sys.stderr.write("Warning: failed to symlink or copy candidate to expected filename.\n")
85
- sys.stderr.write("Model verified as GGUF and ready.\n")
86
- return EXPECTED_TARGET
87
- else:
88
- sys.stderr.write("Downloaded file is not a valid GGUF (header mismatch). Removing and trying next.\n")
89
- try:
90
- os.remove(dest)
91
- except Exception:
92
- pass
93
  else:
94
- sys.stderr.write("Download failed for candidate; trying next.\n")
 
 
 
 
95
 
96
- raise FileNotFoundError("Failed to download a valid GGUF model from candidates. Check URLs and repo availability.")
97
 
98
- # Ensure model exists and is a GGUF before importing/initializing Llama
99
- MODEL_PATH = ensure_model()
100
- if not os.path.exists(MODEL_PATH):
101
- raise FileNotFoundError(f"Model not found at {MODEL_PATH} after download attempt.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
102
 
103
  def download_bytes(url: str, timeout: int = 30) -> bytes:
104
  with requests.get(url, stream=True, timeout=timeout) as r:
@@ -117,11 +149,6 @@ def make_prompt_for_image(image_path: str, user_prompt: str = "Describe the imag
117
  # JoyCaption-style multimodal GGUFs accept <img>{path}</img>
118
  return f"<img>{image_path}</img>\nUser: {user_prompt}\nAssistant:"
119
 
120
- # Initialize model (low-resource options)
121
- print("Loading GGUF model (this can take 30–120s)...", file=sys.stderr)
122
- # Adjust n_threads for the Space CPU; increase if you know you have more cores available.
123
- llm = Llama(model_path=MODEL_PATH, n_ctx=2048, n_threads=2)
124
-
125
  def generate_caption_from_url(url: str, prompt: str = "Describe the image."):
126
  if not url:
127
  return "No URL provided."
 
14
  raise RuntimeError("llama-cpp-python import failed: " + str(e))
15
 
16
  MODEL_DIR = "model"
17
+ MODEL_MAIN = os.path.join(MODEL_DIR, "llama-joycaption-q4_k_m.gguf")
18
+ MODEL_FALLBACK = os.path.join(MODEL_DIR, "llama-joycaption-q4_k_s.gguf")
19
 
20
  # Candidate direct-download URLs (try in order)
21
  CANDIDATES = [
22
+ # Primary Q4_K_M (Jasaga then mradermacher)
23
  ("https://huggingface.co/Jasaga7818/llama-joycaption-beta-one-hf-llava-Q4_K_M-GGUF/resolve/main/llama-joycaption-beta-one-hf-llava-q4_k_m.gguf",
24
+ MODEL_MAIN),
 
25
  ("https://huggingface.co/mradermacher/llama-joycaption-beta-one-hf-llava-GGUF/resolve/main/llama-joycaption-beta-one-hf-llava-q4_k_m.gguf",
26
+ MODEL_MAIN),
27
+ # Fallback Q4_K_S (mradermacher / Jasaga)
 
 
28
  ("https://huggingface.co/mradermacher/llama-joycaption-beta-one-hf-llava-GGUF/resolve/main/llama-joycaption-beta-one-hf-llava-q4_k_s.gguf",
29
+ MODEL_FALLBACK),
30
+ ("https://huggingface.co/Jasaga7818/llama-joycaption-beta-one-hf-llava-Q4_K_M-GGUF/resolve/main/llama-joycaption-beta-one-hf-llava-q4_k_s.gguf",
31
+ MODEL_FALLBACK),
32
  ]
33
 
34
  def download_curl(url: str, path: str) -> bool:
35
  os.makedirs(os.path.dirname(path), exist_ok=True)
36
  try:
 
37
  subprocess.check_call(["curl", "-L", "-C", "-", "-o", path, url])
38
  return True
39
  except Exception:
 
45
  return False
46
 
47
  def is_valid_gguf(path: str) -> bool:
 
 
48
  try:
49
  with open(path, "rb") as f:
50
  head = f.read(8)
 
52
  except Exception:
53
  return False
54
 
55
+ def ensure_models_downloaded():
56
+ # If main present and valid, done.
57
+ if os.path.exists(MODEL_MAIN) and is_valid_gguf(MODEL_MAIN):
58
+ sys.stderr.write(f"Found valid main model: {MODEL_MAIN}\n")
59
+ return
60
+ # If fallback present and valid, done.
61
+ if os.path.exists(MODEL_FALLBACK) and is_valid_gguf(MODEL_FALLBACK):
62
+ sys.stderr.write(f"Found valid fallback model: {MODEL_FALLBACK}\n")
63
+ return
64
+
65
+ sys.stderr.write("Model(s) missing or invalid; attempting downloads...\n")
66
  for url, dest in CANDIDATES:
67
+ sys.stderr.write(f"Downloading {url} -> {dest}\n")
68
+ ok = download_curl(url, dest)
69
+ if not ok:
70
+ sys.stderr.write(f"Download failed for {url}\n")
71
+ continue
72
+ if is_valid_gguf(dest):
73
+ sys.stderr.write(f"Downloaded and verified GGUF at {dest}\n")
74
+ # if we downloaded fallback but main missing, don't copy; we'll try to load fallback later
75
+ if dest == MODEL_MAIN:
76
+ return
77
+ # if dest is fallback, still continue loop to attempt main first (if available)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
78
  else:
79
+ sys.stderr.write(f"Downloaded file at {dest} is not a valid GGUF (header mismatch). Removing.\n")
80
+ try:
81
+ os.remove(dest)
82
+ except Exception:
83
+ pass
84
 
85
+ sys.stderr.write("Download attempts finished.\n")
86
 
87
+ def try_load_model(path: str, n_ctx: int = 2048, n_threads: int = 2):
88
+ try:
89
+ sys.stderr.write(f"Initializing Llama with model {path}...\n")
90
+ llm = Llama(model_path=path, n_ctx=n_ctx, n_threads=n_threads)
91
+ sys.stderr.write("Model loaded successfully.\n")
92
+ return llm
93
+ except Exception as e:
94
+ sys.stderr.write(f"Failed to load model {path}: {e}\n")
95
+ return None
96
+
97
+ # Ensure at least one model file is present (download if needed)
98
+ ensure_models_downloaded()
99
+
100
+ # Prefer main, then fallback
101
+ model_to_try = None
102
+ if os.path.exists(MODEL_MAIN) and is_valid_gguf(MODEL_MAIN):
103
+ model_to_try = MODEL_MAIN
104
+ elif os.path.exists(MODEL_FALLBACK) and is_valid_gguf(MODEL_FALLBACK):
105
+ model_to_try = MODEL_FALLBACK
106
+ else:
107
+ # attempt to download again and pick whatever exists
108
+ ensure_models_downloaded()
109
+ if os.path.exists(MODEL_MAIN) and is_valid_gguf(MODEL_MAIN):
110
+ model_to_try = MODEL_MAIN
111
+ elif os.path.exists(MODEL_FALLBACK) and is_valid_gguf(MODEL_FALLBACK):
112
+ model_to_try = MODEL_FALLBACK
113
+
114
+ if model_to_try is None:
115
+ raise FileNotFoundError("No valid GGUF model found. Place a compatible GGUF under model/ with filename\n"
116
+ "model/llama-joycaption-q4_k_m.gguf or model/llama-joycaption-q4_k_s.gguf.")
117
+
118
+ # Attempt to load chosen model; if load fails for magic/version, try fallback (if different)
119
+ llm = try_load_model(model_to_try, n_ctx=2048, n_threads=2)
120
+ if llm is None and model_to_try == MODEL_MAIN and os.path.exists(MODEL_FALLBACK) and is_valid_gguf(MODEL_FALLBACK):
121
+ sys.stderr.write("Primary model failed to load; attempting fallback model.\n")
122
+ llm = try_load_model(MODEL_FALLBACK, n_ctx=2048, n_threads=2)
123
+
124
+ if llm is None:
125
+ # Provide clear diagnostic and exit
126
+ sys.stderr.write("\nERROR: All model load attempts failed. Likely causes:\n"
127
+ " - The GGUF uses a newer GGUF version not supported by the installed llama.cpp/llama-cpp-python.\n"
128
+ " - The file is corrupted despite the header check.\n\n"
129
+ "Recommended fixes:\n"
130
+ " - Install a newer llama.cpp/llama-cpp-python built from main/master (supports newer GGUF versions).\n"
131
+ " - Or place a known-compatible GGUF (Q4_K_S from mradermacher or older GGUF) at model/llama-joycaption-q4_k_m.gguf\n"
132
+ " - To inspect the header run: hexdump -n4 model/llama-joycaption-q4_k_m.gguf\n")
133
+ raise RuntimeError("Model load failed for all candidates.")
134
 
135
  def download_bytes(url: str, timeout: int = 30) -> bytes:
136
  with requests.get(url, stream=True, timeout=timeout) as r:
 
149
  # JoyCaption-style multimodal GGUFs accept <img>{path}</img>
150
  return f"<img>{image_path}</img>\nUser: {user_prompt}\nAssistant:"
151
 
 
 
 
 
 
152
  def generate_caption_from_url(url: str, prompt: str = "Describe the image."):
153
  if not url:
154
  return "No URL provided."