import gradio as gr import requests import json import os from datetime import datetime, timedelta from huggingface_hub import InferenceClient # LLM 사용을 위해 필요 # 환경 변수에서 API 키 가져오기 (API 키는 안전하게 관리되어야 합니다) API_KEY = os.getenv("SERPHOUSE_API_KEY") # 본인의 SerpHouse API 키를 환경 변수로 설정하세요. HF_TOKEN = os.getenv("HF_TOKEN") # Hugging Face API 토큰을 환경 변수로 설정하세요. # 국가 이름과 Google 검색에서 사용하는 국가 코드를 매핑 COUNTRY_CODE_MAPPING = { "United States": "us", "United Kingdom": "uk", "Canada": "ca", "Australia": "au", "Germany": "de", "France": "fr", "Japan": "jp", "South Korea": "kr", "China": "cn", "India": "in", "Brazil": "br", "Mexico": "mx", "Russia": "ru", "Italy": "it", "Spain": "es", "Netherlands": "nl", "Sweden": "se", "Switzerland": "ch", "Norway": "no", "Denmark": "dk", "Finland": "fi", "Belgium": "be", "Austria": "at", "New Zealand": "nz", "Ireland": "ie", "Singapore": "sg", "Hong Kong": "hk", "Israel": "il", "United Arab Emirates": "ae", "Saudi Arabia": "sa", "South Africa": "za", "Turkey": "tr", "Egypt": "eg", "Poland": "pl", "Czech Republic": "cz", "Hungary": "hu", "Greece": "gr", "Portugal": "pt", "Argentina": "ar", "Chile": "cl", "Colombia": "co", "Peru": "pe", "Venezuela": "ve", "Thailand": "th", "Malaysia": "my", "Indonesia": "id", "Philippines": "ph", "Vietnam": "vn", "Pakistan": "pk", "Bangladesh": "bd" } MAJOR_COUNTRIES = [ "United States", "United Kingdom", "Canada", "Australia", "Germany", "France", "Japan", "South Korea", "China", "India", "Brazil", "Mexico", "Russia", "Italy", "Spain", "Netherlands", "Sweden", "Switzerland", "Norway", "Denmark", "Finland", "Belgium", "Austria", "New Zealand", "Ireland", "Singapore", "Hong Kong", "Israel", "United Arab Emirates", "Saudi Arabia", "South Africa", "Turkey", "Egypt", "Poland", "Czech Republic", "Hungary", "Greece", "Portugal", "Argentina", "Chile", "Colombia", "Peru", "Venezuela", "Thailand", "Malaysia", "Indonesia", "Philippines", "Vietnam", "Pakistan", "Bangladesh" ] def search_serphouse(query, country, page=1, num_result=100): url = "https://api.serphouse.com/serp/live" now = datetime.utcnow() yesterday = now - timedelta(days=1) date_range = f"{yesterday.strftime('%Y-%m-%d')},{now.strftime('%Y-%m-%d')}" payload = { "data": { "q": query, "domain": "google.com", "loc": COUNTRY_CODE_MAPPING.get(country, "us"), # 여기가 문제의 원인입니다 "lang": "en", "device": "desktop", "serp_type": "news", "page": str(page), "verbatim": "1", "num": str(num_result), "date_range": date_range } } def format_results_from_raw(results): try: if isinstance(results, dict) and "error" in results: return "Error: " + results["error"], [] if not isinstance(results, dict): raise ValueError("결과가 사전 형식이 아닙니다.") # 'results' 키 내부의 구조 확인 (중첩된 'results' 처리) if 'results' in results: results_content = results['results'] if 'results' in results_content: results_content = results_content['results'] # 'news' 키 확인 if 'news' in results_content: news_results = results_content['news'] else: news_results = [] else: news_results = [] else: news_results = [] if not news_results: return "검색 결과가 없습니다.", [] articles = [] for idx, result in enumerate(news_results, 1): title = result.get("title", "제목 없음") link = result.get("url", result.get("link", "#")) snippet = result.get("snippet", "내용 없음") channel = result.get("channel", result.get("source", "알 수 없음")) time = result.get("time", result.get("date", "알 수 없는 시간")) image_url = result.get("img", result.get("thumbnail", "")) articles.append({ "index": idx, "title": title, "link": link, "snippet": snippet, "channel": channel, "time": time, "image_url": image_url }) return "", articles except Exception as e: error_message = f"결과 처리 중 오류 발생: {str(e)}" return "Error: " + error_message, [] def serphouse_search(query, country): # 페이지와 결과 수의 기본값을 설정합니다. page = 1 num_result = 100 results = search_serphouse(query, country, page, num_result) error_message, articles = format_results_from_raw(results) return error_message, articles # LLM 설정 hf_client = InferenceClient("CohereForAI/c4ai-command-r-plus-08-2024", token=HF_TOKEN) def summarize_article(title, snippet): try: # 기사 제목과 스니펫을 기반으로 요약 생성 prompt = f"다음 뉴스 제목과 요약을 바탕으로 한국어로 3문장으로 요약하세요:\n제목: {title}\n요약: {snippet}" summary = hf_client.text_generation(prompt, max_new_tokens=500) return summary except Exception as e: return f"요약 중 오류 발생: {str(e)}" css = """ footer { visibility: hidden; } /* 분석 버튼 스타일 개선 */ .analyze-button { background-color: #4CAF50; /* Green */ border: none; color: white; padding: 6px 12px; text-align: center; text-decoration: none; font-size: 14px; margin: 2px; cursor: pointer; border-radius: 4px; } .analyze-button:hover { background-color: #45a049; } """ # Gradio 인터페이스 구성 with gr.Blocks(css=css, title="NewsAI 서비스") as iface: gr.Markdown("검색어를 입력하고 원하는 국가를 선택하면, 검색어와 일치하는 24시간 이내 뉴스를 최대 100개 출력합니다.") with gr.Column(): with gr.Row(): query = gr.Textbox(label="검색어") country = gr.Dropdown(MAJOR_COUNTRIES, label="국가", value="South Korea") search_button = gr.Button("검색") output_table = gr.HTML() summary_output = gr.Markdown(visible=False) def search_and_display(query, country): error_message, articles = serphouse_search(query, country) if error_message: return f"
{error_message}
", gr.update(visible=False) else: # 기사 목록을 HTML 테이블로 생성 table_html = """번호 | 제목 | 출처 | 시간 | 분석 |
---|---|---|---|---|
{article['index']} | {article['title']} | {article['channel']} | {article['time']} | {analyze_button} |