| import os |
| import time |
| import base64 |
| import io |
| import traceback |
| import threading |
| import atexit |
| import asyncio |
| from datetime import datetime |
| from typing import Optional, Tuple |
|
|
| import gradio as gr |
| import anthropic |
| from playwright.async_api import async_playwright |
| from playwright.sync_api import sync_playwright, Browser, Page |
| from PIL import Image |
| import requests |
| from dotenv import load_dotenv |
|
|
| |
| load_dotenv() |
|
|
| |
| browser = None |
| page = None |
| playwright_instance = None |
| browser_lock = threading.Lock() |
| is_browser_ready = False |
| browser_thread_id = None |
|
|
| |
| def get_claude_client(): |
| api_key = os.getenv("ANTHROPIC_API_KEY") |
| if not api_key: |
| raise ValueError("ANTHROPIC_API_KEY ํ๊ฒฝ๋ณ์๊ฐ ์ค์ ๋์ง ์์์ต๋๋ค.") |
| |
| try: |
| |
| client = anthropic.Anthropic( |
| api_key=api_key, |
| max_retries=2, |
| timeout=60.0 |
| ) |
| return client |
| except Exception as e: |
| print(f"Claude ํด๋ผ์ด์ธํธ ์ด๊ธฐํ ์ค๋ฅ: {e}") |
| |
| return anthropic.Anthropic(api_key=api_key) |
|
|
| def install_browsers(): |
| """Playwright ๋ธ๋ผ์ฐ์ ๋ฐ ํ๊ธ ํฐํธ ์ค์น""" |
| try: |
| print("Playwright ๋ธ๋ผ์ฐ์ ์ค์น ์ค...") |
| os.system("playwright install chromium") |
| |
| print("ํ๊ธ ํฐํธ ์ค์น ์ค...") |
| |
| os.system("apt-get update") |
| os.system("apt-get install -y fonts-nanum fonts-nanum-coding fonts-nanum-extra") |
| os.system("fc-cache -fv") |
| |
| print("Playwright ๋ธ๋ผ์ฐ์ ๋ฐ ํฐํธ ์ค์น ์๋ฃ!") |
| return True |
| except Exception as e: |
| print(f"๋ธ๋ผ์ฐ์ /ํฐํธ ์ค์น ์คํจ: {e}") |
| return False |
|
|
| def init_browser(): |
| """Playwright ๋ธ๋ผ์ฐ์ ๋ฅผ ์ด๊ธฐํํ๊ณ Google Trends ํ์ด์ง๋ก ์ด๋""" |
| global browser, page, playwright_instance, is_browser_ready, browser_thread_id |
| |
| try: |
| |
| browser_thread_id = threading.current_thread().ident |
| print(f"๋ธ๋ผ์ฐ์ ์ด๊ธฐํ ์ค๋ ๋ ID: {browser_thread_id}") |
| |
| print("Playwright ๋ธ๋ผ์ฐ์ ์ด๊ธฐํ ์ค...") |
| |
| |
| install_browsers() |
| |
| |
| playwright_instance = sync_playwright().start() |
| |
| |
| browser = playwright_instance.chromium.launch( |
| headless=True, |
| args=[ |
| '--no-sandbox', |
| '--disable-dev-shm-usage', |
| '--disable-gpu', |
| '--disable-extensions', |
| '--disable-web-security', |
| '--allow-running-insecure-content', |
| '--disable-features=VizDisplayCompositor', |
| '--disable-background-timer-throttling', |
| '--disable-backgrounding-occluded-windows', |
| '--disable-renderer-backgrounding', |
| '--disable-features=TranslateUI', |
| '--disable-ipc-flooding-protection', |
| '--disable-plugins', |
| '--disable-images', |
| '--force-device-scale-factor=1', |
| '--font-render-hinting=medium', |
| '--disable-font-subpixel-positioning' |
| ] |
| ) |
| |
| |
| page = browser.new_page() |
| |
| |
| page.set_viewport_size({"width": 1920, "height": 1080}) |
| |
| |
| page.set_extra_http_headers({ |
| "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36", |
| "Accept-Language": "ko-KR,ko;q=0.9,en;q=0.8" |
| }) |
| |
| |
| page.add_style_tag(content=""" |
| * { |
| font-family: 'Nanum Gothic', 'Malgun Gothic', '๋ง์ ๊ณ ๋', 'Noto Sans CJK KR', 'Apple SD Gothic Neo', sans-serif !important; |
| } |
| """) |
| |
| print("Google Trends ํ์ด์ง๋ก ์ด๋ ์ค...") |
| page.goto("https://trends.google.com/trending?geo=KR", wait_until="networkidle", timeout=30000) |
| |
| |
| time.sleep(5) |
| |
| is_browser_ready = True |
| print("๋ธ๋ผ์ฐ์ ์ด๊ธฐํ ์๋ฃ!") |
| |
| except Exception as e: |
| print(f"๋ธ๋ผ์ฐ์ ์ด๊ธฐํ ์คํจ: {str(e)}") |
| print(traceback.format_exc()) |
| is_browser_ready = False |
| cleanup_browser() |
|
|
| def ensure_browser_ready(): |
| """๋ธ๋ผ์ฐ์ ๊ฐ ์ค๋น๋์ด ์๋์ง ํ์ธํ๊ณ , ํ์์ ์ด๊ธฐํ""" |
| global is_browser_ready, browser, page, browser_thread_id |
| |
| current_thread_id = threading.current_thread().ident |
| |
| |
| if not is_browser_ready or browser_thread_id != current_thread_id or not browser or not page: |
| print(f"๋ธ๋ผ์ฐ์ ์ฌ์ด๊ธฐํ ํ์ (ํ์ฌ ์ค๋ ๋: {current_thread_id}, ๋ธ๋ผ์ฐ์ ์ค๋ ๋: {browser_thread_id})") |
| |
| |
| cleanup_browser() |
| |
| |
| init_browser() |
| |
| return is_browser_ready |
|
|
| def cleanup_browser(): |
| """๋ธ๋ผ์ฐ์ ์ ๋ฆฌ""" |
| global browser, page, playwright_instance |
| |
| try: |
| if page: |
| page.close() |
| page = None |
| if browser: |
| browser.close() |
| browser = None |
| if playwright_instance: |
| playwright_instance.stop() |
| playwright_instance = None |
| print("๋ธ๋ผ์ฐ์ ์ ๋ฆฌ ์๋ฃ") |
| except Exception as e: |
| print(f"๋ธ๋ผ์ฐ์ ์ ๋ฆฌ ์ค ์ค๋ฅ: {e}") |
|
|
| def apply_filters(geo: str, time_range: str, category: str) -> bool: |
| """Google Trends ํํฐ ์ ์ฉ""" |
| global page |
| |
| |
| if not ensure_browser_ready(): |
| print("๋ธ๋ผ์ฐ์ ์ค๋น ์คํจ") |
| return False |
| |
| try: |
| print(f"ํํฐ ์ ์ฉ: ์ง์ญ={geo}") |
| |
| |
| geo_map = { |
| "KR": "KR", "US": "US", "JP": "JP", |
| "GB": "GB", "DE": "DE", "FR": "FR" |
| } |
| |
| base_url = "https://trends.google.com/trending" |
| geo_param = geo_map.get(geo, "KR") |
| url = f"{base_url}?geo={geo_param}" |
| |
| print(f"ํํฐ ์ ์ฉ๋ URL๋ก ์ด๋: {url}") |
| page.goto(url, wait_until="networkidle", timeout=30000) |
| |
| |
| time.sleep(3) |
| |
| |
| try: |
| |
| if time_range != "24์๊ฐ": |
| time_selector = page.locator('[data-bucket="0"]').first |
| if time_selector.is_visible(): |
| time_selector.click() |
| time.sleep(1) |
| |
| |
| if time_range == "7์ผ": |
| page.locator('text="Past 7 days"').first.click() |
| elif time_range == "30์ผ": |
| page.locator('text="Past 30 days"').first.click() |
| time.sleep(2) |
| |
| |
| if category != "๋ชจ๋ ์นดํ
๊ณ ๋ฆฌ": |
| category_selector = page.locator('[data-bucket="2"]').first |
| if category_selector.is_visible(): |
| category_selector.click() |
| time.sleep(1) |
| |
| |
| category_map = { |
| "์ํฐํ
์ธ๋จผํธ": "Entertainment", |
| "์คํฌ์ธ ": "Sports", |
| "๋น์ฆ๋์ค": "Business", |
| "๊ณผํ๊ธฐ์ ": "Science & Tech", |
| "๊ฑด๊ฐ": "Health" |
| } |
| |
| if category in category_map: |
| page.locator(f'text="{category_map[category]}"').first.click() |
| time.sleep(2) |
| |
| except Exception as filter_error: |
| print(f"ํํฐ ์์ ํด๋ฆญ ์คํจ (๊ณ์ ์งํ): {filter_error}") |
| |
| print("ํํฐ ์ ์ฉ ์๋ฃ") |
| return True |
| |
| except Exception as e: |
| print(f"ํํฐ ์ ์ฉ ์คํจ: {str(e)}") |
| print(traceback.format_exc()) |
| return False |
|
|
| def capture_screenshot() -> Optional[Image.Image]: |
| """ํ์ฌ ํ์ด์ง์ ์คํฌ๋ฆฐ์ท ์บก์ฒ (ํธ๋ ๋ ํ
์ด๋ธ ์์ญ๋ง)""" |
| global page |
| |
| |
| if not ensure_browser_ready(): |
| print("๋ธ๋ผ์ฐ์ ์ค๋น ์คํจ") |
| return None |
| |
| try: |
| print("์คํฌ๋ฆฐ์ท ์บก์ฒ ์ค...") |
| |
| |
| time.sleep(2) |
| |
| |
| try: |
| |
| selectors = [ |
| '[data-module="TrendingSearches"]', |
| '.trends-table', |
| '.trending-searches', |
| '[role="main"]', |
| 'main' |
| ] |
| |
| element = None |
| for selector in selectors: |
| try: |
| element = page.locator(selector).first |
| if element.is_visible(): |
| print(f"์บก์ฒ ์์ญ ๋ฐ๊ฒฌ: {selector}") |
| break |
| except: |
| continue |
| |
| if element and element.is_visible(): |
| |
| screenshot_bytes = element.screenshot() |
| print("ํธ๋ ๋ ํ
์ด๋ธ ์์ญ ์บก์ฒ ์๋ฃ") |
| else: |
| |
| print("ํน์ ์์ญ์ ์ฐพ์ง ๋ชปํด ํ์ด์ง ์๋จ ์์ญ ์บก์ฒ") |
| screenshot_bytes = page.screenshot(clip={"x": 0, "y": 100, "width": 1920, "height": 800}) |
| |
| except Exception as selector_error: |
| print(f"์์ญ ์ ํ ์คํจ, ์ ์ฒด ํ์ด์ง ์บก์ฒ: {selector_error}") |
| screenshot_bytes = page.screenshot(full_page=True) |
| |
| screenshot = Image.open(io.BytesIO(screenshot_bytes)) |
| print("์คํฌ๋ฆฐ์ท ์บก์ฒ ์๋ฃ") |
| return screenshot |
| |
| except Exception as e: |
| print(f"์คํฌ๋ฆฐ์ท ์บก์ฒ ์คํจ: {str(e)}") |
| print(traceback.format_exc()) |
| return None |
|
|
| def analyze_with_claude(image: Image.Image) -> str: |
| """Claude API๋ฅผ ์ฌ์ฉํ์ฌ ์ด๋ฏธ์ง ๋ถ์""" |
| try: |
| client = get_claude_client() |
| |
| |
| buffer = io.BytesIO() |
| image.save(buffer, format="PNG") |
| image_base64 = base64.b64encode(buffer.getvalue()).decode() |
| |
| |
| prompt = """ |
| ์ด Google Trends ์ค์๊ฐ ์ธ๊ธฐ ๊ฒ์์ด ์คํฌ๋ฆฐ์ท์ ๋ถ์ํด์ฃผ์ธ์. |
| |
| ๋ค์ ๋ด์ฉ์ ํฌํจํด์ ๋ถ์ํด์ฃผ์ธ์: |
| 1. ํ์ฌ ๊ฐ์ฅ ์ธ๊ธฐ ์๋ ๊ฒ์์ด๋ค๊ณผ ๊ทธ ์์ |
| 2. ๊ฐ ๊ฒ์์ด์ ์ฆ๊ฐ ์ถ์ธ๋ ํน์ด์ฌํญ |
| 3. ๊ฒ์์ด๋ค์์ ๋ฐ๊ฒฌ๋๋ ์ฃผ์ ํธ๋ ๋๋ ํจํด |
| 4. ์์ฌ์ /๋ฌธํ์ ๋งฅ๋ฝ์์์ ํด์ |
| |
| ํ๊ตญ์ด๋ก ์์ธํ๊ณ ๊ตฌ์ฒด์ ์ผ๋ก ๋ถ์ํด์ฃผ์ธ์. |
| """ |
| |
| response = client.messages.create( |
| model="claude-3-5-sonnet-20241022", |
| max_tokens=1500, |
| messages=[ |
| { |
| "role": "user", |
| "content": [ |
| { |
| "type": "text", |
| "text": prompt |
| }, |
| { |
| "type": "image", |
| "source": { |
| "type": "base64", |
| "media_type": "image/png", |
| "data": image_base64 |
| } |
| } |
| ] |
| } |
| ] |
| ) |
| |
| return response.content[0].text |
| |
| except Exception as e: |
| error_msg = f"Claude API ๋ถ์ ์คํจ: {str(e)}" |
| print(error_msg) |
| return error_msg |
|
|
| def reinit_browser(): |
| """๋ธ๋ผ์ฐ์ ์ฌ์ด๊ธฐํ""" |
| global is_browser_ready |
| |
| print("๋ธ๋ผ์ฐ์ ์ฌ์ด๊ธฐํ ์์...") |
| |
| |
| cleanup_browser() |
| is_browser_ready = False |
| |
| |
| init_browser() |
| |
| if is_browser_ready: |
| return "๋ธ๋ผ์ฐ์ ์ฌ์ด๊ธฐํ ์๋ฃ!" |
| else: |
| return "๋ธ๋ผ์ฐ์ ์ฌ์ด๊ธฐํ ์คํจ. ๋ค์ ์๋ํด์ฃผ์ธ์." |
|
|
| def refresh_trends_page(): |
| """Google Trends ํ์ด์ง ์๋ก๊ณ ์นจ""" |
| global page |
| |
| if not ensure_browser_ready(): |
| return "๋ธ๋ผ์ฐ์ ๊ฐ ์ค๋น๋์ง ์์์ต๋๋ค." |
| |
| try: |
| page.reload(wait_until="networkidle", timeout=30000) |
| time.sleep(3) |
| return "ํ์ด์ง๊ฐ ์๋ก๊ณ ์นจ๋์์ต๋๋ค." |
| except Exception as e: |
| return f"ํ์ด์ง ์๋ก๊ณ ์นจ ์คํจ: {str(e)}" |
|
|
| def main_process_screenshot(geo: str, time_range: str, category: str) -> Tuple[Optional[Image.Image], str]: |
| """์คํฌ๋ฆฐ์ท ์บก์ฒ๋ง ์ํํ๋ ํจ์""" |
| try: |
| |
| if not ensure_browser_ready(): |
| return None, "๋ธ๋ผ์ฐ์ ๊ฐ ์ค๋น๋์ง ์์์ต๋๋ค. '๋ธ๋ผ์ฐ์ ์ฌ์ด๊ธฐํ' ๋ฒํผ์ ํด๋ฆญํด์ฃผ์ธ์." |
| |
| |
| print(f"ํํฐ ์ ์ฉ ์ค: ์ง์ญ={geo}, ์๊ฐ={time_range}, ์นดํ
๊ณ ๋ฆฌ={category}") |
| filter_success = apply_filters(geo, time_range, category) |
| |
| if not filter_success: |
| return None, "ํํฐ ์ ์ฉ์ ์คํจํ์ต๋๋ค." |
| |
| |
| print("์คํฌ๋ฆฐ์ท ์บก์ฒ ์ค...") |
| screenshot = capture_screenshot() |
| |
| if screenshot is None: |
| return None, "์คํฌ๋ฆฐ์ท ์บก์ฒ์ ์คํจํ์ต๋๋ค." |
| |
| return screenshot, "์คํฌ๋ฆฐ์ท ์บก์ฒ ์๋ฃ! Claude ๋ถ์์ ์งํํฉ๋๋ค..." |
| |
| except Exception as e: |
| error_msg = f"์คํฌ๋ฆฐ์ท ์บก์ฒ ์ค ์ค๋ฅ ๋ฐ์: {str(e)}" |
| print(error_msg) |
| print(traceback.format_exc()) |
| return None, error_msg |
|
|
| def analyze_screenshot_with_claude(screenshot: Image.Image) -> str: |
| """Claude API๋ก ์คํฌ๋ฆฐ์ท ๋ถ์""" |
| if screenshot is None: |
| return "๋ถ์ํ ์คํฌ๋ฆฐ์ท์ด ์์ต๋๋ค." |
| |
| try: |
| print("Claude API๋ก ๋ถ์ ์ค...") |
| analysis_result = analyze_with_claude(screenshot) |
| return analysis_result |
| |
| except Exception as e: |
| error_msg = f"Claude ๋ถ์ ์ค ์ค๋ฅ ๋ฐ์: {str(e)}" |
| print(error_msg) |
| return error_msg |
|
|
| def main_process(geo: str, time_range: str, category: str) -> Tuple[Optional[Image.Image], str]: |
| """์ ์ฒด ํ๋ก์ธ์ค (ํธํ์ฑ์ ์ํด ์ ์ง)""" |
| try: |
| |
| if not ensure_browser_ready(): |
| return None, "๋ธ๋ผ์ฐ์ ๊ฐ ์ค๋น๋์ง ์์์ต๋๋ค. '๋ธ๋ผ์ฐ์ ์ฌ์ด๊ธฐํ' ๋ฒํผ์ ํด๋ฆญํด์ฃผ์ธ์." |
| |
| |
| print(f"ํํฐ ์ ์ฉ ์ค: ์ง์ญ={geo}, ์๊ฐ={time_range}, ์นดํ
๊ณ ๋ฆฌ={category}") |
| filter_success = apply_filters(geo, time_range, category) |
| |
| if not filter_success: |
| return None, "ํํฐ ์ ์ฉ์ ์คํจํ์ต๋๋ค." |
| |
| |
| print("์คํฌ๋ฆฐ์ท ์บก์ฒ ์ค...") |
| screenshot = capture_screenshot() |
| |
| if screenshot is None: |
| return None, "์คํฌ๋ฆฐ์ท ์บก์ฒ์ ์คํจํ์ต๋๋ค." |
| |
| |
| print("Claude API๋ก ๋ถ์ ์ค...") |
| analysis_result = analyze_with_claude(screenshot) |
| |
| return screenshot, analysis_result |
| |
| except Exception as e: |
| error_msg = f"์ฒ๋ฆฌ ์ค ์ค๋ฅ ๋ฐ์: {str(e)}" |
| print(error_msg) |
| print(traceback.format_exc()) |
| return None, error_msg |
|
|
| def check_browser_status(): |
| """๋ธ๋ผ์ฐ์ ์ํ ํ์ธ""" |
| global is_browser_ready, page, browser_thread_id |
| |
| current_thread_id = threading.current_thread().ident |
| |
| if not page: |
| return "๋ธ๋ผ์ฐ์ ๊ฐ ์ด๊ธฐํ๋์ง ์์์ต๋๋ค." |
| |
| if not is_browser_ready: |
| return "๋ธ๋ผ์ฐ์ ์ด๊ธฐํ ์ค์
๋๋ค..." |
| |
| try: |
| current_url = page.url |
| return f"๋ธ๋ผ์ฐ์ ์ค๋น ์๋ฃ - ํ์ฌ URL: {current_url} (์ค๋ ๋: {current_thread_id}, ๋ธ๋ผ์ฐ์ ์ค๋ ๋: {browser_thread_id})" |
| except Exception as e: |
| return f"๋ธ๋ผ์ฐ์ ์ฐ๊ฒฐ์ ๋ฌธ์ ๊ฐ ์์ต๋๋ค: {str(e)}" |
|
|
| |
| def create_interface(): |
| """Gradio ์ธํฐํ์ด์ค ์์ฑ""" |
| |
| with gr.Blocks(title="Google Trends ์ค์๊ฐ ๋ถ์๊ธฐ", theme=gr.themes.Soft()) as interface: |
| gr.Markdown("# Google Trends ์ค์๊ฐ ์ธ๊ธฐ ๊ฒ์์ด ๋ถ์๊ธฐ") |
| gr.Markdown("Google Trends์ ์ค์๊ฐ ์ธ๊ธฐ ๊ฒ์์ด๋ฅผ ์บก์ฒํ๊ณ Claude AI๋ก ๋ถ์ํฉ๋๋ค.") |
| |
| |
| screenshot_state = gr.State(None) |
| |
| with gr.Row(): |
| with gr.Column(scale=1): |
| geo_dropdown = gr.Dropdown( |
| choices=["KR", "US", "JP", "GB", "DE", "FR"], |
| value="KR", |
| label="์ง์ญ ์ ํ" |
| ) |
| |
| time_dropdown = gr.Dropdown( |
| choices=["24์๊ฐ", "7์ผ", "30์ผ", "90์ผ", "12๊ฐ์"], |
| value="24์๊ฐ", |
| label="๊ธฐ๊ฐ ์ ํ" |
| ) |
| |
| category_dropdown = gr.Dropdown( |
| choices=["๋ชจ๋ ์นดํ
๊ณ ๋ฆฌ", "์ํฐํ
์ธ๋จผํธ", "์คํฌ์ธ ", "๋น์ฆ๋์ค", "๊ณผํ๊ธฐ์ ", "๊ฑด๊ฐ"], |
| value="๋ชจ๋ ์นดํ
๊ณ ๋ฆฌ", |
| label="์นดํ
๊ณ ๋ฆฌ ์ ํ" |
| ) |
| |
| with gr.Row(): |
| capture_btn = gr.Button("๐ฏ ์คํฌ๋ฆฐ์ท ์บก์ฒ", variant="primary") |
| analyze_btn = gr.Button("๐ค Claude ๋ถ์", variant="secondary", interactive=False) |
| |
| with gr.Row(): |
| refresh_btn = gr.Button("๐ ํ์ด์ง ์๋ก๊ณ ์นจ", variant="secondary") |
| reinit_btn = gr.Button("โ๏ธ ๋ธ๋ผ์ฐ์ ์ด๊ธฐํ", variant="secondary") |
| status_btn = gr.Button("๐ ๋ธ๋ผ์ฐ์ ์ํ ํ์ธ", variant="secondary") |
| |
| with gr.Column(scale=2): |
| screenshot_output = gr.Image(label="Google Trends ์คํฌ๋ฆฐ์ท") |
| analysis_output = gr.Textbox( |
| label="Claude AI ๋ถ์ ๊ฒฐ๊ณผ", |
| lines=10, |
| max_lines=20, |
| placeholder="์คํฌ๋ฆฐ์ท์ ์บก์ฒํ ํ 'Claude ๋ถ์' ๋ฒํผ์ ํด๋ฆญํ์ธ์." |
| ) |
| status_output = gr.Textbox(label="์ํ ๋ฉ์์ง") |
| |
| |
| |
| |
| def on_capture_click(geo, time_range, category): |
| screenshot, message = main_process_screenshot(geo, time_range, category) |
| if screenshot is not None: |
| |
| return screenshot, screenshot, message, gr.update(interactive=True) |
| else: |
| return None, None, message, gr.update(interactive=False) |
| |
| capture_btn.click( |
| fn=on_capture_click, |
| inputs=[geo_dropdown, time_dropdown, category_dropdown], |
| outputs=[screenshot_output, screenshot_state, status_output, analyze_btn] |
| ) |
| |
| |
| def on_analyze_click(screenshot): |
| if screenshot is None: |
| return "๋ถ์ํ ์คํฌ๋ฆฐ์ท์ด ์์ต๋๋ค. ๋จผ์ '์คํฌ๋ฆฐ์ท ์บก์ฒ' ๋ฒํผ์ ํด๋ฆญํ์ธ์." |
| |
| analysis_result = analyze_screenshot_with_claude(screenshot) |
| return analysis_result |
| |
| analyze_btn.click( |
| fn=on_analyze_click, |
| inputs=[screenshot_state], |
| outputs=[analysis_output] |
| ) |
| |
| |
| refresh_btn.click( |
| fn=refresh_trends_page, |
| outputs=status_output |
| ) |
| |
| reinit_btn.click( |
| fn=reinit_browser, |
| outputs=status_output |
| ) |
| |
| status_btn.click( |
| fn=check_browser_status, |
| outputs=status_output |
| ) |
| |
| return interface |
|
|
| def main(): |
| """๋ฉ์ธ ํจ์""" |
| print("=" * 50) |
| print("Google Trends ์ค์๊ฐ ๋ถ์๊ธฐ ์์!") |
| print("=" * 50) |
| |
| |
| api_key = os.getenv("ANTHROPIC_API_KEY") |
| if not api_key: |
| print("โ ANTHROPIC_API_KEY ํ๊ฒฝ๋ณ์๊ฐ ์ค์ ๋์ง ์์์ต๋๋ค.") |
| return |
| else: |
| print("โ Claude API ํค ํ์ธ๋จ") |
| |
| print("โ Gradio ์น ์ธํฐํ์ด์ค ์ค๋น ์ค...") |
| |
| |
| if os.getenv("SPACE_ID"): |
| print("โ Hugging Face Space ํ๊ฒฝ์์ ์คํ ์ค...") |
| |
| print("โ ๋ธ๋ผ์ฐ์ ๋ ์ฒซ ๋ฒ์งธ ์ฌ์ฉ ์ ์๋์ผ๋ก ์ด๊ธฐํ๋ฉ๋๋ค.") |
| |
| |
| atexit.register(cleanup_browser) |
| |
| |
| interface = create_interface() |
| |
| |
| interface.launch( |
| server_name="0.0.0.0", |
| server_port=7860, |
| share=False, |
| show_error=True, |
| quiet=False |
| ) |
|
|
| if __name__ == "__main__": |
| main() |