devZenaight commited on
Commit
e0b4d0a
·
1 Parent(s): f3acecd
Files changed (2) hide show
  1. Dockerfile +11 -8
  2. app.py +38 -3
Dockerfile CHANGED
@@ -29,20 +29,20 @@
29
 
30
  FROM python:3.10-slim
31
 
32
- # System deps for OpenCV headless (no GUI) – keep these
33
  RUN apt-get update && apt-get install -y --no-install-recommends \
34
  libgl1 \
35
  libglib2.0-0 \
36
- && rm -rf /var/lib/apt/lists/*
37
 
38
- # Non-root user (HF best practice)
39
  RUN useradd -m -u 1000 user
40
  USER user
41
  ENV PATH="/home/user/.local/bin:$PATH"
42
 
43
  WORKDIR /app
44
 
45
- # Install Python deps
46
  COPY --chown=user requirements.txt .
47
  RUN pip install --no-cache-dir --upgrade pip \
48
  && pip install --no-cache-dir -r requirements.txt
@@ -50,17 +50,20 @@ RUN pip install --no-cache-dir --upgrade pip \
50
  # App code
51
  COPY --chown=user . /app
52
 
53
- # Perf hints (safe defaults; can override via Space Secrets)
54
  ENV OMP_NUM_THREADS=1 \
55
  OPENBLAS_NUM_THREADS=1 \
56
  UVICORN_WORKERS=2 \
57
  YOLO_CONCURRENCY=1 \
58
  HTTP_MAX_CONNECTIONS=50 \
59
  DB_POOL_MAX=10 \
60
- AUTH_CACHE_TTL_SECONDS=45
 
 
 
61
 
62
  EXPOSE 7860
63
 
64
- # Run the app. We call python so app.py reads env (workers, etc.)
65
- CMD ["python", "app.py"]
66
 
 
29
 
30
  FROM python:3.10-slim
31
 
32
+ # System deps for OpenCV headless
33
  RUN apt-get update && apt-get install -y --no-install-recommends \
34
  libgl1 \
35
  libglib2.0-0 \
36
+ && rm -rf /var/lib/apt/lists/*
37
 
38
+ # Non-root user
39
  RUN useradd -m -u 1000 user
40
  USER user
41
  ENV PATH="/home/user/.local/bin:$PATH"
42
 
43
  WORKDIR /app
44
 
45
+ # Python deps
46
  COPY --chown=user requirements.txt .
47
  RUN pip install --no-cache-dir --upgrade pip \
48
  && pip install --no-cache-dir -r requirements.txt
 
50
  # App code
51
  COPY --chown=user . /app
52
 
53
+ # Perf + Ultralytics config dir
54
  ENV OMP_NUM_THREADS=1 \
55
  OPENBLAS_NUM_THREADS=1 \
56
  UVICORN_WORKERS=2 \
57
  YOLO_CONCURRENCY=1 \
58
  HTTP_MAX_CONNECTIONS=50 \
59
  DB_POOL_MAX=10 \
60
+ AUTH_CACHE_TTL_SECONDS=45 \
61
+ YOLO_CONFIG_DIR=/tmp/Ultralytics
62
+
63
+ RUN mkdir -p /tmp/Ultralytics
64
 
65
  EXPOSE 7860
66
 
67
+ # Run via import string so multi-workers work cleanly
68
+ CMD ["bash", "-lc", "uvicorn app:app --host 0.0.0.0 --port 7860 --workers ${UVICORN_WORKERS:-2}"]
69
 
app.py CHANGED
@@ -775,26 +775,61 @@ def category_to_slug(category: str | None) -> str:
775
  .replace("-", "_")
776
  )
777
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
778
  def parse_extracted_json(raw_text: str) -> dict:
779
  if not raw_text:
780
  return {}
781
  text = str(raw_text).strip()
 
 
782
  s, e = text.find("{"), text.rfind("}")
783
  if s != -1 and e != -1 and e > s:
 
784
  try:
785
- return json.loads(text[s:e+1])
786
  except Exception:
787
  pass
 
 
788
  if text.startswith("```") and text.endswith("```"):
789
  lines = text.splitlines()
790
- if lines and lines[0].startswith("```"): lines = lines[1:]
791
- if lines and lines[-1].startswith("```"): lines = lines[:-1]
 
 
792
  try:
793
  return json.loads("\n".join(lines).strip())
794
  except Exception:
 
 
 
 
 
 
 
 
795
  return {}
796
  return {}
797
 
 
798
  def parse_total(value: str | float | int | None) -> float:
799
  if value is None:
800
  return 0.0
 
775
  .replace("-", "_")
776
  )
777
 
778
+ # def parse_extracted_json(raw_text: str) -> dict:
779
+ # if not raw_text:
780
+ # return {}
781
+ # text = str(raw_text).strip()
782
+ # s, e = text.find("{"), text.rfind("}")
783
+ # if s != -1 and e != -1 and e > s:
784
+ # try:
785
+ # return json.loads(text[s:e+1])
786
+ # except Exception:
787
+ # pass
788
+ # if text.startswith("```") and text.endswith("```"):
789
+ # lines = text.splitlines()
790
+ # if lines and lines[0].startswith("```"): lines = lines[1:]
791
+ # if lines and lines[-1].startswith("```"): lines = lines[:-1]
792
+ # try:
793
+ # return json.loads("\n".join(lines).strip())
794
+ # except Exception:
795
+ # return {}
796
+ # return {}
797
  def parse_extracted_json(raw_text: str) -> dict:
798
  if not raw_text:
799
  return {}
800
  text = str(raw_text).strip()
801
+
802
+ # 1) Try largest JSON object between first '{' and last '}'
803
  s, e = text.find("{"), text.rfind("}")
804
  if s != -1 and e != -1 and e > s:
805
+ candidate = text[s:e + 1]
806
  try:
807
+ return json.loads(candidate)
808
  except Exception:
809
  pass
810
+
811
+ # 2) Handle fenced code blocks ```json ... ```
812
  if text.startswith("```") and text.endswith("```"):
813
  lines = text.splitlines()
814
+ if lines and lines[0].startswith("```"):
815
+ lines = lines[1:]
816
+ if lines and lines[-1].startswith("```"):
817
+ lines = lines[:-1]
818
  try:
819
  return json.loads("\n".join(lines).strip())
820
  except Exception:
821
+ # last-chance bracket slice inside the fence
822
+ inner = "\n".join(lines).strip()
823
+ s2, e2 = inner.find("{"), inner.rfind("}")
824
+ if s2 != -1 and e2 != -1 and e2 > s2:
825
+ try:
826
+ return json.loads(inner[s2:e2 + 1])
827
+ except Exception:
828
+ return {}
829
  return {}
830
  return {}
831
 
832
+
833
  def parse_total(value: str | float | int | None) -> float:
834
  if value is None:
835
  return 0.0