Update app.py
Browse files
app.py
CHANGED
@@ -2,114 +2,72 @@ import gradio as gr
|
|
2 |
import requests
|
3 |
from datetime import datetime, timedelta
|
4 |
import json
|
5 |
-
|
6 |
|
7 |
# Google Custom Search API 키와 검색 엔진 ID
|
8 |
API_KEY = "AIzaSyB8wNdEL8-SAvelRq-zenLLU-cUEmsj7uE"
|
9 |
SEARCH_ENGINE_ID = "c01abc75e1b95483d"
|
10 |
|
11 |
-
|
12 |
-
# 지원되는 국가 리스트 (Google Custom Search API에서 지원하는 모든 국가)
|
13 |
COUNTRIES = {
|
14 |
-
'
|
15 |
-
'
|
16 |
-
'
|
17 |
-
'
|
18 |
-
'Bahrain': 'countryBH', 'Bangladesh': 'countryBD', 'Barbados': 'countryBB', 'Belarus': 'countryBY',
|
19 |
-
'Belgium': 'countryBE', 'Belize': 'countryBZ', 'Benin': 'countryBJ', 'Bermuda': 'countryBM',
|
20 |
-
'Bhutan': 'countryBT', 'Bolivia': 'countryBO', 'Bosnia and Herzegovina': 'countryBA', 'Botswana': 'countryBW',
|
21 |
-
'Bouvet Island': 'countryBV', 'Brazil': 'countryBR', 'British Indian Ocean Territory': 'countryIO',
|
22 |
-
'Brunei Darussalam': 'countryBN', 'Bulgaria': 'countryBG', 'Burkina Faso': 'countryBF', 'Burundi': 'countryBI',
|
23 |
-
'Cambodia': 'countryKH', 'Cameroon': 'countryCM', 'Canada': 'countryCA', 'Cape Verde': 'countryCV',
|
24 |
-
'Cayman Islands': 'countryKY', 'Central African Republic': 'countryCF', 'Chad': 'countryTD', 'Chile': 'countryCL',
|
25 |
-
'China': 'countryCN', 'Christmas Island': 'countryCX', 'Cocos (Keeling) Islands': 'countryCC', 'Colombia': 'countryCO',
|
26 |
-
'Comoros': 'countryKM', 'Congo': 'countryCG', 'Congo, Democratic Republic': 'countryCD', 'Cook Islands': 'countryCK',
|
27 |
-
'Costa Rica': 'countryCR', "Cote D'Ivoire": 'countryCI', 'Croatia': 'countryHR', 'Cuba': 'countryCU', 'Cyprus': 'countryCY',
|
28 |
-
'Czech Republic': 'countryCZ', 'Denmark': 'countryDK', 'Djibouti': 'countryDJ', 'Dominica': 'countryDM',
|
29 |
-
'Dominican Republic': 'countryDO', 'Ecuador': 'countryEC', 'Egypt': 'countryEG', 'El Salvador': 'countrySV',
|
30 |
-
'Equatorial Guinea': 'countryGQ', 'Eritrea': 'countryER', 'Estonia': 'countryEE', 'Ethiopia': 'countryET',
|
31 |
-
'Falkland Islands (Malvinas)': 'countryFK', 'Faroe Islands': 'countryFO', 'Fiji': 'countryFJ', 'Finland': 'countryFI',
|
32 |
-
'France': 'countryFR', 'French Guiana': 'countryGF', 'French Polynesia': 'countryPF', 'French Southern Territories': 'countryTF',
|
33 |
-
'Gabon': 'countryGA', 'Gambia': 'countryGM', 'Georgia': 'countryGE', 'Germany': 'countryDE', 'Ghana': 'countryGH',
|
34 |
-
'Gibraltar': 'countryGI', 'Greece': 'countryGR', 'Greenland': 'countryGL', 'Grenada': 'countryGD', 'Guadeloupe': 'countryGP',
|
35 |
-
'Guam': 'countryGU', 'Guatemala': 'countryGT', 'Guinea': 'countryGN', 'Guinea-Bissau': 'countryGW', 'Guyana': 'countryGY',
|
36 |
-
'Haiti': 'countryHT', 'Heard Island and Mcdonald Islands': 'countryHM', 'Holy See (Vatican City State)': 'countryVA',
|
37 |
-
'Honduras': 'countryHN', 'Hong Kong': 'countryHK', 'Hungary': 'countryHU', 'Iceland': 'countryIS', 'India': 'countryIN',
|
38 |
-
'Indonesia': 'countryID', 'Iran, Islamic Republic of': 'countryIR', 'Iraq': 'countryIQ', 'Ireland': 'countryIE',
|
39 |
-
'Israel': 'countryIL', 'Italy': 'countryIT', 'Jamaica': 'countryJM', 'Japan': 'countryJP', 'Jordan': 'countryJO',
|
40 |
-
'Kazakhstan': 'countryKZ', 'Kenya': 'countryKE', 'Kiribati': 'countryKI', "Korea, Democratic People's Republic of": 'countryKP',
|
41 |
-
'Korea, Republic of': 'countryKR', 'Kuwait': 'countryKW', 'Kyrgyzstan': 'countryKG', "Lao People's Democratic Republic": 'countryLA',
|
42 |
-
'Latvia': 'countryLV', 'Lebanon': 'countryLB', 'Lesotho': 'countryLS', 'Liberia': 'countryLR', 'Libyan Arab Jamahiriya': 'countryLY',
|
43 |
-
'Liechtenstein': 'countryLI', 'Lithuania': 'countryLT', 'Luxembourg': 'countryLU', 'Macao': 'countryMO',
|
44 |
-
'Macedonia, The Former Yugoslav Republic of': 'countryMK', 'Madagascar': 'countryMG', 'Malawi': 'countryMW',
|
45 |
-
'Malaysia': 'countryMY', 'Maldives': 'countryMV', 'Mali': 'countryML', 'Malta': 'countryMT', 'Marshall Islands': 'countryMH',
|
46 |
-
'Martinique': 'countryMQ', 'Mauritania': 'countryMR', 'Mauritius': 'countryMU', 'Mayotte': 'countryYT', 'Mexico': 'countryMX',
|
47 |
-
'Micronesia, Federated States of': 'countryFM', 'Moldova, Republic of': 'countryMD', 'Monaco': 'countryMC', 'Mongolia': 'countryMN',
|
48 |
-
'Montserrat': 'countryMS', 'Morocco': 'countryMA', 'Mozambique': 'countryMZ', 'Myanmar': 'countryMM', 'Namibia': 'countryNA',
|
49 |
-
'Nauru': 'countryNR', 'Nepal': 'countryNP', 'Netherlands': 'countryNL', 'Netherlands Antilles': 'countryAN', 'New Caledonia': 'countryNC',
|
50 |
-
'New Zealand': 'countryNZ', 'Nicaragua': 'countryNI', 'Niger': 'countryNE', 'Nigeria': 'countryNG', 'Niue': 'countryNU',
|
51 |
-
'Norfolk Island': 'countryNF', 'Northern Mariana Islands': 'countryMP', 'Norway': 'countryNO', 'Oman': 'countryOM',
|
52 |
-
'Pakistan': 'countryPK', 'Palau': 'countryPW', 'Palestinian Territory, Occupied': 'countryPS', 'Panama': 'countryPA',
|
53 |
-
'Papua New Guinea': 'countryPG', 'Paraguay': 'countryPY', 'Peru': 'countryPE', 'Philippines': 'countryPH', 'Pitcairn': 'countryPN',
|
54 |
-
'Poland': 'countryPL', 'Portugal': 'countryPT', 'Puerto Rico': 'countryPR', 'Qatar': 'countryQA', 'Reunion': 'countryRE',
|
55 |
-
'Romania': 'countryRO', 'Russian Federation': 'countryRU', 'Rwanda': 'countryRW', 'Saint Helena': 'countrySH',
|
56 |
-
'Saint Kitts and Nevis': 'countryKN', 'Saint Lucia': 'countryLC', 'Saint Pierre and Miquelon': 'countryPM',
|
57 |
-
'Saint Vincent and the Grenadines': 'countryVC', 'Samoa': 'countryWS', 'San Marino': 'countrySM', 'Sao Tome and Principe': 'countryST',
|
58 |
-
'Saudi Arabia': 'countrySA', 'Senegal': 'countrySN', 'Serbia and Montenegro': 'countryCS', 'Seychelles': 'countrySC',
|
59 |
-
'Sierra Leone': 'countrySL', 'Singapore': 'countrySG', 'Slovakia': 'countrySK', 'Slovenia': 'countrySI', 'Solomon Islands': 'countrySB',
|
60 |
-
'Somalia': 'countrySO', 'South Africa': 'countryZA', 'South Georgia and the South Sandwich Islands': 'countryGS', 'Spain': 'countryES',
|
61 |
-
'Sri Lanka': 'countryLK', 'Sudan': 'countrySD', 'Suriname': 'countrySR', 'Svalbard and Jan Mayen': 'countrySJ', 'Swaziland': 'countrySZ',
|
62 |
-
'Sweden': 'countrySE', 'Switzerland': 'countryCH', 'Syrian Arab Republic': 'countrySY', 'Taiwan, Province of China': 'countryTW',
|
63 |
-
'Tajikistan': 'countryTJ', 'Tanzania, United Republic of': 'countryTZ', 'Thailand': 'countryTH', 'Timor-Leste': 'countryTL',
|
64 |
-
'Togo': 'countryTG', 'Tokelau': 'countryTK', 'Tonga': 'countryTO', 'Trinidad and Tobago': 'countryTT', 'Tunisia': 'countryTN',
|
65 |
-
'Turkey': 'countryTR', 'Turkmenistan': 'countryTM', 'Turks and Caicos Islands': 'countryTC', 'Tuvalu': 'countryTV', 'Uganda': 'countryUG',
|
66 |
-
'Ukraine': 'countryUA', 'United Arab Emirates': 'countryAE', 'United Kingdom': 'countryGB', 'United States': 'countryUS',
|
67 |
-
'United States Minor Outlying Islands': 'countryUM', 'Uruguay': 'countryUY', 'Uzbekistan': 'countryUZ', 'Vanuatu': 'countryVU',
|
68 |
-
'Venezuela': 'countryVE', 'Viet Nam': 'countryVN', 'Virgin Islands, British': 'countryVG', 'Virgin Islands, U.S.': 'countryVI',
|
69 |
-
'Wallis and Futuna': 'countryWF', 'Western Sahara': 'countryEH', 'Yemen': 'countryYE', 'Zambia': 'countryZM', 'Zimbabwe': 'countryZW'
|
70 |
}
|
71 |
|
|
|
|
|
|
|
|
|
72 |
def search_news(keyword, country):
|
73 |
-
|
74 |
-
|
75 |
|
76 |
-
|
77 |
url = "https://www.googleapis.com/customsearch/v1"
|
78 |
params = {
|
79 |
'key': API_KEY,
|
80 |
'cx': SEARCH_ENGINE_ID,
|
81 |
-
'q': keyword,
|
82 |
-
'dateRestrict': 'd1', # 최근 1일 내 결과만
|
83 |
'lr': 'lang_en', # 영어 결과만
|
84 |
'sort': 'date', # 날짜순 정렬
|
85 |
'num': 100, # 최대 100개 결과
|
86 |
-
'siteSearch': 'news.google.com', # Google News로 제한
|
87 |
}
|
88 |
|
89 |
if country != 'All Countries':
|
90 |
-
params['
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
91 |
|
92 |
-
|
93 |
-
|
94 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
95 |
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
|
|
100 |
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
for item in results['items']:
|
105 |
-
title = item['title']
|
106 |
-
link = item['link']
|
107 |
-
snippet = item['snippet']
|
108 |
-
formatted_results += f"<h3><a href='{link}' target='_blank'>{title}</a></h3>"
|
109 |
-
formatted_results += f"<p>{snippet}</p><br>"
|
110 |
-
formatted_results += f"<p>Total results: {len(results['items'])}</p>"
|
111 |
-
else:
|
112 |
-
formatted_results = f"No news found for '{keyword}' in {country} within the last 24 hours."
|
113 |
|
114 |
formatted_results += f"<details><summary>Debug Info</summary><pre>{debug_info}</pre></details>"
|
115 |
|
|
|
2 |
import requests
|
3 |
from datetime import datetime, timedelta
|
4 |
import json
|
5 |
+
from functools import lru_cache
|
6 |
|
7 |
# Google Custom Search API 키와 검색 엔진 ID
|
8 |
API_KEY = "AIzaSyB8wNdEL8-SAvelRq-zenLLU-cUEmsj7uE"
|
9 |
SEARCH_ENGINE_ID = "c01abc75e1b95483d"
|
10 |
|
11 |
+
# 지원되는 국가 리스트
|
|
|
12 |
COUNTRIES = {
|
13 |
+
'United States': 'US', 'United Kingdom': 'GB', 'Canada': 'CA', 'Australia': 'AU', 'India': 'IN',
|
14 |
+
'Germany': 'DE', 'France': 'FR', 'Japan': 'JP', 'South Korea': 'KR', 'Brazil': 'BR',
|
15 |
+
'Mexico': 'MX', 'Spain': 'ES', 'Italy': 'IT', 'Netherlands': 'NL', 'Russia': 'RU',
|
16 |
+
'Sweden': 'SE', 'Switzerland': 'CH', 'Poland': 'PL', 'Turkey': 'TR', 'Saudi Arabia': 'SA'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
17 |
}
|
18 |
|
19 |
+
@lru_cache(maxsize=100)
|
20 |
+
def cached_search(cache_key):
|
21 |
+
return search_news_impl(*json.loads(cache_key))
|
22 |
+
|
23 |
def search_news(keyword, country):
|
24 |
+
cache_key = json.dumps((keyword, country))
|
25 |
+
return cached_search(cache_key)
|
26 |
|
27 |
+
def search_news_impl(keyword, country):
|
28 |
url = "https://www.googleapis.com/customsearch/v1"
|
29 |
params = {
|
30 |
'key': API_KEY,
|
31 |
'cx': SEARCH_ENGINE_ID,
|
32 |
+
'q': f"{keyword} when:1d", # 최근 1일 내 결과만
|
|
|
33 |
'lr': 'lang_en', # 영어 결과만
|
34 |
'sort': 'date', # 날짜순 정렬
|
35 |
'num': 100, # 최대 100개 결과
|
|
|
36 |
}
|
37 |
|
38 |
if country != 'All Countries':
|
39 |
+
params['gl'] = COUNTRIES[country]
|
40 |
+
|
41 |
+
try:
|
42 |
+
response = requests.get(url, params=params)
|
43 |
+
response.raise_for_status()
|
44 |
+
results = response.json()
|
45 |
+
|
46 |
+
debug_info = f"API Request URL: {response.url}\n"
|
47 |
+
debug_info += f"API Response Status: {response.status_code}\n"
|
48 |
+
debug_info += f"API Response Body: {json.dumps(results, indent=2)}\n"
|
49 |
|
50 |
+
formatted_results = ""
|
51 |
+
if 'items' in results:
|
52 |
+
for item in results['items']:
|
53 |
+
title = item['title']
|
54 |
+
link = item['link']
|
55 |
+
snippet = item.get('snippet', 'No snippet available')
|
56 |
+
formatted_results += f"<h3><a href='{link}' target='_blank'>{title}</a></h3>"
|
57 |
+
formatted_results += f"<p>{snippet}</p><br>"
|
58 |
+
formatted_results += f"<p>Total results: {len(results['items'])}</p>"
|
59 |
+
else:
|
60 |
+
formatted_results = f"No news found for '{keyword}' in {country} within the last 24 hours."
|
61 |
|
62 |
+
except requests.exceptions.HTTPError as e:
|
63 |
+
formatted_results = f"An error occurred: {str(e)}"
|
64 |
+
debug_info = f"Error: {str(e)}\n"
|
65 |
+
debug_info += f"API Response Status: {e.response.status_code}\n"
|
66 |
+
debug_info += f"API Response Body: {e.response.text}\n"
|
67 |
|
68 |
+
except Exception as e:
|
69 |
+
formatted_results = f"An unexpected error occurred: {str(e)}"
|
70 |
+
debug_info = f"Unexpected Error: {str(e)}\n"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
71 |
|
72 |
formatted_results += f"<details><summary>Debug Info</summary><pre>{debug_info}</pre></details>"
|
73 |
|