Spaces:
Sleeping
Sleeping
| """yfinance fallback ์บ์ ๋น๋. | |
| ๋ก์ปฌ(yfinance ๊ฐ ์ ์ ๋์ํ๋ ํ๊ฒฝ)์์ ์คํํด ๊ฐ ๋ผ์ฐํฐ ํจ์๋ฅผ ์ง์ ํธ์ถํ๊ณ , | |
| ๊ทธ ๊ฒฐ๊ณผ JSON ์ backend/cache/ ์ ์ ์ฅํ๋ค. Hugging Face Spaces ์ฒ๋ผ ๋ฐ์ดํฐ์ผํฐ | |
| IP ์์ yfinance ๊ฐ 401 ๋ก ์ฐจ๋จ๋๋ ํ๊ฒฝ์์ ์ด ์บ์๊ฐ fallback ์ผ๋ก ์ ๊ณต๋๋ค. | |
| ์คํ: | |
| cd D:/OStock/backend | |
| .venv/Scripts/python.exe scripts/build_cache.py | |
| ์ฃผ์: news/prediction ๋ผ์ฐํฐ๋ transformers->torch ๋ฅผ ๋์ด์ import ์์ ์ด์๊ฐ | |
| ์์ผ๋ฏ๋ก, ์ฌ๊ธฐ์๋ yfinance ๊ธฐ๋ฐ ๋ผ์ฐํฐ(market/quotes/financial/technical)๋ง import ํ๋ค. | |
| """ | |
| import os | |
| import sys | |
| import json | |
| import datetime | |
| # scripts/ ์์ ์คํํด๋ backend/ ๋ชจ๋์ import ํ ์ ์๋๋ก backend ๊ฒฝ๋ก ์ถ๊ฐ | |
| BACKEND_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) | |
| sys.path.insert(0, BACKEND_DIR) | |
| from config import SECTOR_TICKERS # noqa: E402 | |
| from routers import market, quotes, financial, technical # noqa: E402 | |
| CACHE_DIR = os.path.join(BACKEND_DIR, "cache") | |
| def _save(relpath, data): | |
| path = os.path.join(CACHE_DIR, relpath) | |
| os.makedirs(os.path.dirname(path), exist_ok=True) | |
| with open(path, "w", encoding="utf-8") as f: | |
| json.dump(data, f, ensure_ascii=False, indent=2) | |
| def _is_error(result): | |
| """์๋ํฌ์ธํธ ๊ฒฐ๊ณผ๊ฐ ์๋ฌ/๋น๊ฐ์ด๋ฉด True (์ ์ฅ ์คํต + ์คํจ ์นด์ดํธ์ฉ).""" | |
| if result is None: | |
| return True | |
| if isinstance(result, dict): | |
| if "error" in result: | |
| return True | |
| vals = list(result.values()) | |
| # sectors/bond ์ฒ๋ผ ๋ชจ๋ ํ์ ํญ๋ชฉ์ด ์๋ฌ dict ์ธ ๊ฒฝ์ฐ | |
| if vals and all(isinstance(v, dict) and "error" in v for v in vals): | |
| return True | |
| return False | |
| if isinstance(result, list): | |
| return len(result) == 0 | |
| return False | |
| def main(): | |
| os.makedirs(CACHE_DIR, exist_ok=True) | |
| stats = {"ok": 0, "fail": 0, "failed": []} | |
| def run(label, relpath, fn): | |
| try: | |
| result = fn() | |
| except Exception as e: # noqa: BLE001 | |
| result = {"error": str(e)} | |
| if _is_error(result): | |
| stats["fail"] += 1 | |
| stats["failed"].append(label) | |
| print(f" [FAIL] {label}") | |
| else: | |
| _save(relpath, result) | |
| stats["ok"] += 1 | |
| print(f" [ OK ] {label}") | |
| print("== ๋ฌดํ๋ผ๋ฏธํฐ ์๋ํฌ์ธํธ ==") | |
| run("indices", "indices.json", market.get_market_indices) | |
| run("sectors", "sectors.json", market.get_sector_data) | |
| run("get_bond_data", "get_bond_data.json", market.get_bond_data) | |
| print(f"== ์ข ๋ชฉ๋ณ ์๋ํฌ์ธํธ ({len(SECTOR_TICKERS)} ์ข ๋ชฉ x 4) ==") | |
| for _name, tk in SECTOR_TICKERS.items(): | |
| run(f"stocks/{tk}", f"stocks/{tk}.json", | |
| lambda tk=tk: quotes.get_stock_data(ticker=tk)) | |
| # period/interval ์ ๋ช ์ ์ ๋ฌํด์ผ ํ๋ค. ํจ์๋ฅผ ์ง์ ํธ์ถํ๋ฉด FastAPI ๊ฐ | |
| # ์ฃผ์ ํ์ง ์์ ๊ธฐ๋ณธ๊ฐ์ด Query(...) ๊ฐ์ฒด๋ก ๋จ์ .lower() ์์ ๊นจ์ง๋ค. | |
| run(f"stock_chart/{tk}", f"stock_chart/{tk}.json", | |
| lambda tk=tk: quotes.get_stock_chart(ticker=tk, period="1mo", interval="1d")) | |
| run(f"financial_info/{tk}", f"financial_info/{tk}.json", | |
| lambda tk=tk: financial.get_financial_info(ticker=tk)) | |
| run(f"technical_info/{tk}", f"technical_info/{tk}.json", | |
| lambda tk=tk: technical.get_technical_info(ticker=tk)) | |
| meta = { | |
| "generated_at": datetime.datetime.now().astimezone().isoformat(timespec="seconds"), | |
| "endpoints": [ | |
| "indices", "sectors", "get_bond_data", | |
| "stocks", "stock_chart", "financial_info", "technical_info", | |
| ], | |
| "ticker_count": len(SECTOR_TICKERS), | |
| "success": stats["ok"], | |
| "failed": stats["fail"], | |
| } | |
| with open(os.path.join(CACHE_DIR, ".meta.json"), "w", encoding="utf-8") as f: | |
| json.dump(meta, f, ensure_ascii=False, indent=2) | |
| print(f"\n์๋ฃ: ์ฑ๊ณต {stats['ok']} / ์คํจ {stats['fail']}") | |
| if stats["failed"]: | |
| print("์คํจ ํญ๋ชฉ:", ", ".join(stats["failed"])) | |
| print("์์ฑ ์๊ฐ:", meta["generated_at"]) | |
| if __name__ == "__main__": | |
| main() | |