Download text_utils.py from ssboost/672gjsds: direct link, hf CLI and curl.
- Browser
- Download file 10 kB
-
https://huggingface.co/spaces/ssboost/672gjsds/resolve/main/text_utils.py
- Command line
-
hf download hf://spaces/ssboost/672gjsds/text_utils.py
-
curl -L -o text_utils.py https://huggingface.co/spaces/ssboost/672gjsds/resolve/main/text_utils.py
10 kB
| """ | |
| ν μ€νΈ μ²λ¦¬ κ΄λ ¨ μ νΈλ¦¬ν° ν¨μ λͺ¨μ | |
| - ν μ€νΈ λΆλ¦¬ λ° μ μ | |
| - ν€μλ μΆμΆ | |
| - Gemini API ν€ ν΅ν© κ΄λ¦¬ μ μ© | |
| """ | |
| import re | |
| import google.generativeai as genai | |
| import os | |
| import logging | |
| import api_utils # API ν€ ν΅ν© κ΄λ¦¬λ₯Ό μν μν¬νΈ | |
| # λ‘κΉ μ€μ | |
| logger = logging.getLogger(__name__) | |
| logger.setLevel(logging.INFO) | |
| formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') | |
| handler = logging.StreamHandler() | |
| handler.setFormatter(formatter) | |
| logger.addHandler(handler) | |
| # ===== Gemini λͺ¨λΈ κ΄λ¦¬ ν¨μλ€ ===== | |
| def get_gemini_model(): | |
| """api_utilsμμ Gemini λͺ¨λΈ κ°μ Έμ€κΈ° (ν΅ν© κ΄λ¦¬)""" | |
| try: | |
| model = api_utils.get_gemini_model() | |
| if model: | |
| logger.info("Gemini λͺ¨λΈ λ‘λ μ±κ³΅ (api_utils ν΅ν© κ΄λ¦¬)") | |
| return model | |
| else: | |
| logger.warning("μ¬μ© κ°λ₯ν Gemini API ν€κ° μμ΅λλ€.") | |
| return None | |
| except Exception as e: | |
| logger.error(f"Gemini λͺ¨λΈ λ‘λ μ€ν¨: {e}") | |
| return None | |
| # ν μ€νΈ λΆλ¦¬ λ° μ μ ν¨μ | |
| def clean_and_split(text, only_korean=False): | |
| """ν μ€νΈλ₯Ό λΆλ¦¬νκ³ μ μ νλ ν¨μ""" | |
| text = re.sub(r"[()\[\]-]", " ", text) | |
| text = text.replace("/", " ") | |
| if only_korean: | |
| # νκΈλ§ μΆμΆ μ΅μ μ΄ μΌμ§ κ²½μ° | |
| # 곡백μ΄λ μΌνλ‘ κ΅¬λΆν λ€ νκΈλ§ μΆμΆ | |
| words = re.split(r"[ ,]", text) | |
| cleaned = [] | |
| for word in words: | |
| word = word.strip() | |
| # νκΈλ§ λ¨κΈ°κ³ λ€λ₯Έ λ¬Έμλ μ κ±° | |
| word = re.sub(r"[^κ°-ν£]", "", word) | |
| if word and len(word) >= 1: # λΉ λ¬Έμμ΄μ΄ μλκ³ 1κΈμ μ΄μμΈ κ²½μ°λ§ μΆκ° | |
| cleaned.append(word) | |
| else: | |
| # νκΈλ§ μΆμΆ μ΅μ μ΄ κΊΌμ§ κ²½μ° - λ¨μ΄ ν΅μ§Έλ‘ μ²λ¦¬ | |
| # 곡백과 μΌνλ‘ κ΅¬λΆνμ¬ λ¨μ΄ μ 체λ₯Ό μ μ§ | |
| words = re.split(r"[,\s]+", text) | |
| cleaned = [] | |
| for word in words: | |
| word = word.strip() | |
| if word and len(word) >= 1: # λΉ λ¬Έμμ΄μ΄ μλκ³ 1κΈμ μ΄μμΈ κ²½μ°λ§ μΆκ° | |
| cleaned.append(word) | |
| return cleaned | |
| def filter_keywords_with_gemini(pairs, gemini_model=None): | |
| """Gemini AIλ₯Ό μ¬μ©νμ¬ ν€μλ μ‘°ν© νν°λ§ (κ°μ λ²μ ) - API ν€ ν΅ν© κ΄λ¦¬""" | |
| if gemini_model is None: | |
| # api_utilsμμ Gemini λͺ¨λΈ κ°μ Έμ€κΈ° | |
| gemini_model = get_gemini_model() | |
| if gemini_model is None: | |
| logger.error("Gemini λͺ¨λΈμ κ°μ Έμ¬ μ μμ΅λλ€. λͺ¨λ ν€μλλ₯Ό μ μ§ν©λλ€.") | |
| # μμ νκ² μ²λ¦¬: λͺ¨λ ν€μλλ₯Ό μ μ§ | |
| all_keywords = set() | |
| for pair in pairs: | |
| for keyword in pair: | |
| all_keywords.add(keyword) | |
| return list(all_keywords) | |
| # λͺ¨λ ν€μλλ₯Ό λͺ©λ‘μΌλ‘ μΆμΆ (μ κ±°λ ν€μλ νμΈμ©) | |
| all_keywords = set() | |
| for pair in pairs: | |
| for keyword in pair: | |
| all_keywords.add(keyword) | |
| # λ무 λ§μ μμ΄ μμΌλ©΄ μ ν | |
| max_pairs = 50 # μ΅λ 50κ° μλ§ μ²λ¦¬ | |
| pairs_to_process = list(pairs)[:max_pairs] if len(pairs) > max_pairs else pairs | |
| logger.info(f"νν°λ§ν ν€μλ μ: μ΄ {len(pairs)}κ° μ€ {len(pairs_to_process)}κ° μ²λ¦¬") | |
| # 보μμ μΈ ν둬ννΈ μ¬μ© - ν€μλ μ κ±° μ΅μν | |
| prompt = ( | |
| "λ€μμ μλΉμκ° κ²μν κ°λ₯μ±μ΄ μλ ν€μλ μ λͺ©λ‘μ λλ€.\n" | |
| "κ° μμ κ°μ λ¨μ΄ μ‘°ν©μ΄μ§λ§ μμλ§ λ€λ₯Έ κ²½μ°μ λλ€ (μ: μμ§μ€μ§μ΄ vs μ€μ§μ΄μμ§).\n\n" | |
| "μλμ κΈ°μ€μ λ°λΌ κ° μμμ λ μμ°μ€λ¬μ΄ ν€μλλ₯Ό μ νν΄μ£ΌμΈμ:\n" | |
| "1. μλΉμκ° μΌμμ μΌλ‘ μ¬μ©νλ μμ°μ€λ¬μ΄ ννμ μ°μ μ ννμΈμ.\n" | |
| "2. λ ν€μλκ° λͺ¨λ μμ°μ€λ½κ±°λ μλ―Έκ° μ½κ° λ€λ₯΄λ€λ©΄, λ°λμ λ λ€ μ μ§νμΈμ.\n" | |
| "3. νμ€ν λΉμμ°μ€λ½κ±°λ μ΄μν κ²½μ°μλ§ μ κ±°νμΈμ.\n" | |
| "4. λΆνμ€ν κ²½μ°μλ λ°λμ ν€μλλ₯Ό μ μ§νμΈμ.\n" | |
| "5. μ«μλ μμ΄κ° ν¬ν¨λ ν€μλλ νκΈ λ©μΈ ν€μλκ° μμͺ½μ μ€λ ννλ₯Ό μ ννμΈμ. (μ: '10kg μ€μ§μ΄' λ³΄λ€ 'μ€μ§μ΄ 10kg' μ ν)\n" | |
| "6. κ²μλμ΄ 0μΈ ν€μλλΌλ μΌμμ μΈ ννμ΄λΌλ©΄ κ°λ₯ν μ μ§νμΈμ. λͺ λ°±νκ² λΉμ μμ μΈ ννλ§ μ κ±°νμΈμ.\n\n" | |
| "μ£Όμ: κΈ°λ³Έμ μΌλ‘ λλΆλΆμ ν€μλλ₯Ό μ μ§νκ³ , λ§€μ° λͺ ννκ² λΉμμ°μ€λ¬μ΄ κ²λ§ μ κ±°νμΈμ.\n\n" | |
| "κ²°κ³Όλ λ€μ νμμΌλ‘ μ 곡ν΄μ£ΌμΈμ:\n" | |
| "- μ νλ ν€μλ (μ΄μ : μμ°μ€λ¬μ΄ ννμ΄κΈ° λλ¬Έ)\n" | |
| "- μ νλ ν€μλ1, μ νλ ν€μλ2 (μ΄μ : λ λ€ μμ°μ€λ½κ³ μλ―Έκ° μ‘°κΈ λ€λ¦)\n\n" | |
| ) | |
| # ν€μλ μ λͺ©λ‘ | |
| formatted = "\n".join([f"- {a}, {b}" for a, b in pairs_to_process]) | |
| full_prompt = prompt + formatted | |
| try: | |
| # νμμμ μΆκ° | |
| logger.info(f"Gemini API νΈμΆ μμ - {len(pairs_to_process)}κ° ν€μλ μ μ²λ¦¬ μ€...") | |
| # μλ΅ λ°κΈ° (νμμμ κΈ°λ₯μ΄ μμΌλ©΄ μΆκ°) | |
| response = gemini_model.generate_content(full_prompt) | |
| logger.info("Gemini API μλ΅ μ±κ³΅") | |
| lines = response.text.strip().split("\n") | |
| # μ νλ ν€μλ μΆμΆ (μΌνλ‘ κ΅¬λΆλ κ²½μ° λͺ¨λ ν¬ν¨) | |
| final_keywords = [] | |
| for line in lines: | |
| if line.startswith("-"): | |
| # μ΄μ λΆλΆ μ κ±° | |
| keywords_part = line.strip("- ").split("(μ΄μ :")[0].strip() | |
| # μΌνλ‘ κ΅¬λΆλ ν€μλ λͺ¨λ μΆκ° | |
| for kw in keywords_part.split(","): | |
| kw = kw.strip() | |
| if kw: | |
| final_keywords.append(kw) | |
| # μ²λ¦¬λμ§ μμ μμ 첫 λ²μ§Έ ν€μλλ μΆκ° (LLMμ΄ μ²λ¦¬νμ§ μμ ν€μλ) | |
| if len(pairs) > max_pairs: | |
| logger.info(f"μΆκ° ν€μλ μ²λ¦¬: λ¨μ {len(pairs) - max_pairs}κ° μμ 첫 λ²μ§Έ ν€μλ μΆκ°") | |
| for pair in list(pairs)[max_pairs:]: | |
| # κ° μμ 첫 λ²μ§Έ ν€μλλ§ μ¬μ© | |
| final_keywords.append(pair[0]) | |
| # μ νλ ν€μλκ° μμΌλ©΄ κΈ°μ‘΄ ν€μλ λͺ¨λ λ°ν | |
| if not final_keywords: | |
| logger.warning("κ²½κ³ : μ νλ ν€μλκ° μμ΄ λͺ¨λ ν€μλλ₯Ό μ μ§ν©λλ€.") | |
| final_keywords = list(all_keywords) | |
| # μμ κ°μ μμ | |
| corrected_keywords = [] | |
| # λ¨μμ μ«μ κ΄λ ¨ μ κ·μ ν¨ν΄ | |
| unit_pattern = re.compile(r'(?i)(kg|g|mm|cm|ml|l|리ν°|κ°|ν©|λ°μ€|μΈνΈ|2l|l2)') | |
| number_pattern = re.compile(r'\d+') | |
| for kw in final_keywords: | |
| # 곡백μΌλ‘ λΆλ¦¬ | |
| if ' ' in kw: | |
| parts = kw.split() | |
| first_part = parts[0] | |
| # 첫 λΆλΆμ΄ λ¨μλ μ«μλ₯Ό ν¬ν¨νλμ§ νμΈ | |
| if (unit_pattern.search(first_part) or number_pattern.search(first_part)) and len(parts) > 1: | |
| # μμ λ°κΎΈκΈ°: λ¨μ/μ«μ λΆλΆμ λ€λ‘ μ΄λ | |
| corrected_kw = " ".join(parts[1:] + [first_part]) | |
| logger.info(f"ν€μλ μμ κ°μ μμ : '{kw}' -> '{corrected_kw}'") | |
| corrected_keywords.append(corrected_kw) | |
| else: | |
| corrected_keywords.append(kw) | |
| else: | |
| corrected_keywords.append(kw) | |
| # νΉλ³ μ²λ¦¬: "L μ€μ§μ΄", "2L μ€μ§μ΄" κ°μ κ²½μ°λ₯Ό λͺ μμ μΌλ‘ νμΈνκ³ μμ | |
| specific_fixes = [] | |
| for kw in corrected_keywords: | |
| # νΉμ ν¨ν΄ μ²΄ν¬ | |
| l_pattern = re.compile(r'^([0-9]*L) (.+)$', re.IGNORECASE) | |
| match = l_pattern.match(kw) | |
| if match: | |
| # L λ¨μλ₯Ό λ€λ‘ μ΄λ | |
| l_part = match.group(1) | |
| main_part = match.group(2) | |
| fixed_kw = f"{main_part} {l_part}" | |
| logger.info(f"νΉμ ν¨ν΄ μμ : '{kw}' -> '{fixed_kw}'") | |
| specific_fixes.append(fixed_kw) | |
| else: | |
| specific_fixes.append(kw) | |
| # μ κ±°λ ν€μλ λͺ©λ‘ νμΈ | |
| selected_set = set(specific_fixes) | |
| removed_keywords = all_keywords - selected_set | |
| # μ κ±°λ ν€μλ μΆλ ₯ | |
| logger.info("\n=== LLMμ μν΄ μ κ±°λ ν€μλ λͺ©λ‘ ===") | |
| for kw in removed_keywords: | |
| logger.info(f" - {kw}") | |
| logger.info(f"μ΄ {len(all_keywords)}κ° μ€ {len(removed_keywords)}κ° μ κ±°λ¨ ({len(selected_set)}κ° μ μ§)\n") | |
| return specific_fixes | |
| except Exception as e: | |
| logger.error(f"Gemini μ€λ₯: {e}") | |
| logger.error("μ€λ₯ λ°μμΌλ‘ μΈν΄ λͺ¨λ ν€μλλ₯Ό μ μ§ν©λλ€.") | |
| logger.error(f"μ€λ₯ μ ν: {type(e).__name__}") | |
| import traceback | |
| traceback.print_exc() | |
| # μμ νκ² μ²λ¦¬: λͺ¨λ ν€μλλ₯Ό μ μ§ | |
| logger.info(f"μμ λͺ¨λ: {len(all_keywords)}κ° ν€μλ λͺ¨λ μ μ§") | |
| return list(all_keywords) | |
| def get_search_volume_range(total_volume): | |
| """μ΄ κ²μλμ κΈ°λ°μΌλ‘ κ²μλ ꡬκ°μ λ°ν""" | |
| if total_volume == 0: | |
| return "100λ―Έλ§" | |
| elif total_volume <= 100: | |
| return "100λ―Έλ§" | |
| elif total_volume <= 1000: | |
| return "1000λ―Έλ§" | |
| elif total_volume <= 2000: | |
| return "2000λ―Έλ§" | |
| elif total_volume <= 5000: | |
| return "5000λ―Έλ§" | |
| elif total_volume <= 10000: | |
| return "10000λ―Έλ§" | |
| else: | |
| return "10000μ΄μ" |