Spaces:
Running
Running
Update main.py
Browse files
main.py
CHANGED
|
@@ -253,6 +253,17 @@ def groq_use(text_content: Any) -> str:
|
|
| 253 |
logger.error(f"🚨 Groq 호출 실패: {repr(e)}")
|
| 254 |
return "추출 실패"
|
| 255 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 256 |
|
| 257 |
# ---------------------------------------
|
| 258 |
# 1) 요약 단계
|
|
@@ -538,35 +549,27 @@ async def produce_progress(analysis_id: str, user_id: str | None, percent: int,
|
|
| 538 |
|
| 539 |
def get_stock_info(company_name: str) -> Dict[str, str] | None:
|
| 540 |
try:
|
| 541 |
-
|
| 542 |
-
if not
|
| 543 |
-
|
| 544 |
-
|
| 545 |
-
|
| 546 |
-
|
| 547 |
-
|
| 548 |
-
|
| 549 |
-
|
| 550 |
-
|
| 551 |
-
|
| 552 |
-
|
| 553 |
-
|
| 554 |
-
|
| 555 |
-
|
| 556 |
-
|
| 557 |
-
|
| 558 |
-
if 'Name' in us_listings.columns and 'Symbol' in us_listings.columns:
|
| 559 |
-
us_match = us_listings[
|
| 560 |
-
us_listings['Name'].str.contains(name, case=False, na=False) |
|
| 561 |
-
us_listings['Symbol'].str.fullmatch(name, case=False)
|
| 562 |
-
]
|
| 563 |
-
if not us_match.empty:
|
| 564 |
-
s = us_match.iloc[0]
|
| 565 |
-
return {"market": "US", "symbol": str(s['Symbol']), "name": s['Name']}
|
| 566 |
|
| 567 |
except Exception as e:
|
| 568 |
-
logger.error(f"주식 종목 검색 중 오류 발생: {
|
| 569 |
-
|
| 570 |
return None
|
| 571 |
|
| 572 |
|
|
@@ -640,12 +643,13 @@ async def consume_loop():
|
|
| 640 |
# ✅ threadpool에서 호출될 progress 콜백
|
| 641 |
def progress_cb(percent: int, stage: str, message: str):
|
| 642 |
# threadpool(다른 스레드) -> 현재 이벤트루프에서 코루틴 실행
|
| 643 |
-
|
| 644 |
-
asyncio.run_coroutine_threadsafe(
|
| 645 |
produce_progress(analysis_id, user_id, percent, stage, message),
|
| 646 |
loop
|
| 647 |
-
|
| 648 |
-
|
|
|
|
|
|
|
| 649 |
except Exception as e:
|
| 650 |
logger.warning(f"[KAFKA] progress send failed: {e}")
|
| 651 |
|
|
@@ -665,9 +669,7 @@ async def consume_loop():
|
|
| 665 |
"userId": user_id,
|
| 666 |
"result": result
|
| 667 |
}, ensure_ascii=False).encode("utf-8")
|
| 668 |
-
|
| 669 |
-
logger.info("DONE topic=%s bytes=%d", KAFKA_DONE_TOPIC, len(done_payload))
|
| 670 |
-
|
| 671 |
await producer.send_and_wait(
|
| 672 |
KAFKA_DONE_TOPIC,
|
| 673 |
key=analysis_id.encode("utf-8"),
|
|
@@ -678,22 +680,6 @@ async def consume_loop():
|
|
| 678 |
except Exception as e:
|
| 679 |
logger.error(f"[KAFKA] analysis failed analysisId={analysis_id}: {repr(e)}", exc_info=True)
|
| 680 |
await produce_progress(analysis_id, user_id, 100, "ERROR", f"오류: {type(e).__name__}")
|
| 681 |
-
if producer:
|
| 682 |
-
err_payload = {
|
| 683 |
-
"analysisId": analysis_id,
|
| 684 |
-
"userId": user_id,
|
| 685 |
-
"result": {
|
| 686 |
-
"error": True,
|
| 687 |
-
"message": f"분석 실패: {type(e).__name__}",
|
| 688 |
-
"url": url,
|
| 689 |
-
}
|
| 690 |
-
}
|
| 691 |
-
await producer.send_and_wait(
|
| 692 |
-
KAFKA_DONE_TOPIC,
|
| 693 |
-
key=analysis_id.encode("utf-8"),
|
| 694 |
-
value=json.dumps(err_payload, ensure_ascii=False).encode("utf-8")
|
| 695 |
-
)
|
| 696 |
-
logger.info(f"[KAFKA] produced error-done analysisId={analysis_id}")
|
| 697 |
|
| 698 |
finally:
|
| 699 |
logger.info("[KAFKA] stopped")
|
|
|
|
| 253 |
logger.error(f"🚨 Groq 호출 실패: {repr(e)}")
|
| 254 |
return "추출 실패"
|
| 255 |
|
| 256 |
+
def get_stock_info(company_info: str) -> Dict[str, str] | None:
|
| 257 |
+
try:
|
| 258 |
+
if krx_listings is not None:
|
| 259 |
+
# 포함 관계 확인
|
| 260 |
+
for _, row in krx_listings.iterrows():
|
| 261 |
+
if row['Name'] in company_info:
|
| 262 |
+
return {"market": "KRX", "symbol": row['Code'], "name": row['Name']}
|
| 263 |
+
except Exception as e:
|
| 264 |
+
logger.error(f"주식 검색 에러: {e}")
|
| 265 |
+
return None
|
| 266 |
+
|
| 267 |
|
| 268 |
# ---------------------------------------
|
| 269 |
# 1) 요약 단계
|
|
|
|
| 549 |
|
| 550 |
def get_stock_info(company_name: str) -> Dict[str, str] | None:
|
| 551 |
try:
|
| 552 |
+
# 1. 한국 주식(KRX) 검색
|
| 553 |
+
if krx_listings is not None:
|
| 554 |
+
kr_match = krx_listings[krx_listings['Name'].str.contains(company_name, case=False, na=False)]
|
| 555 |
+
if not kr_match.empty:
|
| 556 |
+
s = kr_match.iloc[0]
|
| 557 |
+
return {"market": "KRX", "symbol": s['Code'], "name": s['Name']}
|
| 558 |
+
|
| 559 |
+
# 2. 미국 주식 검색 (번역기 없이 이름으로 직접 검색)
|
| 560 |
+
if us_listings is not None:
|
| 561 |
+
# 영어 이름이 포함되어 있을 수 있으므로 대소문자 무시하고 검색
|
| 562 |
+
us_match = us_listings[
|
| 563 |
+
us_listings['Name'].str.contains(company_name, case=False, na=False) |
|
| 564 |
+
us_listings['Symbol'].str.fullmatch(company_name, case=False)
|
| 565 |
+
]
|
| 566 |
+
if not us_match.empty:
|
| 567 |
+
s = us_match.iloc[0]
|
| 568 |
+
return {"market": "US", "symbol": s['Symbol'], "name": s['Name']}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 569 |
|
| 570 |
except Exception as e:
|
| 571 |
+
logger.error(f"주식 종목 검색 중 오류 발생: {e}")
|
| 572 |
+
|
| 573 |
return None
|
| 574 |
|
| 575 |
|
|
|
|
| 643 |
# ✅ threadpool에서 호출될 progress 콜백
|
| 644 |
def progress_cb(percent: int, stage: str, message: str):
|
| 645 |
# threadpool(다른 스레드) -> 현재 이벤트루프에서 코루틴 실행
|
| 646 |
+
fut = asyncio.run_coroutine_threadsafe(
|
|
|
|
| 647 |
produce_progress(analysis_id, user_id, percent, stage, message),
|
| 648 |
loop
|
| 649 |
+
)
|
| 650 |
+
# (선택) progress 전송 실패 로그 보고 싶으면:
|
| 651 |
+
try:
|
| 652 |
+
fut.result(timeout=2)
|
| 653 |
except Exception as e:
|
| 654 |
logger.warning(f"[KAFKA] progress send failed: {e}")
|
| 655 |
|
|
|
|
| 669 |
"userId": user_id,
|
| 670 |
"result": result
|
| 671 |
}, ensure_ascii=False).encode("utf-8")
|
| 672 |
+
|
|
|
|
|
|
|
| 673 |
await producer.send_and_wait(
|
| 674 |
KAFKA_DONE_TOPIC,
|
| 675 |
key=analysis_id.encode("utf-8"),
|
|
|
|
| 680 |
except Exception as e:
|
| 681 |
logger.error(f"[KAFKA] analysis failed analysisId={analysis_id}: {repr(e)}", exc_info=True)
|
| 682 |
await produce_progress(analysis_id, user_id, 100, "ERROR", f"오류: {type(e).__name__}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 683 |
|
| 684 |
finally:
|
| 685 |
logger.info("[KAFKA] stopped")
|