vnai 2.0.7__py3-none-any.whl → 2.0.8__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
vnai/scope/promo.py CHANGED
@@ -1,286 +1,96 @@
1
- """
2
- Promo module for vnai: fetches and presents promotional content periodically or on demand,
3
- using logging instead of printing to avoid polluting stdout for AI tools.
4
- """
5
- import logging
6
- import requests
1
+ _H='init'
2
+ _G='simple'
3
+ _F='markdown'
4
+ _E='terminal'
5
+ _D='html'
6
+ _C=True
7
+ _B=False
8
+ _A=None
9
+ import logging,requests
7
10
  from datetime import datetime
8
- import random
9
- import threading
10
- import time
11
- import urllib.parse
12
-
13
- _vnii_check_attempted = False
14
-
15
- # Enum AdCategory (tương thích với vnii)
16
- class AdCategory:
17
- FREE = 0
18
- MANDATORY = 1
19
- ANNOUNCEMENT = 2
20
- REFERRAL = 3
21
- FEATURE = 4
22
- GUIDE = 5
23
- SURVEY = 6
24
- PROMOTION = 7
25
- SECURITY = 8
26
- MAINTENANCE = 9
27
- WARNING = 10
28
-
29
- # Thêm import kiểm tra license từ vnii
30
- try:
31
- from vnii import lc_init
32
- except ImportError:
33
- lc_init = None # Nếu không có vnii, luôn coi là free user
34
-
35
- # Module-level logger setup
36
- logger = logging.getLogger(__name__)
37
- if not logger.hasHandlers():
38
- # Add a simple stream handler that only outputs the message text
39
- handler = logging.StreamHandler()
40
- handler.setFormatter(logging.Formatter('%(message)s'))
41
- logger.addHandler(handler)
42
- logger.setLevel(logging.INFO)
43
-
11
+ import random,threading,time,urllib.parse
12
+ _vnii_check_attempted=_B
13
+ class AdCategory:FREE=0;MANDATORY=1;ANNOUNCEMENT=2;REFERRAL=3;FEATURE=4;GUIDE=5;SURVEY=6;PROMOTION=7;SECURITY=8;MAINTENANCE=9;WARNING=10
14
+ try:from vnii import lc_init
15
+ except ImportError:lc_init=_A
16
+ logger=logging.getLogger(__name__)
17
+ if not logger.hasHandlers():handler=logging.StreamHandler();handler.setFormatter(logging.Formatter('%(message)s'));logger.addHandler(handler);logger.setLevel(logging.INFO)
44
18
  class ContentManager:
45
- """
46
- Singleton manager to fetch remote or fallback promotional content and
47
- present it in different environments (Jupyter, terminal, other).
48
-
49
- Displays content automatically at randomized intervals via a background thread.
50
- """
51
- _instance = None
52
- _lock = threading.Lock()
53
-
54
- def __new__(cls):
55
- """
56
- Ensure only one instance of ContentManager is created (thread-safe).
57
- """
58
- with cls._lock:
59
- if cls._instance is None:
60
- cls._instance = super(ContentManager, cls).__new__(cls)
61
- cls._instance._initialize()
62
- return cls._instance
63
-
64
- def _initialize(self):
65
- """
66
- Internal initializer: sets up display timing, URLs, and starts the periodic display thread.
67
- """
68
- global _vnii_check_attempted
69
- if _vnii_check_attempted:
70
- # Đã kiểm tra/cài đặt vnii trước đó, không làm lại nữa
71
- return
72
- _vnii_check_attempted = True
73
- # Nếu máy đã từng cài vnii, luôn cài lại bản mới nhất; nếu chưa từng cài thì coi free user
74
- import sys
75
- import importlib
76
- try:
77
- import importlib.metadata
78
- try:
79
- old_version = importlib.metadata.version("vnii")
80
- # Nếu đã từng cài, luôn force cài bản mới nhất
81
- VNII_LATEST_VERSION = "0.0.9"
82
- VNII_URL = f"https://github.com/vnstock-hq/licensing/releases/download/vnii-{VNII_LATEST_VERSION}/vnii-{VNII_LATEST_VERSION}.tar.gz"
83
- logger.debug(f"Đã phát hiện vnii version {old_version}. Đang cập nhật lên bản mới nhất...")
84
- import subprocess
85
- subprocess.check_call([sys.executable, "-m", "pip", "install", f"vnii@{VNII_URL}"])
86
- importlib.invalidate_caches()
87
- if "vnii" in sys.modules:
88
- importlib.reload(sys.modules["vnii"])
89
- else:
90
- import vnii
91
- new_version = importlib.metadata.version("vnii")
92
- logger.debug(f"Đã cập nhật vnii lên version {new_version}")
93
- except importlib.metadata.PackageNotFoundError:
94
- # Nếu chưa từng cài, không cài, luôn coi là free user
95
- logger.debug("Không phát hiện vnii trên hệ thống. Luôn coi free user, không kiểm tra license.")
96
- self.is_paid_user = False
97
- return
98
- except Exception as e:
99
- logger.warning(f"Lỗi khi kiểm tra/cài đặt vnii: {e}")
100
- user_msg = (
101
- "Không thể tự động cài đặt/cập nhật vnii. "
102
- "Vui lòng liên hệ admin hoặc hỗ trợ kỹ thuật của Vnstock để được trợ giúp. "
103
- f"Chi tiết lỗi: {e}"
104
- )
105
- logger.error(user_msg)
106
- try:
107
- print(user_msg)
108
- except Exception:
109
- pass
110
- self.is_paid_user = False
111
- return
112
-
113
- # Kiểm tra trạng thái paid user (sponsor) cache lại
114
- self.is_paid_user = False
115
- logger.debug("[promo] Bắt đầu kiểm tra trạng thái paid user với vnii...")
116
- if lc_init is not None:
117
- try:
118
- license_info = lc_init(repo_name='vnstock')
119
- logger.debug(f"[promo] license_info trả về: {license_info}")
120
- status = license_info.get('status', '').lower()
121
- if 'recognized and verified' in status:
122
- self.is_paid_user = True
123
- logger.debug("[promo] Đã xác nhận paid user từ vnii. Sẽ không hiện quảng cáo.")
124
- else:
125
- logger.debug(f"[promo] Không xác nhận được paid user từ vnii. Status: {status}")
126
- except Exception as e:
127
- logger.warning(f"[promo] Không thể kiểm tra trạng thái sponsor: {e}. Sẽ coi là free user và hiện quảng cáo.")
128
- else:
129
- logger.debug("[promo] Không tìm thấy module vnii. Luôn coi là free user và hiện quảng cáo.")
130
-
131
- # Timestamp of last content display (epoch seconds)
132
- self.last_display = 0
133
- # Minimum interval between displays (24 hours)
134
- self.display_interval = 24 * 3600
135
-
136
- # Base endpoints for fetching remote content and linking
137
- self.content_base_url = "https://hq.vnstocks.com/static"
138
- self.target_url = "https://vnstocks.com/lp-khoa-hoc-python-chung-khoan"
139
- self.image_url = (
140
- "https://vnstocks.com/img/trang-chu-vnstock-python-api-phan-tich-giao-dich-chung-khoan.jpg"
141
- )
142
-
143
- # Launch the background thread to periodically present content
144
- logger.debug(f"[promo] is_paid_user = {self.is_paid_user}")
145
- self._start_periodic_display()
146
-
147
- def _start_periodic_display(self):
148
- """
149
- Launch a daemon thread that sleeps a random duration between 2–6 hours,
150
- then checks if the display interval has elapsed and calls present_content.
151
- """
152
- logger.debug("[promo] Khởi tạo thread hiển thị quảng cáo định kỳ...")
153
- def periodic_display():
154
- logger.debug("[promo] Thread quảng cáo bắt đầu chạy.")
155
- while True:
156
- # Nếu là paid user thì không bao giờ hiện ads
157
- if self.is_paid_user:
158
- logger.debug("[promo] Đang là paid user trong thread. Không hiện quảng cáo, dừng thread.")
159
- break
160
- # Randomize sleep to avoid synchronized requests across instances
161
- sleep_time = random.randint(2 * 3600, 6 * 3600)
162
- logger.debug(f"[promo] Thread quảng cáo sẽ ngủ {sleep_time//3600} giờ...")
163
- time.sleep(sleep_time)
164
-
165
- # Present content if enough time has passed since last_display
166
- current_time = time.time()
167
- logger.debug(f"[promo] Kiểm tra điều kiện hiện quảng cáo: time since last_display = {current_time - self.last_display}s")
168
- if current_time - self.last_display >= self.display_interval:
169
- logger.debug("[promo] Đã đủ thời gian, sẽ gọi present_content(context='periodic')")
170
- self.present_content(context="periodic")
171
- else:
172
- logger.debug("[promo] Chưa đủ thời gian, chưa hiện quảng cáo.")
173
-
174
- thread = threading.Thread(target=periodic_display, daemon=True)
175
- thread.start()
176
-
177
- def fetch_remote_content(self, context: str = "init", html: bool = True) -> str:
178
- if self.is_paid_user:
179
- logger.debug("Paid user detected. Skip fetching remote content (ads).")
180
- return ""
181
-
182
- """
183
- Fetch promotional content from remote service with context and format flag.
184
-
185
- Args:
186
- context: usage context (e.g., "init", "periodic", "loop").
187
- html: if True, request HTML; otherwise plain text.
188
-
189
- Returns:
190
- The content string on HTTP 200, or None on failure.
191
- """
192
- try:
193
- # Build query params and URL
194
- params = {"context": context, "html": "true" if html else "false"}
195
- url = f"{self.content_base_url}?{urllib.parse.urlencode(params)}"
196
-
197
- response = requests.get(url, timeout=3)
198
- if response.status_code == 200:
199
- return response.text
200
- # Log non-200 responses at debug level
201
- logger.debug(f"Non-200 response fetching content: {response.status_code}")
202
- return None
203
- except Exception as e:
204
- # Log exceptions without interrupting user code
205
- logger.debug(f"Failed to fetch remote content: {e}")
206
- return None
207
-
208
- def present_content(self, context: str = "init", ad_category: int = AdCategory.FREE) -> None:
209
- environment = None
210
- logger.debug(f"[promo] Gọi present_content(context={context}, ad_category={ad_category}). is_paid_user = {getattr(self, 'is_paid_user', None)}")
211
- """
212
- Display promotional content in the appropriate environment.
213
- ad_category: Loại quảng cáo (FREE, ANNOUNCEMENT, ...)
214
- """
215
- # Nếu là paid user và ad_category là FREE thì skip, còn lại vẫn hiện
216
- if getattr(self, 'is_paid_user', False) and ad_category == AdCategory.FREE:
217
- logger.debug("[promo] Đang là paid user và ad_category là FREE. Không hiện quảng cáo.")
218
- return
219
-
220
- # Chỉ hiện log này nếu debug mode
221
- if logger.level <= logging.DEBUG:
222
- logger.debug(f"[promo] Sẽ hiển thị quảng cáo với context={context}, ad_category={ad_category}")
223
- # Update last display timestamp
224
- self.last_display = time.time()
225
-
226
- # Auto-detect environment if not provided
227
- if environment is None:
228
- try:
229
- from vnai.scope.profile import inspector
230
- environment = inspector.examine().get("environment", "unknown")
231
- logger.debug(f"[promo] Đã detect environment: {environment}")
232
- except Exception as e:
233
- logger.debug(f"[promo] Không detect được environment: {e}")
234
- environment = "unknown"
235
-
236
- # Retrieve remote or HTML/text content based on environment
237
- remote_content = self.fetch_remote_content(
238
- context=context, html=(environment == "jupyter")
239
- )
240
- logger.debug(f"[promo] remote_content = {bool(remote_content)} (None -> False, có nội dung -> True)")
241
- # Generate fallback messages if remote fetch fails
242
- fallback = self._generate_fallback_content(context)
243
- logger.debug(f"[promo] fallback keys: {list(fallback.keys())}")
244
-
245
- if environment == "jupyter":
246
- logger.debug("[promo] Đang ở môi trường Jupyter, sẽ thử display HTML/Markdown.")
247
- try:
248
- from IPython.display import display, HTML, Markdown
249
-
250
- if remote_content:
251
- logger.debug("[promo] Hiển thị quảng cáo bằng HTML từ remote_content.")
252
- display(HTML(remote_content))
253
- else:
254
- logger.debug("[promo] Không có remote_content, thử display fallback Markdown/HTML.")
255
- try:
256
- display(Markdown(fallback["markdown"]))
257
- except Exception as e:
258
- logger.debug(f"[promo] Lỗi khi display Markdown: {e}, fallback HTML.")
259
- display(HTML(fallback["html"]))
260
- except Exception as e:
261
- logger.debug(f"[promo] Jupyter display failed: {e}")
262
-
263
- elif environment == "terminal":
264
- logger.debug("[promo] Đang ở môi trường terminal, sẽ log quảng cáo ra logger.")
265
- # Log terminal-friendly or raw content via logger
266
- if remote_content:
267
- logger.debug("[promo] Hiển thị quảng cáo bằng remote_content cho terminal.")
268
- logger.debug(remote_content)
269
- else:
270
- logger.debug("[promo] Không có remote_content, hiển thị fallback terminal.")
271
- logger.debug(fallback["terminal"])
272
-
273
- else:
274
- logger.debug(f"[promo] Môi trường khác ({environment}), hiển thị fallback simple.")
275
- # Generic simple message for other environments
276
- logger.debug(fallback["simple"])
277
-
278
- def _generate_fallback_content(self, context):
279
- fallback = {"html": "", "markdown": "", "terminal": "", "simple": ""}
280
-
281
- if context == "loop":
282
- fallback["html"] = (
283
- f"""
19
+ _instance=_A;_lock=threading.Lock()
20
+ def __new__(cls):
21
+ with cls._lock:
22
+ if cls._instance is _A:cls._instance=super(ContentManager,cls).__new__(cls);cls._instance._initialize()
23
+ return cls._instance
24
+ def _initialize(self):
25
+ A='vnii';global _vnii_check_attempted
26
+ if _vnii_check_attempted:return
27
+ _vnii_check_attempted=_C;import sys,importlib
28
+ try:
29
+ import importlib.metadata
30
+ try:
31
+ old_version=importlib.metadata.version(A);VNII_LATEST_VERSION='0.0.9';VNII_URL=f"https://github.com/vnstock-hq/licensing/releases/download/vnii-{VNII_LATEST_VERSION}/vnii-{VNII_LATEST_VERSION}.tar.gz";logger.debug(f"Đã phát hiện vnii version {old_version}. Đang cập nhật lên bản mới nhất...");import subprocess;subprocess.check_call([sys.executable,'-m','pip','install',f"vnii@{VNII_URL}"]);importlib.invalidate_caches()
32
+ if A in sys.modules:importlib.reload(sys.modules[A])
33
+ else:import vnii
34
+ new_version=importlib.metadata.version(A);logger.debug(f"Đã cập nhật vnii lên version {new_version}")
35
+ except importlib.metadata.PackageNotFoundError:logger.debug('Không phát hiện vnii trên hệ thống. Luôn coi là free user, không kiểm tra license.');self.is_paid_user=_B;return
36
+ except Exception as e:
37
+ logger.warning(f"Lỗi khi kiểm tra/cài đặt vnii: {e}");user_msg=f"Không thể tự động cài đặt/cập nhật vnii. Vui lòng liên hệ admin hoặc hỗ trợ kỹ thuật của Vnstock để được trợ giúp. Chi tiết lỗi: {e}";logger.error(user_msg)
38
+ try:print(user_msg)
39
+ except Exception:pass
40
+ self.is_paid_user=_B;return
41
+ self.is_paid_user=_B;logger.debug('[promo] Bắt đầu kiểm tra trạng thái paid user với vnii...')
42
+ if lc_init is not _A:
43
+ try:
44
+ license_info=lc_init(repo_name='vnstock');logger.debug(f"[promo] license_info trả về: {license_info}");status=license_info.get('status','').lower()
45
+ if'recognized and verified'in status:self.is_paid_user=_C;logger.debug('[promo] Đã xác nhận paid user từ vnii. Sẽ không hiện quảng cáo.')
46
+ else:logger.debug(f"[promo] Không xác nhận được paid user từ vnii. Status: {status}")
47
+ except Exception as e:logger.warning(f"[promo] Không thể kiểm tra trạng thái sponsor: {e}. Sẽ coi free user hiện quảng cáo.")
48
+ else:logger.debug('[promo] Không tìm thấy module vnii. Luôn coi là free user và hiện quảng cáo.')
49
+ self.last_display=0;self.display_interval=86400;self.content_base_url='https://hq.vnstocks.com/static';self.target_url='https://vnstocks.com/lp-khoa-hoc-python-chung-khoan';self.image_url='https://vnstocks.com/img/trang-chu-vnstock-python-api-phan-tich-giao-dich-chung-khoan.jpg';logger.debug(f"[promo] is_paid_user = {self.is_paid_user}");self._start_periodic_display()
50
+ def _start_periodic_display(self):
51
+ logger.debug('[promo] Khởi tạo thread hiển thị quảng cáo định kỳ...')
52
+ def periodic_display():
53
+ logger.debug('[promo] Thread quảng cáo bắt đầu chạy.')
54
+ while _C:
55
+ if self.is_paid_user:logger.debug('[promo] Đang là paid user trong thread. Không hiện quảng cáo, dừng thread.');break
56
+ sleep_time=random.randint(7200,21600);logger.debug(f"[promo] Thread quảng cáo sẽ ngủ {sleep_time//3600} giờ...");time.sleep(sleep_time);current_time=time.time();logger.debug(f"[promo] Kiểm tra điều kiện hiện quảng cáo: time since last_display = {current_time-self.last_display}s")
57
+ if current_time-self.last_display>=self.display_interval:logger.debug("[promo] Đã đủ thời gian, sẽ gọi present_content(context='periodic')");self.present_content(context='periodic')
58
+ else:logger.debug('[promo] Chưa đủ thời gian, chưa hiện quảng cáo.')
59
+ thread=threading.Thread(target=periodic_display,daemon=_C);thread.start()
60
+ def fetch_remote_content(self,context:str=_H,html:bool=_C)->str:
61
+ if self.is_paid_user:logger.debug('Paid user detected. Skip fetching remote content (ads).');return''
62
+ try:
63
+ params={'context':context,_D:'true'if html else'false'};url=f"{self.content_base_url}?{urllib.parse.urlencode(params)}";response=requests.get(url,timeout=3)
64
+ if response.status_code==200:return response.text
65
+ logger.debug(f"Non-200 response fetching content: {response.status_code}");return
66
+ except Exception as e:logger.debug(f"Failed to fetch remote content: {e}");return
67
+ def present_content(self,context:str=_H,ad_category:int=AdCategory.FREE)->_A:
68
+ C='jupyter';B='unknown';A='is_paid_user';environment=_A;logger.debug(f"[promo] Gọi present_content(context={context}, ad_category={ad_category}). is_paid_user = {getattr(self,A,_A)}")
69
+ if getattr(self,A,_B)and ad_category==AdCategory.FREE:logger.debug('[promo] Đang paid user ad_categoryFREE. Không hiện quảng cáo.');return
70
+ if logger.level<=logging.DEBUG:logger.debug(f"[promo] Sẽ hiển thị quảng cáo với context={context}, ad_category={ad_category}")
71
+ self.last_display=time.time()
72
+ if environment is _A:
73
+ try:from vnai.scope.profile import inspector;environment=inspector.examine().get('environment',B);logger.debug(f"[promo] Đã detect environment: {environment}")
74
+ except Exception as e:logger.debug(f"[promo] Không detect được environment: {e}");environment=B
75
+ remote_content=self.fetch_remote_content(context=context,html=environment==C);logger.debug(f"[promo] remote_content = {bool(remote_content)} (None -> False, có nội dung -> True)");fallback=self._generate_fallback_content(context);logger.debug(f"[promo] fallback keys: {list(fallback.keys())}")
76
+ if environment==C:
77
+ logger.debug('[promo] Đang môi trường Jupyter, sẽ thử display HTML/Markdown.')
78
+ try:
79
+ from IPython.display import display,HTML,Markdown
80
+ if remote_content:logger.debug('[promo] Hiển thị quảng cáo bằng HTML từ remote_content.');display(HTML(remote_content))
81
+ else:
82
+ logger.debug('[promo] Không có remote_content, thử display fallback Markdown/HTML.')
83
+ try:display(Markdown(fallback[_F]))
84
+ except Exception as e:logger.debug(f"[promo] Lỗi khi display Markdown: {e}, fallback HTML.");display(HTML(fallback[_D]))
85
+ except Exception as e:logger.debug(f"[promo] Jupyter display failed: {e}")
86
+ elif environment==_E:
87
+ logger.debug('[promo] Đang môi trường terminal, sẽ log quảng cáo ra logger.')
88
+ if remote_content:logger.debug('[promo] Hiển thị quảng cáo bằng remote_content cho terminal.');logger.debug(remote_content)
89
+ else:logger.debug('[promo] Không remote_content, hiển thị fallback terminal.');logger.debug(fallback[_E])
90
+ else:logger.debug(f"[promo] Môi trường khác ({environment}), hiển thị fallback simple.");logger.debug(fallback[_G])
91
+ def _generate_fallback_content(self,context):
92
+ fallback={_D:'',_F:'',_E:'',_G:''}
93
+ if context=='loop':fallback[_D]=f'''
284
94
  <div style="border: 1px solid #e74c3c; padding: 15px; border-radius: 5px; margin: 10px 0;">
285
95
  <h3 style="color: #e74c3c;">⚠️ Bạn đang sử dụng vòng lặp với quá nhiều requests</h3>
286
96
  <p>Để tránh bị giới hạn tốc độ và tối ưu hiệu suất:</p>
@@ -290,40 +100,8 @@ class ContentManager:
290
100
  <li>Tham gia gói tài trợ <a href="https://vnstocks.com/insiders-program" style="color: #3498db;">Vnstock Insider</a> để tăng 5X giới hạn API</li>
291
101
  </ul>
292
102
  </div>
293
- """
294
- )
295
- fallback["markdown"] = (
296
- """
297
- ## ⚠️ Bạn đang sử dụng vòng lặp với quá nhiều requests
298
-
299
- Để tránh bị giới hạn tốc độ và tối ưu hiệu suất:
300
- * Thêm thời gian chờ giữa các lần gọi API
301
- * Sử dụng xử lý theo batch thay vì lặp liên tục
302
- * Tham gia gói tài trợ [Vnstock Insider](https://vnstocks.com/insiders-program) để tăng 5X giới hạn API
303
- """
304
- )
305
- fallback["terminal"] = (
306
- """
307
- ╔═════════════════════════════════════════════════════════════════╗
308
- ║ ║
309
- ║ 🚫 ĐANG BỊ CHẶN BỞI GIỚI HẠN API? GIẢI PHÁP Ở ĐÂY! ║
310
- ║ ║
311
- ║ ✓ Tăng ngay 500% tốc độ gọi API - Không còn lỗi RateLimit ║
312
- ║ ✓ Tiết kiệm 85% thời gian chờ đợi giữa các request ║
313
- ║ ║
314
- ║ ➤ NÂNG CẤP NGAY VỚI GÓI TÀI TRỢ VNSTOCK: ║
315
- ║ https://vnstocks.com/insiders-program ║
316
- ║ ║
317
- ╚═════════════════════════════════════════════════════════════════╝
318
- """
319
- )
320
- fallback["simple"] = (
321
- "🚫 Đang bị giới hạn API? Tăng tốc độ gọi API lên 500% với gói "
322
- "Vnstock Insider: https://vnstocks.com/insiders-program"
323
- )
324
- else:
325
- fallback["html"] = (
326
- f"""
103
+ ''';fallback[_F]='\n## ⚠️ Bạn đang sử dụng vòng lặp với quá nhiều requests\n\nĐể tránh bị giới hạn tốc độ và tối ưu hiệu suất:\n* Thêm thời gian chờ giữa các lần gọi API\n* Sử dụng xử lý theo batch thay vì lặp liên tục\n* Tham gia gói tài trợ [Vnstock Insider](https://vnstocks.com/insiders-program) để tăng 5X giới hạn API\n ';fallback[_E]='\n╔═════════════════════════════════════════════════════════════════╗\n║ ║\n║ 🚫 ĐANG BỊ CHẶN BỞI GIỚI HẠN API? GIẢI PHÁP Ở ĐÂY! ║\n║ ║\n║ ✓ Tăng ngay 500% tốc độ gọi API - Không còn lỗi RateLimit ║\n║ ✓ Tiết kiệm 85% thời gian chờ đợi giữa các request ║\n║ ║\n║ ➤ NÂNG CẤP NGAY VỚI GÓI TÀI TRỢ VNSTOCK: ║\n║ https://vnstocks.com/insiders-program ║\n║ ║\n╚═════════════════════════════════════════════════════════════════╝\n ';fallback[_G]='🚫 Đang bị giới hạn API? Tăng tốc độ gọi API lên 500% với gói Vnstock Insider: https://vnstocks.com/insiders-program'
104
+ else:fallback[_D]=f'''
327
105
  <div style="border: 1px solid #3498db; padding: 15px; border-radius: 5px; margin: 10px 0;">
328
106
  <h3 style="color: #3498db;">👋 Chào mừng bạn đến với Vnstock!</h3>
329
107
  <p>Cảm ơn bạn đã sử dụng thư viện phân tích chứng khoán #1 tại Việt Nam cho Python</p>
@@ -333,54 +111,7 @@ class ContentManager:
333
111
  </ul>
334
112
  <p>Khám phá các tính năng mới nhất và tham gia cộng đồng để nhận hỗ trợ.</p>
335
113
  </div>
336
- """
337
- )
338
- fallback["markdown"] = (
339
- """
340
- ## 👋 Chào mừng bạn đến với Vnstock!
341
-
342
- Cảm ơn bạn đã sử dụng package phân tích chứng khoán #1 tại Việt Nam
343
-
344
- * Tài liệu: [Sổ tay hướng dẫn](https://vnstocks.com/docs)
345
- * Cộng đồng: [Nhóm Facebook](https://facebook.com/groups/vnstock.official)
346
-
347
- Khám phá các tính năng mới nhất và tham gia cộng đồng để nhận hỗ trợ.
348
- """
349
- )
350
- fallback["terminal"] = (
351
- """
352
- ╔════════════════════════════════════════════════════════════╗
353
- ║ ║
354
- ║ 👋 Chào mừng bạn đến với Vnstock! ║
355
- ║ ║
356
- ║ Cảm ơn bạn đã sử dụng package phân tích ║
357
- ║ chứng khoán #1 tại Việt Nam ║
358
- ║ ║
359
- ║ ✓ Tài liệu: https://vnstocks.com/docs ║
360
- ║ ✓ Cộng đồng: https://facebook.com/groups/vnstock.official ║
361
- ║ ║
362
- ║ Khám phá các tính năng mới nhất và tham gia ║
363
- ║ cộng đồng để nhận hỗ trợ. ║
364
- ║ ║
365
- ╚════════════════════════════════════════════════════════════╝
366
- """
367
- )
368
- fallback["simple"] = (
369
- "👋 Chào mừng bạn đến với Vnstock! "
370
- "Tài liệu: https://vnstocks.com/onboard | "
371
- "Cộng đồng: https://facebook.com/groups/vnstock.official"
372
- )
373
- return fallback
374
-
375
- # Singleton instance for module-level use
376
- manager = ContentManager()
377
-
378
- def present(context: str = "init", ad_category: int = AdCategory.FREE) -> None:
379
- """
380
- Shortcut to ContentManager.present_content for external callers.
381
-
382
- Args:
383
- context: propagate context string to ContentManager.
384
- ad_category: loại quảng cáo (FREE, ANNOUNCEMENT, ...)
385
- """
386
- manager.present_content(context=context, ad_category=ad_category)
114
+ ''';fallback[_F]='\n## 👋 Chào mừng bạn đến với Vnstock!\n\nCảm ơn bạn đã sử dụng package phân tích chứng khoán #1 tại Việt Nam\n\n* Tài liệu: [Sổ tay hướng dẫn](https://vnstocks.com/docs)\n* Cộng đồng: [Nhóm Facebook](https://facebook.com/groups/vnstock.official)\n\nKhám phá các tính năng mới nhất và tham gia cộng đồng để nhận hỗ trợ.\n ';fallback[_E]='\n╔════════════════════════════════════════════════════════════╗\n║ ║\n║ 👋 Chào mừng bạn đến với Vnstock! ║\n║ ║\n║ Cảm ơn bạn đã sử dụng package phân tích ║\n║ chứng khoán #1 tại Việt Nam ║\n║ ║\n║ ✓ Tài liệu: https://vnstocks.com/docs ║\n║ ✓ Cộng đồng: https://facebook.com/groups/vnstock.official ║\n║ ║\n║ Khám phá các tính năng mới nhất và tham gia ║\n║ cộng đồng để nhận hỗ trợ. ║\n║ ║\n╚════════════════════════════════════════════════════════════╝\n ';fallback[_G]='👋 Chào mừng bạn đến với Vnstock! Tài liệu: https://vnstocks.com/onboard | Cộng đồng: https://facebook.com/groups/vnstock.official'
115
+ return fallback
116
+ manager=ContentManager()
117
+ def present(context:str=_H,ad_category:int=AdCategory.FREE)->_A:manager.present_content(context=context,ad_category=ad_category)