Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
@@ -14,7 +14,7 @@ import pathlib
|
|
14 |
import sqlite3
|
15 |
import pytz
|
16 |
|
17 |
-
# List of target companies/keywords
|
18 |
KOREAN_COMPANIES = [
|
19 |
"NVIDIA",
|
20 |
"ALPHABET",
|
@@ -36,7 +36,7 @@ KOREAN_COMPANIES = [
|
|
36 |
|
37 |
def convert_to_seoul_time(timestamp_str):
|
38 |
"""
|
39 |
-
|
40 |
"""
|
41 |
try:
|
42 |
dt = datetime.strptime(timestamp_str, '%Y-%m-%d %H:%M:%S')
|
@@ -44,36 +44,36 @@ def convert_to_seoul_time(timestamp_str):
|
|
44 |
seoul_time = seoul_tz.localize(dt)
|
45 |
return seoul_time.strftime('%Y-%m-%d %H:%M:%S KST')
|
46 |
except Exception as e:
|
47 |
-
print(f"
|
48 |
return timestamp_str
|
49 |
|
50 |
def analyze_sentiment_batch(articles, client):
|
51 |
"""
|
52 |
-
|
|
|
53 |
"""
|
54 |
try:
|
55 |
-
#
|
56 |
combined_text = "\n\n".join([
|
57 |
-
f"
|
58 |
for article in articles
|
59 |
])
|
60 |
|
61 |
-
prompt = f"""
|
62 |
|
63 |
-
|
64 |
{combined_text}
|
65 |
|
66 |
-
|
67 |
-
1.
|
68 |
-
2.
|
69 |
-
- [
|
70 |
-
- [
|
71 |
-
3.
|
72 |
-
- [
|
73 |
-
- [
|
74 |
-
4.
|
75 |
"""
|
76 |
-
|
77 |
response = client.chat.completions.create(
|
78 |
model="CohereForAI/c4ai-command-r-plus-08-2024",
|
79 |
messages=[{"role": "user", "content": prompt}],
|
@@ -83,13 +83,13 @@ Please follow this format:
|
|
83 |
|
84 |
return response.choices[0].message.content
|
85 |
except Exception as e:
|
86 |
-
return f"
|
87 |
|
88 |
|
89 |
-
#
|
90 |
def init_db():
|
91 |
"""
|
92 |
-
|
93 |
"""
|
94 |
db_path = pathlib.Path("search_results.db")
|
95 |
conn = sqlite3.connect(db_path)
|
@@ -105,7 +105,7 @@ def init_db():
|
|
105 |
|
106 |
def save_to_db(keyword, country, results):
|
107 |
"""
|
108 |
-
|
109 |
"""
|
110 |
conn = sqlite3.connect("search_results.db")
|
111 |
c = conn.cursor()
|
@@ -122,8 +122,8 @@ def save_to_db(keyword, country, results):
|
|
122 |
|
123 |
def load_from_db(keyword, country):
|
124 |
"""
|
125 |
-
|
126 |
-
|
127 |
"""
|
128 |
conn = sqlite3.connect("search_results.db")
|
129 |
c = conn.cursor()
|
@@ -139,84 +139,83 @@ def load_from_db(keyword, country):
|
|
139 |
|
140 |
def display_results(articles):
|
141 |
"""
|
142 |
-
|
143 |
"""
|
144 |
output = ""
|
145 |
for idx, article in enumerate(articles, 1):
|
146 |
output += f"### {idx}. {article['title']}\n"
|
147 |
-
output += f"
|
148 |
-
output += f"
|
149 |
-
output += f"
|
150 |
-
output += f"
|
151 |
return output
|
152 |
|
153 |
|
154 |
########################################
|
155 |
-
# 1)
|
156 |
########################################
|
157 |
def search_company(company):
|
158 |
"""
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
"""
|
165 |
error_message, articles = serphouse_search(company, "United States")
|
166 |
if not error_message and articles:
|
167 |
-
#
|
168 |
analysis = analyze_sentiment_batch(articles, client)
|
169 |
|
170 |
-
#
|
171 |
store_dict = {
|
172 |
"articles": articles,
|
173 |
"analysis": analysis
|
174 |
}
|
175 |
save_to_db(company, "United States", store_dict)
|
176 |
|
177 |
-
#
|
178 |
output = display_results(articles)
|
179 |
-
output += f"\n\n###
|
180 |
return output
|
181 |
-
return f"
|
182 |
|
183 |
########################################
|
184 |
-
# 2)
|
185 |
########################################
|
186 |
def load_company(company):
|
187 |
"""
|
188 |
-
|
189 |
-
and return the articles + analysis in a single output.
|
190 |
"""
|
191 |
data, timestamp = load_from_db(company, "United States")
|
192 |
if data:
|
193 |
articles = data.get("articles", [])
|
194 |
analysis = data.get("analysis", "")
|
195 |
|
196 |
-
output = f"### {company}
|
197 |
output += display_results(articles)
|
198 |
-
output += f"\n\n###
|
199 |
return output
|
200 |
-
return f"
|
201 |
|
202 |
|
203 |
########################################
|
204 |
-
# 3)
|
205 |
########################################
|
206 |
def show_stats():
|
207 |
"""
|
208 |
-
|
209 |
-
-
|
210 |
-
-
|
211 |
-
-
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
"""
|
216 |
conn = sqlite3.connect("search_results.db")
|
217 |
c = conn.cursor()
|
218 |
|
219 |
-
output = "## EarnBOT
|
220 |
|
221 |
data_list = []
|
222 |
for company in KOREAN_COMPANIES:
|
@@ -253,10 +252,10 @@ def show_stats():
|
|
253 |
for comp, tstamp, count, analysis in results_list:
|
254 |
seoul_time = convert_to_seoul_time(tstamp)
|
255 |
output += f"### {comp}\n"
|
256 |
-
output += f"-
|
257 |
-
output += f"-
|
258 |
if analysis:
|
259 |
-
output += "####
|
260 |
output += f"{analysis}\n\n"
|
261 |
output += "---\n\n"
|
262 |
|
@@ -265,10 +264,10 @@ def show_stats():
|
|
265 |
|
266 |
def search_all_companies():
|
267 |
"""
|
268 |
-
|
269 |
-
|
270 |
"""
|
271 |
-
overall_result = "# [
|
272 |
|
273 |
def do_search(comp):
|
274 |
return comp, search_company(comp)
|
@@ -284,9 +283,9 @@ def search_all_companies():
|
|
284 |
|
285 |
def load_all_companies():
|
286 |
"""
|
287 |
-
|
288 |
"""
|
289 |
-
overall_result = "# [
|
290 |
|
291 |
for comp in KOREAN_COMPANIES:
|
292 |
overall_result += f"## {comp}\n"
|
@@ -296,81 +295,81 @@ def load_all_companies():
|
|
296 |
|
297 |
def full_summary_report():
|
298 |
"""
|
299 |
-
1)
|
300 |
-
|
301 |
"""
|
302 |
-
# 1)
|
303 |
search_result_text = search_all_companies()
|
304 |
|
305 |
-
# 2)
|
306 |
load_result_text = load_all_companies()
|
307 |
|
308 |
-
# 3)
|
309 |
stats_text = show_stats()
|
310 |
|
311 |
combined_report = (
|
312 |
-
"#
|
313 |
-
"
|
314 |
-
"1.
|
315 |
f"{search_result_text}\n\n"
|
316 |
f"{load_result_text}\n\n"
|
317 |
-
"## [
|
318 |
f"{stats_text}"
|
319 |
)
|
320 |
return combined_report
|
321 |
|
322 |
|
323 |
########################################
|
324 |
-
#
|
325 |
########################################
|
326 |
def search_custom(query, country):
|
327 |
"""
|
328 |
-
|
329 |
-
1)
|
330 |
-
2)
|
331 |
"""
|
332 |
error_message, articles = serphouse_search(query, country)
|
333 |
if error_message:
|
334 |
-
return f"
|
335 |
if not articles:
|
336 |
-
return "
|
337 |
|
338 |
-
# 1)
|
339 |
analysis = analyze_sentiment_batch(articles, client)
|
340 |
|
341 |
-
# 2)
|
342 |
save_data = {
|
343 |
"articles": articles,
|
344 |
"analysis": analysis
|
345 |
}
|
346 |
save_to_db(query, country, save_data)
|
347 |
|
348 |
-
# 3)
|
349 |
loaded_data, timestamp = load_from_db(query, country)
|
350 |
if not loaded_data:
|
351 |
-
return "
|
352 |
|
353 |
-
# 4)
|
354 |
-
out = f"## [
|
355 |
-
out += f"
|
356 |
-
out += f"
|
357 |
-
out += f"
|
358 |
|
359 |
arts = loaded_data.get("articles", [])
|
360 |
analy = loaded_data.get("analysis", "")
|
361 |
|
362 |
out += display_results(arts)
|
363 |
-
out += f"###
|
364 |
|
365 |
return out
|
366 |
|
367 |
|
368 |
########################################
|
369 |
-
# API
|
370 |
########################################
|
371 |
ACCESS_TOKEN = os.getenv("HF_TOKEN")
|
372 |
if not ACCESS_TOKEN:
|
373 |
-
raise ValueError("HF_TOKEN
|
374 |
|
375 |
client = OpenAI(
|
376 |
base_url="https://api-inference.huggingface.co/v1/",
|
@@ -381,7 +380,7 @@ API_KEY = os.getenv("SERPHOUSE_API_KEY")
|
|
381 |
|
382 |
|
383 |
########################################
|
384 |
-
#
|
385 |
########################################
|
386 |
COUNTRY_LANGUAGES = {
|
387 |
"United States": "en",
|
@@ -439,8 +438,8 @@ COUNTRY_LANGUAGES = {
|
|
439 |
"Nigeria": "en",
|
440 |
"Kenya": "sw",
|
441 |
"Ukraine": "uk",
|
442 |
-
"Croatia": "
|
443 |
-
"Slovakia": "
|
444 |
"Bulgaria": "bg",
|
445 |
"Serbia": "sr",
|
446 |
"Estonia": "et",
|
@@ -527,8 +526,8 @@ COUNTRY_LOCATIONS = {
|
|
527 |
@lru_cache(maxsize=100)
|
528 |
def translate_query(query, country):
|
529 |
"""
|
530 |
-
|
531 |
-
|
532 |
"""
|
533 |
try:
|
534 |
if is_english(query):
|
@@ -558,20 +557,20 @@ def translate_query(query, country):
|
|
558 |
return query
|
559 |
|
560 |
except Exception as e:
|
561 |
-
print(f"
|
562 |
return query
|
563 |
|
564 |
def is_english(text):
|
565 |
"""
|
566 |
-
|
567 |
"""
|
568 |
return all(ord(char) < 128 for char in text.replace(' ', '').replace('-', '').replace('_', ''))
|
569 |
|
570 |
def search_serphouse(query, country, page=1, num_result=10):
|
571 |
"""
|
572 |
-
|
573 |
-
|
574 |
-
|
575 |
"""
|
576 |
url = "https://api.serphouse.com/serp/live"
|
577 |
|
@@ -628,26 +627,26 @@ def search_serphouse(query, country, page=1, num_result=10):
|
|
628 |
|
629 |
except requests.exceptions.Timeout:
|
630 |
return {
|
631 |
-
"error": "
|
632 |
"translated_query": query
|
633 |
}
|
634 |
except requests.exceptions.RequestException as e:
|
635 |
return {
|
636 |
-
"error": f"
|
637 |
"translated_query": query
|
638 |
}
|
639 |
except Exception as e:
|
640 |
return {
|
641 |
-
"error": f"
|
642 |
"translated_query": query
|
643 |
}
|
644 |
|
645 |
def format_results_from_raw(response_data):
|
646 |
"""
|
647 |
-
|
648 |
"""
|
649 |
if "error" in response_data:
|
650 |
-
return "
|
651 |
|
652 |
try:
|
653 |
results = response_data["results"]
|
@@ -655,9 +654,9 @@ def format_results_from_raw(response_data):
|
|
655 |
|
656 |
news_results = results.get('results', {}).get('results', {}).get('news', [])
|
657 |
if not news_results:
|
658 |
-
return "
|
659 |
|
660 |
-
#
|
661 |
korean_domains = [
|
662 |
'.kr', 'korea', 'korean', 'yonhap', 'hankyung', 'chosun',
|
663 |
'donga', 'joins', 'hani', 'koreatimes', 'koreaherald'
|
@@ -678,27 +677,27 @@ def format_results_from_raw(response_data):
|
|
678 |
any(keyword in title for keyword in korean_keywords)
|
679 |
)
|
680 |
|
681 |
-
#
|
682 |
if not is_korean_content:
|
683 |
filtered_articles.append({
|
684 |
"index": idx,
|
685 |
-
"title": result.get("title", "
|
686 |
"link": url,
|
687 |
-
"snippet": result.get("snippet", "
|
688 |
-
"channel": result.get("channel", result.get("source", "
|
689 |
-
"time": result.get("time", result.get("date", "
|
690 |
"image_url": result.get("img", result.get("thumbnail", "")),
|
691 |
"translated_query": translated_query
|
692 |
})
|
693 |
|
694 |
return "", filtered_articles
|
695 |
except Exception as e:
|
696 |
-
return f"
|
697 |
|
698 |
def serphouse_search(query, country):
|
699 |
"""
|
700 |
-
|
701 |
-
|
702 |
"""
|
703 |
response_data = search_serphouse(query, country)
|
704 |
return format_results_from_raw(response_data)
|
@@ -907,9 +906,9 @@ footer {
|
|
907 |
}
|
908 |
"""
|
909 |
|
910 |
-
# --- Gradio
|
911 |
-
with gr.Blocks(css=css, title="NewsAI
|
912 |
-
#
|
913 |
init_db()
|
914 |
|
915 |
gr.HTML("""<a href="https://visitorbadge.io/status?path=https%3A%2F%2Fopenfree-MoneyRadar.hf.space">
|
@@ -919,50 +918,54 @@ with gr.Blocks(css=css, title="NewsAI Service") as iface:
|
|
919 |
|
920 |
with gr.Tabs():
|
921 |
with gr.Tab("MoneyRadar"):
|
922 |
-
#
|
923 |
gr.Markdown(
|
924 |
"""
|
925 |
-
## MoneyRadar
|
926 |
-
|
927 |
-
|
928 |
-
|
929 |
-
|
930 |
-
|
931 |
-
|
932 |
-
|
933 |
-
|
934 |
-
-
|
935 |
-
-
|
936 |
-
|
937 |
-
|
938 |
-
|
939 |
-
|
940 |
-
|
941 |
-
-
|
942 |
-
|
943 |
-
|
|
|
|
|
|
|
|
|
944 |
"""
|
945 |
)
|
946 |
|
947 |
-
#
|
948 |
with gr.Group():
|
949 |
-
gr.Markdown("###
|
950 |
with gr.Row():
|
951 |
with gr.Column():
|
952 |
user_input = gr.Textbox(
|
953 |
-
label="
|
954 |
-
placeholder="
|
955 |
elem_classes="textbox"
|
956 |
)
|
957 |
with gr.Column():
|
958 |
country_selection = gr.Dropdown(
|
959 |
choices=list(COUNTRY_LOCATIONS.keys()),
|
960 |
value="United States",
|
961 |
-
label="
|
962 |
)
|
963 |
with gr.Column():
|
964 |
custom_search_btn = gr.Button(
|
965 |
-
"
|
966 |
variant="primary",
|
967 |
elem_classes="primary-btn"
|
968 |
)
|
@@ -975,10 +978,10 @@ with gr.Blocks(css=css, title="NewsAI Service") as iface:
|
|
975 |
outputs=custom_search_output
|
976 |
)
|
977 |
|
978 |
-
#
|
979 |
with gr.Row():
|
980 |
full_report_btn = gr.Button(
|
981 |
-
"
|
982 |
variant="primary",
|
983 |
elem_classes="primary-btn"
|
984 |
)
|
@@ -989,23 +992,23 @@ with gr.Blocks(css=css, title="NewsAI Service") as iface:
|
|
989 |
outputs=full_report_display
|
990 |
)
|
991 |
|
992 |
-
#
|
993 |
with gr.Column():
|
994 |
for i in range(0, len(KOREAN_COMPANIES), 2):
|
995 |
with gr.Row():
|
996 |
-
#
|
997 |
with gr.Column():
|
998 |
company = KOREAN_COMPANIES[i]
|
999 |
with gr.Group():
|
1000 |
gr.Markdown(f"### {company}")
|
1001 |
with gr.Row():
|
1002 |
search_btn = gr.Button(
|
1003 |
-
"
|
1004 |
variant="primary",
|
1005 |
elem_classes="primary-btn"
|
1006 |
)
|
1007 |
load_btn = gr.Button(
|
1008 |
-
"
|
1009 |
variant="secondary",
|
1010 |
elem_classes="secondary-btn"
|
1011 |
)
|
@@ -1020,7 +1023,7 @@ with gr.Blocks(css=css, title="NewsAI Service") as iface:
|
|
1020 |
outputs=result_display
|
1021 |
)
|
1022 |
|
1023 |
-
#
|
1024 |
if i + 1 < len(KOREAN_COMPANIES):
|
1025 |
with gr.Column():
|
1026 |
company = KOREAN_COMPANIES[i + 1]
|
@@ -1028,12 +1031,12 @@ with gr.Blocks(css=css, title="NewsAI Service") as iface:
|
|
1028 |
gr.Markdown(f"### {company}")
|
1029 |
with gr.Row():
|
1030 |
search_btn = gr.Button(
|
1031 |
-
"
|
1032 |
variant="primary",
|
1033 |
elem_classes="primary-btn"
|
1034 |
)
|
1035 |
load_btn = gr.Button(
|
1036 |
-
"
|
1037 |
variant="secondary",
|
1038 |
elem_classes="secondary-btn"
|
1039 |
)
|
@@ -1048,7 +1051,7 @@ with gr.Blocks(css=css, title="NewsAI Service") as iface:
|
|
1048 |
outputs=result_display
|
1049 |
)
|
1050 |
|
1051 |
-
#
|
1052 |
iface.launch(
|
1053 |
server_name="0.0.0.0",
|
1054 |
server_port=7860,
|
|
|
14 |
import sqlite3
|
15 |
import pytz
|
16 |
|
17 |
+
# List of target companies/keywords (์๋ฌธ์ผ๋ก ๊ฒ์์ด๋ ๊ทธ๋๋ก ์ ์ง)
|
18 |
KOREAN_COMPANIES = [
|
19 |
"NVIDIA",
|
20 |
"ALPHABET",
|
|
|
36 |
|
37 |
def convert_to_seoul_time(timestamp_str):
|
38 |
"""
|
39 |
+
์ฃผ์ด์ง UTC ํ์์คํฌํ ๋ฌธ์์ด์ ์์ธ ์๊ฐ(KST)์ผ๋ก ๋ณํ.
|
40 |
"""
|
41 |
try:
|
42 |
dt = datetime.strptime(timestamp_str, '%Y-%m-%d %H:%M:%S')
|
|
|
44 |
seoul_time = seoul_tz.localize(dt)
|
45 |
return seoul_time.strftime('%Y-%m-%d %H:%M:%S KST')
|
46 |
except Exception as e:
|
47 |
+
print(f"์๊ฐ ๋ณํ ์ค๋ฅ: {str(e)}")
|
48 |
return timestamp_str
|
49 |
|
50 |
def analyze_sentiment_batch(articles, client):
|
51 |
"""
|
52 |
+
OpenAI API๋ฅผ ์ฌ์ฉํ์ฌ ๋ด์ค ๊ธฐ์ฌ ๋ชจ์์ ๋ํ ์ ๋ฐ์ ์ธ ๊ฐ์ฑ ๋ถ์์ ์ํํ๋ค.
|
53 |
+
๋ถ์ ๊ฒฐ๊ณผ๋ ํ๊ธ๋ก ๋ฐํ๋๋ค.
|
54 |
"""
|
55 |
try:
|
56 |
+
# ๋ชจ๋ ๊ธฐ์ฌ๋ฅผ ํ๋์ ํ
์คํธ๋ก ๊ฒฐํฉ
|
57 |
combined_text = "\n\n".join([
|
58 |
+
f"์ ๋ชฉ: {article.get('title', '')}\n๋ด์ฉ: {article.get('snippet', '')}"
|
59 |
for article in articles
|
60 |
])
|
61 |
|
62 |
+
prompt = f"""์๋ ๋ด์ค ๊ธฐ์ฌ ๋ชจ์์ ๋ํ ์ ๋ฐ์ ์ธ ๊ฐ์ฑ ๋ถ์์ ์ํํ์ธ์.
|
63 |
|
64 |
+
๋ด์ค ๋ด์ฉ:
|
65 |
{combined_text}
|
66 |
|
67 |
+
๋ค์ ํ์์ ๋ฐ๋ผ ์์ฑํด ์ฃผ์ธ์:
|
68 |
+
1. ์ ์ฒด ๊ฐ์ฑ: [๊ธ์ /๋ถ์ /์ค๋ฆฝ]
|
69 |
+
2. ์ฃผ์ ๊ธ์ ์์ธ:
|
70 |
+
- [ํญ๋ชฉ1]
|
71 |
+
- [ํญ๋ชฉ2]
|
72 |
+
3. ์ฃผ์ ๋ถ์ ์์ธ:
|
73 |
+
- [ํญ๋ชฉ1]
|
74 |
+
- [ํญ๋ชฉ2]
|
75 |
+
4. ์์ฝ: [์์ธํ ์ค๋ช
]
|
76 |
"""
|
|
|
77 |
response = client.chat.completions.create(
|
78 |
model="CohereForAI/c4ai-command-r-plus-08-2024",
|
79 |
messages=[{"role": "user", "content": prompt}],
|
|
|
83 |
|
84 |
return response.choices[0].message.content
|
85 |
except Exception as e:
|
86 |
+
return f"๊ฐ์ฑ ๋ถ์ ์คํจ: {str(e)}"
|
87 |
|
88 |
|
89 |
+
# ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ด๊ธฐํ
|
90 |
def init_db():
|
91 |
"""
|
92 |
+
SQLite ๋ฐ์ดํฐ๋ฒ ์ด์ค(search_results.db)๋ฅผ ์ด๊ธฐํ (์์ผ๋ฉด ์์ฑ).
|
93 |
"""
|
94 |
db_path = pathlib.Path("search_results.db")
|
95 |
conn = sqlite3.connect(db_path)
|
|
|
105 |
|
106 |
def save_to_db(keyword, country, results):
|
107 |
"""
|
108 |
+
ํน์ (ํค์๋, ๊ตญ๊ฐ) ์กฐํฉ์ ๋ํ ๊ฒ์ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ์ฅ.
|
109 |
"""
|
110 |
conn = sqlite3.connect("search_results.db")
|
111 |
c = conn.cursor()
|
|
|
122 |
|
123 |
def load_from_db(keyword, country):
|
124 |
"""
|
125 |
+
ํน์ (ํค์๋, ๊ตญ๊ฐ) ์กฐํฉ์ ๋ํ ๊ฐ์ฅ ์ต๊ทผ ๊ฒ์ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ๋ถ๋ฌ์ด.
|
126 |
+
๋ฐ์ดํฐ๋ฅผ ๋ถ๋ฌ์ค๊ณ ํ์์คํฌํ๋ฅผ ๋ณํํ์ฌ ๋ฐํ.
|
127 |
"""
|
128 |
conn = sqlite3.connect("search_results.db")
|
129 |
c = conn.cursor()
|
|
|
139 |
|
140 |
def display_results(articles):
|
141 |
"""
|
142 |
+
๋ด์ค ๊ธฐ์ฌ ๋ชฉ๋ก์ ๋งํฌ๋ค์ด ๋ฌธ์์ด๋ก ๋ณํํ์ฌ ๋ฐํ.
|
143 |
"""
|
144 |
output = ""
|
145 |
for idx, article in enumerate(articles, 1):
|
146 |
output += f"### {idx}. {article['title']}\n"
|
147 |
+
output += f"์ถ์ฒ: {article['channel']}\n"
|
148 |
+
output += f"์๊ฐ: {article['time']}\n"
|
149 |
+
output += f"๋งํฌ: {article['link']}\n"
|
150 |
+
output += f"์์ฝ: {article['snippet']}\n\n"
|
151 |
return output
|
152 |
|
153 |
|
154 |
########################################
|
155 |
+
# 1) ๊ฒ์ => ๊ธฐ์ฌ + ๊ฐ์ฑ ๋ถ์, DB ์ ์ฅ
|
156 |
########################################
|
157 |
def search_company(company):
|
158 |
"""
|
159 |
+
๋จ์ผ ํ์ฌ(๋๋ ํค์๋)์ ๋ํด ๋ฏธ๊ตญ ๋ด์ค ๊ฒ์์ ์งํ:
|
160 |
+
1) ๊ธฐ์ฌ ๋ชฉ๋ก์ ๊ฒ์
|
161 |
+
2) ๊ฐ์ฑ ๋ถ์ ์ํ
|
162 |
+
3) ๊ฒฐ๊ณผ๋ฅผ DB์ ์ ์ฅ
|
163 |
+
4) ๊ธฐ์ฌ์ ๋ถ์ ๊ฒฐ๊ณผ๋ฅผ ํ๋์ ์ถ๋ ฅ์ผ๋ก ๋ฐํ
|
164 |
"""
|
165 |
error_message, articles = serphouse_search(company, "United States")
|
166 |
if not error_message and articles:
|
167 |
+
# ๊ฐ์ฑ ๋ถ์ ์ํ (ํ๊ธ ๊ฒฐ๊ณผ ๋ฐํ)
|
168 |
analysis = analyze_sentiment_batch(articles, client)
|
169 |
|
170 |
+
# DB์ ์ ์ฅํ ๋ฐ์ดํฐ ์ค๋น
|
171 |
store_dict = {
|
172 |
"articles": articles,
|
173 |
"analysis": analysis
|
174 |
}
|
175 |
save_to_db(company, "United States", store_dict)
|
176 |
|
177 |
+
# ์ถ๋ ฅ์ฉ ๋ฐ์ดํฐ ์ค๋น
|
178 |
output = display_results(articles)
|
179 |
+
output += f"\n\n### ๊ฐ์ฑ ๋ถ์ ๋ณด๊ณ ์\n{analysis}\n"
|
180 |
return output
|
181 |
+
return f"{company}์ ๋ํ ๊ฒ์ ๊ฒฐ๊ณผ๊ฐ ์์ต๋๋ค."
|
182 |
|
183 |
########################################
|
184 |
+
# 2) ๋ถ๋ฌ์ค๊ธฐ => DB์์ ๊ธฐ์ฌ + ๋ถ์ ๊ฒฐ๊ณผ ๋ฐํ
|
185 |
########################################
|
186 |
def load_company(company):
|
187 |
"""
|
188 |
+
์ฃผ์ด์ง ํ์ฌ(๋๋ ํค์๋)์ ๋ํด ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ๊ฐ์ฅ ์ต๊ทผ ๋ฏธ๊ตญ ๋ด์ค ๊ฒ์ ๊ฒฐ๊ณผ(๊ธฐ์ฌ + ๊ฐ์ฑ ๋ถ์)๋ฅผ ๋ถ๋ฌ์ด.
|
|
|
189 |
"""
|
190 |
data, timestamp = load_from_db(company, "United States")
|
191 |
if data:
|
192 |
articles = data.get("articles", [])
|
193 |
analysis = data.get("analysis", "")
|
194 |
|
195 |
+
output = f"### {company} ๊ฒ์ ๊ฒฐ๊ณผ\n๋ง์ง๋ง ์
๋ฐ์ดํธ: {timestamp}\n\n"
|
196 |
output += display_results(articles)
|
197 |
+
output += f"\n\n### ๊ฐ์ฑ ๋ถ์ ๋ณด๊ณ ์\n{analysis}\n"
|
198 |
return output
|
199 |
+
return f"{company}์ ๋ํ ์ ์ฅ๋ ๊ฒฐ๊ณผ๊ฐ ์์ต๋๋ค."
|
200 |
|
201 |
|
202 |
########################################
|
203 |
+
# 3) show_stats() โ ๋ณด๊ณ ์ ์ ๋ชฉ ๋ณ๊ฒฝ
|
204 |
########################################
|
205 |
def show_stats():
|
206 |
"""
|
207 |
+
๊ฐ ํ์ฌ(KOREAN_COMPANIES)์ ๋ํด:
|
208 |
+
- DB์ ์ ์ฅ๋ ์ต์ ํ์์คํฌํ
|
209 |
+
- ์ ์ฅ๋ ๊ธฐ์ฌ ๊ฐ์
|
210 |
+
- ๊ฐ์ฑ ๋ถ์ ๊ฒฐ๊ณผ
|
211 |
+
์ ๋ณด๊ณ ์ ํ์์ผ๋ก ๋ฐํ.
|
212 |
+
|
213 |
+
์ ๋ชฉ: "EarnBOT ๋ถ์ ๋ณด๊ณ ์"
|
214 |
"""
|
215 |
conn = sqlite3.connect("search_results.db")
|
216 |
c = conn.cursor()
|
217 |
|
218 |
+
output = "## EarnBOT ๋ถ์ ๋ณด๊ณ ์\n\n"
|
219 |
|
220 |
data_list = []
|
221 |
for company in KOREAN_COMPANIES:
|
|
|
252 |
for comp, tstamp, count, analysis in results_list:
|
253 |
seoul_time = convert_to_seoul_time(tstamp)
|
254 |
output += f"### {comp}\n"
|
255 |
+
output += f"- ๋ง์ง๋ง ์
๋ฐ์ดํธ: {seoul_time}\n"
|
256 |
+
output += f"- ์ ์ฅ๋ ๊ธฐ์ฌ ์: {count}\n\n"
|
257 |
if analysis:
|
258 |
+
output += "#### ๋ด์ค ๊ฐ์ฑ ๋ถ์\n"
|
259 |
output += f"{analysis}\n\n"
|
260 |
output += "---\n\n"
|
261 |
|
|
|
264 |
|
265 |
def search_all_companies():
|
266 |
"""
|
267 |
+
KOREAN_COMPANIES์ ๋ชจ๋ ํญ๋ชฉ์ ๋ํด(๋ณ๋ ฌ ์ฒ๋ฆฌ) ๊ฒ์ ํ,
|
268 |
+
๊ฐ์ฑ ๋ถ์ ์ํ ๋ฐ DB ์ ์ฅ => ๋ชจ๋ ๊ฒฐ๊ณผ๋ฅผ ๋งํฌ๋ค์ด ๋ฌธ์์ด๋ก ๋ฐํ.
|
269 |
"""
|
270 |
+
overall_result = "# [์ ์ฒด ํ์ฌ ๊ฒ์ ๊ฒฐ๊ณผ]\n\n"
|
271 |
|
272 |
def do_search(comp):
|
273 |
return comp, search_company(comp)
|
|
|
283 |
|
284 |
def load_all_companies():
|
285 |
"""
|
286 |
+
DB์ ์ ์ฅ๋ ๋ชจ๋ ํ์ฌ(KOREAN_COMPANIES)์ ๊ธฐ์ฌ์ ๋ถ์ ๊ฒฐ๊ณผ๋ฅผ ๋ถ๋ฌ์ ๋งํฌ๋ค์ด์ผ๋ก ๋ฐํ.
|
287 |
"""
|
288 |
+
overall_result = "# [์ ์ฒด ํ์ฌ ๋ฐ์ดํฐ ์ถ๋ ฅ]\n\n"
|
289 |
|
290 |
for comp in KOREAN_COMPANIES:
|
291 |
overall_result += f"## {comp}\n"
|
|
|
295 |
|
296 |
def full_summary_report():
|
297 |
"""
|
298 |
+
1) ๋ชจ๋ ํ์ฌ๋ฅผ ๊ฒ์(๋ณ๋ ฌ ์ฒ๋ฆฌ) -> 2) DB์์ ๊ฒฐ๊ณผ ๋ถ๋ฌ์ค๊ธฐ -> 3) ๊ฐ์ฑ ๋ถ์ ํต๊ณ ํ์
|
299 |
+
์ธ ๋จ๊ณ์ ๊ฒฐ๊ณผ๋ฅผ ํ๋์ ์ข
ํฉ ๋ณด๊ณ ์๋ก ๋ฐํ.
|
300 |
"""
|
301 |
+
# 1) ๋ชจ๋ ํ์ฌ ๊ฒ์ ๋ฐ DB ์ ์ฅ
|
302 |
search_result_text = search_all_companies()
|
303 |
|
304 |
+
# 2) DB์์ ๊ฒฐ๊ณผ ๋ถ๋ฌ์ค๊ธฐ
|
305 |
load_result_text = load_all_companies()
|
306 |
|
307 |
+
# 3) ํต๊ณ ํ์ โ EarnBOT ๋ถ์ ๋ณด๊ณ ์
|
308 |
stats_text = show_stats()
|
309 |
|
310 |
combined_report = (
|
311 |
+
"# ์ ์ฒด ๋ถ์ ์ข
ํฉ ๋ณด๊ณ ์\n\n"
|
312 |
+
"์คํ ์์:\n"
|
313 |
+
"1. ๋ชจ๋ ํ์ฌ ๊ฒ์(๋ณ๋ ฌ ์ฒ๋ฆฌ) ๋ฐ ๊ฐ์ฑ ๋ถ์ โ 2. DB์์ ๊ฒฐ๊ณผ ๋ถ๋ฌ์ค๊ธฐ โ 3. ์ ์ฒด ๊ฐ์ฑ ๋ถ์ ํต๊ณ ํ์\n\n"
|
314 |
f"{search_result_text}\n\n"
|
315 |
f"{load_result_text}\n\n"
|
316 |
+
"## [์ ์ฒด ๊ฐ์ฑ ๋ถ์ ํต๊ณ]\n\n"
|
317 |
f"{stats_text}"
|
318 |
)
|
319 |
return combined_report
|
320 |
|
321 |
|
322 |
########################################
|
323 |
+
# ์ถ๊ฐ ๊ธฐ๋ฅ: ์ฌ์ฉ์ ์ ์ ๊ฒ์
|
324 |
########################################
|
325 |
def search_custom(query, country):
|
326 |
"""
|
327 |
+
์ฌ์ฉ์๊ฐ ์
๋ ฅํ (ํค์๋, ๊ตญ๊ฐ)์ ๋ํด:
|
328 |
+
1) ๊ฒ์ ๋ฐ ๊ฐ์ฑ ๋ถ์ ์ํ ํ DB ์ ์ฅ
|
329 |
+
2) DB์์ ๋ถ๋ฌ์ ๊ธฐ์ฌ์ ๋ถ์ ๊ฒฐ๊ณผ ํ์
|
330 |
"""
|
331 |
error_message, articles = serphouse_search(query, country)
|
332 |
if error_message:
|
333 |
+
return f"์ค๋ฅ ๋ฐ์: {error_message}"
|
334 |
if not articles:
|
335 |
+
return "์
๋ ฅํ์ ๊ฒ์์ด์ ๋ํ ๊ฒฐ๊ณผ๊ฐ ์์ต๋๋ค."
|
336 |
|
337 |
+
# 1) ๊ฐ์ฑ ๋ถ์ ์ํ (ํ๊ธ)
|
338 |
analysis = analyze_sentiment_batch(articles, client)
|
339 |
|
340 |
+
# 2) DB์ ์ ์ฅ
|
341 |
save_data = {
|
342 |
"articles": articles,
|
343 |
"analysis": analysis
|
344 |
}
|
345 |
save_to_db(query, country, save_data)
|
346 |
|
347 |
+
# 3) DB์์ ๋ถ๋ฌ์ค๊ธฐ
|
348 |
loaded_data, timestamp = load_from_db(query, country)
|
349 |
if not loaded_data:
|
350 |
+
return "DB์์ ๋ฐ์ดํฐ๋ฅผ ๋ถ๋ฌ์ค์ง ๋ชปํ์ต๋๋ค."
|
351 |
|
352 |
+
# 4) ์ต์ข
์ถ๋ ฅ ์ค๋น
|
353 |
+
out = f"## [์ฌ์ฉ์ ์ ์ ๊ฒ์ ๊ฒฐ๊ณผ]\n\n"
|
354 |
+
out += f"**๊ฒ์์ด**: {query}\n\n"
|
355 |
+
out += f"**๊ตญ๊ฐ**: {country}\n\n"
|
356 |
+
out += f"**ํ์์คํฌํ**: {timestamp}\n\n"
|
357 |
|
358 |
arts = loaded_data.get("articles", [])
|
359 |
analy = loaded_data.get("analysis", "")
|
360 |
|
361 |
out += display_results(arts)
|
362 |
+
out += f"### ๋ด์ค ๊ฐ์ฑ ๋ถ์\n{analy}\n"
|
363 |
|
364 |
return out
|
365 |
|
366 |
|
367 |
########################################
|
368 |
+
# API ์ธ์ฆ ์ค์
|
369 |
########################################
|
370 |
ACCESS_TOKEN = os.getenv("HF_TOKEN")
|
371 |
if not ACCESS_TOKEN:
|
372 |
+
raise ValueError("HF_TOKEN ํ๊ฒฝ๋ณ์๊ฐ ์ค์ ๋์ด ์์ง ์์ต๋๋ค.")
|
373 |
|
374 |
client = OpenAI(
|
375 |
base_url="https://api-inference.huggingface.co/v1/",
|
|
|
380 |
|
381 |
|
382 |
########################################
|
383 |
+
# ๊ตญ๊ฐ๋ณ ์ค์
|
384 |
########################################
|
385 |
COUNTRY_LANGUAGES = {
|
386 |
"United States": "en",
|
|
|
438 |
"Nigeria": "en",
|
439 |
"Kenya": "sw",
|
440 |
"Ukraine": "uk",
|
441 |
+
"Croatia": "Croatia",
|
442 |
+
"Slovakia": "Slovakia",
|
443 |
"Bulgaria": "bg",
|
444 |
"Serbia": "sr",
|
445 |
"Estonia": "et",
|
|
|
526 |
@lru_cache(maxsize=100)
|
527 |
def translate_query(query, country):
|
528 |
"""
|
529 |
+
๋น๊ณต์ Google Translation API๋ฅผ ์ฌ์ฉํด ๋์ ๊ตญ๊ฐ์ ์ธ์ด๋ก ๊ฒ์์ด ๋ฒ์ญ.
|
530 |
+
๋ฒ์ญ์ ์คํจํ๊ฑฐ๋ ์์ด์ผ ๊ฒฝ์ฐ ์๋ณธ ๊ฒ์์ด ๋ฐํ.
|
531 |
"""
|
532 |
try:
|
533 |
if is_english(query):
|
|
|
557 |
return query
|
558 |
|
559 |
except Exception as e:
|
560 |
+
print(f"๋ฒ์ญ ์ค๋ฅ: {str(e)}")
|
561 |
return query
|
562 |
|
563 |
def is_english(text):
|
564 |
"""
|
565 |
+
๋ฌธ์์ด์ด ์ฃผ๋ก ์์ด์ธ์ง ํ์ธ (๋ฌธ์ ์ฝ๋ ๋ฒ์ ํ์ธ).
|
566 |
"""
|
567 |
return all(ord(char) < 128 for char in text.replace(' ', '').replace('-', '').replace('_', ''))
|
568 |
|
569 |
def search_serphouse(query, country, page=1, num_result=10):
|
570 |
"""
|
571 |
+
SerpHouse API์ ์ค์๊ฐ ๊ฒ์ ์์ฒญ์ ๋ณด๋ด๋ฉฐ,
|
572 |
+
'news' ํญ(๋ ์ง์ ์ ๋ ฌ)๋ก ๊ฒ์.
|
573 |
+
๋ฐํ๊ฐ์ 'results' ๋๋ 'error'๊ฐ ํฌํจ๋ dict.
|
574 |
"""
|
575 |
url = "https://api.serphouse.com/serp/live"
|
576 |
|
|
|
627 |
|
628 |
except requests.exceptions.Timeout:
|
629 |
return {
|
630 |
+
"error": "๊ฒ์ ์๊ฐ์ด ์ด๊ณผ๋์์ต๋๋ค. ์ ์ ํ ๋ค์ ์๋ํด ์ฃผ์ธ์.",
|
631 |
"translated_query": query
|
632 |
}
|
633 |
except requests.exceptions.RequestException as e:
|
634 |
return {
|
635 |
+
"error": f"๊ฒ์ ์ค ์ค๋ฅ ๋ฐ์: {str(e)}",
|
636 |
"translated_query": query
|
637 |
}
|
638 |
except Exception as e:
|
639 |
return {
|
640 |
+
"error": f"์์์น ๋ชปํ ์ค๋ฅ ๋ฐ์: {str(e)}",
|
641 |
"translated_query": query
|
642 |
}
|
643 |
|
644 |
def format_results_from_raw(response_data):
|
645 |
"""
|
646 |
+
SerpHouse API์ ์๋ต ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ์ฌ (์ค๋ฅ ๋ฉ์์ง, ๊ธฐ์ฌ ๋ชฉ๋ก)์ ๋ฐํ.
|
647 |
"""
|
648 |
if "error" in response_data:
|
649 |
+
return "์ค๋ฅ: " + response_data["error"], []
|
650 |
|
651 |
try:
|
652 |
results = response_data["results"]
|
|
|
654 |
|
655 |
news_results = results.get('results', {}).get('results', {}).get('news', [])
|
656 |
if not news_results:
|
657 |
+
return "๊ฒ์ ๊ฒฐ๊ณผ๊ฐ ์์ต๋๋ค.", []
|
658 |
|
659 |
+
# ํ๊ตญ ๋๋ฉ์ธ ๋ฐ ํค์๋ ํํฐ๋ง (์์)
|
660 |
korean_domains = [
|
661 |
'.kr', 'korea', 'korean', 'yonhap', 'hankyung', 'chosun',
|
662 |
'donga', 'joins', 'hani', 'koreatimes', 'koreaherald'
|
|
|
677 |
any(keyword in title for keyword in korean_keywords)
|
678 |
)
|
679 |
|
680 |
+
# ํ๊ตญ ๊ด๋ จ ์ฝํ
์ธ ์ ์ธ
|
681 |
if not is_korean_content:
|
682 |
filtered_articles.append({
|
683 |
"index": idx,
|
684 |
+
"title": result.get("title", "์ ๋ชฉ ์์"),
|
685 |
"link": url,
|
686 |
+
"snippet": result.get("snippet", "๋ด์ฉ ์์"),
|
687 |
+
"channel": result.get("channel", result.get("source", "์ ์ ์์")),
|
688 |
+
"time": result.get("time", result.get("date", "์๊ฐ ์ ๋ณด ์์")),
|
689 |
"image_url": result.get("img", result.get("thumbnail", "")),
|
690 |
"translated_query": translated_query
|
691 |
})
|
692 |
|
693 |
return "", filtered_articles
|
694 |
except Exception as e:
|
695 |
+
return f"๊ฒฐ๊ณผ ์ฒ๋ฆฌ ์ค ์ค๋ฅ ๋ฐ์: {str(e)}", []
|
696 |
|
697 |
def serphouse_search(query, country):
|
698 |
"""
|
699 |
+
๊ฒ์ ๋ฐ ๊ฒฐ๊ณผ ํฌ๋งทํ
์ ์ํ ํฌํผ ํจ์.
|
700 |
+
(์ค๋ฅ ๋ฉ์์ง, ๊ธฐ์ฌ ๋ชฉ๋ก)์ ๋ฐํ.
|
701 |
"""
|
702 |
response_data = search_serphouse(query, country)
|
703 |
return format_results_from_raw(response_data)
|
|
|
906 |
}
|
907 |
"""
|
908 |
|
909 |
+
# --- Gradio ์ธํฐํ์ด์ค (UI ๋ถ๋ถ) ---
|
910 |
+
with gr.Blocks(css=css, title="NewsAI ์๏ฟฝ๏ฟฝ์ค") as iface:
|
911 |
+
# ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ด๊ธฐํ (init_db() ํธ์ถ)
|
912 |
init_db()
|
913 |
|
914 |
gr.HTML("""<a href="https://visitorbadge.io/status?path=https%3A%2F%2Fopenfree-MoneyRadar.hf.space">
|
|
|
918 |
|
919 |
with gr.Tabs():
|
920 |
with gr.Tab("MoneyRadar"):
|
921 |
+
# ์ฌ์ฉ ๋ฐฉ๋ฒ ๋ฐ ๊ธฐ๋ฅ ์ค๋ช
(ํ๊ธ)
|
922 |
gr.Markdown(
|
923 |
"""
|
924 |
+
## MoneyRadar
|
925 |
+
์ต์ 24์๊ฐ ๋ด ์์ 100๊ฐ์ ์ฐ์ ์์ ๋ด์ค๋ฅผ ์๋์ผ๋ก ์ถ์ถํ์ฌ
|
926 |
+
์์ต ๊ธฐํ๋ฅผ ํฌ์ฐฉํฉ๋๋ค.
|
927 |
+
|
928 |
+
**์๋น์ค ์ฌ์ฉ ๋ฐฉ๋ฒ**:
|
929 |
+
1. **์ฌ์ฉ์ ์ ์ ๊ฒ์**: ํค์๋๋ฅผ ์
๋ ฅํ๊ณ ๋์ ๊ตญ๊ฐ๋ฅผ ์ ํํ์ฌ ์ต์ ๋ด์ค๋ฅผ ๊ฐ์ ธ์ต๋๋ค.
|
930 |
+
์์คํ
์ด ์๋์ผ๋ก ๊ฐ์ฑ ๋ถ์์ ์ํํ๊ณ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ์ฅํฉ๋๋ค.
|
931 |
+
2. **์ ์ฒด ๋ถ์ ์ข
ํฉ ๋ณด๊ณ ์ ์์ฑ**: ์๋ ์์
์ ์๋์ผ๋ก ์ํํฉ๋๋ค.
|
932 |
+
- ์ฌ์ ์ ์๋ ๋ชจ๋ ํ์ฌ๋ฅผ ๋ณ๋ ฌ๋ก ๊ฒ์
|
933 |
+
- ๊ธฐ์ฌ์ ๊ฐ์ฑ ๋ถ์ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ์ฅ
|
934 |
+
- ์ ์ฒด ๊ฒฐ๊ณผ๋ฅผ ์ข
ํฉ ๋ณด๊ณ ์๋ก ํ์
|
935 |
+
3. **๊ฐ๋ณ ํ์ฌ ๊ฒ์/๋ถ๋ฌ์ค๊ธฐ**:
|
936 |
+
- **๊ฒ์**: ์ ํํ ํ์ฌ์ ๋ํด Google์์ ์ต์ ๋ด์ค๋ฅผ ๊ฒ์ ๋ฐ ๋ถ์
|
937 |
+
- **DB ๋ถ๋ฌ์ค๊ธฐ**: ๋ก์ปฌ ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ์ ์ฅ๋ ์ต์ ๋ด์ค์ ๊ฐ์ฑ ๋ถ์ ๊ฒฐ๊ณผ๋ฅผ ๋ถ๋ฌ์ต๋๋ค.
|
938 |
+
|
939 |
+
**์ฃผ์ ๊ธฐ๋ฅ**:
|
940 |
+
- **์ค์๊ฐ ๋ด์ค ์คํฌ๋ํ**: ์ฌ๋ฌ ์ง์ญ์์ ์ต์ ๊ธฐ์ฌ๋ฅผ ๊ฐ์ ธ์ต๋๋ค.
|
941 |
+
- **๊ณ ๊ธ ๊ฐ์ฑ ๋ถ์**: ์ต์ NLP ๋ชจ๋ธ์ ํ์ฉํ ๊ฐ์ฑ ๋ถ์์ ์ํํฉ๋๋ค.
|
942 |
+
- **๋ฐ์ดํฐ ์์์ฑ**: ๊ฒ์ ๊ฒฐ๊ณผ๋ฅผ SQLite ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์๋ ์ ์ฅ ๋ฐ ๋ถ๋ฌ์ค๊ธฐ.
|
943 |
+
- **์ ์ฐ์ฑ**: ์ฌ์ ์ ์๋ ํค์๋๋ฟ ์๋๋ผ ์ํ๋ ํค์๋/๊ตญ๊ฐ ๊ฒ์์ด ๊ฐ๋ฅํฉ๋๋ค.
|
944 |
+
|
945 |
+
**์ปค๋ฎค๋ํฐ**: https://discord.gg/openfreeai
|
946 |
+
---
|
947 |
"""
|
948 |
)
|
949 |
|
950 |
+
# ์ฌ์ฉ์ ์ ์ ๊ฒ์ ์น์
|
951 |
with gr.Group():
|
952 |
+
gr.Markdown("### ์ฌ์ฉ์ ์ ์ ๊ฒ์")
|
953 |
with gr.Row():
|
954 |
with gr.Column():
|
955 |
user_input = gr.Textbox(
|
956 |
+
label="ํค์๋๋ฅผ ์
๋ ฅํ์ธ์",
|
957 |
+
placeholder="์: Apple, Samsung ๋ฑ",
|
958 |
elem_classes="textbox"
|
959 |
)
|
960 |
with gr.Column():
|
961 |
country_selection = gr.Dropdown(
|
962 |
choices=list(COUNTRY_LOCATIONS.keys()),
|
963 |
value="United States",
|
964 |
+
label="๊ตญ๊ฐ ์ ํ"
|
965 |
)
|
966 |
with gr.Column():
|
967 |
custom_search_btn = gr.Button(
|
968 |
+
"๊ฒ์",
|
969 |
variant="primary",
|
970 |
elem_classes="primary-btn"
|
971 |
)
|
|
|
978 |
outputs=custom_search_output
|
979 |
)
|
980 |
|
981 |
+
# ์ ์ฒด ๋ณด๊ณ ์ ์์ฑ์ ์ํ ๋ฒํผ
|
982 |
with gr.Row():
|
983 |
full_report_btn = gr.Button(
|
984 |
+
"์ ์ฒด ๋ถ์ ์ข
ํฉ ๋ณด๊ณ ์ ์์ฑ",
|
985 |
variant="primary",
|
986 |
elem_classes="primary-btn"
|
987 |
)
|
|
|
992 |
outputs=full_report_display
|
993 |
)
|
994 |
|
995 |
+
# ๊ฐ๋ณ ํ์ฌ์ ๋ํ ๊ฒ์/๋ถ๋ฌ์ค๊ธฐ
|
996 |
with gr.Column():
|
997 |
for i in range(0, len(KOREAN_COMPANIES), 2):
|
998 |
with gr.Row():
|
999 |
+
# ์ผ์ชฝ ์ปฌ๋ผ
|
1000 |
with gr.Column():
|
1001 |
company = KOREAN_COMPANIES[i]
|
1002 |
with gr.Group():
|
1003 |
gr.Markdown(f"### {company}")
|
1004 |
with gr.Row():
|
1005 |
search_btn = gr.Button(
|
1006 |
+
"๊ฒ์",
|
1007 |
variant="primary",
|
1008 |
elem_classes="primary-btn"
|
1009 |
)
|
1010 |
load_btn = gr.Button(
|
1011 |
+
"DB ๋ถ๋ฌ์ค๊ธฐ",
|
1012 |
variant="secondary",
|
1013 |
elem_classes="secondary-btn"
|
1014 |
)
|
|
|
1023 |
outputs=result_display
|
1024 |
)
|
1025 |
|
1026 |
+
# ์ค๋ฅธ์ชฝ ์ปฌ๋ผ (์กด์ฌํ ๊ฒฝ์ฐ)
|
1027 |
if i + 1 < len(KOREAN_COMPANIES):
|
1028 |
with gr.Column():
|
1029 |
company = KOREAN_COMPANIES[i + 1]
|
|
|
1031 |
gr.Markdown(f"### {company}")
|
1032 |
with gr.Row():
|
1033 |
search_btn = gr.Button(
|
1034 |
+
"๊ฒ์",
|
1035 |
variant="primary",
|
1036 |
elem_classes="primary-btn"
|
1037 |
)
|
1038 |
load_btn = gr.Button(
|
1039 |
+
"DB ๋ถ๋ฌ์ค๊ธฐ",
|
1040 |
variant="secondary",
|
1041 |
elem_classes="secondary-btn"
|
1042 |
)
|
|
|
1051 |
outputs=result_display
|
1052 |
)
|
1053 |
|
1054 |
+
# Gradio ์ธํฐํ์ด์ค ์คํ
|
1055 |
iface.launch(
|
1056 |
server_name="0.0.0.0",
|
1057 |
server_port=7860,
|