CassianK commited on
Commit
455146e
ยท
verified ยท
1 Parent(s): 62ba053

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +75 -90
app.py CHANGED
@@ -1,44 +1,31 @@
1
- # app.py โ€” DeepSeek-OCR (HF Space, Gradio-only stable)
2
- # - Gradio UI ์ œ๊ณต (Claude Skill์€ Gradio /run/predict API๋กœ ํ˜ธ์ถœ)
3
- # - deepseek_ocr.py ๋˜๋Š” run_dpsk_ocr_image.py๋ฅผ ํŒŒ์ผ๊ฒฝ๋กœ๋กœ ์ง์ ‘ ๋กœ๋“œ
4
-
5
  import io, os, sys, base64, importlib.util, tempfile, traceback
6
- from typing import Optional
7
  from PIL import Image
8
  import numpy as np
9
  import gradio as gr
10
 
11
  ROOT = os.path.dirname(__file__)
12
 
13
- # ํ›„๋ณด ๋””๋ ‰ํ„ฐ๋ฆฌ: ๋ฃจํŠธ/DeepSeek-OCR-master, DeepSeek-OCR-main/DeepSeek-OCR-master, DeepSeek-OCR-hf ๋“ฑ
14
- DIR_CANDIDATES = [
15
- "DeepSeek-OCR-master",
16
- os.path.join("DeepSeek-OCR-main", "DeepSeek-OCR-master"),
17
- "DeepSeek-OCR-hf",
18
- os.path.join("DeepSeek-OCR-main", "DeepSeek-OCR-hf"),
19
- ]
20
-
21
- FILE_CANDIDATES = [
22
- "deepseek_ocr.py", # ํ•จ์ˆ˜ํ˜• ๋˜๋Š” ํด๋ž˜์Šคํ˜• ์—”ํŠธ๋ฆฌ ๊ธฐ๋Œ€
23
- "run_dpsk_ocr_image.py", # CLI ์Šคํƒ€์ผ ์—”ํŠธ๋ฆฌ ๊ฐ€๋Šฅ
24
- "run_dpsk_ocr.py", # HF ์Šคํฌ๋ฆฝํŠธ
25
  ]
26
 
27
- def _find_file():
28
- for d in DIR_CANDIDATES:
29
- absd = os.path.join(ROOT, d)
30
- if not os.path.isdir(absd):
31
- continue
32
- for fname in FILE_CANDIDATES:
33
- path = os.path.join(absd, fname)
34
- if os.path.isfile(path):
35
- return path
36
- return None
37
 
38
- def _load_module_from_path(path: str):
39
  name = os.path.splitext(os.path.basename(path))[0]
40
  spec = importlib.util.spec_from_file_location(name, path)
41
- if spec is None or spec.loader is None:
42
  raise ImportError(f"Cannot load module from {path}")
43
  mod = importlib.util.module_from_spec(spec)
44
  sys.modules[name] = mod
@@ -47,52 +34,50 @@ def _load_module_from_path(path: str):
47
 
48
  class OCRAdapter:
49
  def __init__(self):
50
- self.entry = None
51
  self.mode = "demo"
52
- self.path = _find_file()
53
- print(f"[Adapter] candidate path: {self.path}")
54
- if not self.path:
55
- return
56
- try:
57
- mod = _load_module_from_path(self.path)
58
- # 1) ํ•จ์ˆ˜ํ˜• ์—”ํŠธ๋ฆฌ: ocr_image(image, lang="auto")
59
- if hasattr(mod, "ocr_image"):
60
- self.entry = lambda img, lang="auto": mod.ocr_image(img, lang=lang)
61
- self.mode = "func_ocr_image"
62
- print("[Adapter] using ocr_image(image, lang)")
63
- return
64
- # 2) ํด๋ž˜์Šคํ˜• ์—”ํŠธ๋ฆฌ: DeepSeekOCR().recognize(image, lang)
65
- if hasattr(mod, "DeepSeekOCR"):
66
- inst = mod.DeepSeekOCR()
67
- if hasattr(inst, "recognize"):
68
- self.entry = lambda img, lang="auto": inst.recognize(img, lang=lang)
69
- self.mode = "class_recognize"
70
- print("[Adapter] using DeepSeekOCR().recognize(image, lang)")
71
- return
72
- # 3) ์Šคํฌ๋ฆฝํŠธ/CLIํ˜•: run() / infer() / main() โ€” ๊ฒฝ๋กœ ์š”๊ตฌ ๊ฐ€๋Šฅ
73
- for cand in ("run", "infer", "main", "predict"):
74
- if hasattr(mod, cand):
75
- fn = getattr(mod, cand)
76
- def _call(img, lang="auto", _fn=fn):
77
- # ์ด๋ฏธ์ง€๊ฐ€ ํŒŒ์ผ๊ฒฝ๋กœ๋ฅผ ์š”๊ตฌํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์ž„์‹œ ์ €์žฅ
78
- with tempfile.NamedTemporaryFile(suffix=".png", delete=True) as tmp:
79
- img.save(tmp.name)
80
- try:
81
- return str(_fn(tmp.name))
82
- except TypeError:
83
- # ํ˜น์‹œ lang ๋“ฑ ๋‹ค๋ฅธ ์ธ์ž ๊ตฌ์กฐ์ผ ๊ฒฝ์šฐ ์‹œ๋„
84
- return str(_fn(tmp.name, lang=lang))
85
- self.entry = _call
86
- self.mode = f"script_{cand}"
87
- print(f"[Adapter] using {os.path.basename(self.path)}.{cand}(...) via temp file")
88
- return
89
- except Exception as e:
90
- print("[Adapter] load failed:", e)
91
- print(traceback.format_exc())
92
 
93
- # fallback
94
- self.entry = lambda img, lang="auto": "[DEMO] ์—ฐ๊ฒฐ ์„ฑ๊ณต โ€” ์‹ค์ œ ์ถ”๋ก  ํ•จ์ˆ˜ ํ™•์ธ ํ•„์š”."
95
- self.mode = "demo"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
96
 
97
  def recognize(self, image: Image.Image, lang="auto") -> str:
98
  return self.entry(image.convert("RGB"), lang)
@@ -100,33 +85,33 @@ class OCRAdapter:
100
  ADAPTER = OCRAdapter()
101
 
102
  def _to_pil(x) -> Image.Image:
103
- if isinstance(x, Image.Image):
104
- return x.convert("RGB")
105
- if isinstance(x, (bytes, bytearray)):
106
- return Image.open(io.BytesIO(x)).convert("RGB")
107
- if isinstance(x, np.ndarray):
108
- return Image.fromarray(x).convert("RGB")
109
  raise TypeError("Unsupported image type")
110
 
111
  def _b64_to_image(image_b64: str) -> Image.Image:
112
- import base64
113
  return _to_pil(base64.b64decode(image_b64))
114
 
115
- # โ”€โ”€ Gradio UI (Claude Skill์€ /run/predict API ์‚ฌ์šฉ) โ”€โ”€
116
  def gradio_predict(image, lang):
117
- if image is None:
118
- return "No image provided."
119
- return ADAPTER.recognize(_to_pil(image), lang)
 
 
120
 
121
- with gr.Blocks(title="DeepSeek-OCR (HF Gradio)") as demo:
122
- gr.Markdown("### DeepSeek-OCR (HF Space, Gradio)\nํ˜„์žฌ ๋ชจ๋“œ: **" + ADAPTER.mode + "** \n๊ฒฝ๋กœ: " + str(ADAPTER.path))
 
 
 
 
 
123
  with gr.Row():
124
  img = gr.Image(type="pil", label="Input Image")
125
- out = gr.Textbox(label="OCR Result", lines=8)
126
  lang = gr.Radio(["auto","en","ko","ja","zh"], value="auto", label="Language")
127
  btn = gr.Button("Run OCR")
128
  btn.click(gradio_predict, inputs=[img, lang], outputs=[out])
129
 
130
- # Hugging Face (sdk: gradio)๋Š” ์ „์—ญ ๋ณ€์ˆ˜ `demo`๋ฅผ ์ž๋™ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.
131
- # demo.queue() # ํ•„์š”์‹œ ์‚ฌ์šฉ (๋ฒ„์ „๋ณ„ ์ธ์ž ์—†์ด)
132
- demo.launch()
 
1
+ # app.py โ€” DeepSeek-OCR (HF Space, Gradio only, recursive finder)
 
 
 
2
  import io, os, sys, base64, importlib.util, tempfile, traceback
3
+ from typing import Optional, List
4
  from PIL import Image
5
  import numpy as np
6
  import gradio as gr
7
 
8
  ROOT = os.path.dirname(__file__)
9
 
10
+ TARGET_FILENAMES = [
11
+ "deepseek_ocr.py", # ํ•จ์ˆ˜ํ˜•/ํด๋ž˜์Šคํ˜•
12
+ "run_dpsk_ocr_image.py", # CLI ์Šคํƒ€์ผ
13
+ "run_dpsk_ocr.py", # HF ์ „์šฉ ์Šคํฌ๋ฆฝํŠธ
 
 
 
 
 
 
 
 
14
  ]
15
 
16
+ def find_candidates(root: str) -> List[str]:
17
+ """ํ”„๋กœ์ ํŠธ ์ „์ฒด๋ฅผ ์žฌ๊ท€์ ์œผ๋กœ ๋’ค์ ธ ํƒ€๊ฒŸ ํŒŒ์ผ ๊ฒฝ๋กœ๋“ค์„ ๋ชจ๋‘ ์ˆ˜์ง‘"""
18
+ hits = []
19
+ for dirpath, dirnames, filenames in os.walk(root):
20
+ for fn in filenames:
21
+ if fn in TARGET_FILENAMES:
22
+ hits.append(os.path.join(dirpath, fn))
23
+ return sorted(hits)
 
 
24
 
25
+ def load_module_from_path(path: str):
26
  name = os.path.splitext(os.path.basename(path))[0]
27
  spec = importlib.util.spec_from_file_location(name, path)
28
+ if not spec or not spec.loader:
29
  raise ImportError(f"Cannot load module from {path}")
30
  mod = importlib.util.module_from_spec(spec)
31
  sys.modules[name] = mod
 
34
 
35
  class OCRAdapter:
36
  def __init__(self):
 
37
  self.mode = "demo"
38
+ self.path = None
39
+ self.debug = []
40
+ self.entry = lambda img, lang="auto": "[DEMO] DeepSeek ์ฝ”๋“œ ์—ฐ๊ฒฐ ์ „์ž…๋‹ˆ๋‹ค."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41
 
42
+ hits = find_candidates(ROOT)
43
+ self.debug.append(f"ROOT={ROOT}")
44
+ self.debug.append("FOUND=" + ("; ".join(hits) if hits else "(none)"))
45
+
46
+ for path in hits:
47
+ try:
48
+ mod = load_module_from_path(path)
49
+ # 1) ํ•จ์ˆ˜ํ˜•: ocr_image(image, lang="auto")
50
+ if hasattr(mod, "ocr_image"):
51
+ self.entry = lambda img, lang="auto", _m=mod: _m.ocr_image(img, lang=lang)
52
+ self.mode, self.path = "func_ocr_image", path
53
+ self.debug.append(f"USE {path} :: ocr_image")
54
+ return
55
+ # 2) ํด๋ž˜์Šคํ˜•: DeepSeekOCR().recognize(image, lang)
56
+ if hasattr(mod, "DeepSeekOCR"):
57
+ inst = mod.DeepSeekOCR()
58
+ if hasattr(inst, "recognize"):
59
+ self.entry = lambda img, lang="auto", _i=inst: _i.recognize(img, lang=lang)
60
+ self.mode, self.path = "class_recognize", path
61
+ self.debug.append(f"USE {path} :: DeepSeekOCR.recognize")
62
+ return
63
+ # 3) ์Šคํฌ๋ฆฝํŠธํ˜•: run / infer / main (ํŒŒ์ผ๊ฒฝ๋กœ ์š”๊ตฌ ๊ฐ€๋Šฅ)
64
+ for cand in ("run", "infer", "main", "predict"):
65
+ if hasattr(mod, cand):
66
+ fn = getattr(mod, cand)
67
+ def _call(img, lang="auto", _fn=fn):
68
+ with tempfile.NamedTemporaryFile(suffix=".png", delete=True) as tmp:
69
+ img.save(tmp.name)
70
+ try:
71
+ return str(_fn(tmp.name))
72
+ except TypeError:
73
+ return str(_fn(tmp.name, lang=lang))
74
+ self.entry = _call
75
+ self.mode, self.path = f"script_{cand}", path
76
+ self.debug.append(f"USE {path} :: {cand}(path)")
77
+ return
78
+ self.debug.append(f"NO ENTRY in {path}")
79
+ except Exception as e:
80
+ self.debug.append(f"LOAD FAIL {path} :: {e}")
81
 
82
  def recognize(self, image: Image.Image, lang="auto") -> str:
83
  return self.entry(image.convert("RGB"), lang)
 
85
  ADAPTER = OCRAdapter()
86
 
87
  def _to_pil(x) -> Image.Image:
88
+ if isinstance(x, Image.Image): return x.convert("RGB")
89
+ if isinstance(x, (bytes, bytearray)): return Image.open(io.BytesIO(x)).convert("RGB")
90
+ if isinstance(x, np.ndarray): return Image.fromarray(x).convert("RGB")
 
 
 
91
  raise TypeError("Unsupported image type")
92
 
93
  def _b64_to_image(image_b64: str) -> Image.Image:
 
94
  return _to_pil(base64.b64decode(image_b64))
95
 
 
96
  def gradio_predict(image, lang):
97
+ if image is None: return "No image provided."
98
+ try:
99
+ return ADAPTER.recognize(_to_pil(image), lang)
100
+ except Exception as e:
101
+ return f"[ERROR] {e}\n" + traceback.format_exc()
102
 
103
+ with gr.Blocks(title="DeepSeek-OCR (HF Space, Gradio)") as demo:
104
+ gr.Markdown(
105
+ "### DeepSeek-OCR (HF Space, Gradio)\n"
106
+ f"**ํ˜„์žฌ ๋ชจ๋“œ:** `{ADAPTER.mode}` \n"
107
+ f"**๊ฒฝ๋กœ:** `{ADAPTER.path}` \n"
108
+ f"**์ฐพ์€ ํ›„๋ณด:** \n```\n" + "\n".join(ADAPTER.debug) + "\n```"
109
+ )
110
  with gr.Row():
111
  img = gr.Image(type="pil", label="Input Image")
112
+ out = gr.Textbox(label="OCR Result", lines=10)
113
  lang = gr.Radio(["auto","en","ko","ja","zh"], value="auto", label="Language")
114
  btn = gr.Button("Run OCR")
115
  btn.click(gradio_predict, inputs=[img, lang], outputs=[out])
116
 
117
+ demo.launch()