Spaces:
Building
Building
Update app-backup2.py
Browse files- app-backup2.py +110 -62
app-backup2.py
CHANGED
@@ -141,37 +141,72 @@ def display_results(articles):
|
|
141 |
output += f"요약: {article['snippet']}\n\n"
|
142 |
return output
|
143 |
|
|
|
|
|
|
|
|
|
144 |
def search_company(company):
|
145 |
"""
|
146 |
-
단일 기업(또는 키워드)에 대해 미국 뉴스
|
|
|
|
|
147 |
"""
|
148 |
error_message, articles = serphouse_search(company, "United States")
|
149 |
if not error_message and articles:
|
150 |
-
|
151 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
152 |
return f"{company}에 대한 검색 결과가 없습니다."
|
153 |
|
|
|
|
|
|
|
154 |
def load_company(company):
|
155 |
"""
|
156 |
-
DB에서 단일 기업(또는 키워드)의 미국 뉴스 검색 결과를 불러와
|
|
|
157 |
"""
|
158 |
-
|
159 |
-
if
|
160 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
161 |
return f"{company}에 대한 저장된 결과가 없습니다."
|
162 |
|
|
|
|
|
|
|
|
|
163 |
def show_stats():
|
164 |
"""
|
165 |
KOREAN_COMPANIES 목록 내 모든 기업에 대해:
|
166 |
- 가장 최근 DB 저장 일자
|
167 |
- 기사 수
|
168 |
- 감성 분석 결과
|
169 |
-
를
|
|
|
|
|
170 |
"""
|
171 |
conn = sqlite3.connect("search_results.db")
|
172 |
c = conn.cursor()
|
173 |
|
174 |
-
output = "##
|
175 |
|
176 |
# 모든 기업에 대해 DB에서 읽어올 (company, timestamp, articles) 목록 수집
|
177 |
data_list = []
|
@@ -187,45 +222,48 @@ def show_stats():
|
|
187 |
row = c.fetchone()
|
188 |
if row:
|
189 |
results_json, timestamp = row
|
190 |
-
|
191 |
-
seoul_time = convert_to_seoul_time(timestamp)
|
192 |
-
data_list.append((company, seoul_time, articles))
|
193 |
|
194 |
conn.close()
|
195 |
|
196 |
-
#
|
197 |
def analyze_data(item):
|
198 |
-
comp, tstamp,
|
199 |
-
|
200 |
-
|
201 |
-
|
202 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
203 |
|
204 |
-
# ThreadPoolExecutor로 병렬 감성 분석
|
205 |
results_list = []
|
206 |
with ThreadPoolExecutor(max_workers=5) as executor:
|
207 |
futures = [executor.submit(analyze_data, dl) for dl in data_list]
|
208 |
for future in as_completed(futures):
|
209 |
results_list.append(future.result())
|
210 |
|
211 |
-
# 결과
|
212 |
-
for comp, tstamp, count,
|
|
|
213 |
output += f"### {comp}\n"
|
214 |
-
output += f"- 마지막 업데이트: {
|
215 |
output += f"- 저장된 기사 수: {count}건\n\n"
|
216 |
-
if
|
217 |
output += "#### 뉴스 감성 분석\n"
|
218 |
-
output += f"{
|
219 |
output += "---\n\n"
|
220 |
|
221 |
return output
|
222 |
|
223 |
|
224 |
-
### (1) 전체 검색: 멀티스레드 적용
|
225 |
def search_all_companies():
|
226 |
"""
|
227 |
-
KOREAN_COMPANIES 리스트 내 모든
|
228 |
-
|
229 |
"""
|
230 |
overall_result = "# [전체 검색 결과]\n\n"
|
231 |
|
@@ -243,8 +281,8 @@ def search_all_companies():
|
|
243 |
|
244 |
def load_all_companies():
|
245 |
"""
|
246 |
-
KOREAN_COMPANIES 리스트 내 모든
|
247 |
-
|
248 |
"""
|
249 |
overall_result = "# [전체 출력 결과]\n\n"
|
250 |
|
@@ -256,22 +294,22 @@ def load_all_companies():
|
|
256 |
|
257 |
def full_summary_report():
|
258 |
"""
|
259 |
-
(1) 모든 기업 검색 -> (2) DB에서
|
260 |
순서대로 실행하여, 전체 리포트를 합쳐 반환
|
261 |
"""
|
262 |
-
# 1) 전체 검색(병렬)
|
263 |
search_result_text = search_all_companies()
|
264 |
|
265 |
-
# 2) 전체 출력
|
266 |
load_result_text = load_all_companies()
|
267 |
|
268 |
-
# 3) 전체 통계(감성 분석)
|
269 |
stats_text = show_stats()
|
270 |
|
271 |
combined_report = (
|
272 |
"# 전체 분석 보고 요약\n\n"
|
273 |
"아래 순서로 실행되었습니다:\n"
|
274 |
-
"1. 모든 종목 검색(병렬)
|
275 |
f"{search_result_text}\n\n"
|
276 |
f"{load_result_text}\n\n"
|
277 |
"## [전체 감성 분석 통계]\n\n"
|
@@ -280,46 +318,54 @@ def full_summary_report():
|
|
280 |
return combined_report
|
281 |
|
282 |
|
283 |
-
|
|
|
|
|
284 |
def search_custom(query, country):
|
285 |
"""
|
286 |
-
사용자가 입력한 (query, country)
|
287 |
-
|
288 |
-
|
289 |
-
- DB 로드 후 감성 분석
|
290 |
-
- 최종 결과를 Markdown 형태로 반환
|
291 |
"""
|
292 |
-
# 1) 검색
|
293 |
error_message, articles = serphouse_search(query, country)
|
294 |
if error_message:
|
295 |
return f"오류 발생: {error_message}"
|
296 |
if not articles:
|
297 |
return "검색 결과가 없습니다."
|
298 |
|
299 |
-
#
|
300 |
-
|
301 |
|
302 |
-
#
|
303 |
-
|
304 |
-
|
305 |
-
|
|
|
|
|
306 |
|
307 |
-
#
|
308 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
309 |
|
310 |
-
|
311 |
-
|
312 |
-
output += f"**키워드**: {query}\n\n"
|
313 |
-
output += f"**국가**: {country}\n\n"
|
314 |
-
output += f"**저장 시간**: {timestamp}\n\n"
|
315 |
-
output += display_results(results)
|
316 |
|
317 |
-
|
318 |
-
output += f"{sentiment_analysis}\n"
|
319 |
-
return output
|
320 |
|
321 |
|
322 |
-
|
|
|
|
|
323 |
ACCESS_TOKEN = os.getenv("HF_TOKEN")
|
324 |
if not ACCESS_TOKEN:
|
325 |
raise ValueError("HF_TOKEN environment variable is not set")
|
@@ -332,7 +378,9 @@ client = OpenAI(
|
|
332 |
API_KEY = os.getenv("SERPHOUSE_API_KEY")
|
333 |
|
334 |
|
335 |
-
|
|
|
|
|
336 |
COUNTRY_LANGUAGES = {
|
337 |
"United States": "en",
|
338 |
"KOREA": "ko",
|
@@ -840,7 +888,7 @@ with gr.Blocks(theme="Yntec/HaleyCH_Theme_Orange", css=css, title="NewsAI 서비
|
|
840 |
gr.Markdown("## EarnBot: 글로벌 빅테크 기업 및 투자 전망 AI 자동 분석")
|
841 |
gr.Markdown(" * '전체 분석 보고 요약' 클릭 시 전체 자동 보고 생성.\n * 아래 개별 종목의 '검색(DB 자동 저장)'과 '출력(DB 자동 호출)'도 가능.\n * 추가로, 원하는 임의 키워드 및 국가로 검색/분석할 수도 있습니다.")
|
842 |
|
843 |
-
# (
|
844 |
with gr.Group():
|
845 |
gr.Markdown("### 사용자 임의 검색")
|
846 |
with gr.Row():
|
@@ -876,7 +924,7 @@ with gr.Blocks(theme="Yntec/HaleyCH_Theme_Orange", css=css, title="NewsAI 서비
|
|
876 |
outputs=full_report_display
|
877 |
)
|
878 |
|
879 |
-
#
|
880 |
with gr.Column():
|
881 |
for i in range(0, len(KOREAN_COMPANIES), 2):
|
882 |
with gr.Row():
|
|
|
141 |
output += f"요약: {article['snippet']}\n\n"
|
142 |
return output
|
143 |
|
144 |
+
|
145 |
+
########################################
|
146 |
+
# 1) 검색 시 => 기사 + 분석 동시 출력, DB 저장
|
147 |
+
########################################
|
148 |
def search_company(company):
|
149 |
"""
|
150 |
+
단일 기업(또는 키워드)에 대해 미국 뉴스 검색 후,
|
151 |
+
1) 기사 목록 + 2) 감성 분석 보고를 함께 출력
|
152 |
+
=> { "articles": [...], "analysis": ... } 형태로 DB에 저장
|
153 |
"""
|
154 |
error_message, articles = serphouse_search(company, "United States")
|
155 |
if not error_message and articles:
|
156 |
+
# 감성 분석
|
157 |
+
analysis = analyze_sentiment_batch(articles, client)
|
158 |
+
|
159 |
+
# DB 저장용 데이터 구성
|
160 |
+
store_dict = {
|
161 |
+
"articles": articles,
|
162 |
+
"analysis": analysis
|
163 |
+
}
|
164 |
+
save_to_db(company, "United States", store_dict)
|
165 |
+
|
166 |
+
# 화면 출력용
|
167 |
+
output = display_results(articles)
|
168 |
+
output += f"\n\n### 분석 보고\n{analysis}\n"
|
169 |
+
return output
|
170 |
return f"{company}에 대한 검색 결과가 없습니다."
|
171 |
|
172 |
+
########################################
|
173 |
+
# 2) 출력 시 => DB에 저장된 기사 + 분석 함께 출력
|
174 |
+
########################################
|
175 |
def load_company(company):
|
176 |
"""
|
177 |
+
DB에서 단일 기업(또는 키워드)의 미국 뉴스 검색 결과를 불러와
|
178 |
+
기사 목록 + 분석 결과를 함께 출력
|
179 |
"""
|
180 |
+
data, timestamp = load_from_db(company, "United States")
|
181 |
+
if data:
|
182 |
+
# data는 { "articles": [...], "analysis": "..."} 형태
|
183 |
+
articles = data.get("articles", [])
|
184 |
+
analysis = data.get("analysis", "")
|
185 |
+
|
186 |
+
output = f"### {company} 검색 결과\n저장 시간: {timestamp}\n\n"
|
187 |
+
output += display_results(articles)
|
188 |
+
output += f"\n\n### 분석 보고\n{analysis}\n"
|
189 |
+
return output
|
190 |
return f"{company}에 대한 저장된 결과가 없습니다."
|
191 |
|
192 |
+
|
193 |
+
########################################
|
194 |
+
# 3) 기존 show_stats()에서 리포트 제목 변경
|
195 |
+
########################################
|
196 |
def show_stats():
|
197 |
"""
|
198 |
KOREAN_COMPANIES 목록 내 모든 기업에 대해:
|
199 |
- 가장 최근 DB 저장 일자
|
200 |
- 기사 수
|
201 |
- 감성 분석 결과
|
202 |
+
를 병렬처리로 조회하여 보고서 형태로 반환
|
203 |
+
|
204 |
+
(문구 변경) "한국 기업 뉴스 분석 리포트" -> "EarnBOT 분석 리포트"
|
205 |
"""
|
206 |
conn = sqlite3.connect("search_results.db")
|
207 |
c = conn.cursor()
|
208 |
|
209 |
+
output = "## EarnBOT 분석 리포트\n\n" # 여기서 문구 변경
|
210 |
|
211 |
# 모든 기업에 대해 DB에서 읽어올 (company, timestamp, articles) 목록 수집
|
212 |
data_list = []
|
|
|
222 |
row = c.fetchone()
|
223 |
if row:
|
224 |
results_json, timestamp = row
|
225 |
+
data_list.append((company, timestamp, results_json))
|
|
|
|
|
226 |
|
227 |
conn.close()
|
228 |
|
229 |
+
# 감성 분석 병렬 처리 함수
|
230 |
def analyze_data(item):
|
231 |
+
comp, tstamp, results_json = item
|
232 |
+
data = json.loads(results_json)
|
233 |
+
articles = data.get("articles", [])
|
234 |
+
analysis = data.get("analysis", "")
|
235 |
+
|
236 |
+
count_articles = len(articles)
|
237 |
+
# 여기서는 이미 DB에 "analysis"가 들어 있으므로,
|
238 |
+
# 굳이 재분석할 필요가 없으면 그대로 사용
|
239 |
+
# (필요 시 재분석 가능)
|
240 |
+
|
241 |
+
return (comp, tstamp, count_articles, analysis)
|
242 |
|
|
|
243 |
results_list = []
|
244 |
with ThreadPoolExecutor(max_workers=5) as executor:
|
245 |
futures = [executor.submit(analyze_data, dl) for dl in data_list]
|
246 |
for future in as_completed(futures):
|
247 |
results_list.append(future.result())
|
248 |
|
249 |
+
# 결과 출력
|
250 |
+
for comp, tstamp, count, analysis in results_list:
|
251 |
+
seoul_time = convert_to_seoul_time(tstamp)
|
252 |
output += f"### {comp}\n"
|
253 |
+
output += f"- 마지막 업데이트: {seoul_time}\n"
|
254 |
output += f"- 저장된 기사 수: {count}건\n\n"
|
255 |
+
if analysis:
|
256 |
output += "#### 뉴스 감성 분석\n"
|
257 |
+
output += f"{analysis}\n\n"
|
258 |
output += "---\n\n"
|
259 |
|
260 |
return output
|
261 |
|
262 |
|
|
|
263 |
def search_all_companies():
|
264 |
"""
|
265 |
+
KOREAN_COMPANIES 리스트 내 모든 기업 검색 (멀티스레딩) =>
|
266 |
+
=> 분석 + DB 저장 => 결과 Markdown 반환
|
267 |
"""
|
268 |
overall_result = "# [전체 검색 결과]\n\n"
|
269 |
|
|
|
281 |
|
282 |
def load_all_companies():
|
283 |
"""
|
284 |
+
KOREAN_COMPANIES 리스트 내 모든 기업 DB 불러오기 =>
|
285 |
+
기사 목록 + 분석 보고 => 결과 Markdown
|
286 |
"""
|
287 |
overall_result = "# [전체 출력 결과]\n\n"
|
288 |
|
|
|
294 |
|
295 |
def full_summary_report():
|
296 |
"""
|
297 |
+
(1) 모든 기업 검색(병렬) -> (2) DB에서 불러오기 -> (3) 감성 분석 통계
|
298 |
순서대로 실행하여, 전체 리포트를 합쳐 반환
|
299 |
"""
|
300 |
+
# 1) 전체 검색(병렬) => 기사 + 분석 DB 저장
|
301 |
search_result_text = search_all_companies()
|
302 |
|
303 |
+
# 2) 전체 출력 => DB에 저장된 기사 + 분석 결과
|
304 |
load_result_text = load_all_companies()
|
305 |
|
306 |
+
# 3) 전체 통계(감성 분석) - 리포트 제목 변경됨(EarnBOT 분석 리포트)
|
307 |
stats_text = show_stats()
|
308 |
|
309 |
combined_report = (
|
310 |
"# 전체 분석 보고 요약\n\n"
|
311 |
"아래 순서로 실행되었습니다:\n"
|
312 |
+
"1. 모든 종목 검색(병렬) + 분석 => 2. 모든 종목 DB 결과 출력 => 3. 전체 감성 분석 통계\n\n"
|
313 |
f"{search_result_text}\n\n"
|
314 |
f"{load_result_text}\n\n"
|
315 |
"## [전체 감성 분석 통계]\n\n"
|
|
|
318 |
return combined_report
|
319 |
|
320 |
|
321 |
+
########################################
|
322 |
+
# 사용자 임의 검색 (추가 기능)
|
323 |
+
########################################
|
324 |
def search_custom(query, country):
|
325 |
"""
|
326 |
+
사용자가 입력한 (query, country)에 대해
|
327 |
+
1) 검색 + 분석 => DB 저장
|
328 |
+
2) DB 로드 => 결과(기사 목록 + 분석) 출력
|
|
|
|
|
329 |
"""
|
|
|
330 |
error_message, articles = serphouse_search(query, country)
|
331 |
if error_message:
|
332 |
return f"오류 발생: {error_message}"
|
333 |
if not articles:
|
334 |
return "검색 결과가 없습니다."
|
335 |
|
336 |
+
# 1) 분석
|
337 |
+
analysis = analyze_sentiment_batch(articles, client)
|
338 |
|
339 |
+
# 2) DB 저장
|
340 |
+
save_data = {
|
341 |
+
"articles": articles,
|
342 |
+
"analysis": analysis
|
343 |
+
}
|
344 |
+
save_to_db(query, country, save_data)
|
345 |
|
346 |
+
# 3) DB 재로드
|
347 |
+
loaded_data, timestamp = load_from_db(query, country)
|
348 |
+
if not loaded_data:
|
349 |
+
return "DB에서 로드 실패"
|
350 |
+
|
351 |
+
# 4) 결과 표시
|
352 |
+
out = f"## [사용자 임의 검색 결과]\n\n"
|
353 |
+
out += f"**키워드**: {query}\n\n"
|
354 |
+
out += f"**국가**: {country}\n\n"
|
355 |
+
out += f"**저장 시간**: {timestamp}\n\n"
|
356 |
+
|
357 |
+
arts = loaded_data.get("articles", [])
|
358 |
+
analy = loaded_data.get("analysis", "")
|
359 |
|
360 |
+
out += display_results(arts)
|
361 |
+
out += f"### 뉴스 감성 분석\n{analy}\n"
|
|
|
|
|
|
|
|
|
362 |
|
363 |
+
return out
|
|
|
|
|
364 |
|
365 |
|
366 |
+
########################################
|
367 |
+
# API 인증
|
368 |
+
########################################
|
369 |
ACCESS_TOKEN = os.getenv("HF_TOKEN")
|
370 |
if not ACCESS_TOKEN:
|
371 |
raise ValueError("HF_TOKEN environment variable is not set")
|
|
|
378 |
API_KEY = os.getenv("SERPHOUSE_API_KEY")
|
379 |
|
380 |
|
381 |
+
########################################
|
382 |
+
# 국가별 설정
|
383 |
+
########################################
|
384 |
COUNTRY_LANGUAGES = {
|
385 |
"United States": "en",
|
386 |
"KOREA": "ko",
|
|
|
888 |
gr.Markdown("## EarnBot: 글로벌 빅테크 기업 및 투자 전망 AI 자동 분석")
|
889 |
gr.Markdown(" * '전체 분석 보고 요약' 클릭 시 전체 자동 보고 생성.\n * 아래 개별 종목의 '검색(DB 자동 저장)'과 '출력(DB 자동 호출)'도 가능.\n * 추가로, 원하는 임의 키워드 및 국가로 검색/분석할 수도 있습니다.")
|
890 |
|
891 |
+
# (사용자 임의 검색 섹션)
|
892 |
with gr.Group():
|
893 |
gr.Markdown("### 사용자 임의 검색")
|
894 |
with gr.Row():
|
|
|
924 |
outputs=full_report_display
|
925 |
)
|
926 |
|
927 |
+
# 지정된 리스트 (KOREAN_COMPANIES) 개별 기업 검색/출력
|
928 |
with gr.Column():
|
929 |
for i in range(0, len(KOREAN_COMPANIES), 2):
|
930 |
with gr.Row():
|