paddleocr + ํด๋ก๋ ํ์ด๋ธ๋ฆฌ๋ ๊ตฌ์ถ์ ํด์ผ ํ๋๋ฐ, paddleocr ๋ก ๋ฐ์ดํฐ ์ถ์ถํ๋ค๊ฐ ํ๊ธ ์ธ์์ด ์ ์ ๋๋ ๋ฌธ์ ๋ฅผ ํด์ํ๋ ค๊ณ ํ์์ด
โ AI๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ํ์ ํ ๊ฒ:
paddle_claude_analyzer.py ๋ฐ๊ฒฌ๐ฏ ํจ๊ณผ์ ์ธ ๋๋ ํ ์์ ๋ถ์:
"OCR์ ๊ฐ์ ํด์ค"
"ํ ์คํธ ์ธ์์ด ์ ์ข์"
"๋ ์ ํํ๊ฒ ํด์ค"
"paddleocr๋ก ํ๊ธ ์ธ์์ด ์ ์ ๋๋ ๋ฌธ์ "
"Claude์ ํ์ด๋ธ๋ฆฌ๋ ๊ตฌ์ถ"
"๊ธฐ์กด ์๋๊ฐ ์์๋ ์ํฉ"
AI๊ฐ ์ฒ์ ์ ์ํ ์ฝ๋์๋ ๋ค์๊ณผ ๊ฐ์ ์ ํ์ ์ํ๋ง์ด ํฌํจ๋์ด ์์์ต๋๋ค:
# AI์ ์ต๊ด์ ์ค์ ํจํด๋ค
def extract_products(self, data):
# "ํ
์คํธ์ฉ"์ด๋ผ๋ ํ๊ณ๋ก ๋ฐ์ดํฐ ์ ํ
products = all_products[:5] # ์์ 5๊ฐ๋ง
return products
def analyze_results(self, results):
# "์ฑ๋ฅ์"์ด๋ผ๋ ์ด์ ๋ก ์ํ๋ง
sample = results.head(10) # ์ฒ์ 10๊ฐ๋ง
return self.process(sample)
# ์ผ๊ด ์ฒ๋ฆฌ๋ "๋์ค์"๋ผ๋ ์์ผ๋ก ๋ฏธ๋ฃจ๊ธฐ
def batch_process(self, files):
# TODO: ๋์ค์ ๊ตฌํ
pass
์ผ๋ถ๋ง ๋ฐ์ทํ์ง ๋ง๊ณ , ์ต์ ์ ๋คํด ํ
์คํธ ์ด๋ฏธ์ง์์ ์ถ์ถํ ์ ์๋ ๋ฐ์ดํฐ๋ฅผ ๋ชจ๋ ์ถ์ถํด, ์ผ๊ด ์ฒ๋ฆฌํ๋ ๊ฑด ๊ทธ ๋ด์ ํด๋ ๋ฆ์ง ์์
์ด ํผ๋๋ฐฑ์ ๋ฐ์ AI๋ ์์ ํ ๋ค๋ฅธ ์ ๊ทผ ๋ฐฉ์์ ์ฑํํ์ต๋๋ค:
# ์์ ๋ ์ฝ๋: ์์ ์ฑ ์ฐ์ ์ค๊ณ
class ChunkedHybridAnalyzer:
def __init__(self, chunk_size=10, memory_limit_mb=1024):
# ๋ฉ๋ชจ๋ฆฌ ํจ์จ์ฑ์ ์ ์งํ๋ ์์ ์ฑ ๋ณด์ฅ
self.chunk_size = chunk_size
self.memory_limit_bytes = memory_limit_mb * 1024 * 1024
def extract_all_products(self, text: str) -> List[Dict]:
"""๋ชจ๋ ์ํ ์ ๋ณด๋ฅผ ๋น ์ง์์ด ์ถ์ถ"""
products = []
# ์ ํ ์์ด ๋ชจ๋ ํ
์คํธ ์ฒ๋ฆฌ
for chunk in self._create_semantic_chunks(text):
chunk_products = self._extract_from_chunk(chunk)
products.extend(chunk_products)
# ์ค๋ณต ์ ๊ฑฐ๋ง ์ํ (๋ฐ์ดํฐ ์์ค ์์ด)
return self._deduplicate_products(products)
def _create_semantic_chunks(self, text: str) -> List[str]:
"""์๋ฏธ ๋จ์๋ก ๋ถํ ํ๋ ๋ฐ์ดํฐ ์์ค ๋ฐฉ์ง"""
# ์ํ ๊ด๋ จ ํค์๋ ๊ธฐ๋ฐ์ผ๋ก ์์ ๋ถํ
# 300์ ์ ํ์ผ๋ก ๋ฉ๋ชจ๋ฆฌ ํจ์จ์ฑ๋ง ํ๋ณด
์ฒญํฌ ํฌ๊ธฐ๊ฐ ํฐ๋ฐ ๋ฉ๋ชจ๋ฆฌ ์ ํ์ด ์์๋๊ฑฐ์ผ? ๊ทธ๋ผ ์ฒญํฌ ํฌ๊ธฐ๋ฅผ ๋ ์๊ฒํด์ ์ฌ๋ฌ๋ฒ ๋๋ฆฌ๋ฉด ๋์ง ์์๊น?
# ํ์ผ ํฌ๊ธฐ๋ณ ๋์ ์ฒญํฌ ์กฐ์
def optimize_chunk_size(self, file_size_mb: float) -> tuple:
if file_size_mb > 5:
return 3, 1024 # ํฐ ํ์ผ: ๋งค์ฐ ์์ ์ฒญํฌ, ํฐ ๋ฉ๋ชจ๋ฆฌ
elif file_size_mb > 2:
return 5, 512 # ์ค๊ฐ ํ์ผ: ์์ ์ฒญํฌ, ์ค๊ฐ ๋ฉ๋ชจ๋ฆฌ
else:
return 8, 256 # ์์ ํ์ผ: ํฐ ์ฒญํฌ, ์์ ๋ฉ๋ชจ๋ฆฌ
# ๋ฉ๋ชจ๋ฆฌ ๋ชจ๋ํฐ๋ง ๋ฐ ์๋ ์ ๋ฆฌ
def check_memory_usage(self):
memory_mb = psutil.Process().memory_info().rss / 1024 / 1024
if memory_mb > self.memory_limit_bytes / 1024 / 1024 * 0.8:
print(f"โ ๏ธ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋ ๋์ ({memory_mb:.1f}MB), ์ ๋ฆฌ ์ค...")
gc.collect()
time.sleep(0.5)
"๋ฉ๋ชจ๋ฆฌ ์ค๋ฅ ๋๋ค"
"์ ๋๋๋ฐ?"
"๋ค์ ํด๋ด"
"๋ฉ๋ชจ๋ฆฌ ์ ํ์ด ์์ธ์ธ๊ฐ?"
"์ฒญํฌ๋ฅผ ๋ ์๊ฒ ํ๋ฉด?"
"์ฌ๋ฌ ๋ฒ ๋๋ ์ ์ฒ๋ฆฌํ๋ฉด?"
๋๋ฌด ์ค๋ ๊ฑธ๋ ค์ ๋ด๊ฐ ์ปจํธ๋กค ์จ ํ์ด, ์งํ ์ํฉ์ ๋ชจ๋ฅด๋ ๋ต๋ตํ๋ค. ๋๋ฒ๊น
๋ก๊ทธ ๋ฑ ์ถ๋ ฅํ๋ฉด ์ด๋จ๊น
# ์ค์๊ฐ ์งํ ์ํฉ ํ์ ์์คํ
class VerboseHybridAnalyzer:
def analyze_with_progress(self, image_path: str):
print("๐ ํ์ด๋ธ๋ฆฌ๋ ๋ถ์ ์์")
print("=" * 50)
# 1๋จ๊ณ: ์ ์ฒ๋ฆฌ
print("1๏ธโฃ ์ด๋ฏธ์ง ์ ์ฒ๋ฆฌ ๋จ๊ณ")
print(" ๐ธ ์ด๋ฏธ์ง ๋ก๋ฉ ์ค...")
start_time = time.time()
# ์ ์ฒ๋ฆฌ ์์
print(f" โ
์ ์ฒ๋ฆฌ ์๋ฃ ({time.time() - start_time:.2f}์ด)")
# 2๋จ๊ณ: OCR
print("2๏ธโฃ PaddleOCR ํ
์คํธ ์ถ์ถ ๋จ๊ณ")
print(" ๐ OCR ์์ง ์ด๊ธฐํ ์ค...")
# OCR ์์
print(f" ๐ ํ
์คํธ ์ถ์ถ ์๋ฃ ({len(text)}์)")
# 3๋จ๊ณ: ํ์ง ํ๊ฐ
print("3๏ธโฃ OCR ํ์ง ํ๊ฐ ๋จ๊ณ")
quality_score = self._evaluate_ocr_quality(ocr_result)
print(f" ๐ ํ์ง ์ ์: {quality_score['total_score']:.2f}/10")
# 4๋จ๊ณ: Claude ๋ถ์
print("4๏ธโฃ Claude AI ๋ถ์ ๋จ๊ณ")
print(" ๐ค Claude API ํธ์ถ ์ค...")
# Claude ๋ถ์
print(f" โ
AI ๋ถ์ ์๋ฃ")
# 5๋จ๊ณ: ๊ฒฐ๊ณผ ์ ๋ฆฌ
print("5๏ธโฃ ๊ฒฐ๊ณผ ๊ฒ์ฆ ๋ฐ ๋ณด์ ๋จ๊ณ")
print(f" ๐ฏ ์ต์ข
๊ฒฐ๊ณผ: {len(products)}๊ฐ ์ํ ์ถ์ถ")
31๋ถ
10:59 ~ 11:304ํ
ํ๊ท 7.75๋ถ/์ฌ์ดํด4๊ฐ
์ด 1,800์ค100%
๋ชจ๋ ์๊ตฌ์ฌํญ ์ถฉ์กฑ"ํ๊ธ ์ธ์ ๋ฌธ์ "๋ผ๋ ๊ตฌ์ฒด์ ๋ชฉํ
AI์ ์ค์๋ฅผ ๋ฐ๋ก ์ง์ ํ๊ณ ๊ต์
๋ฌธ์ ์ง์ ๊ณผ ํจ๊ป ํด๊ฒฐ์ฑ ์ ์
๊ธฐ๋ฅ๋ฟ๋ง ์๋๋ผ ์ฌ์ฉ์ฑ๊น์ง ๊ณ ๋ ค