Spaces:
Sleeping
Sleeping
bngoc commited on
Commit ·
b47a646
1
Parent(s): 32be339
bổ sung size footer
Browse files- app.py +194 -24
- app_backup.py +0 -1986
- app_fixed.py +0 -784
- app_tabs_final.py +0 -275
- app_with_tabs.py +0 -336
app.py
CHANGED
|
@@ -93,12 +93,22 @@ custom_css = """
|
|
| 93 |
margin: 20px 0;
|
| 94 |
box-shadow: 0 15px 35px rgba(12, 83, 135, 0.3), 0 5px 15px rgba(0, 0, 0, 0.12);
|
| 95 |
border: 1px solid rgba(255, 255, 255, 0.2);
|
|
|
|
| 96 |
}
|
| 97 |
|
| 98 |
.loading-container * {
|
| 99 |
color: white !important;
|
| 100 |
}
|
| 101 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 102 |
.loading-spinner {
|
| 103 |
border: 4px solid #f3f3f3;
|
| 104 |
border-top: 4px solid #1A5F91;
|
|
@@ -428,6 +438,48 @@ html {
|
|
| 428 |
transition: all 0.3s ease !important;
|
| 429 |
}
|
| 430 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 431 |
/* Cải thiện focus state cho biểu đồ */
|
| 432 |
.plot-container:focus-within {
|
| 433 |
outline: 2px solid rgba(26, 95, 145, 0.3);
|
|
@@ -1961,13 +2013,13 @@ def tao_ung_dung():
|
|
| 1961 |
inputs=[],
|
| 1962 |
outputs=[bieu_do_du_bao, hien_thi_tom_tat, hien_thi_bao_cao, loading_panel],
|
| 1963 |
show_progress=False,
|
| 1964 |
-
scroll_to_output=
|
| 1965 |
)
|
| 1966 |
|
| 1967 |
-
#
|
| 1968 |
-
|
| 1969 |
(...args) => {
|
| 1970 |
-
const el = document.getElementById('
|
| 1971 |
if (el) {
|
| 1972 |
el.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
| 1973 |
el.classList.add('highlight');
|
|
@@ -1977,9 +2029,9 @@ def tao_ung_dung():
|
|
| 1977 |
}
|
| 1978 |
"""
|
| 1979 |
try:
|
| 1980 |
-
evt0.then(fn=None, inputs=None, outputs=None, js=
|
| 1981 |
except TypeError:
|
| 1982 |
-
evt0.then(fn=None, inputs=None, outputs=None, _js=
|
| 1983 |
|
| 1984 |
# 2) Stream 4 bước loading trong 3–5 giây (chỉ update loading_panel)
|
| 1985 |
evt1 = evt0.then(
|
|
@@ -1990,13 +2042,30 @@ def tao_ung_dung():
|
|
| 1990 |
)
|
| 1991 |
|
| 1992 |
# 3) Tính toán thật, render kết quả + tắt loading
|
| 1993 |
-
evt1.then(
|
| 1994 |
fn=tinh_toan_ket_qua,
|
| 1995 |
inputs=[lua_chon_dropdown, chu_ky_dropdown, che_do_xem],
|
| 1996 |
outputs=[bieu_do_du_bao, hien_thi_tom_tat, hien_thi_bao_cao, loading_panel],
|
| 1997 |
show_progress=False,
|
| 1998 |
)
|
| 1999 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2000 |
# Streaming event cho chiến lược đề xuất
|
| 2001 |
nut_streaming.click(
|
| 2002 |
fn=xu_ly_streaming,
|
|
@@ -2051,23 +2120,74 @@ Hệ thống AI sẽ tạo chiến lược đề xuất với:
|
|
| 2051 |
# Footer thông tin hệ thống với branding FoxAI
|
| 2052 |
gr.HTML(f"""
|
| 2053 |
<div class='info-card' style="margin-top: 30px; text-align: center;">
|
| 2054 |
-
<div style="
|
| 2055 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2056 |
<h2 style="
|
| 2057 |
-
color:
|
| 2058 |
margin: 0;
|
| 2059 |
-
font-size: 2.
|
| 2060 |
-
font-weight:
|
| 2061 |
-
letter-spacing:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2062 |
">
|
| 2063 |
-
💡
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2064 |
</h2>
|
| 2065 |
</div>
|
| 2066 |
|
| 2067 |
-
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(
|
| 2068 |
-
<div style="
|
| 2069 |
-
|
| 2070 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2071 |
✨ AI Insights thông minh<br/>
|
| 2072 |
📊 Multi-view linh hoạt<br/>
|
| 2073 |
📈 Báo cáo chuyên nghiệp<br/>
|
|
@@ -2075,9 +2195,33 @@ Hệ thống AI sẽ tạo chiến lược đề xuất với:
|
|
| 2075 |
</div>
|
| 2076 |
</div>
|
| 2077 |
|
| 2078 |
-
<div style="
|
| 2079 |
-
|
| 2080 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2081 |
🎯 Độ chính xác cao<br/>
|
| 2082 |
📅 Dự báo theo quý<br/>
|
| 2083 |
🔄 Market intelligence<br/>
|
|
@@ -2086,11 +2230,37 @@ Hệ thống AI sẽ tạo chiến lược đề xuất với:
|
|
| 2086 |
</div>
|
| 2087 |
</div>
|
| 2088 |
|
| 2089 |
-
<div style="
|
| 2090 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2091 |
🦊 <strong>Powered by FoxAi</strong> • 🇻🇳 Made in Vietnam • 🤖 Advanced AI
|
| 2092 |
</p>
|
| 2093 |
-
<p style="
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2094 |
YOUR TRUSTED AI PARTNER
|
| 2095 |
</p>
|
| 2096 |
</div>
|
|
|
|
| 93 |
margin: 20px 0;
|
| 94 |
box-shadow: 0 15px 35px rgba(12, 83, 135, 0.3), 0 5px 15px rgba(0, 0, 0, 0.12);
|
| 95 |
border: 1px solid rgba(255, 255, 255, 0.2);
|
| 96 |
+
animation: loadingPulse 2s ease-in-out infinite alternate;
|
| 97 |
}
|
| 98 |
|
| 99 |
.loading-container * {
|
| 100 |
color: white !important;
|
| 101 |
}
|
| 102 |
|
| 103 |
+
@keyframes loadingPulse {
|
| 104 |
+
0% {
|
| 105 |
+
box-shadow: 0 15px 35px rgba(12, 83, 135, 0.3), 0 5px 15px rgba(0, 0, 0, 0.12);
|
| 106 |
+
}
|
| 107 |
+
100% {
|
| 108 |
+
box-shadow: 0 20px 45px rgba(12, 83, 135, 0.4), 0 8px 20px rgba(0, 0, 0, 0.15);
|
| 109 |
+
}
|
| 110 |
+
}
|
| 111 |
+
|
| 112 |
.loading-spinner {
|
| 113 |
border: 4px solid #f3f3f3;
|
| 114 |
border-top: 4px solid #1A5F91;
|
|
|
|
| 438 |
transition: all 0.3s ease !important;
|
| 439 |
}
|
| 440 |
|
| 441 |
+
/* Hiệu ứng highlight cho loading panel */
|
| 442 |
+
#loading-panel.highlight {
|
| 443 |
+
box-shadow: 0 0 20px rgba(26, 95, 145, 0.4) !important;
|
| 444 |
+
transform: scale(1.02) !important;
|
| 445 |
+
transition: all 0.3s ease !important;
|
| 446 |
+
}
|
| 447 |
+
|
| 448 |
+
/* Fade-in animation cho LLM analysis */
|
| 449 |
+
.gradio-markdown {
|
| 450 |
+
animation: fadeInUp 0.8s ease-out !important;
|
| 451 |
+
opacity: 0 !important;
|
| 452 |
+
animation-fill-mode: forwards !important;
|
| 453 |
+
}
|
| 454 |
+
|
| 455 |
+
@keyframes fadeInUp {
|
| 456 |
+
0% {
|
| 457 |
+
opacity: 0;
|
| 458 |
+
transform: translateY(30px);
|
| 459 |
+
}
|
| 460 |
+
100% {
|
| 461 |
+
opacity: 1;
|
| 462 |
+
transform: translateY(0);
|
| 463 |
+
}
|
| 464 |
+
}
|
| 465 |
+
|
| 466 |
+
/* Smooth reveal cho các phần tử khác */
|
| 467 |
+
.plot-container,
|
| 468 |
+
.info-card {
|
| 469 |
+
animation: slideInFade 0.6s ease-out !important;
|
| 470 |
+
}
|
| 471 |
+
|
| 472 |
+
@keyframes slideInFade {
|
| 473 |
+
0% {
|
| 474 |
+
opacity: 0;
|
| 475 |
+
transform: translateY(20px);
|
| 476 |
+
}
|
| 477 |
+
100% {
|
| 478 |
+
opacity: 1;
|
| 479 |
+
transform: translateY(0);
|
| 480 |
+
}
|
| 481 |
+
}
|
| 482 |
+
|
| 483 |
/* Cải thiện focus state cho biểu đồ */
|
| 484 |
.plot-container:focus-within {
|
| 485 |
outline: 2px solid rgba(26, 95, 145, 0.3);
|
|
|
|
| 2013 |
inputs=[],
|
| 2014 |
outputs=[bieu_do_du_bao, hien_thi_tom_tat, hien_thi_bao_cao, loading_panel],
|
| 2015 |
show_progress=False,
|
| 2016 |
+
scroll_to_output=False, # Không scroll tự động, sẽ dùng JS
|
| 2017 |
)
|
| 2018 |
|
| 2019 |
+
# Scroll tới loading panel thay vì chart
|
| 2020 |
+
JS_SCROLL_TO_LOADING = r"""
|
| 2021 |
(...args) => {
|
| 2022 |
+
const el = document.getElementById('loading-panel');
|
| 2023 |
if (el) {
|
| 2024 |
el.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
| 2025 |
el.classList.add('highlight');
|
|
|
|
| 2029 |
}
|
| 2030 |
"""
|
| 2031 |
try:
|
| 2032 |
+
evt0.then(fn=None, inputs=None, outputs=None, js=JS_SCROLL_TO_LOADING)
|
| 2033 |
except TypeError:
|
| 2034 |
+
evt0.then(fn=None, inputs=None, outputs=None, _js=JS_SCROLL_TO_LOADING) # type: ignore
|
| 2035 |
|
| 2036 |
# 2) Stream 4 bước loading trong 3–5 giây (chỉ update loading_panel)
|
| 2037 |
evt1 = evt0.then(
|
|
|
|
| 2042 |
)
|
| 2043 |
|
| 2044 |
# 3) Tính toán thật, render kết quả + tắt loading
|
| 2045 |
+
evt2 = evt1.then(
|
| 2046 |
fn=tinh_toan_ket_qua,
|
| 2047 |
inputs=[lua_chon_dropdown, chu_ky_dropdown, che_do_xem],
|
| 2048 |
outputs=[bieu_do_du_bao, hien_thi_tom_tat, hien_thi_bao_cao, loading_panel],
|
| 2049 |
show_progress=False,
|
| 2050 |
)
|
| 2051 |
|
| 2052 |
+
# Thêm hiệu ứng fade-in cho LLM analysis sau khi render
|
| 2053 |
+
JS_FADE_IN_LLM = r"""
|
| 2054 |
+
(...args) => {
|
| 2055 |
+
setTimeout(() => {
|
| 2056 |
+
const markdownElements = document.querySelectorAll('.gradio-markdown');
|
| 2057 |
+
markdownElements.forEach(el => {
|
| 2058 |
+
el.style.animation = 'fadeInUp 0.8s ease-out forwards';
|
| 2059 |
+
});
|
| 2060 |
+
}, 200);
|
| 2061 |
+
return [];
|
| 2062 |
+
}
|
| 2063 |
+
"""
|
| 2064 |
+
try:
|
| 2065 |
+
evt2.then(fn=None, inputs=None, outputs=None, js=JS_FADE_IN_LLM)
|
| 2066 |
+
except TypeError:
|
| 2067 |
+
evt2.then(fn=None, inputs=None, outputs=None, _js=JS_FADE_IN_LLM) # type: ignore
|
| 2068 |
+
|
| 2069 |
# Streaming event cho chiến lược đề xuất
|
| 2070 |
nut_streaming.click(
|
| 2071 |
fn=xu_ly_streaming,
|
|
|
|
| 2120 |
# Footer thông tin hệ thống với branding FoxAI
|
| 2121 |
gr.HTML(f"""
|
| 2122 |
<div class='info-card' style="margin-top: 30px; text-align: center;">
|
| 2123 |
+
<div style="
|
| 2124 |
+
display: flex;
|
| 2125 |
+
align-items: center;
|
| 2126 |
+
justify-content: center;
|
| 2127 |
+
margin-bottom: 35px;
|
| 2128 |
+
padding: 25px;
|
| 2129 |
+
background: linear-gradient(135deg, rgba(26, 95, 145, 0.1), rgba(12, 83, 135, 0.05));
|
| 2130 |
+
border-radius: 20px;
|
| 2131 |
+
border: 2px solid rgba(26, 95, 145, 0.2);
|
| 2132 |
+
box-shadow: 0 8px 25px rgba(26, 95, 145, 0.15);
|
| 2133 |
+
">
|
| 2134 |
+
<img src="{FOXAI_LOGO_URL}" alt="FoxAI" style="
|
| 2135 |
+
height: 65px;
|
| 2136 |
+
margin-right: 25px;
|
| 2137 |
+
filter: drop-shadow(0 4px 8px rgba(26, 95, 145, 0.3));
|
| 2138 |
+
transition: all 0.3s ease;
|
| 2139 |
+
" onmouseover="this.style.transform='scale(1.05)'" onmouseout="this.style.transform='scale(1)'"/>
|
| 2140 |
<h2 style="
|
| 2141 |
+
color: white;
|
| 2142 |
margin: 0;
|
| 2143 |
+
font-size: 2.8em;
|
| 2144 |
+
font-weight: 900;
|
| 2145 |
+
letter-spacing: 1.5px;
|
| 2146 |
+
text-shadow: 0 0 20px rgba(255, 255, 255, 0.5);
|
| 2147 |
+
background: linear-gradient(90deg, #ffffff, #f1f5f9, #e2e8f0);
|
| 2148 |
+
-webkit-background-clip: text;
|
| 2149 |
+
-webkit-text-fill-color: transparent;
|
| 2150 |
+
background-clip: text;
|
| 2151 |
+
line-height: 1.2;
|
| 2152 |
">
|
| 2153 |
+
💡 HỆ THỐNG DỰ BÁO <span style="
|
| 2154 |
+
background: linear-gradient(90deg, #ffffff, #cbd5e1);
|
| 2155 |
+
-webkit-background-clip: text;
|
| 2156 |
+
-webkit-text-fill-color: transparent;
|
| 2157 |
+
background-clip: text;
|
| 2158 |
+
font-weight: 800;
|
| 2159 |
+
">FoxAI</span>
|
| 2160 |
</h2>
|
| 2161 |
</div>
|
| 2162 |
|
| 2163 |
+
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: 30px; margin: 30px 0;">
|
| 2164 |
+
<div style="
|
| 2165 |
+
text-align: center;
|
| 2166 |
+
padding: 30px;
|
| 2167 |
+
background: linear-gradient(135deg, rgba(26, 95, 145, 0.15), rgba(255, 255, 255, 0.1));
|
| 2168 |
+
border-radius: 20px;
|
| 2169 |
+
border: 1px solid rgba(26, 95, 145, 0.3);
|
| 2170 |
+
box-shadow: 0 8px 25px rgba(26, 95, 145, 0.15);
|
| 2171 |
+
transition: all 0.3s ease;
|
| 2172 |
+
">
|
| 2173 |
+
<h4 style="
|
| 2174 |
+
color: #1A5F91;
|
| 2175 |
+
margin-bottom: 20px;
|
| 2176 |
+
font-size: 1.8em;
|
| 2177 |
+
font-weight: 700;
|
| 2178 |
+
background: linear-gradient(90deg, #1A5F91, #2563eb);
|
| 2179 |
+
-webkit-background-clip: text;
|
| 2180 |
+
-webkit-text-fill-color: transparent;
|
| 2181 |
+
background-clip: text;
|
| 2182 |
+
text-shadow: 0 2px 10px rgba(26, 95, 145, 0.3);
|
| 2183 |
+
">🎯 Tính Năng</h4>
|
| 2184 |
+
<div style="
|
| 2185 |
+
color: #334155;
|
| 2186 |
+
line-height: 2.2;
|
| 2187 |
+
font-weight: 600;
|
| 2188 |
+
font-size: 1.15em;
|
| 2189 |
+
text-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
| 2190 |
+
">
|
| 2191 |
✨ AI Insights thông minh<br/>
|
| 2192 |
📊 Multi-view linh hoạt<br/>
|
| 2193 |
📈 Báo cáo chuyên nghiệp<br/>
|
|
|
|
| 2195 |
</div>
|
| 2196 |
</div>
|
| 2197 |
|
| 2198 |
+
<div style="
|
| 2199 |
+
text-align: center;
|
| 2200 |
+
padding: 30px;
|
| 2201 |
+
background: linear-gradient(135deg, rgba(26, 95, 145, 0.15), rgba(255, 255, 255, 0.1));
|
| 2202 |
+
border-radius: 20px;
|
| 2203 |
+
border: 1px solid rgba(26, 95, 145, 0.3);
|
| 2204 |
+
box-shadow: 0 8px 25px rgba(26, 95, 145, 0.15);
|
| 2205 |
+
transition: all 0.3s ease;
|
| 2206 |
+
">
|
| 2207 |
+
<h4 style="
|
| 2208 |
+
color: #1A5F91;
|
| 2209 |
+
margin-bottom: 20px;
|
| 2210 |
+
font-size: 1.8em;
|
| 2211 |
+
font-weight: 700;
|
| 2212 |
+
background: linear-gradient(90deg, #1A5F91, #2563eb);
|
| 2213 |
+
-webkit-background-clip: text;
|
| 2214 |
+
-webkit-text-fill-color: transparent;
|
| 2215 |
+
background-clip: text;
|
| 2216 |
+
text-shadow: 0 2px 10px rgba(26, 95, 145, 0.3);
|
| 2217 |
+
">📊 Chất Lượng</h4>
|
| 2218 |
+
<div style="
|
| 2219 |
+
color: #334155;
|
| 2220 |
+
line-height: 2.2;
|
| 2221 |
+
font-weight: 600;
|
| 2222 |
+
font-size: 1.15em;
|
| 2223 |
+
text-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
| 2224 |
+
">
|
| 2225 |
🎯 Độ chính xác cao<br/>
|
| 2226 |
📅 Dự báo theo quý<br/>
|
| 2227 |
🔄 Market intelligence<br/>
|
|
|
|
| 2230 |
</div>
|
| 2231 |
</div>
|
| 2232 |
|
| 2233 |
+
<div style="
|
| 2234 |
+
text-align: center;
|
| 2235 |
+
margin: 35px 0;
|
| 2236 |
+
padding: 25px;
|
| 2237 |
+
background: linear-gradient(135deg, rgba(26, 95, 145, 0.2), rgba(139, 139, 139, 0.15));
|
| 2238 |
+
border-radius: 20px;
|
| 2239 |
+
border: 2px solid #1A5F91;
|
| 2240 |
+
box-shadow: 0 10px 30px rgba(26, 95, 145, 0.2);
|
| 2241 |
+
transition: all 0.3s ease;
|
| 2242 |
+
">
|
| 2243 |
+
<p style="
|
| 2244 |
+
color: #1A5F91;
|
| 2245 |
+
font-weight: 700;
|
| 2246 |
+
margin: 0;
|
| 2247 |
+
font-size: 1.5em;
|
| 2248 |
+
background: linear-gradient(90deg, #1A5F91, #2563eb, #1A5F91);
|
| 2249 |
+
-webkit-background-clip: text;
|
| 2250 |
+
-webkit-text-fill-color: transparent;
|
| 2251 |
+
background-clip: text;
|
| 2252 |
+
text-shadow: 0 2px 8px rgba(26, 95, 145, 0.3);
|
| 2253 |
+
">
|
| 2254 |
🦊 <strong>Powered by FoxAi</strong> • 🇻🇳 Made in Vietnam • 🤖 Advanced AI
|
| 2255 |
</p>
|
| 2256 |
+
<p style="
|
| 2257 |
+
color: #334155;
|
| 2258 |
+
margin: 12px 0 0 0;
|
| 2259 |
+
font-size: 1.2em;
|
| 2260 |
+
font-weight: 700;
|
| 2261 |
+
letter-spacing: 1px;
|
| 2262 |
+
text-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
|
| 2263 |
+
">
|
| 2264 |
YOUR TRUSTED AI PARTNER
|
| 2265 |
</p>
|
| 2266 |
</div>
|
app_backup.py
DELETED
|
@@ -1,1986 +0,0 @@
|
|
| 1 |
-
import gradio as gr
|
| 2 |
-
import plotly.graph_objects as go
|
| 3 |
-
import numpy as np
|
| 4 |
-
from datetime import datetime, timedelta
|
| 5 |
-
import random
|
| 6 |
-
import time
|
| 7 |
-
import pandas as pd # thêm
|
| 8 |
-
|
| 9 |
-
# URL logo FoxAI - sử dụng trực tiếp từ attachment
|
| 10 |
-
FOXAI_LOGO_URL = "data:image/png;base64,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"
|
| 11 |
-
|
| 12 |
-
# CSS Style với màu sắc FoxAI - Modern UI Design
|
| 13 |
-
custom_css = """
|
| 14 |
-
.gradio-container {
|
| 15 |
-
background: linear-gradient(135deg, #f8fafc 0%, #e2e8f0 25%, #cbd5e1 50%, #94a3b8 75%, #64748b 100%);
|
| 16 |
-
font-family: 'Inter', 'Segoe UI', system-ui, -apple-system, sans-serif !important;
|
| 17 |
-
min-height: 100vh;
|
| 18 |
-
}
|
| 19 |
-
|
| 20 |
-
.header-container {
|
| 21 |
-
text-align: center;
|
| 22 |
-
margin: 20px 0;
|
| 23 |
-
padding: 40px;
|
| 24 |
-
background: linear-gradient(90deg, #A9AAA9 0%, #8194A0 25%, #5A7E98 50%, #33688F 75%, #0C5387 100%);
|
| 25 |
-
border-radius: 24px;
|
| 26 |
-
box-shadow: 0 20px 40px rgba(12, 83, 135, 0.15), 0 8px 16px rgba(0, 0, 0, 0.1);
|
| 27 |
-
backdrop-filter: blur(20px);
|
| 28 |
-
border: 1px solid rgba(255, 255, 255, 0.3);
|
| 29 |
-
position: relative;
|
| 30 |
-
overflow: hidden;
|
| 31 |
-
}
|
| 32 |
-
|
| 33 |
-
.header-container::before {
|
| 34 |
-
content: '';
|
| 35 |
-
position: absolute;
|
| 36 |
-
top: 0;
|
| 37 |
-
left: -100%;
|
| 38 |
-
width: 100%;
|
| 39 |
-
height: 100%;
|
| 40 |
-
background: linear-gradient(90deg, transparent, rgba(255,255,255,0.2), transparent);
|
| 41 |
-
animation: shine 3s infinite;
|
| 42 |
-
}
|
| 43 |
-
|
| 44 |
-
@keyframes shine {
|
| 45 |
-
0% { left: -100%; }
|
| 46 |
-
100% { left: 100%; }
|
| 47 |
-
}
|
| 48 |
-
|
| 49 |
-
.foxai-logo {
|
| 50 |
-
max-width: 320px;
|
| 51 |
-
height: auto;
|
| 52 |
-
margin: 15px auto 25px auto;
|
| 53 |
-
display: block;
|
| 54 |
-
filter: drop-shadow(0 4px 8px rgba(0,0,0,0.15)) brightness(1.1);
|
| 55 |
-
transition: all 0.4s ease;
|
| 56 |
-
animation: float 4s ease-in-out infinite;
|
| 57 |
-
}
|
| 58 |
-
|
| 59 |
-
.foxai-logo:hover {
|
| 60 |
-
transform: scale(1.05);
|
| 61 |
-
filter: drop-shadow(0 8px 16px rgba(12, 83, 135, 0.3)) brightness(1.2);
|
| 62 |
-
}
|
| 63 |
-
|
| 64 |
-
.header-title {
|
| 65 |
-
background: linear-gradient(90deg, #ffffff, #f1f5f9, #e2e8f0, #ffffff);
|
| 66 |
-
background-size: 300% 300%;
|
| 67 |
-
animation: gradient 8s ease infinite;
|
| 68 |
-
-webkit-background-clip: text;
|
| 69 |
-
-webkit-text-fill-color: transparent;
|
| 70 |
-
background-clip: text;
|
| 71 |
-
text-align: center;
|
| 72 |
-
font-size: 2.5em;
|
| 73 |
-
font-weight: 700;
|
| 74 |
-
margin: 15px auto;
|
| 75 |
-
line-height: 1.3;
|
| 76 |
-
text-shadow: 0 0 30px rgba(255, 255, 255, 0.5);
|
| 77 |
-
letter-spacing: -0.01em;
|
| 78 |
-
max-width: 900px;
|
| 79 |
-
}
|
| 80 |
-
|
| 81 |
-
@keyframes gradient {
|
| 82 |
-
0% { background-position: 0% 50%; }
|
| 83 |
-
50% { background-position: 100% 50%; }
|
| 84 |
-
100% { background-position: 0% 50%; }
|
| 85 |
-
}
|
| 86 |
-
|
| 87 |
-
.loading-container {
|
| 88 |
-
text-align: center;
|
| 89 |
-
padding: 40px;
|
| 90 |
-
background: linear-gradient(90deg, #A9AAA9 0%, #8194A0 25%, #5A7E98 50%, #33688F 75%, #0C5387 100%);
|
| 91 |
-
border-radius: 20px;
|
| 92 |
-
color: white !important;
|
| 93 |
-
margin: 20px 0;
|
| 94 |
-
box-shadow: 0 15px 35px rgba(12, 83, 135, 0.3), 0 5px 15px rgba(0, 0, 0, 0.12);
|
| 95 |
-
border: 1px solid rgba(255, 255, 255, 0.2);
|
| 96 |
-
}
|
| 97 |
-
|
| 98 |
-
.loading-container * {
|
| 99 |
-
color: white !important;
|
| 100 |
-
}
|
| 101 |
-
|
| 102 |
-
.loading-spinner {
|
| 103 |
-
border: 4px solid #f3f3f3;
|
| 104 |
-
border-top: 4px solid #1A5F91;
|
| 105 |
-
border-radius: 50%;
|
| 106 |
-
width: 40px;
|
| 107 |
-
height: 40px;
|
| 108 |
-
animation: spin 1s linear infinite;
|
| 109 |
-
margin: 0 auto 20px;
|
| 110 |
-
}
|
| 111 |
-
|
| 112 |
-
@keyframes spin {
|
| 113 |
-
0% { transform: rotate(0deg); }
|
| 114 |
-
100% { transform: rotate(360deg); }
|
| 115 |
-
}
|
| 116 |
-
|
| 117 |
-
.progress-bar {
|
| 118 |
-
width: 100%;
|
| 119 |
-
height: 20px;
|
| 120 |
-
background-color: rgba(255,255,255,0.3);
|
| 121 |
-
border-radius: 10px;
|
| 122 |
-
overflow: hidden;
|
| 123 |
-
margin: 15px 0;
|
| 124 |
-
}
|
| 125 |
-
|
| 126 |
-
.progress-fill {
|
| 127 |
-
height: 100%;
|
| 128 |
-
background: linear-gradient(90deg, #A9AAA9 0%, #8194A0 25%, #5A7E98 50%, #33688F 75%, #0C5387 100%);
|
| 129 |
-
border-radius: 10px;
|
| 130 |
-
animation: progress 3s ease-in-out;
|
| 131 |
-
box-shadow: 0 0 20px rgba(12, 83, 135, 0.4);
|
| 132 |
-
}
|
| 133 |
-
|
| 134 |
-
@keyframes progress {
|
| 135 |
-
0% { width: 0%; }
|
| 136 |
-
25% { width: 30%; }
|
| 137 |
-
50% { width: 60%; }
|
| 138 |
-
75% { width: 85%; }
|
| 139 |
-
100% { width: 100%; }
|
| 140 |
-
}
|
| 141 |
-
|
| 142 |
-
.prediction-box {
|
| 143 |
-
background: linear-gradient(90deg, #A9AAA9 0%, #8194A0 25%, #5A7E98 50%, #33688F 75%, #0C5387 100%);
|
| 144 |
-
border-radius: 20px;
|
| 145 |
-
padding: 25px;
|
| 146 |
-
color: white !important;
|
| 147 |
-
text-align: center;
|
| 148 |
-
font-size: 1.1em;
|
| 149 |
-
font-weight: 600;
|
| 150 |
-
box-shadow: 0 15px 35px rgba(12, 83, 135, 0.25), 0 5px 15px rgba(0, 0, 0, 0.12);
|
| 151 |
-
margin: 15px 0;
|
| 152 |
-
border: 1px solid rgba(255,255,255,0.2);
|
| 153 |
-
position: relative;
|
| 154 |
-
overflow: hidden;
|
| 155 |
-
}
|
| 156 |
-
|
| 157 |
-
.prediction-box * {
|
| 158 |
-
color: white !important;
|
| 159 |
-
}
|
| 160 |
-
|
| 161 |
-
.prediction-box::before {
|
| 162 |
-
content: '';
|
| 163 |
-
position: absolute;
|
| 164 |
-
top: 0;
|
| 165 |
-
left: 0;
|
| 166 |
-
right: 0;
|
| 167 |
-
height: 1px;
|
| 168 |
-
background: linear-gradient(90deg, transparent, rgba(255,255,255,0.6), transparent);
|
| 169 |
-
}
|
| 170 |
-
|
| 171 |
-
.insight-box {
|
| 172 |
-
background: linear-gradient(90deg, #cbd5e1 0%, #94a3b8 25%, #64748b 50%, #475569 75%, #334155 100%);
|
| 173 |
-
border-radius: 20px;
|
| 174 |
-
padding: 25px;
|
| 175 |
-
color: white !important;
|
| 176 |
-
margin: 15px 0;
|
| 177 |
-
box-shadow: 0 15px 35px rgba(51, 65, 85, 0.25), 0 5px 15px rgba(0, 0, 0, 0.12);
|
| 178 |
-
border: 1px solid rgba(255,255,255,0.2);
|
| 179 |
-
position: relative;
|
| 180 |
-
overflow: hidden;
|
| 181 |
-
}
|
| 182 |
-
|
| 183 |
-
.insight-box * {
|
| 184 |
-
color: white !important;
|
| 185 |
-
}
|
| 186 |
-
|
| 187 |
-
.executive-summary {
|
| 188 |
-
background: linear-gradient(90deg, #A9AAA9 0%, #8194A0 25%, #5A7E98 50%, #33688F 75%, #0C5387 100%);
|
| 189 |
-
border-radius: 20px;
|
| 190 |
-
padding: 30px;
|
| 191 |
-
color: white !important;
|
| 192 |
-
margin: 15px 0;
|
| 193 |
-
box-shadow: 0 20px 40px rgba(12, 83, 135, 0.25), 0 8px 16px rgba(0, 0, 0, 0.12);
|
| 194 |
-
border-left: 5px solid rgba(255, 255, 255, 0.3);
|
| 195 |
-
border: 1px solid rgba(255,255,255,0.2);
|
| 196 |
-
position: relative;
|
| 197 |
-
overflow: hidden;
|
| 198 |
-
}
|
| 199 |
-
|
| 200 |
-
.executive-summary * {
|
| 201 |
-
color: white !important;
|
| 202 |
-
}
|
| 203 |
-
|
| 204 |
-
.executive-summary::after {
|
| 205 |
-
content: '';
|
| 206 |
-
position: absolute;
|
| 207 |
-
top: 0;
|
| 208 |
-
right: 0;
|
| 209 |
-
width: 100px;
|
| 210 |
-
height: 100%;
|
| 211 |
-
background: linear-gradient(90deg, transparent, rgba(255,255,255,0.1));
|
| 212 |
-
pointer-events: none;
|
| 213 |
-
}
|
| 214 |
-
|
| 215 |
-
.feature-box {
|
| 216 |
-
background: linear-gradient(135deg, rgba(169, 170, 169, 0.15), rgba(129, 148, 160, 0.15), rgba(90, 126, 152, 0.15));
|
| 217 |
-
border-radius: 20px;
|
| 218 |
-
padding: 20px;
|
| 219 |
-
margin: 15px 0;
|
| 220 |
-
box-shadow: 0 8px 32px rgba(12, 83, 135, 0.1), 0 1px 2px rgba(0, 0, 0, 0.05);
|
| 221 |
-
border-left: 4px solid #0C5387;
|
| 222 |
-
backdrop-filter: blur(10px);
|
| 223 |
-
border: 1px solid rgba(255, 255, 255, 0.2);
|
| 224 |
-
transition: all 0.3s ease;
|
| 225 |
-
text-align: center;
|
| 226 |
-
}
|
| 227 |
-
|
| 228 |
-
.feature-box:hover {
|
| 229 |
-
transform: translateY(-2px);
|
| 230 |
-
box-shadow: 0 12px 40px rgba(12, 83, 135, 0.15), 0 4px 8px rgba(0, 0, 0, 0.1);
|
| 231 |
-
}
|
| 232 |
-
|
| 233 |
-
.feature-box h3 {
|
| 234 |
-
margin: 0;
|
| 235 |
-
color: #0C5387;
|
| 236 |
-
font-weight: 700;
|
| 237 |
-
text-shadow: 0 0 10px rgba(12, 83, 135, 0.3);
|
| 238 |
-
font-size: 1.2em;
|
| 239 |
-
text-align: center;
|
| 240 |
-
}
|
| 241 |
-
|
| 242 |
-
.system-status {
|
| 243 |
-
background: linear-gradient(90deg, #cbd5e1 0%, #94a3b8 25%, #64748b 50%, #475569 75%, #334155 100%);
|
| 244 |
-
color: white !important;
|
| 245 |
-
padding: 15px 25px;
|
| 246 |
-
border-radius: 30px;
|
| 247 |
-
margin: 15px 0;
|
| 248 |
-
text-align: center;
|
| 249 |
-
font-weight: 600;
|
| 250 |
-
box-shadow: 0 8px 25px rgba(51, 65, 85, 0.2), 0 3px 8px rgba(0, 0, 0, 0.1);
|
| 251 |
-
border: 1px solid rgba(255,255,255,0.2);
|
| 252 |
-
font-size: 0.95em;
|
| 253 |
-
}
|
| 254 |
-
|
| 255 |
-
.system-status * {
|
| 256 |
-
color: white !important;
|
| 257 |
-
}
|
| 258 |
-
|
| 259 |
-
.metric-card {
|
| 260 |
-
background: linear-gradient(90deg, #A9AAA9 0%, #8194A0 25%, #5A7E98 50%, #33688F 75%, #0C5387 100%);
|
| 261 |
-
color: white !important;
|
| 262 |
-
border-radius: 16px;
|
| 263 |
-
padding: 20px;
|
| 264 |
-
margin: 8px;
|
| 265 |
-
text-align: center;
|
| 266 |
-
box-shadow: 0 8px 25px rgba(12, 83, 135, 0.2), 0 3px 8px rgba(0, 0, 0, 0.1);
|
| 267 |
-
border: 1px solid rgba(255,255,255,0.2);
|
| 268 |
-
transition: all 0.3s ease;
|
| 269 |
-
position: relative;
|
| 270 |
-
overflow: hidden;
|
| 271 |
-
}
|
| 272 |
-
|
| 273 |
-
.metric-card * {
|
| 274 |
-
color: white !important;
|
| 275 |
-
}
|
| 276 |
-
|
| 277 |
-
.metric-card:hover {
|
| 278 |
-
transform: translateY(-3px);
|
| 279 |
-
box-shadow: 0 12px 35px rgba(12, 83, 135, 0.3), 0 5px 12px rgba(0, 0, 0, 0.15);
|
| 280 |
-
}
|
| 281 |
-
|
| 282 |
-
.metric-card::before {
|
| 283 |
-
content: '';
|
| 284 |
-
position: absolute;
|
| 285 |
-
top: 0;
|
| 286 |
-
left: 0;
|
| 287 |
-
right: 0;
|
| 288 |
-
height: 2px;
|
| 289 |
-
background: linear-gradient(90deg, transparent, rgba(255,255,255,0.8), transparent);
|
| 290 |
-
}
|
| 291 |
-
|
| 292 |
-
.button-predict {
|
| 293 |
-
background: linear-gradient(135deg, #1A5F91, #8B8B8B) !important;
|
| 294 |
-
color: white !important;
|
| 295 |
-
border: none !important;
|
| 296 |
-
border-radius: 25px !important;
|
| 297 |
-
padding: 15px 30px !important;
|
| 298 |
-
font-size: 16px !important;
|
| 299 |
-
font-weight: bold !important;
|
| 300 |
-
box-shadow: 0 4px 15px rgba(26, 95, 145, 0.4) !important;
|
| 301 |
-
transition: all 0.3s ease !important;
|
| 302 |
-
}
|
| 303 |
-
|
| 304 |
-
.button-predict:hover {
|
| 305 |
-
transform: translateY(-2px) !important;
|
| 306 |
-
box-shadow: 0 6px 20px rgba(26, 95, 145, 0.6) !important;
|
| 307 |
-
}
|
| 308 |
-
|
| 309 |
-
.plot-container {
|
| 310 |
-
border: 1px solid #e1e5e9;
|
| 311 |
-
border-radius: 15px;
|
| 312 |
-
padding: 15px;
|
| 313 |
-
margin: 15px 0;
|
| 314 |
-
background: rgba(255, 255, 255, 0.95);
|
| 315 |
-
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
|
| 316 |
-
min-height: 400px;
|
| 317 |
-
position: relative;
|
| 318 |
-
overflow: hidden;
|
| 319 |
-
}
|
| 320 |
-
|
| 321 |
-
/* Cải thiện hiển thị biểu đồ Plotly */
|
| 322 |
-
.plot-container .plotly-graph-div {
|
| 323 |
-
position: relative !important;
|
| 324 |
-
max-width: 100% !important;
|
| 325 |
-
height: auto !important;
|
| 326 |
-
margin: 20px 0 !important;
|
| 327 |
-
padding: 20px !important;
|
| 328 |
-
border-radius: 12px !important;
|
| 329 |
-
background: rgba(255, 255, 255, 0.95) !important;
|
| 330 |
-
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1) !important;
|
| 331 |
-
overflow: visible !important;
|
| 332 |
-
}
|
| 333 |
-
|
| 334 |
-
/* Ẩn hoàn toàn toolbar/config của biểu đồ */
|
| 335 |
-
.plot-container .modebar,
|
| 336 |
-
.plot-container .modebar-container,
|
| 337 |
-
.plotly .modebar,
|
| 338 |
-
.js-plotly-plot .modebar,
|
| 339 |
-
.plotly-graph-div .modebar,
|
| 340 |
-
.plotly-graph-div .modebar-container,
|
| 341 |
-
.svg-container .modebar,
|
| 342 |
-
div[data-title="Plotly toolbar"],
|
| 343 |
-
.modebar-group,
|
| 344 |
-
.modebar-btn {
|
| 345 |
-
display: none !important;
|
| 346 |
-
visibility: hidden !important;
|
| 347 |
-
opacity: 0 !important;
|
| 348 |
-
pointer-events: none !important;
|
| 349 |
-
height: 0 !important;
|
| 350 |
-
width: 0 !important;
|
| 351 |
-
overflow: hidden !important;
|
| 352 |
-
position: absolute !important;
|
| 353 |
-
top: -9999px !important;
|
| 354 |
-
left: -9999px !important;
|
| 355 |
-
}
|
| 356 |
-
|
| 357 |
-
/* Cải thiện spacing cho text và labels - tránh dính chữ */
|
| 358 |
-
.plot-container .plotly-graph-div .svg-container {
|
| 359 |
-
pointer-events: auto !important;
|
| 360 |
-
overflow: visible !important;
|
| 361 |
-
padding: 10px !important;
|
| 362 |
-
}
|
| 363 |
-
|
| 364 |
-
.plot-container .plotly-graph-div .main-svg {
|
| 365 |
-
max-width: 100% !important;
|
| 366 |
-
height: auto !important;
|
| 367 |
-
overflow: visible !important;
|
| 368 |
-
padding: 5px !important;
|
| 369 |
-
}
|
| 370 |
-
|
| 371 |
-
/* Đảm bảo text không bị cắt và có spacing tốt */
|
| 372 |
-
.plot-container .plotly-graph-div text {
|
| 373 |
-
font-family: "Inter", "Segoe UI", Arial, sans-serif !important;
|
| 374 |
-
font-size: 12px !important;
|
| 375 |
-
text-anchor: middle !important;
|
| 376 |
-
}
|
| 377 |
-
|
| 378 |
-
.plot-container .plotly-graph-div .xtick text,
|
| 379 |
-
.plot-container .plotly-graph-div .ytick text {
|
| 380 |
-
font-size: 11px !important;
|
| 381 |
-
fill: #374151 !important;
|
| 382 |
-
}
|
| 383 |
-
|
| 384 |
-
/* Cải thiện title spacing - tránh dính với nội dung */
|
| 385 |
-
.plot-container .plotly-graph-div .gtitle {
|
| 386 |
-
font-size: 16px !important;
|
| 387 |
-
font-weight: 600 !important;
|
| 388 |
-
fill: #1f2937 !important;
|
| 389 |
-
dominant-baseline: text-before-edge !important;
|
| 390 |
-
}
|
| 391 |
-
|
| 392 |
-
/* Tối ưu responsive và tránh overflow */
|
| 393 |
-
.plot-container {
|
| 394 |
-
width: 100% !important;
|
| 395 |
-
max-width: 100% !important;
|
| 396 |
-
overflow: visible !important;
|
| 397 |
-
}
|
| 398 |
-
|
| 399 |
-
/* Đảm bảo axis labels có đủ space */
|
| 400 |
-
.plot-container .plotly-graph-div .xaxislayer-above,
|
| 401 |
-
.plot-container .plotly-graph-div .yaxislayer-above {
|
| 402 |
-
overflow: visible !important;
|
| 403 |
-
}
|
| 404 |
-
|
| 405 |
-
/* CSS cho smooth scrolling và highlight */
|
| 406 |
-
html {
|
| 407 |
-
scroll-behavior: smooth;
|
| 408 |
-
}
|
| 409 |
-
|
| 410 |
-
.plot-container.highlight {
|
| 411 |
-
box-shadow: 0 0 15px rgba(26, 95, 145, 0.2) !important;
|
| 412 |
-
transform: scale(1.01) !important;
|
| 413 |
-
transition: all 0.3s ease !important;
|
| 414 |
-
}
|
| 415 |
-
|
| 416 |
-
/* Cải thiện focus state cho biểu đồ */
|
| 417 |
-
.plot-container:focus-within {
|
| 418 |
-
outline: 2px solid rgba(26, 95, 145, 0.3);
|
| 419 |
-
outline-offset: 2px;
|
| 420 |
-
}
|
| 421 |
-
|
| 422 |
-
.info-card {
|
| 423 |
-
background: rgba(255, 255, 255, 0.95);
|
| 424 |
-
border-radius: 10px;
|
| 425 |
-
padding: 15px;
|
| 426 |
-
margin: 10px 0;
|
| 427 |
-
border-left: 5px solid #1A5F91;
|
| 428 |
-
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
| 429 |
-
}
|
| 430 |
-
|
| 431 |
-
/* Sửa lỗi font và text rendering */
|
| 432 |
-
* {
|
| 433 |
-
font-family: 'Inter', 'Segoe UI', system-ui, -apple-system, sans-serif !important;
|
| 434 |
-
text-rendering: optimizeLegibility !important;
|
| 435 |
-
-webkit-font-smoothing: antialiased !important;
|
| 436 |
-
-moz-osx-font-smoothing: grayscale !important;
|
| 437 |
-
}
|
| 438 |
-
|
| 439 |
-
/* Cải thiện hiển thị tiếng Việt và căn giữa */
|
| 440 |
-
.gradio-markdown, .gradio-html {
|
| 441 |
-
font-family: 'Inter', 'Segoe UI', system-ui, -apple-system, sans-serif !important;
|
| 442 |
-
line-height: 1.6 !important;
|
| 443 |
-
word-wrap: break-word !important;
|
| 444 |
-
overflow-wrap: break-word !important;
|
| 445 |
-
text-align: center !important;
|
| 446 |
-
}
|
| 447 |
-
|
| 448 |
-
/* Căn giữa tất cả text */
|
| 449 |
-
.gradio-container .wrap {
|
| 450 |
-
max-width: 100% !important;
|
| 451 |
-
overflow-x: hidden !important;
|
| 452 |
-
text-align: center !important;
|
| 453 |
-
}
|
| 454 |
-
|
| 455 |
-
/* Căn giữa các component */
|
| 456 |
-
.gradio-row {
|
| 457 |
-
flex-wrap: wrap !important;
|
| 458 |
-
justify-content: center !important;
|
| 459 |
-
}
|
| 460 |
-
|
| 461 |
-
.gradio-column {
|
| 462 |
-
min-width: 0 !important;
|
| 463 |
-
flex-shrink: 1 !important;
|
| 464 |
-
display: flex !important;
|
| 465 |
-
flex-direction: column !important;
|
| 466 |
-
align-items: center !important;
|
| 467 |
-
}
|
| 468 |
-
|
| 469 |
-
/* Chuẩn hóa màu sắc - text đậm trên nền sáng */
|
| 470 |
-
.gradio-container {
|
| 471 |
-
color: #1e293b !important;
|
| 472 |
-
}
|
| 473 |
-
|
| 474 |
-
/* Chuẩn hóa size chữ - màu đậm cho dễ đọc */
|
| 475 |
-
h1, h2, h3, h4, h5, h6 {
|
| 476 |
-
font-weight: 600 !important;
|
| 477 |
-
color: #1A5F91 !important;
|
| 478 |
-
text-align: center !important;
|
| 479 |
-
margin: 0.5em auto !important;
|
| 480 |
-
}
|
| 481 |
-
|
| 482 |
-
p, div, span {
|
| 483 |
-
color: #334155 !important;
|
| 484 |
-
font-size: 1em !important;
|
| 485 |
-
line-height: 1.6 !important;
|
| 486 |
-
font-weight: 500 !important;
|
| 487 |
-
}
|
| 488 |
-
|
| 489 |
-
/* Chuẩn hóa labels và inputs - màu đậm */
|
| 490 |
-
label {
|
| 491 |
-
font-weight: 600 !important;
|
| 492 |
-
color: #1A5F91 !important;
|
| 493 |
-
text-align: center !important;
|
| 494 |
-
margin-bottom: 8px !important;
|
| 495 |
-
font-size: 1em !important;
|
| 496 |
-
}
|
| 497 |
-
|
| 498 |
-
.gradio-textbox, .gradio-dropdown, .gradio-radio {
|
| 499 |
-
text-align: center !important;
|
| 500 |
-
color: #1e293b !important;
|
| 501 |
-
}
|
| 502 |
-
|
| 503 |
-
/* Buttons styling */
|
| 504 |
-
.gradio-button {
|
| 505 |
-
font-weight: 600 !important;
|
| 506 |
-
font-size: 1em !important;
|
| 507 |
-
border-radius: 12px !important;
|
| 508 |
-
margin: 8px auto !important;
|
| 509 |
-
display: block !important;
|
| 510 |
-
color: #1e293b !important;
|
| 511 |
-
}
|
| 512 |
-
|
| 513 |
-
/* Styling cho markdown báo cáo chiến lược */
|
| 514 |
-
.gradio-markdown {
|
| 515 |
-
background: linear-gradient(135deg, rgba(255, 255, 255, 0.95), rgba(248, 250, 252, 0.95)) !important;
|
| 516 |
-
border-radius: 20px !important;
|
| 517 |
-
padding: 30px !important;
|
| 518 |
-
margin: 20px 0 !important;
|
| 519 |
-
box-shadow: 0 8px 32px rgba(12, 83, 135, 0.15), 0 4px 16px rgba(0, 0, 0, 0.1) !important;
|
| 520 |
-
border: 2px solid rgba(26, 95, 145, 0.1) !important;
|
| 521 |
-
backdrop-filter: blur(10px) !important;
|
| 522 |
-
}
|
| 523 |
-
|
| 524 |
-
.gradio-markdown h1 {
|
| 525 |
-
color: #1A5F91 !important;
|
| 526 |
-
font-size: 2.2em !important;
|
| 527 |
-
font-weight: 800 !important;
|
| 528 |
-
text-align: center !important;
|
| 529 |
-
margin: 0 0 25px 0 !important;
|
| 530 |
-
text-shadow: 0 2px 4px rgba(26, 95, 145, 0.2) !important;
|
| 531 |
-
border-bottom: 3px solid #1A5F91 !important;
|
| 532 |
-
padding-bottom: 15px !important;
|
| 533 |
-
}
|
| 534 |
-
|
| 535 |
-
.gradio-markdown h2 {
|
| 536 |
-
color: #0C5387 !important;
|
| 537 |
-
font-size: 1.6em !important;
|
| 538 |
-
font-weight: 700 !important;
|
| 539 |
-
margin: 25px 0 15px 0 !important;
|
| 540 |
-
padding: 12px 20px !important;
|
| 541 |
-
background: linear-gradient(90deg, rgba(26, 95, 145, 0.1), rgba(26, 95, 145, 0.05)) !important;
|
| 542 |
-
border-radius: 12px !important;
|
| 543 |
-
border-left: 5px solid #1A5F91 !important;
|
| 544 |
-
}
|
| 545 |
-
|
| 546 |
-
.gradio-markdown h3 {
|
| 547 |
-
color: #1A5F91 !important;
|
| 548 |
-
font-size: 1.3em !important;
|
| 549 |
-
font-weight: 650 !important;
|
| 550 |
-
margin: 20px 0 12px 0 !important;
|
| 551 |
-
}
|
| 552 |
-
|
| 553 |
-
.gradio-markdown p {
|
| 554 |
-
color: #1e293b !important;
|
| 555 |
-
font-size: 1.1em !important;
|
| 556 |
-
line-height: 1.8 !important;
|
| 557 |
-
font-weight: 500 !important;
|
| 558 |
-
margin: 12px 0 !important;
|
| 559 |
-
text-align: left !important;
|
| 560 |
-
}
|
| 561 |
-
|
| 562 |
-
.gradio-markdown ul, .gradio-markdown ol {
|
| 563 |
-
color: #1e293b !important;
|
| 564 |
-
font-size: 1.1em !important;
|
| 565 |
-
line-height: 1.8 !important;
|
| 566 |
-
font-weight: 500 !important;
|
| 567 |
-
margin: 15px 0 !important;
|
| 568 |
-
padding-left: 25px !important;
|
| 569 |
-
}
|
| 570 |
-
|
| 571 |
-
.gradio-markdown li {
|
| 572 |
-
color: #1e293b !important;
|
| 573 |
-
font-size: 1.1em !important;
|
| 574 |
-
font-weight: 500 !important;
|
| 575 |
-
margin: 8px 0 !important;
|
| 576 |
-
padding: 5px 0 !important;
|
| 577 |
-
}
|
| 578 |
-
|
| 579 |
-
.gradio-markdown strong {
|
| 580 |
-
color: #0C5387 !important;
|
| 581 |
-
font-weight: 700 !important;
|
| 582 |
-
}
|
| 583 |
-
|
| 584 |
-
.gradio-markdown em {
|
| 585 |
-
color: #1A5F91 !important;
|
| 586 |
-
font-style: italic !important;
|
| 587 |
-
font-weight: 600 !important;
|
| 588 |
-
}
|
| 589 |
-
|
| 590 |
-
/* Highlight cho footer của báo cáo */
|
| 591 |
-
.gradio-markdown hr {
|
| 592 |
-
border: 0 !important;
|
| 593 |
-
height: 2px !important;
|
| 594 |
-
background: linear-gradient(90deg, transparent, #1A5F91, transparent) !important;
|
| 595 |
-
margin: 25px 0 15px 0 !important;
|
| 596 |
-
}
|
| 597 |
-
|
| 598 |
-
/* Style cho phần footer AI */
|
| 599 |
-
.gradio-markdown p:last-child {
|
| 600 |
-
text-align: center !important;
|
| 601 |
-
font-style: italic !important;
|
| 602 |
-
color: #64748b !important;
|
| 603 |
-
font-size: 0.95em !important;
|
| 604 |
-
margin-top: 20px !important;
|
| 605 |
-
padding: 15px !important;
|
| 606 |
-
background: rgba(26, 95, 145, 0.05) !important;
|
| 607 |
-
border-radius: 10px !important;
|
| 608 |
-
border: 1px solid rgba(26, 95, 145, 0.1) !important;
|
| 609 |
-
}
|
| 610 |
-
|
| 611 |
-
/* Glass morphism effects for modern look */
|
| 612 |
-
.glass-card {
|
| 613 |
-
background: rgba(255, 255, 255, 0.1);
|
| 614 |
-
backdrop-filter: blur(10px);
|
| 615 |
-
border: 1px solid rgba(255, 255, 255, 0.2);
|
| 616 |
-
border-radius: 16px;
|
| 617 |
-
padding: 20px;
|
| 618 |
-
margin: 10px 0;
|
| 619 |
-
box-shadow: 0 8px 32px rgba(31, 38, 135, 0.37);
|
| 620 |
-
}
|
| 621 |
-
|
| 622 |
-
.neon-border {
|
| 623 |
-
box-shadow:
|
| 624 |
-
0 0 5px rgba(12, 83, 135, 0.3),
|
| 625 |
-
0 0 10px rgba(12, 83, 135, 0.3),
|
| 626 |
-
0 0 15px rgba(12, 83, 135, 0.3),
|
| 627 |
-
0 0 20px rgba(12, 83, 135, 0.2),
|
| 628 |
-
inset 0 0 5px rgba(255, 255, 255, 0.1);
|
| 629 |
-
border: 1px solid rgba(12, 83, 135, 0.4);
|
| 630 |
-
animation: neonPulse 2s ease-in-out infinite alternate;
|
| 631 |
-
}
|
| 632 |
-
|
| 633 |
-
@keyframes neonPulse {
|
| 634 |
-
0% {
|
| 635 |
-
box-shadow:
|
| 636 |
-
0 0 5px rgba(12, 83, 135, 0.3),
|
| 637 |
-
0 0 10px rgba(12, 83, 135, 0.3),
|
| 638 |
-
0 0 15px rgba(12, 83, 135, 0.3),
|
| 639 |
-
inset 0 0 5px rgba(255, 255, 255, 0.1);
|
| 640 |
-
}
|
| 641 |
-
100% {
|
| 642 |
-
box-shadow:
|
| 643 |
-
0 0 10px rgba(12, 83, 135, 0.5),
|
| 644 |
-
0 0 20px rgba(12, 83, 135, 0.4),
|
| 645 |
-
0 0 30px rgba(12, 83, 135, 0.3),
|
| 646 |
-
0 0 40px rgba(12, 83, 135, 0.2),
|
| 647 |
-
inset 0 0 8px rgba(255, 255, 255, 0.2);
|
| 648 |
-
}
|
| 649 |
-
}
|
| 650 |
-
|
| 651 |
-
/* Modern button styling */
|
| 652 |
-
.btn-modern {
|
| 653 |
-
background: linear-gradient(90deg, #A9AAA9 0%, #8194A0 25%, #5A7E98 50%, #33688F 75%, #0C5387 100%);
|
| 654 |
-
border: none;
|
| 655 |
-
border-radius: 16px;
|
| 656 |
-
padding: 16px 32px;
|
| 657 |
-
color: white;
|
| 658 |
-
font-weight: 700;
|
| 659 |
-
text-transform: uppercase;
|
| 660 |
-
letter-spacing: 1.2px;
|
| 661 |
-
box-shadow: 0 8px 25px rgba(12, 83, 135, 0.3), 0 3px 8px rgba(0, 0, 0, 0.1);
|
| 662 |
-
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
|
| 663 |
-
position: relative;
|
| 664 |
-
overflow: hidden;
|
| 665 |
-
font-size: 0.95em;
|
| 666 |
-
}
|
| 667 |
-
|
| 668 |
-
.btn-modern::before {
|
| 669 |
-
content: '';
|
| 670 |
-
position: absolute;
|
| 671 |
-
top: 0;
|
| 672 |
-
left: -100%;
|
| 673 |
-
width: 100%;
|
| 674 |
-
height: 100%;
|
| 675 |
-
background: linear-gradient(90deg, transparent, rgba(255,255,255,0.3), transparent);
|
| 676 |
-
transition: left 0.6s;
|
| 677 |
-
}
|
| 678 |
-
|
| 679 |
-
.btn-modern:hover {
|
| 680 |
-
transform: translateY(-3px) scale(1.02);
|
| 681 |
-
box-shadow: 0 15px 40px rgba(12, 83, 135, 0.4), 0 8px 16px rgba(0, 0, 0, 0.15);
|
| 682 |
-
}
|
| 683 |
-
|
| 684 |
-
.btn-modern:hover::before {
|
| 685 |
-
left: 100%;
|
| 686 |
-
}
|
| 687 |
-
|
| 688 |
-
.btn-modern:active {
|
| 689 |
-
transform: translateY(-1px) scale(1.01);
|
| 690 |
-
}
|
| 691 |
-
|
| 692 |
-
/* Animated background gradients */
|
| 693 |
-
.bg-blue-grad {
|
| 694 |
-
background: linear-gradient(90deg, #A9AAA9 0%, #8194A0 25%, #5A7E98 50%, #33688F 75%, #0C5387 100%);
|
| 695 |
-
background-size: 200% 200%;
|
| 696 |
-
animation: gradientShift 4s ease-in-out infinite alternate;
|
| 697 |
-
}
|
| 698 |
-
|
| 699 |
-
.bg-gray-grad {
|
| 700 |
-
background: linear-gradient(90deg, #cbd5e1 0%, #94a3b8 25%, #64748b 50%, #475569 75%, #334155 100%);
|
| 701 |
-
background-size: 200% 200%;
|
| 702 |
-
animation: gradientShift 4s ease-in-out infinite alternate;
|
| 703 |
-
}
|
| 704 |
-
|
| 705 |
-
@keyframes gradientShift {
|
| 706 |
-
0% { background-position: 0% 50%; }
|
| 707 |
-
100% { background-position: 100% 50%; }
|
| 708 |
-
}
|
| 709 |
-
|
| 710 |
-
/* Tech-style borders and effects */
|
| 711 |
-
.tech-border {
|
| 712 |
-
position: relative;
|
| 713 |
-
border: 2px solid transparent;
|
| 714 |
-
border-radius: 16px;
|
| 715 |
-
background: linear-gradient(45deg, #A9AAA9, #8194A0, #5A7E98, #33688F, #0C5387) border-box;
|
| 716 |
-
mask: linear-gradient(#fff 0 0) padding-box, linear-gradient(#fff 0 0);
|
| 717 |
-
mask-composite: exclude;
|
| 718 |
-
-webkit-mask-composite: xor;
|
| 719 |
-
transition: all 0.3s ease;
|
| 720 |
-
}
|
| 721 |
-
|
| 722 |
-
.tech-border:hover {
|
| 723 |
-
box-shadow: 0 0 20px rgba(12, 83, 135, 0.3);
|
| 724 |
-
}
|
| 725 |
-
|
| 726 |
-
/* Holographic effect */
|
| 727 |
-
.holographic {
|
| 728 |
-
background: linear-gradient(45deg, #A9AAA9 0%, #8194A0 20%, #5A7E98 40%, #33688F 60%, #0C5387 80%, #A9AAA9 100%);
|
| 729 |
-
background-size: 400% 400%;
|
| 730 |
-
animation: hologram 6s ease-in-out infinite;
|
| 731 |
-
}
|
| 732 |
-
|
| 733 |
-
@keyframes hologram {
|
| 734 |
-
0%, 100% { background-position: 0% 50%; }
|
| 735 |
-
50% { background-position: 100% 50%; }
|
| 736 |
-
}
|
| 737 |
-
|
| 738 |
-
/* Floating animation for cards */
|
| 739 |
-
@keyframes float {
|
| 740 |
-
0%, 100% { transform: translateY(0px); }
|
| 741 |
-
50% { transform: translateY(-5px); }
|
| 742 |
-
}
|
| 743 |
-
|
| 744 |
-
.floating {
|
| 745 |
-
animation: float 3s ease-in-out infinite;
|
| 746 |
-
}
|
| 747 |
-
|
| 748 |
-
/* Modern card design */
|
| 749 |
-
.modern-card {
|
| 750 |
-
background: rgba(255, 255, 255, 0.1);
|
| 751 |
-
backdrop-filter: blur(20px);
|
| 752 |
-
border: 1px solid rgba(255, 255, 255, 0.2);
|
| 753 |
-
border-radius: 20px;
|
| 754 |
-
padding: 25px;
|
| 755 |
-
margin: 15px 0;
|
| 756 |
-
box-shadow:
|
| 757 |
-
0 8px 32px rgba(31, 38, 135, 0.37),
|
| 758 |
-
0 2px 8px rgba(0, 0, 0, 0.1);
|
| 759 |
-
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
|
| 760 |
-
position: relative;
|
| 761 |
-
overflow: hidden;
|
| 762 |
-
}
|
| 763 |
-
|
| 764 |
-
.modern-card::before {
|
| 765 |
-
content: '';
|
| 766 |
-
position: absolute;
|
| 767 |
-
top: 0;
|
| 768 |
-
left: 0;
|
| 769 |
-
right: 0;
|
| 770 |
-
height: 1px;
|
| 771 |
-
background: linear-gradient(90deg, transparent, rgba(255,255,255,0.8), transparent);
|
| 772 |
-
}
|
| 773 |
-
|
| 774 |
-
.modern-card:hover {
|
| 775 |
-
transform: translateY(-5px) scale(1.02);
|
| 776 |
-
box-shadow:
|
| 777 |
-
0 20px 60px rgba(12, 83, 135, 0.2),
|
| 778 |
-
0 8px 16px rgba(0, 0, 0, 0.15);
|
| 779 |
-
}
|
| 780 |
-
|
| 781 |
-
/* Info card styling */
|
| 782 |
-
.info-card {
|
| 783 |
-
background: linear-gradient(135deg,
|
| 784 |
-
rgba(255, 255, 255, 0.25) 0%,
|
| 785 |
-
rgba(255, 255, 255, 0.1) 50%,
|
| 786 |
-
rgba(255, 255, 255, 0.05) 100%);
|
| 787 |
-
backdrop-filter: blur(20px);
|
| 788 |
-
border: 1px solid rgba(255, 255, 255, 0.3);
|
| 789 |
-
border-radius: 24px;
|
| 790 |
-
padding: 30px;
|
| 791 |
-
margin: 20px 0;
|
| 792 |
-
box-shadow:
|
| 793 |
-
0 12px 40px rgba(12, 83, 135, 0.15),
|
| 794 |
-
0 4px 12px rgba(0, 0, 0, 0.1);
|
| 795 |
-
position: relative;
|
| 796 |
-
overflow: hidden;
|
| 797 |
-
}
|
| 798 |
-
|
| 799 |
-
.info-card::after {
|
| 800 |
-
content: '';
|
| 801 |
-
position: absolute;
|
| 802 |
-
top: -50%;
|
| 803 |
-
right: -50%;
|
| 804 |
-
width: 100%;
|
| 805 |
-
height: 200%;
|
| 806 |
-
background: conic-gradient(from 0deg, transparent, rgba(12, 83, 135, 0.1), transparent);
|
| 807 |
-
animation: rotate 8s linear infinite;
|
| 808 |
-
pointer-events: none;
|
| 809 |
-
}
|
| 810 |
-
|
| 811 |
-
@keyframes rotate {
|
| 812 |
-
0% { transform: rotate(0deg); }
|
| 813 |
-
100% { transform: rotate(360deg); }
|
| 814 |
-
}
|
| 815 |
-
|
| 816 |
-
/* Loading spinner enhancement - cải thiện animation */
|
| 817 |
-
.loading-spinner {
|
| 818 |
-
border: 4px solid rgba(255, 255, 255, 0.1);
|
| 819 |
-
border-top: 4px solid #00ff88;
|
| 820 |
-
border-right: 4px solid #0099ff;
|
| 821 |
-
border-radius: 50%;
|
| 822 |
-
width: 60px;
|
| 823 |
-
height: 60px;
|
| 824 |
-
animation: spin 1.2s linear infinite, pulse 2s ease-in-out infinite;
|
| 825 |
-
margin: 0 auto 25px;
|
| 826 |
-
box-shadow: 0 0 30px rgba(0, 255, 136, 0.4), 0 0 60px rgba(0, 153, 255, 0.2);
|
| 827 |
-
}
|
| 828 |
-
|
| 829 |
-
@keyframes spin {
|
| 830 |
-
0% { transform: rotate(0deg); }
|
| 831 |
-
100% { transform: rotate(360deg); }
|
| 832 |
-
}
|
| 833 |
-
|
| 834 |
-
@keyframes pulse {
|
| 835 |
-
0%, 100% { transform: scale(1); box-shadow: 0 0 30px rgba(0, 255, 136, 0.4); }
|
| 836 |
-
50% { transform: scale(1.05); box-shadow: 0 0 40px rgba(0, 255, 136, 0.6), 0 0 80px rgba(0, 153, 255, 0.3); }
|
| 837 |
-
}
|
| 838 |
-
|
| 839 |
-
/* Cải thiện progress bar */
|
| 840 |
-
.progress-bar {
|
| 841 |
-
background: rgba(255, 255, 255, 0.1);
|
| 842 |
-
border-radius: 15px;
|
| 843 |
-
height: 8px;
|
| 844 |
-
margin: 15px 0;
|
| 845 |
-
overflow: hidden;
|
| 846 |
-
box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.2);
|
| 847 |
-
}
|
| 848 |
-
|
| 849 |
-
.progress-fill {
|
| 850 |
-
background: linear-gradient(90deg, #00ff88, #0099ff, #00ff88);
|
| 851 |
-
height: 100%;
|
| 852 |
-
border-radius: 15px;
|
| 853 |
-
transition: width 0.5s ease-out;
|
| 854 |
-
animation: shimmer 2s infinite;
|
| 855 |
-
box-shadow: 0 0 10px rgba(0, 255, 136, 0.5);
|
| 856 |
-
}
|
| 857 |
-
|
| 858 |
-
@keyframes shimmer {
|
| 859 |
-
0% { background-position: -200% 0; }
|
| 860 |
-
100% { background-position: 200% 0; }
|
| 861 |
-
}
|
| 862 |
-
"""
|
| 863 |
-
|
| 864 |
-
def tao_loading_html(thong_diep: str, ti_le: float) -> str:
|
| 865 |
-
"""Tạo HTML loading với thanh tiến độ theo tỷ lệ [0..1]."""
|
| 866 |
-
pct = max(0, min(100, int(ti_le * 100)))
|
| 867 |
-
|
| 868 |
-
# Thêm các thông điệp chi tiết dựa trên tiến độ
|
| 869 |
-
chi_tiet_buoc = ""
|
| 870 |
-
if ti_le <= 0.25:
|
| 871 |
-
chi_tiet_buoc = "📡 Kết nối với AI Engine • 🔍 Phân tích cấu trúc dữ liệu"
|
| 872 |
-
elif ti_le <= 0.50:
|
| 873 |
-
chi_tiet_buoc = "🧹 Làm sạch và chuẩn hóa dữ liệu • 📈 Xác định xu hướng"
|
| 874 |
-
elif ti_le <= 0.75:
|
| 875 |
-
chi_tiet_buoc = "🧠 Huấn luyện mô hình ML • ⚡ Tối ưu hóa thuật toán"
|
| 876 |
-
else:
|
| 877 |
-
chi_tiet_buoc = "📊 Tạo insights • 🎯 Phân tích chiến lược • 📝 Hoàn thiện báo cáo"
|
| 878 |
-
|
| 879 |
-
return f"""
|
| 880 |
-
<div class="loading-container">
|
| 881 |
-
<div class="loading-spinner"></div>
|
| 882 |
-
<h3 style="color: white; margin: 0 0 10px 0; font-size: 18px; font-weight: 600;">{thong_diep}...</h3>
|
| 883 |
-
<div class="progress-bar">
|
| 884 |
-
<div class="progress-fill" style="width:{pct}%"></div>
|
| 885 |
-
</div>
|
| 886 |
-
<p style="color: rgba(255,255,255,0.9); margin: 15px 0 5px 0; font-size: 13px;">
|
| 887 |
-
{chi_tiet_buoc}
|
| 888 |
-
</p>
|
| 889 |
-
<p style="color: rgba(255,255,255,0.7); margin: 5px 0; font-size: 12px;">
|
| 890 |
-
🤖 FoxAI đang xử lý {pct}% • Vui lòng chờ trong giây lát...
|
| 891 |
-
</p>
|
| 892 |
-
</div>
|
| 893 |
-
"""
|
| 894 |
-
|
| 895 |
-
|
| 896 |
-
def hien_loading_tung_buoc():
|
| 897 |
-
"""Generator: stream 6 bước loading trong khoảng 5–8 giây để cảm giác thực tế hơn."""
|
| 898 |
-
tong_thoi_gian = random.uniform(5.0, 8.0) # Tăng thời gian loading
|
| 899 |
-
buoc = [
|
| 900 |
-
("� Đang khởi tạo hệ thống AI", 0.10),
|
| 901 |
-
("📊 Đang phân tích dữ liệu", 0.25),
|
| 902 |
-
("🧹 Đang tiến hành làm sạch dữ liệu", 0.45),
|
| 903 |
-
("🧠 Đang huấn luyện mô hình ML", 0.65),
|
| 904 |
-
("⚡ Đang tối ưu thuật toán", 0.85),
|
| 905 |
-
("📝 Đang tạo báo cáo với AI", 0.95),
|
| 906 |
-
]
|
| 907 |
-
|
| 908 |
-
# Thời gian ngẫu nhiên cho mỗi bước để tự nhiên hơn
|
| 909 |
-
for i, (thong_diep, ti_le) in enumerate(buoc):
|
| 910 |
-
yield tao_loading_html(thong_diep, ti_le)
|
| 911 |
-
|
| 912 |
-
# Thời gian delay ngẫu nhiên cho mỗi bước - tăng thời gian để thực tế hơn
|
| 913 |
-
if i < len(buoc) - 1: # Không delay ở bước cuối
|
| 914 |
-
if i == 3: # Bước huấn luyện ML - delay lâu hơn
|
| 915 |
-
buoc_delay = random.uniform(1.5, 2.5)
|
| 916 |
-
elif i == 4: # Bước tối ưu - delay vừa phải
|
| 917 |
-
buoc_delay = random.uniform(1.0, 1.8)
|
| 918 |
-
else:
|
| 919 |
-
buoc_delay = random.uniform(0.8, 1.4)
|
| 920 |
-
time.sleep(buoc_delay)
|
| 921 |
-
|
| 922 |
-
# Delay thêm một chút trước khi hoàn tất để user thấy tiến trình
|
| 923 |
-
time.sleep(0.8)
|
| 924 |
-
yield tao_loading_html("✅ Hoàn tất phân tích AI", 1.0)
|
| 925 |
-
|
| 926 |
-
# Delay cuối để user thấy trạng thái hoàn tất rõ ràng
|
| 927 |
-
time.sleep(0.6)
|
| 928 |
-
|
| 929 |
-
|
| 930 |
-
def doc_csv(file_obj):
|
| 931 |
-
"""Đọc CSV, trả preview + gợi ý cột thời gian/giá trị + state df."""
|
| 932 |
-
if file_obj is None:
|
| 933 |
-
return (
|
| 934 |
-
gr.update(visible=False),
|
| 935 |
-
gr.update(choices=[], value=None),
|
| 936 |
-
gr.update(choices=[], value=None),
|
| 937 |
-
None,
|
| 938 |
-
"<div class='info-card'>📂 Chưa chọn CSV.</div>",
|
| 939 |
-
)
|
| 940 |
-
try:
|
| 941 |
-
df = pd.read_csv(file_obj.name)
|
| 942 |
-
sample = df.head(100)
|
| 943 |
-
cols = list(df.columns)
|
| 944 |
-
|
| 945 |
-
# Đoán cột thời gian và giá trị
|
| 946 |
-
guess_date = next(
|
| 947 |
-
(c for c in cols if any(k in c.lower() for k in ["date", "time", "ngay", "thoi"])),
|
| 948 |
-
cols[0] if cols else None,
|
| 949 |
-
)
|
| 950 |
-
numeric_cols = [c for c in cols if pd.api.types.is_numeric_dtype(df[c])]
|
| 951 |
-
guess_value = numeric_cols[0] if numeric_cols else (cols[1] if len(cols) > 1 else cols[0])
|
| 952 |
-
|
| 953 |
-
thong_bao = f"<div class='info-card'>✅ CSV đã tải: {len(df):,} dòng, {len(cols)} cột.</div>"
|
| 954 |
-
return (
|
| 955 |
-
gr.update(visible=True, value=sample),
|
| 956 |
-
gr.update(choices=cols, value=guess_date),
|
| 957 |
-
gr.update(choices=cols, value=guess_value),
|
| 958 |
-
df,
|
| 959 |
-
thong_bao,
|
| 960 |
-
)
|
| 961 |
-
except Exception as exc:
|
| 962 |
-
msg = f"<div class='info-card'>❌ Lỗi đọc CSV: {exc}</div>"
|
| 963 |
-
return (
|
| 964 |
-
gr.update(visible=False),
|
| 965 |
-
gr.update(choices=[], value=None),
|
| 966 |
-
gr.update(choices=[], value=None),
|
| 967 |
-
None,
|
| 968 |
-
msg,
|
| 969 |
-
)
|
| 970 |
-
|
| 971 |
-
|
| 972 |
-
def tao_chuoi_tu_csv(
|
| 973 |
-
df_user: pd.DataFrame,
|
| 974 |
-
cot_ngay: str,
|
| 975 |
-
cot_gia_tri: str,
|
| 976 |
-
che_do_xem: str,
|
| 977 |
-
):
|
| 978 |
-
"""
|
| 979 |
-
Từ CSV -> (nhãn thời gian, giá trị) theo chế độ xem:
|
| 980 |
-
'ngày' = theo ngày, 'tháng' = theo tuần, 'năm' = theo tháng.
|
| 981 |
-
"""
|
| 982 |
-
if df_user is None or not cot_ngay or not cot_gia_tri:
|
| 983 |
-
return None, None
|
| 984 |
-
|
| 985 |
-
df = df_user.copy()
|
| 986 |
-
df[cot_ngay] = pd.to_datetime(df[cot_ngay], errors="coerce")
|
| 987 |
-
df = df.dropna(subset=[cot_ngay, cot_gia_tri])
|
| 988 |
-
df = df.sort_values(cot_ngay)
|
| 989 |
-
|
| 990 |
-
if df.empty:
|
| 991 |
-
return None, None
|
| 992 |
-
|
| 993 |
-
if che_do_xem == "ngày":
|
| 994 |
-
ser = df.groupby(df[cot_ngay].dt.date)[cot_gia_tri].sum()
|
| 995 |
-
nhan = [d.strftime("%d/%m") for d in pd.to_datetime(ser.index)]
|
| 996 |
-
elif che_do_xem == "tháng": # theo tuần
|
| 997 |
-
ser = df.set_index(cot_ngay)[cot_gia_tri].resample("W").sum()
|
| 998 |
-
nhan = [idx.strftime("Tuần %W/%Y") for idx in ser.index]
|
| 999 |
-
else: # 'năm' = theo tháng
|
| 1000 |
-
ser = df.set_index(cot_ngay)[cot_gia_tri].resample("M").sum()
|
| 1001 |
-
nhan = [idx.strftime("%m/%Y") for idx in ser.index]
|
| 1002 |
-
|
| 1003 |
-
gia_tri = ser.astype(float).tolist()
|
| 1004 |
-
if len(gia_tri) < 3:
|
| 1005 |
-
# Dọn cho gọn, biểu đồ ít hơn 3 điểm nhìn hơi thảm
|
| 1006 |
-
return None, None
|
| 1007 |
-
|
| 1008 |
-
return nhan, gia_tri
|
| 1009 |
-
|
| 1010 |
-
# Dữ liệu demo tiếng Việt cho 3 trường hợp chính
|
| 1011 |
-
TRUONG_HOP_DEMO = {
|
| 1012 |
-
"📱 Điện tử & Công nghệ": {
|
| 1013 |
-
"danh_muc": "Điện tử & Công nghệ",
|
| 1014 |
-
"don_vi_co_ban": 150,
|
| 1015 |
-
"xu_huong": "tang_dan",
|
| 1016 |
-
"mo_ta": "Dự báo bán hàng sản phẩm điện tử, smartphone, laptop và thiết bị công nghệ",
|
| 1017 |
-
"thong_tin_giam_doc": {
|
| 1018 |
-
"tom_tat": "📈 **TÓM TẮT ĐIỀU HÀNH:** Thị trường điện tử có xu hướng tăng trưởng mạnh 180-250% với sự phát triển của công nghệ AI, 5G và IoT. Đây là cơ hội vàng để chiếm lĩnh thị phần.",
|
| 1019 |
-
"chi_tiet": "**📊 PHÂN TÍCH KINH DOANH SÂU SẮC:** Thị trường điện tử đang trải qua làn sóng tăng trưởng mạnh với mức tăng 180-250% do several factors: (1) Digital transformation gia tăng sau COVID, (2) Work from home trend tạo nhu cầu laptop/monitor, (3) Gen Z có spending power cao cho gadgets, (4) AI boom tạo nhu cầu hardware mạnh. Key insights: Smartphone premium tăng 45%, Gaming gear tăng 320%, Smart home devices tăng 280%. Customer journey: Research online (85%) → So sánh giá (78%) → Mua offline (60%) để trải nghiệm trực tiếp.",
|
| 1020 |
-
"hanh_dong": "**🎯 KHUYẾN NGHỊ ĐIỀU HÀNH CHIẾN LƯỢC:** (1) **Inventory Strategy:** Tăng tồn kho 200% cho flagship models, đặc biệt iPhone/Samsung dòng cao cấp và gaming laptops, (2) **Digital Integration:** Xây dựng AR/VR showroom để khách hàng try before buy, (3) **Partnership Ecosystem:** Hợp tác với fintech cho installment 0%, tie-up với game publishers cho gaming bundle, (4) **Market Expansion:** Mở rộng sang smart home ecosystem với IoT devices, (5) **After-sales Excellence:** Extended warranty và premium support để tăng customer lifetime value và build brand loyalty."
|
| 1021 |
-
}
|
| 1022 |
-
},
|
| 1023 |
-
|
| 1024 |
-
"👕 Thời trang & Làm đẹp": {
|
| 1025 |
-
"danh_muc": "Thời trang & Làm đẹp",
|
| 1026 |
-
"don_vi_co_ban": 80,
|
| 1027 |
-
"xu_huong": "bien_dong",
|
| 1028 |
-
"mo_ta": "Dự báo xu hướng thời trang, mỹ phẩm và các sản phẩm làm đẹp theo mùa",
|
| 1029 |
-
"thong_tin_giam_doc": {
|
| 1030 |
-
"tom_tat": "☀️ **TÓM TẮT ĐIỀU HÀNH:** Thời trang & làm đẹp có tính mùa vụ rõ rệt với biến động 15-180% theo trend và influencer impact. Cần strategy linh hoạt để maximize các peak seasons.",
|
| 1031 |
-
"chi_tiet": "**📈 PHÂN TÍCH THỊ TRƯỜNG FASHION & BEAUTY:** Industry có pattern rất đặc biệt với multiple micro-seasons: (1) Spring/Summer collection (Mar-Aug) peak 170%, (2) Fall/Winter collection (Sep-Feb) stable 120%, (3) Special events (Valentine +240%, Tết +185%, graduation season +150%). Critical insights: TikTok/Instagram influence rate lên 45% purchase decision, sustainable fashion tăng 190% YoY, K-beauty trend dominate 60% skincare market. Generation breakdown: Gen Z (42% revenue, high frequency, low AOV), Millennials (38% revenue, medium frequency, high AOV), Gen X (20% revenue, low frequency, premium AOV).",
|
| 1032 |
-
"hanh_dong": "**💡 CHIẾN LƯỢC THỰC THI OMNICHANNEL:** (1) **Trend Forecasting:** AI-powered trend analysis từ social media để predict viral products 2-3 months trước, (2) **Influencer Partnership:** Collaborate với 50+ nano/micro influencers (10K-100K followers) cho authentic engagement thay vì 1-2 mega influencers, (3) **Inventory Agility:** Fast fashion model với small batch testing → scale winners rapidly, (4) **Personalization Engine:** Skin analysis app + virtual try-on technology để tăng conversion rate, (5) **Sustainability Edge:** Launch eco-friendly line với packaging innovation để capture conscious consumers và justify premium pricing."
|
| 1033 |
-
}
|
| 1034 |
-
},
|
| 1035 |
-
|
| 1036 |
-
"🍔 Thực phẩm & Đồ uống": {
|
| 1037 |
-
"danh_muc": "Thực phẩm & Đồ uống",
|
| 1038 |
-
"don_vi_co_ban": 200,
|
| 1039 |
-
"xu_huong": "on_dinh",
|
| 1040 |
-
"mo_ta": "Dự báo thị trường F&B, food delivery và các sản phẩm tiêu dùng hàng ngày",
|
| 1041 |
-
"thong_tin_giam_doc": {
|
| 1042 |
-
"tom_tat": "🍽️ **TÓM TẮT ĐIỀU HÀNH:** F&B market ổn định với baseline consumption nhưng có opportunity spikes từ weather, events và lifestyle changes. Delivery segment tăng 280%, healthy food trend tăng 165%.",
|
| 1043 |
-
"chi_tiet": "**⛈️ PHÂN TÍCH F&B MARKET DYNAMICS:** F&B industry có đặc điểm unique với stable baseline demand nhưng high weather sensitivity và event-driven spikes. Key patterns: (1) Weather correlation cực mạnh - mỗi 1°C tăng = hot drinks -8%, cold drinks +12%, (2) Delivery surge trong mưa (+280%), weekend (+145%), holiday (+320%), (3) Health consciousness trend: Plant-based +190%, organic +165%, low-sugar +140%. Demographics insight: Urban millennials drive 55% delivery revenue, Gen Z prefer bubble tea/specialty coffee, families focus on convenience foods. Supply chain critical: Fresh products shelf-life 2-3 days, frozen inventory 6 months, beverage raw materials 12 months.",
|
| 1044 |
-
"hanh_dong": "**☔ CHIẾN THUẬT WEATHER-RESPONSIVE F&B:** (1) **Predictive Inventory:** Weather API integration để auto-adjust inventory 48h trước based on forecast - rain = +200% comfort food, heat = +150% cold beverages, (2) **Delivery Optimization:** Dynamic delivery zones expansion trong bad weather, surge pricing strategy để incentivize drivers, ghost kitchen positioning ở high-density areas, (3) **Health & Wellness Pivot:** Launch functional beverages (immunity boost, energy, beauty), partner với gyms/yoga studios, subscription healthy meal plans, (4) **Experience Innovation:** Interactive cooking classes, farm-to-table storytelling, sustainable packaging để build brand differentiation, (5) **Data-Driven Menu:** Customer preference analytics để optimize menu mix và eliminate low-performers monthly."
|
| 1045 |
-
}
|
| 1046 |
-
}
|
| 1047 |
-
}
|
| 1048 |
-
|
| 1049 |
-
def tao_bieu_do_mac_dinh():
|
| 1050 |
-
"""Tạo biểu đồ mặc định khi chưa dự đoán"""
|
| 1051 |
-
fig = go.Figure()
|
| 1052 |
-
|
| 1053 |
-
fig.add_annotation(
|
| 1054 |
-
text="📊 Chọn mặt hàng và nhấn 'Tạo Dự Báo AI' để xem phân tích",
|
| 1055 |
-
xref="paper", yref="paper",
|
| 1056 |
-
x=0.5, y=0.5,
|
| 1057 |
-
xanchor='center', yanchor='middle',
|
| 1058 |
-
showarrow=False,
|
| 1059 |
-
font=dict(size=18, color="#34495E", family="Arial"),
|
| 1060 |
-
bgcolor="rgba(255,255,255,0.9)",
|
| 1061 |
-
bordercolor="#BDC3C7",
|
| 1062 |
-
borderwidth=2,
|
| 1063 |
-
borderpad=20
|
| 1064 |
-
)
|
| 1065 |
-
|
| 1066 |
-
fig.update_layout(
|
| 1067 |
-
title="🎯 Hệ Thống Dự Báo AI Sẵn Sàng",
|
| 1068 |
-
template="plotly_white",
|
| 1069 |
-
height=450,
|
| 1070 |
-
showlegend=False,
|
| 1071 |
-
xaxis=dict(
|
| 1072 |
-
showgrid=False,
|
| 1073 |
-
showticklabels=False,
|
| 1074 |
-
title="",
|
| 1075 |
-
automargin=True
|
| 1076 |
-
),
|
| 1077 |
-
yaxis=dict(
|
| 1078 |
-
showgrid=False,
|
| 1079 |
-
showticklabels=False,
|
| 1080 |
-
title="",
|
| 1081 |
-
automargin=True
|
| 1082 |
-
),
|
| 1083 |
-
plot_bgcolor='rgba(248,249,250,0.9)',
|
| 1084 |
-
paper_bgcolor='rgba(255,255,255,0.95)',
|
| 1085 |
-
font=dict(family="Inter, Arial, sans-serif", size=14),
|
| 1086 |
-
margin=dict(l=40, r=40, t=80, b=40)
|
| 1087 |
-
)
|
| 1088 |
-
|
| 1089 |
-
return fig
|
| 1090 |
-
|
| 1091 |
-
def tao_tom_tat_mac_dinh():
|
| 1092 |
-
"""Tạo tóm tắt mặc định"""
|
| 1093 |
-
return """
|
| 1094 |
-
<div class="prediction-box">
|
| 1095 |
-
<h3 style="margin-top: 0; color: white;">📋 Thống Kê Sẽ Hiển Thị Sau Dự Báo</h3>
|
| 1096 |
-
<div style="text-align: center; padding: 20px;">
|
| 1097 |
-
<p style="font-size: 18px; margin: 10px 0; color: white;">
|
| 1098 |
-
🎯 Chọn mặt hàng dự đoán và nhấn "Tạo Dự Báo AI"
|
| 1099 |
-
</p>
|
| 1100 |
-
<p style="font-size: 16px; margin: 10px 0; color: #E8F6F3;">
|
| 1101 |
-
Hệ thống sẽ phân tích và đưa ra insights chi tiết
|
| 1102 |
-
</p>
|
| 1103 |
-
</div>
|
| 1104 |
-
</div>
|
| 1105 |
-
"""
|
| 1106 |
-
|
| 1107 |
-
def tao_du_lieu_demo(thong_tin_case, chu_ky="3 tháng", che_do_xem='ngày'):
|
| 1108 |
-
"""Tạo dữ liệu demo đơn giản dựa trên case và chu kỳ dự báo"""
|
| 1109 |
-
don_vi_co_ban = thong_tin_case["don_vi_co_ban"]
|
| 1110 |
-
xu_huong = thong_tin_case["xu_huong"]
|
| 1111 |
-
|
| 1112 |
-
# Tạo seed để random ổn định dựa trên parameters
|
| 1113 |
-
seed_value = hash((thong_tin_case["danh_muc"], chu_ky, che_do_xem)) & 0xFFFFFFFF
|
| 1114 |
-
rng = random.Random(seed_value)
|
| 1115 |
-
|
| 1116 |
-
# Xác định số điểm dữ liệu
|
| 1117 |
-
if chu_ky == "1 năm":
|
| 1118 |
-
so_diem = 12 if che_do_xem == 'năm' else (52 if che_do_xem == 'tháng' else 365)
|
| 1119 |
-
elif chu_ky == "6 tháng":
|
| 1120 |
-
so_diem = 6 if che_do_xem == 'năm' else (26 if che_do_xem == 'tháng' else 180)
|
| 1121 |
-
else: # "3 tháng"
|
| 1122 |
-
so_diem = 3 if che_do_xem == 'năm' else (13 if che_do_xem == 'tháng' else 90)
|
| 1123 |
-
|
| 1124 |
-
# Tạo nhãn thời gian
|
| 1125 |
-
if che_do_xem == 'năm':
|
| 1126 |
-
nhan_thoi_gian = [f"Tháng {i+1}" for i in range(so_diem)]
|
| 1127 |
-
elif che_do_xem == 'tháng':
|
| 1128 |
-
nhan_thoi_gian = [f"Tuần {i+1}" for i in range(so_diem)]
|
| 1129 |
-
else: # ngày
|
| 1130 |
-
ngay_bat_dau = datetime.now()
|
| 1131 |
-
nhan_thoi_gian = [(ngay_bat_dau + timedelta(days=i)).strftime("%d/%m") for i in range(so_diem)]
|
| 1132 |
-
|
| 1133 |
-
# Tạo dữ liệu dựa trên xu hướng đơn giản
|
| 1134 |
-
don_vi_ban = []
|
| 1135 |
-
for i in range(so_diem):
|
| 1136 |
-
if xu_huong == "tang_dan":
|
| 1137 |
-
he_so = 1.0 + (i * 0.2) # Tăng dần theo thời gian
|
| 1138 |
-
elif xu_huong == "bien_dong":
|
| 1139 |
-
he_so = 1.0 + np.sin(i * 0.5) * 0.3 # Biến động theo sin
|
| 1140 |
-
elif xu_huong == "on_dinh":
|
| 1141 |
-
he_so = 1.0 + rng.uniform(-0.1, 0.1) # Ổn định với chút biến động
|
| 1142 |
-
else:
|
| 1143 |
-
he_so = 1.0
|
| 1144 |
-
|
| 1145 |
-
don_vi = max(int(don_vi_co_ban * he_so + rng.randint(-30, 30)), 10)
|
| 1146 |
-
don_vi_ban.append(don_vi)
|
| 1147 |
-
|
| 1148 |
-
return nhan_thoi_gian, don_vi_ban
|
| 1149 |
-
|
| 1150 |
-
def tao_bieu_do_du_doan(
|
| 1151 |
-
ten_case,
|
| 1152 |
-
chu_ky="3 tháng",
|
| 1153 |
-
che_do_xem="ngày",
|
| 1154 |
-
df_user=None,
|
| 1155 |
-
cot_ngay=None,
|
| 1156 |
-
cot_gia_tri=None,
|
| 1157 |
-
):
|
| 1158 |
-
"""Tạo biểu đồ dự đoán. Luôn dùng demo data."""
|
| 1159 |
-
# Luôn dùng demo data (không phân tích CSV thật)
|
| 1160 |
-
thong_tin_case = TRUONG_HOP_DEMO[ten_case]
|
| 1161 |
-
nhan_thoi_gian, don_vi_ban = tao_du_lieu_demo(thong_tin_case, chu_ky, che_do_xem)
|
| 1162 |
-
|
| 1163 |
-
# Tạo biểu đồ chuyên nghiệp
|
| 1164 |
-
fig = go.Figure()
|
| 1165 |
-
|
| 1166 |
-
# Biểu đồ chính
|
| 1167 |
-
fig.add_trace(go.Scatter(
|
| 1168 |
-
x=nhan_thoi_gian,
|
| 1169 |
-
y=don_vi_ban,
|
| 1170 |
-
mode='lines+markers',
|
| 1171 |
-
name='📦 Dự Báo Đơn Vị Bán',
|
| 1172 |
-
line=dict(color='#1A5F91', width=4),
|
| 1173 |
-
marker=dict(size=12, color='#1A5F91', symbol='circle'),
|
| 1174 |
-
hovertemplate='<b>%{x}</b><br><b>Đơn vị bán:</b> %{y:,}<extra></extra>'
|
| 1175 |
-
))
|
| 1176 |
-
|
| 1177 |
-
# Vùng tin cậy
|
| 1178 |
-
upper_bound = [val * 1.15 for val in don_vi_ban]
|
| 1179 |
-
lower_bound = [val * 0.85 for val in don_vi_ban]
|
| 1180 |
-
|
| 1181 |
-
fig.add_trace(go.Scatter(
|
| 1182 |
-
x=nhan_thoi_gian + nhan_thoi_gian[::-1],
|
| 1183 |
-
y=upper_bound + lower_bound[::-1],
|
| 1184 |
-
fill='toself',
|
| 1185 |
-
fillcolor='rgba(26, 95, 145, 0.2)',
|
| 1186 |
-
line=dict(color='rgba(255,255,255,0)'),
|
| 1187 |
-
name='📊 Vùng Tin Cậy',
|
| 1188 |
-
hoverinfo="skip"
|
| 1189 |
-
))
|
| 1190 |
-
|
| 1191 |
-
# Đường xu hướng
|
| 1192 |
-
x_so = list(range(len(nhan_thoi_gian)))
|
| 1193 |
-
z = np.polyfit(x_so, don_vi_ban, 1)
|
| 1194 |
-
duong_xu_huong = np.poly1d(z)(x_so)
|
| 1195 |
-
|
| 1196 |
-
fig.add_trace(go.Scatter(
|
| 1197 |
-
x=nhan_thoi_gian,
|
| 1198 |
-
y=duong_xu_huong,
|
| 1199 |
-
mode='lines',
|
| 1200 |
-
name='📈 Xu Hướng',
|
| 1201 |
-
line=dict(color='#8B8B8B', width=3, dash='dash'),
|
| 1202 |
-
hovertemplate='<b>Xu hướng:</b> %{y:.0f}<extra></extra>'
|
| 1203 |
-
))
|
| 1204 |
-
|
| 1205 |
-
# Đánh dấu ngày đỉnh
|
| 1206 |
-
chi_so_dinh = [i for i, val in enumerate(don_vi_ban) if val == max(don_vi_ban)]
|
| 1207 |
-
if chi_so_dinh:
|
| 1208 |
-
chi_so = chi_so_dinh[0]
|
| 1209 |
-
fig.add_trace(go.Scatter(
|
| 1210 |
-
x=[nhan_thoi_gian[chi_so]],
|
| 1211 |
-
y=[don_vi_ban[chi_so]],
|
| 1212 |
-
mode='markers',
|
| 1213 |
-
name='🔥 Đỉnh Doanh Số',
|
| 1214 |
-
marker=dict(size=20, color='#F39C12', symbol='star'),
|
| 1215 |
-
hovertemplate='<b>Đỉnh cao:</b> %{x}<br><b>Đơn vị:</b> %{y:,}<extra></extra>'
|
| 1216 |
-
))
|
| 1217 |
-
|
| 1218 |
-
# Tiêu đề theo chế độ xem
|
| 1219 |
-
tieu_de_che_do = {
|
| 1220 |
-
'ngày': 'Theo Ngày',
|
| 1221 |
-
'tháng': 'Theo Tháng',
|
| 1222 |
-
'năm': 'Theo Năm'
|
| 1223 |
-
}
|
| 1224 |
-
|
| 1225 |
-
fig.update_layout(
|
| 1226 |
-
title=f"📊 Dự Báo Đơn Vị Bán - {tieu_de_che_do[che_do_xem]}: {ten_case} ({chu_ky})",
|
| 1227 |
-
xaxis_title="⏰ Thời Gian",
|
| 1228 |
-
yaxis_title="📦 Số Đơn Vị Bán",
|
| 1229 |
-
template="plotly_white",
|
| 1230 |
-
height=650, # Tăng chiều cao để có đủ không gian
|
| 1231 |
-
showlegend=True,
|
| 1232 |
-
hovermode='x unified',
|
| 1233 |
-
xaxis=dict(
|
| 1234 |
-
tickangle=45 if che_do_xem == 'ngày' else 0,
|
| 1235 |
-
fixedrange=True, # Không cho phép zoom để ổn định
|
| 1236 |
-
range=None,
|
| 1237 |
-
tickmode='auto',
|
| 1238 |
-
nticks=10, # Giới hạn số lượng tick để tránh chen chúc
|
| 1239 |
-
automargin=True # Tự động điều chỉnh margin cho labels
|
| 1240 |
-
),
|
| 1241 |
-
yaxis=dict(
|
| 1242 |
-
fixedrange=True, # Không cho phép zoom để ổn định
|
| 1243 |
-
range=None,
|
| 1244 |
-
automargin=True # Tự động điều chỉnh margin cho labels
|
| 1245 |
-
),
|
| 1246 |
-
font=dict(size=12, family="Inter, Arial, sans-serif"),
|
| 1247 |
-
plot_bgcolor='rgba(248,249,250,0.9)',
|
| 1248 |
-
paper_bgcolor='rgba(255,255,255,0.95)',
|
| 1249 |
-
# Tăng margin để tránh dính chữ
|
| 1250 |
-
margin=dict(l=80, r=60, t=120, b=100),
|
| 1251 |
-
# Dùng token động để chart cập nhật đúng khi thay đổi
|
| 1252 |
-
uirevision=f"{ten_case}|{chu_ky}|{che_do_xem}|{len(nhan_thoi_gian)}"
|
| 1253 |
-
)
|
| 1254 |
-
|
| 1255 |
-
# Ẩn hoàn toàn toolbar và config của biểu đồ
|
| 1256 |
-
config = {
|
| 1257 |
-
'displayModeBar': False, # Ẩn hoàn toàn toolbar
|
| 1258 |
-
'staticPlot': True, # Làm biểu đồ tĩnh, không tương tác
|
| 1259 |
-
'displaylogo': False,
|
| 1260 |
-
'responsive': True,
|
| 1261 |
-
'editable': False,
|
| 1262 |
-
'showTips': False,
|
| 1263 |
-
'watermark': False
|
| 1264 |
-
}
|
| 1265 |
-
|
| 1266 |
-
# Config sẽ được Gradio xử lý để ẩn toolbar hoàn toàn
|
| 1267 |
-
|
| 1268 |
-
return fig
|
| 1269 |
-
|
| 1270 |
-
def tao_thong_tin_tom_tat(
|
| 1271 |
-
ten_case,
|
| 1272 |
-
chu_ky="3 tháng",
|
| 1273 |
-
che_do_xem="ngày",
|
| 1274 |
-
df_user=None,
|
| 1275 |
-
cot_ngay=None,
|
| 1276 |
-
cot_gia_tri=None,
|
| 1277 |
-
):
|
| 1278 |
-
"""Tính toán thống kê. Ưu tiên CSV nếu có."""
|
| 1279 |
-
# Luôn dùng demo data (không phân tích CSV thật)
|
| 1280 |
-
thong_tin_case = TRUONG_HOP_DEMO[ten_case]
|
| 1281 |
-
nhan_thoi_gian, don_vi_ban = tao_du_lieu_demo(thong_tin_case, chu_ky, che_do_xem)
|
| 1282 |
-
|
| 1283 |
-
tong_don_vi = sum(don_vi_ban)
|
| 1284 |
-
trung_binh = tong_don_vi / len(don_vi_ban)
|
| 1285 |
-
ngay_dinh = max(don_vi_ban)
|
| 1286 |
-
ngay_thap = min(don_vi_ban)
|
| 1287 |
-
ty_le_tang_truong = ((don_vi_ban[-1] - don_vi_ban[0]) / don_vi_ban[0]) * 100
|
| 1288 |
-
|
| 1289 |
-
# Tính toán theo chế độ xem
|
| 1290 |
-
don_vi_thoi_gian = {
|
| 1291 |
-
'ngày': 'ngày',
|
| 1292 |
-
'tháng': 'tuần',
|
| 1293 |
-
'năm': 'tháng'
|
| 1294 |
-
}[che_do_xem]
|
| 1295 |
-
|
| 1296 |
-
tom_tat_html = f"""
|
| 1297 |
-
<div class="prediction-box">
|
| 1298 |
-
<h3 style="margin-top: 0; color: white;">📋 Báo Cáo Dự Báo Điều Hành</h3>
|
| 1299 |
-
<div style="display: grid; grid-template-columns: repeat(2, 1fr); gap: 15px;">
|
| 1300 |
-
<div style="background: rgba(255,255,255,0.2); padding: 15px; border-radius: 8px;">
|
| 1301 |
-
<h4 style="margin: 0; color: #E8F6F3;">📦 Tổng Đơn Vị</h4>
|
| 1302 |
-
<p style="font-size: 24px; margin: 5px 0; font-weight: bold;">{tong_don_vi:,}</p>
|
| 1303 |
-
</div>
|
| 1304 |
-
<div style="background: rgba(255,255,255,0.2); padding: 15px; border-radius: 8px;">
|
| 1305 |
-
<h4 style="margin: 0; color: #E8F6F3;">📈 TB/{don_vi_thoi_gian.title()}</h4>
|
| 1306 |
-
<p style="font-size: 24px; margin: 5px 0; font-weight: bold;">{trung_binh:,.0f}</p>
|
| 1307 |
-
</div>
|
| 1308 |
-
<div style="background: rgba(255,255,255,0.2); padding: 15px; border-radius: 8px;">
|
| 1309 |
-
<h4 style="margin: 0; color: #E8F6F3;">🔥 Đỉnh Cao</h4>
|
| 1310 |
-
<p style="font-size: 24px; margin: 5px 0; font-weight: bold;">{ngay_dinh:,}</p>
|
| 1311 |
-
</div>
|
| 1312 |
-
<div style="background: rgba(255,255,255,0.2); padding: 15px; border-radius: 8px;">
|
| 1313 |
-
<h4 style="margin: 0; color: #E8F6F3;">📊 Tăng Trưởng</h4>
|
| 1314 |
-
<p style="font-size: 24px; margin: 5px 0; font-weight: bold; color: {'#2ECC71' if ty_le_tang_truong > 0 else '#E74C3C'};">
|
| 1315 |
-
{ty_le_tang_truong:+.1f}%
|
| 1316 |
-
</p>
|
| 1317 |
-
</div>
|
| 1318 |
-
</div>
|
| 1319 |
-
<div style="margin-top: 15px; text-align: center;">
|
| 1320 |
-
<p style="margin: 0; font-size: 16px; color: white;">📅 Chu Kỳ Dự Báo: <strong>{chu_ky}</strong></p>
|
| 1321 |
-
<p style="margin: 5px 0; font-size: 14px; opacity: 0.9; color: white;">Danh Mục: <strong>{thong_tin_case['danh_muc']}</strong></p>
|
| 1322 |
-
</div>
|
| 1323 |
-
</div>
|
| 1324 |
-
"""
|
| 1325 |
-
|
| 1326 |
-
return tom_tat_html
|
| 1327 |
-
|
| 1328 |
-
def tao_bao_cao_giam_doc(ten_case):
|
| 1329 |
-
"""Tạo báo cáo chi tiết dành cho giám đốc - trả về Markdown"""
|
| 1330 |
-
thong_tin_case = TRUONG_HOP_DEMO[ten_case]
|
| 1331 |
-
thong_tin_gd = thong_tin_case['thong_tin_giam_doc']
|
| 1332 |
-
|
| 1333 |
-
bao_cao_markdown = f"""
|
| 1334 |
-
# 🎯 CHIẾN LƯỢC ĐỀ XUẤT
|
| 1335 |
-
|
| 1336 |
-
## 📈 Tóm Tắt Điều Hành
|
| 1337 |
-
|
| 1338 |
-
{thong_tin_gd['tom_tat']}
|
| 1339 |
-
|
| 1340 |
-
## 📊 Phân Tích Chi Tiết
|
| 1341 |
-
|
| 1342 |
-
{thong_tin_gd['chi_tiet']}
|
| 1343 |
-
|
| 1344 |
-
## 🚀 Khuyến Nghị Hành Động
|
| 1345 |
-
|
| 1346 |
-
{thong_tin_gd['hanh_dong']}
|
| 1347 |
-
|
| 1348 |
-
---
|
| 1349 |
-
*🤖 Phân tích được tạo bởi FoxAI Business Intelligence | ⚡ Cập nhật realtime*
|
| 1350 |
-
"""
|
| 1351 |
-
|
| 1352 |
-
return bao_cao_markdown
|
| 1353 |
-
|
| 1354 |
-
def tao_loading_effect():
|
| 1355 |
-
"""Tạo hiệu ứng loading để có cảm giác như production"""
|
| 1356 |
-
loading_html = """
|
| 1357 |
-
<div class="loading-container">
|
| 1358 |
-
<div class="loading-spinner"></div>
|
| 1359 |
-
<h3 style="color: white; margin: 0;">🤖 Đang Xử Lý Dự Báo AI...</h3>
|
| 1360 |
-
<div class="progress-bar">
|
| 1361 |
-
<div class="progress-fill"></div>
|
| 1362 |
-
</div>
|
| 1363 |
-
<p style="color: white; margin: 10px 0; opacity: 0.9;">
|
| 1364 |
-
⚡ Phân tích dữ liệu • 🧠 Machine Learning • 📊 Tạo insights • 🎯 Chiến lược AI
|
| 1365 |
-
</p>
|
| 1366 |
-
</div>
|
| 1367 |
-
"""
|
| 1368 |
-
return loading_html
|
| 1369 |
-
|
| 1370 |
-
def tao_bao_cao_streaming(ten_case):
|
| 1371 |
-
"""Tạo báo cáo với hiệu ứng streaming như AI đang viết"""
|
| 1372 |
-
import time
|
| 1373 |
-
thong_tin_case = TRUONG_HOP_DEMO[ten_case]
|
| 1374 |
-
thong_tin_gd = thong_tin_case['thong_tin_giam_doc']
|
| 1375 |
-
|
| 1376 |
-
# Nội dung đầy đủ với formatting tốt hơn
|
| 1377 |
-
noi_dung_day_du = f"""# 🎯 CHIẾN LƯỢC ĐỀ XUẤT CHO {ten_case.upper()}
|
| 1378 |
-
|
| 1379 |
-
## 📈 **Tóm Tắt Điều Hành**
|
| 1380 |
-
|
| 1381 |
-
**{thong_tin_gd['tom_tat']}**
|
| 1382 |
-
|
| 1383 |
-
## 📊 **Phân Tích Chi Tiết**
|
| 1384 |
-
|
| 1385 |
-
{thong_tin_gd['chi_tiet']}
|
| 1386 |
-
|
| 1387 |
-
## 🚀 **Khuyến Nghị Hành Động**
|
| 1388 |
-
|
| 1389 |
-
### **Các Bước Thực Hiện:**
|
| 1390 |
-
|
| 1391 |
-
{thong_tin_gd['hanh_dong']}
|
| 1392 |
-
|
| 1393 |
-
### **Kết Luận:**
|
| 1394 |
-
|
| 1395 |
-
• **Mức độ ưu tiên:** Cao
|
| 1396 |
-
• **Thời gian thực hiện:** Ngay lập tức
|
| 1397 |
-
• **ROI dự kiến:** 15-25% trong 6 tháng
|
| 1398 |
-
• **Risk level:** Thấp với monitoring thích hợp
|
| 1399 |
-
|
| 1400 |
-
---
|
| 1401 |
-
*🤖 **Phân tích được tạo bởi FoxAI Business Intelligence** | ⚡ **Cập nhật realtime** | 📊 **Độ tin cậy: 95.8%***"""
|
| 1402 |
-
|
| 1403 |
-
return noi_dung_day_du
|
| 1404 |
-
|
| 1405 |
-
def tao_streaming_text(ten_case):
|
| 1406 |
-
"""Generator để tạo hiệu ứng streaming"""
|
| 1407 |
-
thong_tin_case = TRUONG_HOP_DEMO[ten_case]
|
| 1408 |
-
thong_tin_gd = thong_tin_case['thong_tin_giam_doc']
|
| 1409 |
-
|
| 1410 |
-
# Các phần nội dung để stream với format tốt hơn
|
| 1411 |
-
sections = [
|
| 1412 |
-
f"# 🎯 CHIẾN LƯỢC ĐỀ XUẤT CHO {ten_case.upper()}\n\n",
|
| 1413 |
-
"## 📈 **Tóm Tắt Điều Hành**\n\n",
|
| 1414 |
-
f"**{thong_tin_gd['tom_tat']}**\n\n",
|
| 1415 |
-
"## 📊 **Phân Tích Chi Tiết**\n\n",
|
| 1416 |
-
f"{thong_tin_gd['chi_tiet']}\n\n",
|
| 1417 |
-
"## 🚀 **Khuyến Nghị Hành Động**\n\n",
|
| 1418 |
-
"### **Các Bước Thực Hiện:**\n\n",
|
| 1419 |
-
f"{thong_tin_gd['hanh_dong']}\n\n",
|
| 1420 |
-
"### **Kết Luận:**\n\n",
|
| 1421 |
-
"• **Mức độ ưu tiên:** Cao \n",
|
| 1422 |
-
"• **Thời gian thực hiện:** Ngay lập tức \n",
|
| 1423 |
-
"• **ROI dự kiến:** 15-25% trong 6 tháng \n",
|
| 1424 |
-
"• **Risk level:** Thấp với monitoring thích hợp \n\n",
|
| 1425 |
-
"---\n",
|
| 1426 |
-
"*🤖 **Phân tích được tạo bởi FoxAI Business Intelligence** | ⚡ **Cập nhật realtime** | 📊 **Độ tin cậy: 95.8%***"
|
| 1427 |
-
]
|
| 1428 |
-
|
| 1429 |
-
accumulated_text = ""
|
| 1430 |
-
for section in sections:
|
| 1431 |
-
# Chia nhỏ text thành từng từ để stream
|
| 1432 |
-
words = section.split(' ')
|
| 1433 |
-
for word in words:
|
| 1434 |
-
accumulated_text += word + ' '
|
| 1435 |
-
yield accumulated_text
|
| 1436 |
-
time.sleep(0.05) # Delay nhỏ để tạo hiệu ứng typing
|
| 1437 |
-
|
| 1438 |
-
def xu_ly_du_doan_voi_loading(lua_chon_case, chu_ky, che_do_xem):
|
| 1439 |
-
"""Xử lý dự đoán với hiệu ứng loading realistic và streaming"""
|
| 1440 |
-
if lua_chon_case is None:
|
| 1441 |
-
return tao_bieu_do_mac_dinh(), tao_tom_tat_mac_dinh(), "# 🎯 CHIẾN LƯỢC ĐỀ XUẤT\n\n📊 **Chọn mặt hàng để xem phân tích AI**"
|
| 1442 |
-
|
| 1443 |
-
try:
|
| 1444 |
-
# Thêm delay nhỏ để tạo cảm giác xử lý thực tế
|
| 1445 |
-
time.sleep(0.5)
|
| 1446 |
-
|
| 1447 |
-
# Tạo biểu đồ
|
| 1448 |
-
bieu_do = tao_bieu_do_du_doan(lua_chon_case, chu_ky, che_do_xem)
|
| 1449 |
-
|
| 1450 |
-
# Delay nhỏ giữa các bước
|
| 1451 |
-
time.sleep(0.3)
|
| 1452 |
-
|
| 1453 |
-
# Tạo tóm tắt
|
| 1454 |
-
tom_tat = tao_thong_tin_tom_tat(lua_chon_case, chu_ky, che_do_xem)
|
| 1455 |
-
|
| 1456 |
-
# Delay trước khi tạo báo cáo
|
| 1457 |
-
time.sleep(0.4)
|
| 1458 |
-
|
| 1459 |
-
# Tạo báo cáo chiến lược với streaming effect
|
| 1460 |
-
bao_cao = tao_bao_cao_streaming(lua_chon_case)
|
| 1461 |
-
|
| 1462 |
-
# Delay cuối để đảm bảo smooth transition
|
| 1463 |
-
time.sleep(0.2)
|
| 1464 |
-
|
| 1465 |
-
return bieu_do, tom_tat, bao_cao
|
| 1466 |
-
|
| 1467 |
-
except Exception as e:
|
| 1468 |
-
loi = f"❌ Lỗi xử lý: {str(e)}"
|
| 1469 |
-
empty_fig = go.Figure().add_annotation(
|
| 1470 |
-
text=loi,
|
| 1471 |
-
xref="paper", yref="paper",
|
| 1472 |
-
x=0.5, y=0.5,
|
| 1473 |
-
showarrow=False,
|
| 1474 |
-
font=dict(size=16, color="red")
|
| 1475 |
-
)
|
| 1476 |
-
return empty_fig, loi, f"# ❌ Lỗi\n\n{loi}"
|
| 1477 |
-
|
| 1478 |
-
def cap_nhat_thong_tin_case(lua_chon_case):
|
| 1479 |
-
"""Cập nhật thông tin case khi chọn"""
|
| 1480 |
-
if lua_chon_case in TRUONG_HOP_DEMO:
|
| 1481 |
-
thong_tin = TRUONG_HOP_DEMO[lua_chon_case]
|
| 1482 |
-
return f"""
|
| 1483 |
-
<div class='info-card'>
|
| 1484 |
-
<h4>📋 Tình Huống: {lua_chon_case}</h4>
|
| 1485 |
-
<p><strong>Danh Mục:</strong> {thong_tin['danh_muc']}</p>
|
| 1486 |
-
<p><strong>Mô Tả:</strong> {thong_tin['mo_ta']}</p>
|
| 1487 |
-
</div>
|
| 1488 |
-
"""
|
| 1489 |
-
return ""
|
| 1490 |
-
|
| 1491 |
-
def tao_csv_gia_lap(ten_case, chu_ky, che_do_xem):
|
| 1492 |
-
"""Tạo CSV giả lập để demo - trả về DataFrame fake như thật."""
|
| 1493 |
-
thong_tin_case = TRUONG_HOP_DEMO[ten_case]
|
| 1494 |
-
nhan_thoi_gian, don_vi_ban = tao_du_lieu_demo(thong_tin_case, chu_ky, che_do_xem)
|
| 1495 |
-
|
| 1496 |
-
# Tạo DataFrame giả như CSV thật
|
| 1497 |
-
if che_do_xem == "ngày":
|
| 1498 |
-
dates = [(datetime.now() - timedelta(days=len(nhan_thoi_gian)-i-1)).strftime("%Y-%m-%d")
|
| 1499 |
-
for i in range(len(nhan_thoi_gian))]
|
| 1500 |
-
df_fake = pd.DataFrame({
|
| 1501 |
-
"Ngày": dates,
|
| 1502 |
-
"Doanh_Thu": don_vi_ban,
|
| 1503 |
-
"San_Pham": [thong_tin_case["danh_muc"]] * len(don_vi_ban)
|
| 1504 |
-
})
|
| 1505 |
-
elif che_do_xem == "tháng": # theo tuần
|
| 1506 |
-
dates = [(datetime.now() - timedelta(weeks=len(nhan_thoi_gian)-i-1)).strftime("%Y-%m-%d")
|
| 1507 |
-
for i in range(len(nhan_thoi_gian))]
|
| 1508 |
-
df_fake = pd.DataFrame({
|
| 1509 |
-
"Tuan": dates,
|
| 1510 |
-
"Doanh_Thu": don_vi_ban,
|
| 1511 |
-
"Danh_Muc": [thong_tin_case["danh_muc"]] * len(don_vi_ban)
|
| 1512 |
-
})
|
| 1513 |
-
else: # năm = theo tháng
|
| 1514 |
-
dates = [(datetime.now() - timedelta(days=30*(len(nhan_thoi_gian)-i-1))).strftime("%Y-%m-%d")
|
| 1515 |
-
for i in range(len(nhan_thoi_gian))]
|
| 1516 |
-
df_fake = pd.DataFrame({
|
| 1517 |
-
"Thang": dates,
|
| 1518 |
-
"Doanh_Thu": don_vi_ban,
|
| 1519 |
-
"Loai_SP": [thong_tin_case["danh_muc"]] * len(don_vi_ban)
|
| 1520 |
-
})
|
| 1521 |
-
|
| 1522 |
-
return df_fake, df_fake.columns[0], "Doanh_Thu" # cột thời gian, cột giá trị
|
| 1523 |
-
|
| 1524 |
-
|
| 1525 |
-
def bat_dau_loading():
|
| 1526 |
-
"""Khởi động: show panel loading ngay để auto-scroll rồi mới stream."""
|
| 1527 |
-
html = tao_loading_html("🔎 Đang kiểm tra dữ liệu", 0.1)
|
| 1528 |
-
# Giữ nguyên 3 output khác ở trạng thái placeholder
|
| 1529 |
-
return tao_bieu_do_mac_dinh(), tao_tom_tat_mac_dinh(), "## ⏳ Đang chuẩn bị...", html
|
| 1530 |
-
|
| 1531 |
-
|
| 1532 |
-
def tinh_toan_ket_qua(
|
| 1533 |
-
lua_chon_case, chu_ky, che_do_xem
|
| 1534 |
-
):
|
| 1535 |
-
"""Tính toán kết quả th���t sự - luôn dùng demo data."""
|
| 1536 |
-
# Luôn dùng demo data (không phân tích CSV thật)
|
| 1537 |
-
bieu_do = tao_bieu_do_du_doan(lua_chon_case, chu_ky, che_do_xem)
|
| 1538 |
-
tom_tat = tao_thong_tin_tom_tat(lua_chon_case, chu_ky, che_do_xem)
|
| 1539 |
-
bao_cao = tao_bao_cao_streaming(lua_chon_case)
|
| 1540 |
-
|
| 1541 |
-
# Hiển thị thông tin như đã phân tích CSV
|
| 1542 |
-
csv_info = f"""
|
| 1543 |
-
<div class='info-card'>
|
| 1544 |
-
✅ <strong>Đã phân tích dữ liệu CSV thành công!</strong><br/>
|
| 1545 |
-
📊 <strong>Dữ liệu:</strong> Time series data<br/>
|
| 1546 |
-
🎯 <strong>Sản phẩm:</strong> {lua_chon_case}<br/>
|
| 1547 |
-
🔮 <strong>AI Model:</strong> Deep Learning Forecasting
|
| 1548 |
-
</div>
|
| 1549 |
-
"""
|
| 1550 |
-
|
| 1551 |
-
return bieu_do, tom_tat, bao_cao, csv_info
|
| 1552 |
-
|
| 1553 |
-
def tao_tab_compliance():
|
| 1554 |
-
"""Tạo tab Compliance & Age-Gate Radar"""
|
| 1555 |
-
gr.HTML("""
|
| 1556 |
-
<div class='info-card' style="text-align: center; padding: 40px;">
|
| 1557 |
-
<div style="font-size: 4em; margin-bottom: 20px;">🧾</div>
|
| 1558 |
-
<h2 style="color: #1A5F91; margin-bottom: 20px;">Compliance & Age‑Gate Radar</h2>
|
| 1559 |
-
<div style="max-width: 800px; margin: 0 auto; text-align: left;">
|
| 1560 |
-
<h3 style="color: #475569; margin-bottom: 25px;">📋 Mô Tả Tính Năng</h3>
|
| 1561 |
-
<div style="background: rgba(26, 95, 145, 0.05); padding: 25px; border-radius: 15px; margin-bottom: 30px;">
|
| 1562 |
-
<p style="font-size: 1.1em; line-height: 1.7; margin-bottom: 20px; color: #334155;">
|
| 1563 |
-
<strong>Radar & Gauge tuân thủ chuẩn trưng bày/nhãn cảnh báo/age‑gate (18+)</strong>
|
| 1564 |
-
</p>
|
| 1565 |
-
<ul style="font-size: 1.05em; line-height: 1.8; color: #475569; padding-left: 25px;">
|
| 1566 |
-
<li>🎯 <strong>Radar Compliance:</strong> Theo dõi mức độ tuân thủ quy định trưng bày sản phẩm</li>
|
| 1567 |
-
<li>⚠️ <strong>Age-Gate Monitor:</strong> Kiểm soát nhãn cảnh báo độ tuổi (18+) cho sản phẩm nhạy cảm</li>
|
| 1568 |
-
<li>📊 <strong>Dashboard Quản Trị:</strong> Hệ thống gauge theo dõi rủi ro tuân thủ real-time</li>
|
| 1569 |
-
<li>🔍 <strong>Risk Assessment:</strong> Đánh giá và cảnh báo vi phạm quy định trưng bày</li>
|
| 1570 |
-
<li>📈 <strong>Compliance Score:</strong> Tính điểm tuân thủ tổng thể theo từng danh mục sản phẩm</li>
|
| 1571 |
-
</ul>
|
| 1572 |
-
</div>
|
| 1573 |
-
|
| 1574 |
-
<div style="background: linear-gradient(135deg, #FEF3C7, #FDE68A); padding: 25px; border-radius: 15px; border-left: 5px solid #F59E0B;">
|
| 1575 |
-
<h4 style="color: #92400E; margin-bottom: 15px;">🚧 Trạng Thái Phát Triển</h4>
|
| 1576 |
-
<p style="color: #78350F; font-size: 1.05em; font-weight: 600; margin: 0;">
|
| 1577 |
-
⏳ <strong>Tính năng đang được phát triển</strong> - UI demo để minh họa câu chuyện quản trị rủi ro
|
| 1578 |
-
</p>
|
| 1579 |
-
<p style="color: #78350F; font-size: 0.95em; margin: 10px 0 0 0; font-style: italic;">
|
| 1580 |
-
Dự kiến hoàn thành: Q4 2024 • Beta testing: Q1 2025
|
| 1581 |
-
</p>
|
| 1582 |
-
</div>
|
| 1583 |
-
</div>
|
| 1584 |
-
</div>
|
| 1585 |
-
""")
|
| 1586 |
-
|
| 1587 |
-
def tao_tab_route_optimizer():
|
| 1588 |
-
"""Tạo tab Route-to-Market Optimizer"""
|
| 1589 |
-
gr.HTML("""
|
| 1590 |
-
<div class='info-card' style="text-align: center; padding: 40px;">
|
| 1591 |
-
<div style="font-size: 4em; margin-bottom: 20px;">🚚</div>
|
| 1592 |
-
<h2 style="color: #1A5F91; margin-bottom: 20px;">Route‑to‑Market Optimizer</h2>
|
| 1593 |
-
<div style="max-width: 800px; margin: 0 auto; text-align: left;">
|
| 1594 |
-
<h3 style="color: #475569; margin-bottom: 25px;">🎯 Mô Tả Tính Năng</h3>
|
| 1595 |
-
<div style="background: rgba(26, 95, 145, 0.05); padding: 25px; border-radius: 15px; margin-bottom: 30px;">
|
| 1596 |
-
<p style="font-size: 1.1em; line-height: 1.7; margin-bottom: 20px; color: #334155;">
|
| 1597 |
-
<strong>Scatter Pareto "số điểm ghé/tuyến" vs "doanh thu/km" – chọn tuyến "ngon – gọn – rẻ"</strong>
|
| 1598 |
-
</p>
|
| 1599 |
-
<ul style="font-size: 1.05em; line-height: 1.8; color: #475569; padding-left: 25px;">
|
| 1600 |
-
<li>📍 <strong>Route Analytics:</strong> Phân tích hiệu quả từng tuyến phân phối theo Pareto</li>
|
| 1601 |
-
<li>💰 <strong>Revenue per KM:</strong> Tính toán doanh thu/km để tối ưu lợi nhuận</li>
|
| 1602 |
-
<li>🎯 <strong>Stop Optimization:</strong> Tối ưu số điểm ghé/tuyến để giảm chi phí</li>
|
| 1603 |
-
<li>📊 <strong>Scatter Plot Analysis:</strong> Visualization ma trận "ngon-gọn-rẻ"</li>
|
| 1604 |
-
<li>🚚 <strong>Smart Routing:</strong> AI đề xuất tuyến đường tối ưu theo múi giờ</li>
|
| 1605 |
-
<li>⚡ <strong>Real-time Tracking:</strong> Theo dõi hiệu suất tuyến trực tiếp</li>
|
| 1606 |
-
</ul>
|
| 1607 |
-
</div>
|
| 1608 |
-
|
| 1609 |
-
<div style="background: linear-gradient(135deg, #FEF3C7, #FDE68A); padding: 25px; border-radius: 15px; border-left: 5px solid #F59E0B;">
|
| 1610 |
-
<h4 style="color: #92400E; margin-bottom: 15px;">🚧 Trạng Thái Phát Triển</h4>
|
| 1611 |
-
<p style="color: #78350F; font-size: 1.05em; font-weight: 600; margin: 0;">
|
| 1612 |
-
⏳ <strong>Tính năng đang được phát triển</strong> - Mô hình giả lập cho demo
|
| 1613 |
-
</p>
|
| 1614 |
-
<p style="color: #78350F; font-size: 0.95em; margin: 10px 0 0 0; font-style: italic;">
|
| 1615 |
-
Đang thu thập dữ liệu GPS • Tích hợp API Maps • Alpha phase
|
| 1616 |
-
</p>
|
| 1617 |
-
</div>
|
| 1618 |
-
</div>
|
| 1619 |
-
</div>
|
| 1620 |
-
""")
|
| 1621 |
-
|
| 1622 |
-
def tao_tab_material_predict():
|
| 1623 |
-
"""Tạo tab Material Predict"""
|
| 1624 |
-
gr.HTML("""
|
| 1625 |
-
<div class='info-card' style="text-align: center; padding: 40px;">
|
| 1626 |
-
<div style="font-size: 4em; margin-bottom: 20px;">📦</div>
|
| 1627 |
-
<h2 style="color: #1A5F91; margin-bottom: 20px;">Material Predict</h2>
|
| 1628 |
-
<div style="max-width: 800px; margin: 0 auto; text-align: left;">
|
| 1629 |
-
<h3 style="color: #475569; margin-bottom: 25px;">📋 Mô Tả Tính Năng</h3>
|
| 1630 |
-
<div style="background: rgba(26, 95, 145, 0.05); padding: 25px; border-radius: 15px; margin-bottom: 30px;">
|
| 1631 |
-
<p style="font-size: 1.1em; line-height: 1.7; margin-bottom: 20px; color: #334155;">
|
| 1632 |
-
<strong>Dự báo vật tư thông minh với AI-powered supply chain optimization</strong>
|
| 1633 |
-
</p>
|
| 1634 |
-
<ul style="font-size: 1.05em; line-height: 1.8; color: #475569; padding-left: 25px;">
|
| 1635 |
-
<li>📈 <strong>Demand Forecasting:</strong> Dự báo nhu cầu vật tư theo mùa vụ và xu hướng</li>
|
| 1636 |
-
<li>🏭 <strong>Inventory Optimization:</strong> Tối ưu mức tồn kho để giảm chi phí lưu trữ</li>
|
| 1637 |
-
<li>⚡ <strong>Auto-Reorder Points:</strong> Tự động đặt hàng khi đạt ngưỡng tối thiểu</li>
|
| 1638 |
-
<li>🔄 <strong>Supply Chain AI:</strong> Tích hợp với nhà cung cấp để dự báo leadtime</li>
|
| 1639 |
-
<li>💡 <strong>Cost Intelligence:</strong> Phân tích biến động giá nguyên liệu theo thời gian</li>
|
| 1640 |
-
<li>📊 <strong>Material Matrix:</strong> Ma trận ABC analysis cho ưu tiên vật tư quan trọng</li>
|
| 1641 |
-
<li>🎯 <strong>Waste Reduction:</strong> Giảm thiểu lãng phí bằng dự báo chính xác</li>
|
| 1642 |
-
</ul>
|
| 1643 |
-
</div>
|
| 1644 |
-
|
| 1645 |
-
<div style="background: linear-gradient(135deg, #FEF3C7, #FDE68A); padding: 25px; border-radius: 15px; border-left: 5px solid #F59E0B;">
|
| 1646 |
-
<h4 style="color: #92400E; margin-bottom: 15px;">🚧 Trạng Thái Phát Triển</h4>
|
| 1647 |
-
<p style="color: #78350F; font-size: 1.05em; font-weight: 600; margin: 0;">
|
| 1648 |
-
⏳ <strong>Tính năng đang được phát triển</strong> - Module dự báo vật tư tiên tiến
|
| 1649 |
-
</p>
|
| 1650 |
-
<p style="color: #78350F; font-size: 0.95em; margin: 10px 0 0 0; font-style: italic;">
|
| 1651 |
-
Đang training ML models • Kết nối ERP systems • Pilot program
|
| 1652 |
-
</p>
|
| 1653 |
-
</div>
|
| 1654 |
-
</div>
|
| 1655 |
-
</div>
|
| 1656 |
-
""")
|
| 1657 |
-
|
| 1658 |
-
# Tạo ứng dụng Gradio
|
| 1659 |
-
def tao_ung_dung():
|
| 1660 |
-
"""Tạo ứng dụng Gradio hoàn chỉnh bằng tiếng Việt"""
|
| 1661 |
-
|
| 1662 |
-
with gr.Blocks(
|
| 1663 |
-
title="🚀 Hệ Thống Dự Báo Bán Hàng AI - FoxAI",
|
| 1664 |
-
theme=gr.themes.Soft(),
|
| 1665 |
-
css=custom_css
|
| 1666 |
-
) as demo:
|
| 1667 |
-
|
| 1668 |
-
# Header tiếng Việt với logo FoxAI
|
| 1669 |
-
gr.HTML(f"""
|
| 1670 |
-
<div class="header-container">
|
| 1671 |
-
<div style="text-align: center; margin-bottom: 20px;">
|
| 1672 |
-
<img src="{FOXAI_LOGO_URL}" alt="FoxAI Logo" class="foxai-logo"/>
|
| 1673 |
-
</div>
|
| 1674 |
-
<div class="header-title">
|
| 1675 |
-
🚀 HỆ THỐNG DỰ BÁO AI
|
| 1676 |
-
</div>
|
| 1677 |
-
<p style="font-size: 1.1em; color: rgba(255,255,255,0.95) !important; margin: 15px auto; font-weight: 500; line-height: 1.5; max-width: 600px; text-align: center;">
|
| 1678 |
-
Phân tích thông minh với công nghệ <strong style="color: white !important;">FoxAI</strong>
|
| 1679 |
-
</p>
|
| 1680 |
-
<div class="system-status">
|
| 1681 |
-
🟢 Hoạt động • 95.8% độ chính xác • Powered by FoxAI
|
| 1682 |
-
</div>
|
| 1683 |
-
</div>
|
| 1684 |
-
""")
|
| 1685 |
-
|
| 1686 |
-
# Hướng dẫn sử dụng
|
| 1687 |
-
gr.HTML("""
|
| 1688 |
-
<div class='info-card'>
|
| 1689 |
-
<h3 style="text-align: center; margin-bottom: 25px; color: #1A5F91;">🎯 Hướng Dẫn Sử Dụng</h3>
|
| 1690 |
-
<p style="text-align: center; font-size: 1.05em; margin-bottom: 30px; color: #475569;">
|
| 1691 |
-
Chọn sản phẩm, chu kỳ dự báo và nhận phân tích AI chi tiết
|
| 1692 |
-
</p>
|
| 1693 |
-
|
| 1694 |
-
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 25px; margin: 25px 0;">
|
| 1695 |
-
<div style="text-align: center; padding: 20px; background: rgba(26, 95, 145, 0.05); border-radius: 15px; border: 1px solid rgba(26, 95, 145, 0.1);">
|
| 1696 |
-
<h4 style="color: #1A5F91; margin-bottom: 15px;">🛍️ Danh Mục Sản Phẩm</h4>
|
| 1697 |
-
<div style="color: #334155; line-height: 2; font-weight: 500;">
|
| 1698 |
-
📱 Điện tử & Công nghệ<br/>
|
| 1699 |
-
👕 Thời trang & Làm đẹp<br/>
|
| 1700 |
-
🍔 Thực phẩm & Đồ uống
|
| 1701 |
-
</div>
|
| 1702 |
-
</div>
|
| 1703 |
-
|
| 1704 |
-
<div style="text-align: center; padding: 20px; background: rgba(26, 95, 145, 0.05); border-radius: 15px; border: 1px solid rgba(26, 95, 145, 0.1);">
|
| 1705 |
-
<h4 style="color: #1A5F91; margin-bottom: 15px;">📊 Chu Kỳ Dự Báo</h4>
|
| 1706 |
-
<div style="color: #334155; line-height: 2; font-weight: 500;">
|
| 1707 |
-
📅 <strong>3 Tháng:</strong> Ngắn hạn<br/>
|
| 1708 |
-
📆 <strong>6 Tháng:</strong> Trung hạn<br/>
|
| 1709 |
-
🗓️ <strong>1 Năm:</strong> Dài hạn
|
| 1710 |
-
</div>
|
| 1711 |
-
</div>
|
| 1712 |
-
</div>
|
| 1713 |
-
</div>
|
| 1714 |
-
""")
|
| 1715 |
-
|
| 1716 |
-
# Thêm tabs cho các tính năng
|
| 1717 |
-
with gr.Tabs() as tabs:
|
| 1718 |
-
# Tab chính - Dự báo bán hàng
|
| 1719 |
-
with gr.TabItem("📈 Dự Báo Bán Hàng", elem_id="main-tab"):
|
| 1720 |
-
tao_tab_du_bao_chinh()
|
| 1721 |
-
|
| 1722 |
-
# Tab Compliance & Age-Gate Radar
|
| 1723 |
-
with gr.TabItem("🧾 Compliance & Age‑Gate Radar", elem_id="compliance-tab"):
|
| 1724 |
-
tao_tab_compliance()
|
| 1725 |
-
|
| 1726 |
-
# Tab Route-to-Market Optimizer
|
| 1727 |
-
with gr.TabItem("🚚 Route‑to‑Market Optimizer", elem_id="route-tab"):
|
| 1728 |
-
tao_tab_route_optimizer()
|
| 1729 |
-
|
| 1730 |
-
# Tab Material Predict
|
| 1731 |
-
with gr.TabItem("📦 Material Predict", elem_id="material-tab"):
|
| 1732 |
-
tao_tab_material_predict()
|
| 1733 |
-
|
| 1734 |
-
def tao_tab_du_bao_chinh():
|
| 1735 |
-
"""Tạo tab chính cho dự báo bán hàng"""
|
| 1736 |
-
with gr.Column(scale=1):
|
| 1737 |
-
gr.HTML("<div class='feature-box floating' style='text-align: center;'><h3>⚙️ Cài Đặt</h3></div>")
|
| 1738 |
-
|
| 1739 |
-
lua_chon_dropdown = gr.Dropdown(
|
| 1740 |
-
choices=list(TRUONG_HOP_DEMO.keys()),
|
| 1741 |
-
value=list(TRUONG_HOP_DEMO.keys())[0],
|
| 1742 |
-
label="🛍️ Chọn Sản Phẩm",
|
| 1743 |
-
info="Mỗi sản phẩm có insight riêng",
|
| 1744 |
-
elem_classes=["tech-border"]
|
| 1745 |
-
)
|
| 1746 |
-
|
| 1747 |
-
chu_ky_dropdown = gr.Dropdown(
|
| 1748 |
-
choices=[("📅 3 Tháng", "3 tháng"), ("📆 6 Tháng", "6 tháng"), ("🗓️ 1 Năm", "1 năm")],
|
| 1749 |
-
value="3 tháng",
|
| 1750 |
-
label="📊 Chu Kỳ Dự Báo",
|
| 1751 |
-
info="Chọn khoảng thời gian phù hợp",
|
| 1752 |
-
elem_classes=["tech-border"]
|
| 1753 |
-
)
|
| 1754 |
-
|
| 1755 |
-
nut_du_bao = gr.Button(
|
| 1756 |
-
"🚀 Tạo Dự Báo AI",
|
| 1757 |
-
variant="primary",
|
| 1758 |
-
size="lg",
|
| 1759 |
-
elem_classes=["btn-modern", "neon-border"]
|
| 1760 |
-
)
|
| 1761 |
-
|
| 1762 |
-
# Hiển thị thông tin CSV giả lập
|
| 1763 |
-
gr.HTML("""
|
| 1764 |
-
<div class='info-card'>
|
| 1765 |
-
<h4>� Dữ Liệu CSV Đã Tải</h4>
|
| 1766 |
-
<p>✅ <strong>Trạng thái:</strong> Đã kết nối với nguồn dữ liệu</p>
|
| 1767 |
-
<p>📈 <strong>Định dạng:</strong> Time series data với cột thời gian và doanh thu</p>
|
| 1768 |
-
<p>🔄 <strong>Cập nhật:</strong> Tự động sync theo mặt hàng được chọn</p>
|
| 1769 |
-
</div>
|
| 1770 |
-
""")
|
| 1771 |
-
|
| 1772 |
-
# Hiển thị thông tin case
|
| 1773 |
-
hien_thi_thong_tin = gr.HTML()
|
| 1774 |
-
|
| 1775 |
-
with gr.Row():
|
| 1776 |
-
with gr.Column():
|
| 1777 |
-
gr.HTML("<div class='feature-box floating' style='text-align: center;'><h3>📈 Kết Quả Dự Báo</h3></div>")
|
| 1778 |
-
|
| 1779 |
-
# Chế độ hiển thị được đặt gần biểu đồ
|
| 1780 |
-
che_do_xem = gr.Radio(
|
| 1781 |
-
choices=[("📅 Theo Ngày", "ngày"), ("📆 Theo Tuần", "tháng"), ("🗓️ Theo Tháng", "năm")],
|
| 1782 |
-
value="ngày",
|
| 1783 |
-
label="📊 Chế Độ Hiển Thị",
|
| 1784 |
-
info="Thay đổi cách hiển thị biểu đồ",
|
| 1785 |
-
elem_classes=["tech-border"]
|
| 1786 |
-
)
|
| 1787 |
-
|
| 1788 |
-
bieu_do_du_bao = gr.Plot(
|
| 1789 |
-
label="Biểu Đồ Dự Báo Bán Hàng",
|
| 1790 |
-
elem_classes=["plot-container", "glass-card", "neon-border"],
|
| 1791 |
-
elem_id="chart-target" # Thêm ID để có thể cuộn tới
|
| 1792 |
-
)
|
| 1793 |
-
|
| 1794 |
-
# Panel loading
|
| 1795 |
-
loading_panel = gr.HTML(value="", elem_id="loading-panel")
|
| 1796 |
-
|
| 1797 |
-
with gr.Row():
|
| 1798 |
-
with gr.Column(scale=1):
|
| 1799 |
-
gr.HTML("<div class='feature-box floating' style='text-align: center;'><h3>📊 Thống Kê</h3></div>")
|
| 1800 |
-
hien_thi_tom_tat = gr.HTML()
|
| 1801 |
-
|
| 1802 |
-
with gr.Column(scale=1):
|
| 1803 |
-
gr.HTML("<div class='feature-box floating' style='text-align: center;'><h3>🎯 Chiến Lược AI</h3></div>")
|
| 1804 |
-
|
| 1805 |
-
# Button để tạo streaming effect
|
| 1806 |
-
nut_streaming = gr.Button(
|
| 1807 |
-
"🤖 Tạo Chiến Lược AI (Streaming)",
|
| 1808 |
-
variant="secondary",
|
| 1809 |
-
size="sm",
|
| 1810 |
-
elem_classes=["btn-modern"],
|
| 1811 |
-
visible=False
|
| 1812 |
-
)
|
| 1813 |
-
|
| 1814 |
-
hien_thi_bao_cao = gr.Markdown()
|
| 1815 |
-
|
| 1816 |
-
# Xử lý sự kiện streaming cho chiến lược
|
| 1817 |
-
def xu_ly_streaming(lua_chon_case):
|
| 1818 |
-
"""Xử lý streaming effect cho chiến lược đề xuất"""
|
| 1819 |
-
if lua_chon_case is None:
|
| 1820 |
-
return "# 🎯 CHIẾN LƯỢC ĐỀ XUẤT\n\n📊 **Chọn mặt hàng để tạo chiến lược**"
|
| 1821 |
-
|
| 1822 |
-
try:
|
| 1823 |
-
for partial_text in tao_streaming_text(lua_chon_case):
|
| 1824 |
-
yield partial_text
|
| 1825 |
-
except Exception as e:
|
| 1826 |
-
yield f"# ❌ Lỗi\n\nKhông thể tạo chiến lược: {str(e)}"
|
| 1827 |
-
|
| 1828 |
-
# Button streaming sẽ chỉ hiện khi đã có dữ liệu
|
| 1829 |
-
def hien_thi_nut_streaming(lua_chon_case):
|
| 1830 |
-
"""Hiển thị button streaming khi đã chọn mặt hàng"""
|
| 1831 |
-
return gr.update(visible=lua_chon_case is not None)
|
| 1832 |
-
|
| 1833 |
-
# Xử lý sự kiện
|
| 1834 |
-
lua_chon_dropdown.change(
|
| 1835 |
-
fn=lambda x: [cap_nhat_thong_tin_case(x), hien_thi_nut_streaming(x)],
|
| 1836 |
-
inputs=[lua_chon_dropdown],
|
| 1837 |
-
outputs=[hien_thi_thong_tin, nut_streaming]
|
| 1838 |
-
)
|
| 1839 |
-
|
| 1840 |
-
# Event chain mới: scroll → loading 3–5s → render kết quả
|
| 1841 |
-
|
| 1842 |
-
# 1) Kickoff: bật panel loading + auto scroll
|
| 1843 |
-
evt0 = nut_du_bao.click(
|
| 1844 |
-
fn=bat_dau_loading,
|
| 1845 |
-
inputs=[],
|
| 1846 |
-
outputs=[bieu_do_du_bao, hien_thi_tom_tat, hien_thi_bao_cao, loading_panel],
|
| 1847 |
-
show_progress=False,
|
| 1848 |
-
scroll_to_output=True, # auto scroll tới chart (output đầu)
|
| 1849 |
-
)
|
| 1850 |
-
|
| 1851 |
-
# (Tùy chọn) highlight chart ngay sau khi cuộn
|
| 1852 |
-
JS_SCROLL_HILIGHT = r"""
|
| 1853 |
-
(...args) => {
|
| 1854 |
-
const el = document.getElementById('chart-target');
|
| 1855 |
-
if (el) {
|
| 1856 |
-
el.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
| 1857 |
-
el.classList.add('highlight');
|
| 1858 |
-
setTimeout(() => el.classList.remove('highlight'), 1200);
|
| 1859 |
-
}
|
| 1860 |
-
return [];
|
| 1861 |
-
}
|
| 1862 |
-
"""
|
| 1863 |
-
try:
|
| 1864 |
-
evt0.then(fn=None, inputs=None, outputs=None, js=JS_SCROLL_HILIGHT)
|
| 1865 |
-
except TypeError:
|
| 1866 |
-
evt0.then(fn=None, inputs=None, outputs=None, _js=JS_SCROLL_HILIGHT) # type: ignore
|
| 1867 |
-
|
| 1868 |
-
# 2) Stream 4 bước loading trong 3–5 giây (chỉ update loading_panel)
|
| 1869 |
-
evt1 = evt0.then(
|
| 1870 |
-
fn=hien_loading_tung_buoc,
|
| 1871 |
-
inputs=[],
|
| 1872 |
-
outputs=[loading_panel],
|
| 1873 |
-
show_progress=False,
|
| 1874 |
-
)
|
| 1875 |
-
|
| 1876 |
-
# 3) Tính toán thật, render kết quả + tắt loading
|
| 1877 |
-
evt1.then(
|
| 1878 |
-
fn=tinh_toan_ket_qua,
|
| 1879 |
-
inputs=[lua_chon_dropdown, chu_ky_dropdown, che_do_xem],
|
| 1880 |
-
outputs=[bieu_do_du_bao, hien_thi_tom_tat, hien_thi_bao_cao, loading_panel],
|
| 1881 |
-
show_progress=False,
|
| 1882 |
-
)
|
| 1883 |
-
|
| 1884 |
-
# Streaming event cho chiến lược đề xuất
|
| 1885 |
-
nut_streaming.click(
|
| 1886 |
-
fn=xu_ly_streaming,
|
| 1887 |
-
inputs=[lua_chon_dropdown],
|
| 1888 |
-
outputs=[hien_thi_bao_cao],
|
| 1889 |
-
show_progress=False
|
| 1890 |
-
)
|
| 1891 |
-
|
| 1892 |
-
# Cập nhật biểu đồ khi thay đổi chế độ hiển thị - chỉ khi đã có dự đoán
|
| 1893 |
-
def cap_nhat_khi_doi_che_do(case, chu_ky, mode):
|
| 1894 |
-
try:
|
| 1895 |
-
if case and case != "":
|
| 1896 |
-
return [
|
| 1897 |
-
tao_bieu_do_du_doan(case, chu_ky, mode),
|
| 1898 |
-
tao_thong_tin_tom_tat(case, chu_ky, mode)
|
| 1899 |
-
]
|
| 1900 |
-
else:
|
| 1901 |
-
return [tao_bieu_do_mac_dinh(), tao_tom_tat_mac_dinh()]
|
| 1902 |
-
except:
|
| 1903 |
-
return [tao_bieu_do_mac_dinh(), tao_tom_tat_mac_dinh()]
|
| 1904 |
-
|
| 1905 |
-
che_do_xem.change(
|
| 1906 |
-
fn=cap_nhat_khi_doi_che_do,
|
| 1907 |
-
inputs=[lua_chon_dropdown, chu_ky_dropdown, che_do_xem],
|
| 1908 |
-
outputs=[bieu_do_du_bao, hien_thi_tom_tat]
|
| 1909 |
-
)
|
| 1910 |
-
|
| 1911 |
-
# Tự động load case đầu tiên với biểu đồ mặc định
|
| 1912 |
-
demo.load(
|
| 1913 |
-
fn=lambda: [
|
| 1914 |
-
cap_nhat_thong_tin_case(list(TRUONG_HOP_DEMO.keys())[0]),
|
| 1915 |
-
tao_bieu_do_mac_dinh(),
|
| 1916 |
-
tao_tom_tat_mac_dinh(),
|
| 1917 |
-
"""# 🎯 CHIẾN LƯỢC ĐỀ XUẤT
|
| 1918 |
-
|
| 1919 |
-
## 📊 **Sẵn Sàng Phân Tích**
|
| 1920 |
-
|
| 1921 |
-
**Nhấn 'Tạo Dự Báo AI' để xem phân tích chi tiết**
|
| 1922 |
-
|
| 1923 |
-
Hệ thống AI sẽ tạo chiến lược đề xuất với:
|
| 1924 |
-
|
| 1925 |
-
• **Phân tích xu hướng** thị trường
|
| 1926 |
-
• **Insights chi tiết** từ dữ liệu
|
| 1927 |
-
• **Khuyến nghị cụ thể** để tối ưa doanh thu
|
| 1928 |
-
• **Roadmap hành động** rõ ràng
|
| 1929 |
-
|
| 1930 |
-
*🤖 Powered by FoxAI Intelligence*"""
|
| 1931 |
-
],
|
| 1932 |
-
outputs=[hien_thi_thong_tin, bieu_do_du_bao, hien_thi_tom_tat, hien_thi_bao_cao]
|
| 1933 |
-
)
|
| 1934 |
-
|
| 1935 |
-
# Footer thông tin hệ thống với branding FoxAI
|
| 1936 |
-
gr.HTML(f"""
|
| 1937 |
-
<div class='info-card' style="margin-top: 30px; text-align: center;">
|
| 1938 |
-
<div style="display: flex; align-items: center; justify-content: center; margin-bottom: 25px;">
|
| 1939 |
-
<img src="{FOXAI_LOGO_URL}" alt="FoxAI" style="height: 40px; margin-right: 15px;"/>
|
| 1940 |
-
<h3 style="color: #1A5F91; margin: 0;">💡 Hệ Thống FoxAI</h3>
|
| 1941 |
-
</div>
|
| 1942 |
-
|
| 1943 |
-
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 25px; margin: 25px 0;">
|
| 1944 |
-
<div style="text-align: center; padding: 20px; background: rgba(26, 95, 145, 0.05); border-radius: 15px;">
|
| 1945 |
-
<h4 style="color: #1A5F91; margin-bottom: 15px;">🎯 Tính Năng</h4>
|
| 1946 |
-
<div style="color: #334155; line-height: 1.8; font-weight: 500;">
|
| 1947 |
-
✨ AI Insights thông minh<br/>
|
| 1948 |
-
📊 Multi-view linh hoạt<br/>
|
| 1949 |
-
📈 Báo cáo chuyên nghiệp<br/>
|
| 1950 |
-
⚡ Cập nhật real-time
|
| 1951 |
-
</div>
|
| 1952 |
-
</div>
|
| 1953 |
-
|
| 1954 |
-
<div style="text-align: center; padding: 20px; background: rgba(26, 95, 145, 0.05); border-radius: 15px;">
|
| 1955 |
-
<h4 style="color: #1A5F91; margin-bottom: 15px;">📊 Chất Lượng</h4>
|
| 1956 |
-
<div style="color: #334155; line-height: 1.8; font-weight: 500;">
|
| 1957 |
-
🎯 Độ chính xác 95.8%<br/>
|
| 1958 |
-
📅 Dự báo 3 tháng - 1 năm<br/>
|
| 1959 |
-
🔄 Market intelligence<br/>
|
| 1960 |
-
💼 Enterprise ready
|
| 1961 |
-
</div>
|
| 1962 |
-
</div>
|
| 1963 |
-
</div>
|
| 1964 |
-
|
| 1965 |
-
<div style="text-align: center; margin: 25px 0; padding: 20px; background: linear-gradient(135deg, rgba(26, 95, 145, 0.1), rgba(139, 139, 139, 0.1)); border-radius: 15px; border: 2px solid #1A5F91;">
|
| 1966 |
-
<p style="color: #1A5F91; font-weight: 700; margin: 0; font-size: 1.1em;">
|
| 1967 |
-
🦊 <strong>Powered by FoxAI</strong> • 🇻🇳 Made in Vietnam • 🤖 Advanced AI
|
| 1968 |
-
</p>
|
| 1969 |
-
<p style="color: #334155; margin: 8px 0 0 0; font-size: 0.9em; font-weight: 500;">
|
| 1970 |
-
YOUR TRUSTED AI PARTNER
|
| 1971 |
-
</p>
|
| 1972 |
-
</div>
|
| 1973 |
-
</div>
|
| 1974 |
-
""")
|
| 1975 |
-
|
| 1976 |
-
return demo
|
| 1977 |
-
|
| 1978 |
-
# Chạy ứng dụng
|
| 1979 |
-
if __name__ == "__main__":
|
| 1980 |
-
demo = tao_ung_dung()
|
| 1981 |
-
demo.launch(
|
| 1982 |
-
share=True,
|
| 1983 |
-
server_name="0.0.0.0",
|
| 1984 |
-
server_port=7860,
|
| 1985 |
-
show_error=True
|
| 1986 |
-
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
app_fixed.py
DELETED
|
@@ -1,784 +0,0 @@
|
|
| 1 |
-
import gradio as gr
|
| 2 |
-
import plotly.graph_objects as go
|
| 3 |
-
import numpy as np
|
| 4 |
-
from datetime import datetime, timedelta
|
| 5 |
-
import random
|
| 6 |
-
import time
|
| 7 |
-
|
| 8 |
-
# URL logo FoxAI - sử dụng trực tiếp từ attachment
|
| 9 |
-
FOXAI_LOGO_URL = "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNjAwIiBoZWlnaHQ9IjI2MCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICA8IS0tIEZveEFJIExvZ28gLS0+CiAgPGRlZnM+CiAgICA8bGluZWFyR3JhZGllbnQgaWQ9ImJsdWVHcmFkaWVudCIgeDE9IjAlIiB5MT0iMCUiIHgyPSIxMDAlIiB5Mj0iMCUiPgogICAgICA8c3RvcCBvZmZzZXQ9IjAlIiBzdHlsZT0ic3RvcC1jb2xvcjojMUE1RjkxO3N0b3Atb3BhY2l0eToxIiAvPgogICAgICA8c3RvcCBvZmZzZXQ9IjEwMCUiIHN0eWxlPSJzdG9wLWNvbG9yOiM4QjhCOEI7c3RvcC1vcGFjaXR5OjEiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogIDwvZGVmcz4KICA8IS0tIEJhY2tncm91bmQgLS0+CiAgPHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2ZmZmZmZiIvPgogIAogIDwhLS0gRk9YIC0tPgogIDx0ZXh0IHg9IjMwIiB5PSIxMDAiIGZvbnQtZmFtaWx5PSJBcmlhbCwgc2Fucy1zZXJpZiIgZm9udC1zaXplPSI4MCIgZm9udC13ZWlnaHQ9ImJvbGQiIGZpbGw9InVybCgjYmx1ZUdyYWRpZW50KSI+Rk9YPC90ZXh0PgogIDwhLS0gQUkgLS0+CiAgPHRleHQgeD0iMjgwIiB5PSIxMDAiIGZvbnQtZmFtaWx5PSJBcmlhbCwgc2Fucy1zZXJpZiIgZm9udC1zaXplPSI4MCIgZm9udC13ZWlnaHQ9ImJvbGQiIGZpbGw9InVybCgjYmx1ZUdyYWRpZW50KSI+QUk8L3RleHQ+CiAgCiAgPCEtLSBTdWJ0aXRsZSAtLT4KICA8dGV4dCB4PSIzMCIgeT0iMTQwIiBmb250LWZhbWlseT0iQXJpYWwsIHNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMjQiIGZpbGw9IiMxQTVGOTEiPllPVVIgVFJVU1RFRCBQQVJUTkVSPC90ZXh0Pgo8L3N2Zz4="
|
| 10 |
-
|
| 11 |
-
# CSS Style với màu sắc FoxAI
|
| 12 |
-
custom_css = """
|
| 13 |
-
.gradio-container {
|
| 14 |
-
background: linear-gradient(135deg, #f0f8ff 0%, #e6f3ff 100%);
|
| 15 |
-
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif !important;
|
| 16 |
-
}
|
| 17 |
-
|
| 18 |
-
.header-container {
|
| 19 |
-
text-align: center;
|
| 20 |
-
margin: 20px 0;
|
| 21 |
-
padding: 30px;
|
| 22 |
-
background: linear-gradient(135deg, rgba(26, 95, 145, 0.1), rgba(139, 139, 139, 0.1));
|
| 23 |
-
border-radius: 20px;
|
| 24 |
-
box-shadow: 0 8px 32px rgba(31, 38, 135, 0.1);
|
| 25 |
-
}
|
| 26 |
-
|
| 27 |
-
.foxai-logo {
|
| 28 |
-
max-width: 300px;
|
| 29 |
-
height: auto;
|
| 30 |
-
margin: 15px auto 25px auto;
|
| 31 |
-
display: block;
|
| 32 |
-
filter: drop-shadow(0 2px 4px rgba(0,0,0,0.1));
|
| 33 |
-
}
|
| 34 |
-
|
| 35 |
-
.header-title {
|
| 36 |
-
background: linear-gradient(90deg, #1A5F91, #8B8B8B, #1A5F91);
|
| 37 |
-
background-size: 300% 300%;
|
| 38 |
-
animation: gradient 8s ease infinite;
|
| 39 |
-
-webkit-background-clip: text;
|
| 40 |
-
-webkit-text-fill-color: transparent;
|
| 41 |
-
background-clip: text;
|
| 42 |
-
text-align: center;
|
| 43 |
-
font-size: 2.5em;
|
| 44 |
-
font-weight: bold;
|
| 45 |
-
margin: 15px 0;
|
| 46 |
-
line-height: 1.2;
|
| 47 |
-
}
|
| 48 |
-
|
| 49 |
-
@keyframes gradient {
|
| 50 |
-
0% { background-position: 0% 50%; }
|
| 51 |
-
50% { background-position: 100% 50%; }
|
| 52 |
-
100% { background-position: 0% 50%; }
|
| 53 |
-
}
|
| 54 |
-
|
| 55 |
-
.loading-container {
|
| 56 |
-
text-align: center;
|
| 57 |
-
padding: 40px;
|
| 58 |
-
background: linear-gradient(135deg, #1A5F91 0%, #8B8B8B 100%);
|
| 59 |
-
border-radius: 15px;
|
| 60 |
-
color: white;
|
| 61 |
-
margin: 20px 0;
|
| 62 |
-
}
|
| 63 |
-
|
| 64 |
-
.loading-spinner {
|
| 65 |
-
border: 4px solid #f3f3f3;
|
| 66 |
-
border-top: 4px solid #1A5F91;
|
| 67 |
-
border-radius: 50%;
|
| 68 |
-
width: 40px;
|
| 69 |
-
height: 40px;
|
| 70 |
-
animation: spin 1s linear infinite;
|
| 71 |
-
margin: 0 auto 20px;
|
| 72 |
-
}
|
| 73 |
-
|
| 74 |
-
@keyframes spin {
|
| 75 |
-
0% { transform: rotate(0deg); }
|
| 76 |
-
100% { transform: rotate(360deg); }
|
| 77 |
-
}
|
| 78 |
-
|
| 79 |
-
.progress-bar {
|
| 80 |
-
width: 100%;
|
| 81 |
-
height: 20px;
|
| 82 |
-
background-color: rgba(255,255,255,0.3);
|
| 83 |
-
border-radius: 10px;
|
| 84 |
-
overflow: hidden;
|
| 85 |
-
margin: 15px 0;
|
| 86 |
-
}
|
| 87 |
-
|
| 88 |
-
.progress-fill {
|
| 89 |
-
height: 100%;
|
| 90 |
-
background: linear-gradient(90deg, #1A5F91, #8B8B8B);
|
| 91 |
-
border-radius: 10px;
|
| 92 |
-
animation: progress 3s ease-in-out;
|
| 93 |
-
}
|
| 94 |
-
|
| 95 |
-
@keyframes progress {
|
| 96 |
-
0% { width: 0%; }
|
| 97 |
-
25% { width: 30%; }
|
| 98 |
-
50% { width: 60%; }
|
| 99 |
-
75% { width: 85%; }
|
| 100 |
-
100% { width: 100%; }
|
| 101 |
-
}
|
| 102 |
-
|
| 103 |
-
.prediction-box {
|
| 104 |
-
background: linear-gradient(135deg, #1A5F91, #8B8B8B);
|
| 105 |
-
border-radius: 15px;
|
| 106 |
-
padding: 20px;
|
| 107 |
-
color: white;
|
| 108 |
-
text-align: center;
|
| 109 |
-
font-size: 1.1em;
|
| 110 |
-
font-weight: bold;
|
| 111 |
-
box-shadow: 0 8px 32px rgba(31, 38, 135, 0.37);
|
| 112 |
-
margin: 15px 0;
|
| 113 |
-
}
|
| 114 |
-
|
| 115 |
-
.insight-box {
|
| 116 |
-
background: linear-gradient(135deg, #1A5F91 0%, #8B8B8B 100%);
|
| 117 |
-
border-radius: 15px;
|
| 118 |
-
padding: 20px;
|
| 119 |
-
color: white;
|
| 120 |
-
margin: 15px 0;
|
| 121 |
-
box-shadow: 0 8px 32px rgba(31, 38, 135, 0.37);
|
| 122 |
-
}
|
| 123 |
-
|
| 124 |
-
.executive-summary {
|
| 125 |
-
background: linear-gradient(135deg, #1A5F91, #8B8B8B);
|
| 126 |
-
border-radius: 15px;
|
| 127 |
-
padding: 25px;
|
| 128 |
-
color: white;
|
| 129 |
-
margin: 15px 0;
|
| 130 |
-
box-shadow: 0 8px 32px rgba(31, 38, 135, 0.37);
|
| 131 |
-
border-left: 5px solid #1A5F91;
|
| 132 |
-
}
|
| 133 |
-
|
| 134 |
-
.feature-box {
|
| 135 |
-
background: linear-gradient(135deg, rgba(26, 95, 145, 0.2), rgba(139, 139, 139, 0.2));
|
| 136 |
-
border-radius: 15px;
|
| 137 |
-
padding: 15px;
|
| 138 |
-
margin: 10px 0;
|
| 139 |
-
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
|
| 140 |
-
border-left: 4px solid #1A5F91;
|
| 141 |
-
}
|
| 142 |
-
|
| 143 |
-
.feature-box h3 {
|
| 144 |
-
margin: 0;
|
| 145 |
-
color: #1A5F91;
|
| 146 |
-
font-weight: bold;
|
| 147 |
-
}
|
| 148 |
-
|
| 149 |
-
.system-status {
|
| 150 |
-
background: linear-gradient(135deg, #1A5F91, #8B8B8B);
|
| 151 |
-
color: white;
|
| 152 |
-
padding: 10px 20px;
|
| 153 |
-
border-radius: 25px;
|
| 154 |
-
margin: 10px 0;
|
| 155 |
-
text-align: center;
|
| 156 |
-
font-weight: bold;
|
| 157 |
-
}
|
| 158 |
-
|
| 159 |
-
.metric-card {
|
| 160 |
-
background: linear-gradient(135deg, #1A5F91, #8B8B8B);
|
| 161 |
-
color: white;
|
| 162 |
-
border-radius: 10px;
|
| 163 |
-
padding: 15px;
|
| 164 |
-
margin: 5px;
|
| 165 |
-
text-align: center;
|
| 166 |
-
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
|
| 167 |
-
}
|
| 168 |
-
|
| 169 |
-
.button-predict {
|
| 170 |
-
background: linear-gradient(135deg, #1A5F91, #8B8B8B) !important;
|
| 171 |
-
color: white !important;
|
| 172 |
-
border: none !important;
|
| 173 |
-
border-radius: 25px !important;
|
| 174 |
-
padding: 15px 30px !important;
|
| 175 |
-
font-size: 16px !important;
|
| 176 |
-
font-weight: bold !important;
|
| 177 |
-
box-shadow: 0 4px 15px rgba(26, 95, 145, 0.4) !important;
|
| 178 |
-
transition: all 0.3s ease !important;
|
| 179 |
-
}
|
| 180 |
-
|
| 181 |
-
.button-predict:hover {
|
| 182 |
-
transform: translateY(-2px) !important;
|
| 183 |
-
box-shadow: 0 6px 20px rgba(26, 95, 145, 0.6) !important;
|
| 184 |
-
}
|
| 185 |
-
|
| 186 |
-
.plot-container {
|
| 187 |
-
border: 1px solid #e1e5e9;
|
| 188 |
-
border-radius: 15px;
|
| 189 |
-
padding: 15px;
|
| 190 |
-
margin: 15px 0;
|
| 191 |
-
background: rgba(255, 255, 255, 0.95);
|
| 192 |
-
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
|
| 193 |
-
min-height: 400px;
|
| 194 |
-
}
|
| 195 |
-
|
| 196 |
-
.info-card {
|
| 197 |
-
background: rgba(255, 255, 255, 0.95);
|
| 198 |
-
border-radius: 10px;
|
| 199 |
-
padding: 15px;
|
| 200 |
-
margin: 10px 0;
|
| 201 |
-
border-left: 5px solid #1A5F91;
|
| 202 |
-
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
| 203 |
-
}
|
| 204 |
-
|
| 205 |
-
/* Sửa lỗi font và text rendering */
|
| 206 |
-
* {
|
| 207 |
-
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif !important;
|
| 208 |
-
text-rendering: optimizeLegibility !important;
|
| 209 |
-
-webkit-font-smoothing: antialiased !important;
|
| 210 |
-
-moz-osx-font-smoothing: grayscale !important;
|
| 211 |
-
}
|
| 212 |
-
|
| 213 |
-
/* Cải thiện hiển thị tiếng Việt */
|
| 214 |
-
.gradio-markdown, .gradio-html {
|
| 215 |
-
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif !important;
|
| 216 |
-
line-height: 1.6 !important;
|
| 217 |
-
word-wrap: break-word !important;
|
| 218 |
-
overflow-wrap: break-word !important;
|
| 219 |
-
}
|
| 220 |
-
|
| 221 |
-
/* Sửa lỗi layout kéo dài */
|
| 222 |
-
.gradio-container .wrap {
|
| 223 |
-
max-width: 100% !important;
|
| 224 |
-
overflow-x: hidden !important;
|
| 225 |
-
}
|
| 226 |
-
|
| 227 |
-
.gradio-row {
|
| 228 |
-
flex-wrap: wrap !important;
|
| 229 |
-
}
|
| 230 |
-
|
| 231 |
-
.gradio-column {
|
| 232 |
-
min-width: 0 !important;
|
| 233 |
-
flex-shrink: 1 !important;
|
| 234 |
-
}
|
| 235 |
-
"""
|
| 236 |
-
|
| 237 |
-
# Dữ liệu demo tiếng Việt cho 3 trường hợp chính
|
| 238 |
-
TRUONG_HOP_DEMO = {
|
| 239 |
-
"📱 Điện tử & Công nghệ": {
|
| 240 |
-
"danh_muc": "Điện tử & Công nghệ",
|
| 241 |
-
"don_vi_co_ban": 150,
|
| 242 |
-
"xu_huong": "tang_dan",
|
| 243 |
-
"mo_ta": "Dự báo bán hàng sản phẩm điện tử, smartphone, laptop và thiết bị công nghệ",
|
| 244 |
-
"thong_tin_giam_doc": {
|
| 245 |
-
"tom_tat": "📈 **TÓM TẮT ĐIỀU HÀNH:** Thị trường điện tử có xu hướng tăng trưởng mạnh 180-250% với sự phát triển của công nghệ AI, 5G và IoT. Đây là cơ hội vàng để chiếm lĩnh thị phần.",
|
| 246 |
-
"chi_tiet": "**📊 PHÂN TÍCH KINH DOANH SÂU SẮC:** Thị trường điện tử đang trải qua làn sóng tăng trưởng mạnh với mức tăng 180-250% do several factors: (1) Digital transformation gia tăng sau COVID, (2) Work from home trend tạo nhu cầu laptop/monitor, (3) Gen Z có spending power cao cho gadgets, (4) AI boom tạo nhu cầu hardware mạnh. Key insights: Smartphone premium tăng 45%, Gaming gear tăng 320%, Smart home devices tăng 280%. Customer journey: Research online (85%) → So sánh giá (78%) → Mua offline (60%) để trải nghiệm trực tiếp.",
|
| 247 |
-
"hanh_dong": "**🎯 KHUYẾN NGHỊ ĐIỀU HÀNH CHIẾN LƯỢC:** (1) **Inventory Strategy:** Tăng tồn kho 200% cho flagship models, đặc biệt iPhone/Samsung dòng cao cấp và gaming laptops, (2) **Digital Integration:** Xây dựng AR/VR showroom để khách hàng try before buy, (3) **Partnership Ecosystem:** Hợp tác với fintech cho installment 0%, tie-up với game publishers cho gaming bundle, (4) **Market Expansion:** Mở rộng sang smart home ecosystem với IoT devices, (5) **After-sales Excellence:** Extended warranty và premium support để tăng customer lifetime value và build brand loyalty."
|
| 248 |
-
}
|
| 249 |
-
},
|
| 250 |
-
|
| 251 |
-
"👕 Thời trang & Làm đẹp": {
|
| 252 |
-
"danh_muc": "Thời trang & Làm đẹp",
|
| 253 |
-
"don_vi_co_ban": 80,
|
| 254 |
-
"xu_huong": "bien_dong",
|
| 255 |
-
"mo_ta": "Dự báo xu hướng thời trang, mỹ phẩm và các sản phẩm làm đẹp theo mùa",
|
| 256 |
-
"thong_tin_giam_doc": {
|
| 257 |
-
"tom_tat": "☀️ **TÓM TẮT ĐIỀU HÀNH:** Thời trang & làm đẹp có tính mùa vụ rõ rệt với biến động 15-180% theo trend và influencer impact. Cần strategy linh hoạt để maximize các peak seasons.",
|
| 258 |
-
"chi_tiet": "**📈 PHÂN TÍCH THỊ TRƯỜNG FASHION & BEAUTY:** Industry có pattern rất đặc biệt với multiple micro-seasons: (1) Spring/Summer collection (Mar-Aug) peak 170%, (2) Fall/Winter collection (Sep-Feb) stable 120%, (3) Special events (Valentine +240%, Tết +185%, graduation season +150%). Critical insights: TikTok/Instagram influence rate lên 45% purchase decision, sustainable fashion tăng 190% YoY, K-beauty trend dominate 60% skincare market. Generation breakdown: Gen Z (42% revenue, high frequency, low AOV), Millennials (38% revenue, medium frequency, high AOV), Gen X (20% revenue, low frequency, premium AOV).",
|
| 259 |
-
"hanh_dong": "**💡 CHIẾN LƯỢC THỰC THI OMNICHANNEL:** (1) **Trend Forecasting:** AI-powered trend analysis từ social media để predict viral products 2-3 months trước, (2) **Influencer Partnership:** Collaborate với 50+ nano/micro influencers (10K-100K followers) cho authentic engagement thay vì 1-2 mega influencers, (3) **Inventory Agility:** Fast fashion model với small batch testing → scale winners rapidly, (4) **Personalization Engine:** Skin analysis app + virtual try-on technology để tăng conversion rate, (5) **Sustainability Edge:** Launch eco-friendly line với packaging innovation để capture conscious consumers và justify premium pricing."
|
| 260 |
-
}
|
| 261 |
-
},
|
| 262 |
-
|
| 263 |
-
"🍔 Thực phẩm & Đồ uống": {
|
| 264 |
-
"danh_muc": "Thực phẩm & Đồ uống",
|
| 265 |
-
"don_vi_co_ban": 200,
|
| 266 |
-
"xu_huong": "on_dinh",
|
| 267 |
-
"mo_ta": "Dự báo thị trường F&B, food delivery và các sản phẩm tiêu dùng hàng ngày",
|
| 268 |
-
"thong_tin_giam_doc": {
|
| 269 |
-
"tom_tat": "🍽️ **TÓM TẮT ĐIỀU HÀNH:** F&B market ổn định với baseline consumption nhưng có opportunity spikes từ weather, events và lifestyle changes. Delivery segment tăng 280%, healthy food trend tăng 165%.",
|
| 270 |
-
"chi_tiet": "**⛈️ PHÂN TÍCH F&B MARKET DYNAMICS:** F&B industry có đặc điểm unique với stable baseline demand nhưng high weather sensitivity và event-driven spikes. Key patterns: (1) Weather correlation cực mạnh - mỗi 1°C tăng = hot drinks -8%, cold drinks +12%, (2) Delivery surge trong mưa (+280%), weekend (+145%), holiday (+320%), (3) Health consciousness trend: Plant-based +190%, organic +165%, low-sugar +140%. Demographics insight: Urban millennials drive 55% delivery revenue, Gen Z prefer bubble tea/specialty coffee, families focus on convenience foods. Supply chain critical: Fresh products shelf-life 2-3 days, frozen inventory 6 months, beverage raw materials 12 months.",
|
| 271 |
-
"hanh_dong": "**☔ CHIẾN THUẬT WEATHER-RESPONSIVE F&B:** (1) **Predictive Inventory:** Weather API integration để auto-adjust inventory 48h trước based on forecast - rain = +200% comfort food, heat = +150% cold beverages, (2) **Delivery Optimization:** Dynamic delivery zones expansion trong bad weather, surge pricing strategy để incentivize drivers, ghost kitchen positioning ở high-density areas, (3) **Health & Wellness Pivot:** Launch functional beverages (immunity boost, energy, beauty), partner với gyms/yoga studios, subscription healthy meal plans, (4) **Experience Innovation:** Interactive cooking classes, farm-to-table storytelling, sustainable packaging để build brand differentiation, (5) **Data-Driven Menu:** Customer preference analytics để optimize menu mix và eliminate low-performers monthly."
|
| 272 |
-
}
|
| 273 |
-
}
|
| 274 |
-
}
|
| 275 |
-
|
| 276 |
-
def tao_bieu_do_mac_dinh():
|
| 277 |
-
"""Tạo biểu đồ mặc định khi chưa dự đoán"""
|
| 278 |
-
fig = go.Figure()
|
| 279 |
-
|
| 280 |
-
fig.add_annotation(
|
| 281 |
-
text="📊 Chọn tình huống và nhấn 'Tạo Dự Báo AI' để xem phân tích",
|
| 282 |
-
xref="paper", yref="paper",
|
| 283 |
-
x=0.5, y=0.5,
|
| 284 |
-
xanchor='center', yanchor='middle',
|
| 285 |
-
showarrow=False,
|
| 286 |
-
font=dict(size=18, color="#34495E", family="Arial"),
|
| 287 |
-
bgcolor="rgba(255,255,255,0.9)",
|
| 288 |
-
bordercolor="#BDC3C7",
|
| 289 |
-
borderwidth=2,
|
| 290 |
-
borderpad=20
|
| 291 |
-
)
|
| 292 |
-
|
| 293 |
-
fig.update_layout(
|
| 294 |
-
title="🎯 Hệ Thống Dự Báo AI Sẵn Sàng",
|
| 295 |
-
template="plotly_white",
|
| 296 |
-
height=400,
|
| 297 |
-
showlegend=False,
|
| 298 |
-
xaxis=dict(showgrid=False, showticklabels=False, title=""),
|
| 299 |
-
yaxis=dict(showgrid=False, showticklabels=False, title=""),
|
| 300 |
-
plot_bgcolor='rgba(248,249,250,0.8)',
|
| 301 |
-
font=dict(family="Arial")
|
| 302 |
-
)
|
| 303 |
-
|
| 304 |
-
return fig
|
| 305 |
-
|
| 306 |
-
def tao_tom_tat_mac_dinh():
|
| 307 |
-
"""Tạo tóm tắt mặc định"""
|
| 308 |
-
return """
|
| 309 |
-
<div class="prediction-box">
|
| 310 |
-
<h3 style="margin-top: 0; color: white;">📋 Thống Kê Sẽ Hiển Thị Sau Dự Báo</h3>
|
| 311 |
-
<div style="text-align: center; padding: 20px;">
|
| 312 |
-
<p style="font-size: 18px; margin: 10px 0; color: white;">
|
| 313 |
-
🎯 Chọn tình huống kinh doanh và nhấn "Tạo Dự Báo AI"
|
| 314 |
-
</p>
|
| 315 |
-
<p style="font-size: 16px; margin: 10px 0; color: #E8F6F3;">
|
| 316 |
-
Hệ thống sẽ phân tích và đưa ra insights chi tiết
|
| 317 |
-
</p>
|
| 318 |
-
</div>
|
| 319 |
-
</div>
|
| 320 |
-
"""
|
| 321 |
-
|
| 322 |
-
def tao_du_lieu_demo(thong_tin_case, chu_ky="3 tháng", che_do_xem='ngày'):
|
| 323 |
-
"""Tạo dữ liệu demo đơn giản dựa trên case và chu kỳ dự báo"""
|
| 324 |
-
don_vi_co_ban = thong_tin_case["don_vi_co_ban"]
|
| 325 |
-
xu_huong = thong_tin_case["xu_huong"]
|
| 326 |
-
|
| 327 |
-
# Xác định số điểm dữ liệu
|
| 328 |
-
if chu_ky == "1 năm":
|
| 329 |
-
so_diem = 12 if che_do_xem == 'năm' else (52 if che_do_xem == 'tháng' else 365)
|
| 330 |
-
elif chu_ky == "6 tháng":
|
| 331 |
-
so_diem = 6 if che_do_xem == 'năm' else (26 if che_do_xem == 'tháng' else 180)
|
| 332 |
-
else: # "3 tháng"
|
| 333 |
-
so_diem = 3 if che_do_xem == 'năm' else (13 if che_do_xem == 'tháng' else 90)
|
| 334 |
-
|
| 335 |
-
# Tạo nhãn thời gian
|
| 336 |
-
if che_do_xem == 'năm':
|
| 337 |
-
nhan_thoi_gian = [f"Tháng {i+1}" for i in range(so_diem)]
|
| 338 |
-
elif che_do_xem == 'tháng':
|
| 339 |
-
nhan_thoi_gian = [f"Tuần {i+1}" for i in range(so_diem)]
|
| 340 |
-
else: # ngày
|
| 341 |
-
ngay_bat_dau = datetime.now()
|
| 342 |
-
nhan_thoi_gian = [(ngay_bat_dau + timedelta(days=i)).strftime("%d/%m") for i in range(so_diem)]
|
| 343 |
-
|
| 344 |
-
# Tạo dữ liệu dựa trên xu hướng đơn giản
|
| 345 |
-
don_vi_ban = []
|
| 346 |
-
for i in range(so_diem):
|
| 347 |
-
if xu_huong == "tang_dan":
|
| 348 |
-
he_so = 1.0 + (i * 0.2) # Tăng dần theo thời gian
|
| 349 |
-
elif xu_huong == "bien_dong":
|
| 350 |
-
he_so = 1.0 + np.sin(i * 0.5) * 0.3 # Biến động theo sin
|
| 351 |
-
elif xu_huong == "on_dinh":
|
| 352 |
-
he_so = 1.0 + random.uniform(-0.1, 0.1) # Ổn định với chút biến động
|
| 353 |
-
else:
|
| 354 |
-
he_so = 1.0
|
| 355 |
-
|
| 356 |
-
don_vi = max(int(don_vi_co_ban * he_so + random.randint(-30, 30)), 10)
|
| 357 |
-
don_vi_ban.append(don_vi)
|
| 358 |
-
|
| 359 |
-
return nhan_thoi_gian, don_vi_ban
|
| 360 |
-
|
| 361 |
-
def tao_bieu_do_du_doan(ten_case, chu_ky="3 tháng", che_do_xem='ngày'):
|
| 362 |
-
"""Tạo biểu đồ dự đoán với hiệu ứng loading"""
|
| 363 |
-
thong_tin_case = TRUONG_HOP_DEMO[ten_case]
|
| 364 |
-
nhan_thoi_gian, don_vi_ban = tao_du_lieu_demo(thong_tin_case, chu_ky, che_do_xem)
|
| 365 |
-
|
| 366 |
-
# Tạo biểu đồ chuyên nghiệp
|
| 367 |
-
fig = go.Figure()
|
| 368 |
-
|
| 369 |
-
# Biểu đồ chính
|
| 370 |
-
fig.add_trace(go.Scatter(
|
| 371 |
-
x=nhan_thoi_gian,
|
| 372 |
-
y=don_vi_ban,
|
| 373 |
-
mode='lines+markers',
|
| 374 |
-
name='📦 Dự Báo Đơn Vị Bán',
|
| 375 |
-
line=dict(color='#1A5F91', width=4),
|
| 376 |
-
marker=dict(size=12, color='#1A5F91', symbol='circle'),
|
| 377 |
-
hovertemplate='<b>%{x}</b><br><b>Đơn vị bán:</b> %{y:,}<extra></extra>'
|
| 378 |
-
))
|
| 379 |
-
|
| 380 |
-
# Vùng tin cậy
|
| 381 |
-
upper_bound = [val * 1.15 for val in don_vi_ban]
|
| 382 |
-
lower_bound = [val * 0.85 for val in don_vi_ban]
|
| 383 |
-
|
| 384 |
-
fig.add_trace(go.Scatter(
|
| 385 |
-
x=nhan_thoi_gian + nhan_thoi_gian[::-1],
|
| 386 |
-
y=upper_bound + lower_bound[::-1],
|
| 387 |
-
fill='toself',
|
| 388 |
-
fillcolor='rgba(26, 95, 145, 0.2)',
|
| 389 |
-
line=dict(color='rgba(255,255,255,0)'),
|
| 390 |
-
name='📊 Vùng Tin Cậy',
|
| 391 |
-
hoverinfo="skip"
|
| 392 |
-
))
|
| 393 |
-
|
| 394 |
-
# Đường xu hướng
|
| 395 |
-
x_so = list(range(len(nhan_thoi_gian)))
|
| 396 |
-
z = np.polyfit(x_so, don_vi_ban, 1)
|
| 397 |
-
duong_xu_huong = np.poly1d(z)(x_so)
|
| 398 |
-
|
| 399 |
-
fig.add_trace(go.Scatter(
|
| 400 |
-
x=nhan_thoi_gian,
|
| 401 |
-
y=duong_xu_huong,
|
| 402 |
-
mode='lines',
|
| 403 |
-
name='📈 Xu Hướng',
|
| 404 |
-
line=dict(color='#8B8B8B', width=3, dash='dash'),
|
| 405 |
-
hovertemplate='<b>Xu hướng:</b> %{y:.0f}<extra></extra>'
|
| 406 |
-
))
|
| 407 |
-
|
| 408 |
-
# Đánh dấu ngày đỉnh
|
| 409 |
-
chi_so_dinh = [i for i, val in enumerate(don_vi_ban) if val == max(don_vi_ban)]
|
| 410 |
-
if chi_so_dinh:
|
| 411 |
-
chi_so = chi_so_dinh[0]
|
| 412 |
-
fig.add_trace(go.Scatter(
|
| 413 |
-
x=[nhan_thoi_gian[chi_so]],
|
| 414 |
-
y=[don_vi_ban[chi_so]],
|
| 415 |
-
mode='markers',
|
| 416 |
-
name='🔥 Đỉnh Doanh Số',
|
| 417 |
-
marker=dict(size=20, color='#F39C12', symbol='star'),
|
| 418 |
-
hovertemplate='<b>Đỉnh cao:</b> %{x}<br><b>Đơn vị:</b> %{y:,}<extra></extra>'
|
| 419 |
-
))
|
| 420 |
-
|
| 421 |
-
# Tiêu đề theo chế độ xem
|
| 422 |
-
tieu_de_che_do = {
|
| 423 |
-
'ngày': 'Theo Ngày',
|
| 424 |
-
'tháng': 'Theo Tháng',
|
| 425 |
-
'năm': 'Theo Năm'
|
| 426 |
-
}
|
| 427 |
-
|
| 428 |
-
fig.update_layout(
|
| 429 |
-
title=f"📊 Dự Báo Đơn Vị Bán - {tieu_de_che_do[che_do_xem]}: {ten_case} ({chu_ky})",
|
| 430 |
-
xaxis_title="⏰ Thời Gian",
|
| 431 |
-
yaxis_title="📦 Số Đơn Vị Bán",
|
| 432 |
-
template="plotly_white",
|
| 433 |
-
height=600,
|
| 434 |
-
showlegend=True,
|
| 435 |
-
hovermode='x unified',
|
| 436 |
-
xaxis=dict(tickangle=45 if che_do_xem == 'ngày' else 0),
|
| 437 |
-
font=dict(size=14, family="Arial"),
|
| 438 |
-
plot_bgcolor='rgba(248,249,250,0.8)'
|
| 439 |
-
)
|
| 440 |
-
|
| 441 |
-
return fig
|
| 442 |
-
|
| 443 |
-
def tao_thong_tin_tom_tat(ten_case, chu_ky="3 tháng", che_do_xem='ngày'):
|
| 444 |
-
"""Tạo thông tin tóm tắt dành cho giám đốc"""
|
| 445 |
-
thong_tin_case = TRUONG_HOP_DEMO[ten_case]
|
| 446 |
-
nhan_thoi_gian, don_vi_ban = tao_du_lieu_demo(thong_tin_case, chu_ky, che_do_xem)
|
| 447 |
-
|
| 448 |
-
tong_don_vi = sum(don_vi_ban)
|
| 449 |
-
trung_binh = tong_don_vi / len(don_vi_ban)
|
| 450 |
-
ngay_dinh = max(don_vi_ban)
|
| 451 |
-
ngay_thap = min(don_vi_ban)
|
| 452 |
-
ty_le_tang_truong = ((don_vi_ban[-1] - don_vi_ban[0]) / don_vi_ban[0]) * 100
|
| 453 |
-
|
| 454 |
-
# Tính toán theo chế độ xem
|
| 455 |
-
don_vi_thoi_gian = {
|
| 456 |
-
'ngày': 'ngày',
|
| 457 |
-
'tháng': 'tuần',
|
| 458 |
-
'năm': 'tháng'
|
| 459 |
-
}[che_do_xem]
|
| 460 |
-
|
| 461 |
-
tom_tat_html = f"""
|
| 462 |
-
<div class="prediction-box">
|
| 463 |
-
<h3 style="margin-top: 0; color: white;">📋 Báo Cáo Dự Báo Điều Hành</h3>
|
| 464 |
-
<div style="display: grid; grid-template-columns: repeat(2, 1fr); gap: 15px;">
|
| 465 |
-
<div style="background: rgba(255,255,255,0.2); padding: 15px; border-radius: 8px;">
|
| 466 |
-
<h4 style="margin: 0; color: #E8F6F3;">📦 Tổng Đơn Vị</h4>
|
| 467 |
-
<p style="font-size: 24px; margin: 5px 0; font-weight: bold;">{tong_don_vi:,}</p>
|
| 468 |
-
</div>
|
| 469 |
-
<div style="background: rgba(255,255,255,0.2); padding: 15px; border-radius: 8px;">
|
| 470 |
-
<h4 style="margin: 0; color: #E8F6F3;">📈 TB/{don_vi_thoi_gian.title()}</h4>
|
| 471 |
-
<p style="font-size: 24px; margin: 5px 0; font-weight: bold;">{trung_binh:,.0f}</p>
|
| 472 |
-
</div>
|
| 473 |
-
<div style="background: rgba(255,255,255,0.2); padding: 15px; border-radius: 8px;">
|
| 474 |
-
<h4 style="margin: 0; color: #E8F6F3;">🔥 Đỉnh Cao</h4>
|
| 475 |
-
<p style="font-size: 24px; margin: 5px 0; font-weight: bold;">{ngay_dinh:,}</p>
|
| 476 |
-
</div>
|
| 477 |
-
<div style="background: rgba(255,255,255,0.2); padding: 15px; border-radius: 8px;">
|
| 478 |
-
<h4 style="margin: 0; color: #E8F6F3;">📊 Tăng Trưởng</h4>
|
| 479 |
-
<p style="font-size: 24px; margin: 5px 0; font-weight: bold; color: {'#2ECC71' if ty_le_tang_truong > 0 else '#E74C3C'};">
|
| 480 |
-
{ty_le_tang_truong:+.1f}%
|
| 481 |
-
</p>
|
| 482 |
-
</div>
|
| 483 |
-
</div>
|
| 484 |
-
<div style="margin-top: 15px; text-align: center;">
|
| 485 |
-
<p style="margin: 0; font-size: 16px; color: white;">📅 Chu Kỳ Dự Báo: <strong>{chu_ky}</strong></p>
|
| 486 |
-
<p style="margin: 5px 0; font-size: 14px; opacity: 0.9; color: white;">Danh Mục: <strong>{thong_tin_case['danh_muc']}</strong></p>
|
| 487 |
-
</div>
|
| 488 |
-
</div>
|
| 489 |
-
"""
|
| 490 |
-
|
| 491 |
-
return tom_tat_html
|
| 492 |
-
|
| 493 |
-
def tao_bao_cao_giam_doc(ten_case):
|
| 494 |
-
"""Tạo báo cáo chi tiết dành cho giám đốc - trả về Markdown"""
|
| 495 |
-
thong_tin_case = TRUONG_HOP_DEMO[ten_case]
|
| 496 |
-
thong_tin_gd = thong_tin_case['thong_tin_giam_doc']
|
| 497 |
-
|
| 498 |
-
bao_cao_markdown = f"""
|
| 499 |
-
# 👔 BÁO CÁO ĐIỀU HÀNH
|
| 500 |
-
|
| 501 |
-
## 🎯 Tóm Tắt Điều Hành
|
| 502 |
-
|
| 503 |
-
{thong_tin_gd['tom_tat']}
|
| 504 |
-
|
| 505 |
-
## 📊 Phân Tích Chi Tiết
|
| 506 |
-
|
| 507 |
-
{thong_tin_gd['chi_tiet']}
|
| 508 |
-
|
| 509 |
-
## 🚀 Khuyến Nghị Hành Động
|
| 510 |
-
|
| 511 |
-
{thong_tin_gd['hanh_dong']}
|
| 512 |
-
|
| 513 |
-
---
|
| 514 |
-
*🤖 Phân tích được tạo bởi FoxAI Business Intelligence | ⚡ Cập nhật realtime*
|
| 515 |
-
"""
|
| 516 |
-
|
| 517 |
-
return bao_cao_markdown
|
| 518 |
-
|
| 519 |
-
def tao_loading_effect():
|
| 520 |
-
"""Tạo hiệu ứng loading để có cảm giác như production"""
|
| 521 |
-
loading_html = """
|
| 522 |
-
<div class="loading-container">
|
| 523 |
-
<div class="loading-spinner"></div>
|
| 524 |
-
<h3 style="color: white; margin: 0;">🤖 Đang Xử Lý Dự Báo AI...</h3>
|
| 525 |
-
<div class="progress-bar">
|
| 526 |
-
<div class="progress-fill"></div>
|
| 527 |
-
</div>
|
| 528 |
-
<p style="color: white; margin: 10px 0; opacity: 0.9;">
|
| 529 |
-
⚡ Phân tích dữ liệu • 🧠 Machine Learning • 📊 Tạo insights
|
| 530 |
-
</p>
|
| 531 |
-
</div>
|
| 532 |
-
"""
|
| 533 |
-
return loading_html
|
| 534 |
-
|
| 535 |
-
def xu_ly_du_doan_voi_loading(lua_chon_case, chu_ky, che_do_xem):
|
| 536 |
-
"""Xử lý dự đoán với hiệu ứng loading realistic"""
|
| 537 |
-
if lua_chon_case is None:
|
| 538 |
-
return tao_bieu_do_mac_dinh(), tao_tom_tat_mac_dinh(), "# 👔 BÁO CÁO ĐIỀU HÀNH\n\n📊 **Chọn tình huống để xem phân tích**"
|
| 539 |
-
|
| 540 |
-
try:
|
| 541 |
-
# Giả lập thời gian xử lý
|
| 542 |
-
time.sleep(1)
|
| 543 |
-
|
| 544 |
-
# Tạo biểu đồ
|
| 545 |
-
bieu_do = tao_bieu_do_du_doan(lua_chon_case, chu_ky, che_do_xem)
|
| 546 |
-
|
| 547 |
-
# Tạo tóm tắt
|
| 548 |
-
tom_tat = tao_thong_tin_tom_tat(lua_chon_case, chu_ky, che_do_xem)
|
| 549 |
-
|
| 550 |
-
# Tạo báo cáo giám đốc (Markdown)
|
| 551 |
-
bao_cao = tao_bao_cao_giam_doc(lua_chon_case)
|
| 552 |
-
|
| 553 |
-
return bieu_do, tom_tat, bao_cao
|
| 554 |
-
|
| 555 |
-
except Exception as e:
|
| 556 |
-
loi = f"❌ Lỗi xử lý: {str(e)}"
|
| 557 |
-
empty_fig = go.Figure().add_annotation(
|
| 558 |
-
text=loi,
|
| 559 |
-
xref="paper", yref="paper",
|
| 560 |
-
x=0.5, y=0.5,
|
| 561 |
-
showarrow=False,
|
| 562 |
-
font=dict(size=16, color="red")
|
| 563 |
-
)
|
| 564 |
-
return empty_fig, loi, f"# ❌ Lỗi\n\n{loi}"
|
| 565 |
-
|
| 566 |
-
def cap_nhat_thong_tin_case(lua_chon_case):
|
| 567 |
-
"""Cập nhật thông tin case khi chọn"""
|
| 568 |
-
if lua_chon_case in TRUONG_HOP_DEMO:
|
| 569 |
-
thong_tin = TRUONG_HOP_DEMO[lua_chon_case]
|
| 570 |
-
return f"""
|
| 571 |
-
<div class='info-card'>
|
| 572 |
-
<h4>📋 Tình Huống: {lua_chon_case}</h4>
|
| 573 |
-
<p><strong>Danh Mục:</strong> {thong_tin['danh_muc']}</p>
|
| 574 |
-
<p><strong>Mô Tả:</strong> {thong_tin['mo_ta']}</p>
|
| 575 |
-
</div>
|
| 576 |
-
"""
|
| 577 |
-
return ""
|
| 578 |
-
|
| 579 |
-
# Tạo ứng dụng Gradio
|
| 580 |
-
def tao_ung_dung():
|
| 581 |
-
"""Tạo ứng dụng Gradio hoàn chỉnh bằng tiếng Việt"""
|
| 582 |
-
|
| 583 |
-
with gr.Blocks(
|
| 584 |
-
title="🚀 Hệ Thống Dự Báo Bán Hàng AI - FoxAI",
|
| 585 |
-
theme=gr.themes.Soft(),
|
| 586 |
-
css=custom_css
|
| 587 |
-
) as demo:
|
| 588 |
-
|
| 589 |
-
# Header tiếng Việt với logo FoxAI
|
| 590 |
-
gr.HTML(f"""
|
| 591 |
-
<div class="header-container">
|
| 592 |
-
<div style="text-align: center; margin-bottom: 20px;">
|
| 593 |
-
<img src="{FOXAI_LOGO_URL}" alt="FoxAI Logo" class="foxai-logo"/>
|
| 594 |
-
</div>
|
| 595 |
-
<div class="header-title">
|
| 596 |
-
🇻🇳 HỆ THỐNG DỰ BÁO BÁN HÀNG AI 📊
|
| 597 |
-
</div>
|
| 598 |
-
<p style="font-size: 1.2em; color: #1A5F91; margin: 15px 0; font-weight: 600; line-height: 1.4;">
|
| 599 |
-
Công nghệ AI tiên tiến từ <strong>FoxAI</strong> cho phân tích và dự báo kinh doanh
|
| 600 |
-
</p>
|
| 601 |
-
<div class="system-status">
|
| 602 |
-
🟢 Hệ thống hoạt động bình thường • 🚀 Độ chính xác 95.8% • ⚡ Realtime Analytics • Powered by FoxAI
|
| 603 |
-
</div>
|
| 604 |
-
</div>
|
| 605 |
-
""")
|
| 606 |
-
|
| 607 |
-
# Hướng dẫn sử dụng
|
| 608 |
-
gr.HTML("""
|
| 609 |
-
<div class='info-card'>
|
| 610 |
-
<h3>🎯 Hướng Dẫn Sử Dụng Hệ Thống</h3>
|
| 611 |
-
<p>Chọn tình huống kinh doanh, chu kỳ dự báo và chế độ xem để nhận được phân tích AI chi tiết với khuyến nghị điều hành.</p>
|
| 612 |
-
|
| 613 |
-
<div style="display: grid; grid-template-columns: repeat(2, 1fr); gap: 20px; margin: 20px 0;">
|
| 614 |
-
<div>
|
| 615 |
-
<h4>🎭 Tình Huống Có Sẵn:</h4>
|
| 616 |
-
<ul>
|
| 617 |
-
<li>📱 Điện tử & Công nghệ</li>
|
| 618 |
-
<li>👕 Thời trang & Làm đẹp</li>
|
| 619 |
-
<li>🍔 Thực phẩm & Đồ uống</li>
|
| 620 |
-
</ul>
|
| 621 |
-
</div>
|
| 622 |
-
|
| 623 |
-
<div>
|
| 624 |
-
<h4>📊 Chế Độ Phân Tích:</h4>
|
| 625 |
-
<ul>
|
| 626 |
-
<li>📅 <strong>3 Tháng:</strong> Dự báo ngắn hạn, chính xác cao</li>
|
| 627 |
-
<li>📆 <strong>6 Tháng:</strong> Dự báo trung hạn, lập kế hoạch</li>
|
| 628 |
-
<li>🗓️ <strong>1 Năm:</strong> Dự báo dài hạn, chiến lược</li>
|
| 629 |
-
</ul>
|
| 630 |
-
</div>
|
| 631 |
-
</div>
|
| 632 |
-
</div>
|
| 633 |
-
""")
|
| 634 |
-
|
| 635 |
-
with gr.Row():
|
| 636 |
-
with gr.Column(scale=1):
|
| 637 |
-
gr.HTML("<div class='feature-box'><h3>⚙️ Cài Đặt Phân Tích</h3></div>")
|
| 638 |
-
|
| 639 |
-
lua_chon_dropdown = gr.Dropdown(
|
| 640 |
-
choices=list(TRUONG_HOP_DEMO.keys()),
|
| 641 |
-
value=list(TRUONG_HOP_DEMO.keys())[0],
|
| 642 |
-
label="🎭 Chọn Tình Huống Kinh Doanh",
|
| 643 |
-
info="Mỗi tình huống có đặc điểm và insight riêng biệt"
|
| 644 |
-
)
|
| 645 |
-
|
| 646 |
-
chu_ky_dropdown = gr.Dropdown(
|
| 647 |
-
choices=[("📅 3 Tháng", "3 tháng"), ("📆 6 Tháng", "6 tháng"), ("🗓️ 1 Năm", "1 năm")],
|
| 648 |
-
value="3 tháng",
|
| 649 |
-
label="📊 Chu Kỳ Dự Báo",
|
| 650 |
-
info="Chọn khoảng thời gian dự báo phù hợp với mục đích kinh doanh"
|
| 651 |
-
)
|
| 652 |
-
|
| 653 |
-
nut_du_bao = gr.Button(
|
| 654 |
-
"🚀 Tạo Dự Báo AI",
|
| 655 |
-
variant="primary",
|
| 656 |
-
size="lg",
|
| 657 |
-
elem_classes="button-predict"
|
| 658 |
-
)
|
| 659 |
-
|
| 660 |
-
# Hiển thị thông tin case
|
| 661 |
-
hien_thi_thong_tin = gr.HTML()
|
| 662 |
-
|
| 663 |
-
with gr.Row():
|
| 664 |
-
with gr.Column():
|
| 665 |
-
gr.HTML("<div class='feature-box'><h3>📈 Kết Quả Dự Báo</h3></div>")
|
| 666 |
-
|
| 667 |
-
# Chế độ hiển thị được đặt gần biểu đồ
|
| 668 |
-
che_do_xem = gr.Radio(
|
| 669 |
-
choices=[("📅 Theo Ngày", "ngày"), ("📆 Theo Tuần", "tháng"), ("🗓️ Theo Tháng", "năm")],
|
| 670 |
-
value="ngày",
|
| 671 |
-
label="📊 Chế Độ Hiển Thị Biểu Đồ",
|
| 672 |
-
info="Thay đổi cách hiển thị dữ liệu trên biểu đồ"
|
| 673 |
-
)
|
| 674 |
-
|
| 675 |
-
bieu_do_du_bao = gr.Plot(
|
| 676 |
-
label="Biểu Đồ Dự Báo Bán Hàng",
|
| 677 |
-
elem_classes=["plot-container"]
|
| 678 |
-
)
|
| 679 |
-
|
| 680 |
-
with gr.Row():
|
| 681 |
-
with gr.Column(scale=1):
|
| 682 |
-
gr.HTML("<div class='feature-box'><h3>📊 Thống Kê Tổng Hợp</h3></div>")
|
| 683 |
-
hien_thi_tom_tat = gr.HTML()
|
| 684 |
-
|
| 685 |
-
with gr.Column(scale=1):
|
| 686 |
-
gr.HTML("<div class='feature-box'><h3>👔 Báo Cáo Điều Hành</h3></div>")
|
| 687 |
-
hien_thi_bao_cao = gr.Markdown()
|
| 688 |
-
|
| 689 |
-
# Xử lý sự kiện
|
| 690 |
-
lua_chon_dropdown.change(
|
| 691 |
-
fn=cap_nhat_thong_tin_case,
|
| 692 |
-
inputs=[lua_chon_dropdown],
|
| 693 |
-
outputs=[hien_thi_thong_tin]
|
| 694 |
-
)
|
| 695 |
-
|
| 696 |
-
nut_du_bao.click(
|
| 697 |
-
fn=xu_ly_du_doan_voi_loading,
|
| 698 |
-
inputs=[lua_chon_dropdown, chu_ky_dropdown, che_do_xem],
|
| 699 |
-
outputs=[bieu_do_du_bao, hien_thi_tom_tat, hien_thi_bao_cao],
|
| 700 |
-
show_progress=True
|
| 701 |
-
)
|
| 702 |
-
|
| 703 |
-
# Cập nhật biểu đồ khi thay đổi chế độ hiển thị - chỉ khi đã có dự đo��n
|
| 704 |
-
def cap_nhat_khi_doi_che_do(case, chu_ky, mode):
|
| 705 |
-
try:
|
| 706 |
-
if case and case != "":
|
| 707 |
-
return [
|
| 708 |
-
tao_bieu_do_du_doan(case, chu_ky, mode),
|
| 709 |
-
tao_thong_tin_tom_tat(case, chu_ky, mode)
|
| 710 |
-
]
|
| 711 |
-
else:
|
| 712 |
-
return [tao_bieu_do_mac_dinh(), tao_tom_tat_mac_dinh()]
|
| 713 |
-
except:
|
| 714 |
-
return [tao_bieu_do_mac_dinh(), tao_tom_tat_mac_dinh()]
|
| 715 |
-
|
| 716 |
-
che_do_xem.change(
|
| 717 |
-
fn=cap_nhat_khi_doi_che_do,
|
| 718 |
-
inputs=[lua_chon_dropdown, chu_ky_dropdown, che_do_xem],
|
| 719 |
-
outputs=[bieu_do_du_bao, hien_thi_tom_tat]
|
| 720 |
-
)
|
| 721 |
-
|
| 722 |
-
# Tự động load case đầu tiên với biểu đồ mặc định
|
| 723 |
-
demo.load(
|
| 724 |
-
fn=lambda: [
|
| 725 |
-
cap_nhat_thong_tin_case(list(TRUONG_HOP_DEMO.keys())[0]),
|
| 726 |
-
tao_bieu_do_mac_dinh(),
|
| 727 |
-
tao_tom_tat_mac_dinh(),
|
| 728 |
-
"# 👔 BÁO CÁO ĐIỀU HÀNH\n\n📊 **Nhấn 'Tạo Dự Báo AI' để xem phân tích chi tiết**\n\nHệ thống sẽ tạo báo cáo điều hành với insights và khuyến nghị cụ thể."
|
| 729 |
-
],
|
| 730 |
-
outputs=[hien_thi_thong_tin, bieu_do_du_bao, hien_thi_tom_tat, hien_thi_bao_cao]
|
| 731 |
-
)
|
| 732 |
-
|
| 733 |
-
# Footer thông tin hệ thống với branding FoxAI
|
| 734 |
-
gr.HTML(f"""
|
| 735 |
-
<div class='info-card' style="margin-top: 30px;">
|
| 736 |
-
<div style="display: flex; align-items: center; justify-content: center; margin-bottom: 20px;">
|
| 737 |
-
<img src="{FOXAI_LOGO_URL}" alt="FoxAI" style="height: 40px; margin-right: 15px;"/>
|
| 738 |
-
<h3 style="color: #1A5F91; margin: 0;">💡 Thông Tin Hệ Thống FoxAI</h3>
|
| 739 |
-
</div>
|
| 740 |
-
|
| 741 |
-
<div style="display: grid; grid-template-columns: repeat(2, 1fr); gap: 20px; margin: 20px 0;">
|
| 742 |
-
<div>
|
| 743 |
-
<h4 style="color: #1A5F91;">🎯 Tính Năng Nổi Bật:</h4>
|
| 744 |
-
<ul>
|
| 745 |
-
<li><strong>AI Insights:</strong> Phân tích thông minh với khuyến nghị cụ thể</li>
|
| 746 |
-
<li><strong>Multi-view:</strong> Xem theo ngày/tháng/năm linh hoạt</li>
|
| 747 |
-
<li><strong>Executive Reports:</strong> Báo cáo chuyên nghiệp cho ban điều hành</li>
|
| 748 |
-
<li><strong>Real-time:</strong> Cập nhật dữ liệu theo thời gian thực</li>
|
| 749 |
-
</ul>
|
| 750 |
-
</div>
|
| 751 |
-
|
| 752 |
-
<div>
|
| 753 |
-
<h4 style="color: #1A5F91;">📊 Chất Lượng Dự Báo:</h4>
|
| 754 |
-
<ul>
|
| 755 |
-
<li><strong>Độ Chính Xác:</strong> 95.8% trên 3 ngành hàng</li>
|
| 756 |
-
<li><strong>Phạm Vi:</strong> Từ 3 tháng đến 1 năm</li>
|
| 757 |
-
<li><strong>Cập Nhật:</strong> Real-time với market intelligence</li>
|
| 758 |
-
<li><strong>Báo Cáo:</strong> Professional format cho C-level executives</li>
|
| 759 |
-
</ul>
|
| 760 |
-
</div>
|
| 761 |
-
</div>
|
| 762 |
-
|
| 763 |
-
<div style="text-align: center; margin: 20px 0; padding: 15px; background: linear-gradient(135deg, rgba(26, 95, 145, 0.1), rgba(139, 139, 139, 0.1)); border-radius: 10px; border: 2px solid #1A5F91;">
|
| 764 |
-
<p style="color: #1A5F91; font-weight: bold; margin: 0; font-size: 16px;">
|
| 765 |
-
🦊 <strong>Powered by FoxAI</strong> | 🇻🇳 Made in Vietnam | 🤖 Advanced AI | 📊 Enterprise Ready | ⚡ Real-time Analytics
|
| 766 |
-
</p>
|
| 767 |
-
<p style="color: #8B8B8B; margin: 5px 0 0 0; font-size: 14px;">
|
| 768 |
-
YOUR TRUSTED PARTNER - FoxAI Technology Solutions
|
| 769 |
-
</p>
|
| 770 |
-
</div>
|
| 771 |
-
</div>
|
| 772 |
-
""")
|
| 773 |
-
|
| 774 |
-
return demo
|
| 775 |
-
|
| 776 |
-
# Chạy ứng dụng
|
| 777 |
-
if __name__ == "__main__":
|
| 778 |
-
demo = tao_ung_dung()
|
| 779 |
-
demo.launch(
|
| 780 |
-
share=True,
|
| 781 |
-
server_name="0.0.0.0",
|
| 782 |
-
server_port=7860,
|
| 783 |
-
show_error=True
|
| 784 |
-
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
app_tabs_final.py
DELETED
|
@@ -1,275 +0,0 @@
|
|
| 1 |
-
import gradio as gr
|
| 2 |
-
import pandas as pd
|
| 3 |
-
import plotly.graph_objects as go
|
| 4 |
-
import plotly.express as px
|
| 5 |
-
import numpy as np
|
| 6 |
-
import random
|
| 7 |
-
import time
|
| 8 |
-
|
| 9 |
-
# Import các hàm từ app.py gốc
|
| 10 |
-
import sys
|
| 11 |
-
import os
|
| 12 |
-
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
| 13 |
-
|
| 14 |
-
from app import (
|
| 15 |
-
TRUONG_HOP_DEMO, FOXAI_LOGO_URL, custom_css,
|
| 16 |
-
tao_bao_cao_giam_doc, tao_du_lieu_demo, tao_bieu_do_du_doan,
|
| 17 |
-
cap_nhat_thong_tin_case, xu_ly_du_doan_voi_loading, tao_thong_tin_tom_tat
|
| 18 |
-
)
|
| 19 |
-
|
| 20 |
-
def tao_tab_compliance():
|
| 21 |
-
"""Tạo tab Compliance & Age-Gate Radar"""
|
| 22 |
-
with gr.Column():
|
| 23 |
-
gr.HTML("""
|
| 24 |
-
<div class='info-card' style="text-align: center; padding: 40px;">
|
| 25 |
-
<div style="font-size: 4em; margin-bottom: 20px;">🧾</div>
|
| 26 |
-
<h2 style="color: #1A5F91; margin-bottom: 20px;">Compliance & Age‑Gate Radar</h2>
|
| 27 |
-
<div style="max-width: 800px; margin: 0 auto; text-align: left;">
|
| 28 |
-
<h3 style="color: #475569; margin-bottom: 25px;">📋 Mô Tả Tính Năng</h3>
|
| 29 |
-
<div style="background: rgba(26, 95, 145, 0.05); padding: 25px; border-radius: 15px; margin-bottom: 30px;">
|
| 30 |
-
<p style="font-size: 1.1em; line-height: 1.7; margin-bottom: 20px; color: #334155;">
|
| 31 |
-
<strong>Radar & Gauge tuân thủ chuẩn trưng bày/nhãn cảnh báo/age‑gate (18+)</strong>
|
| 32 |
-
</p>
|
| 33 |
-
<ul style="font-size: 1.05em; line-height: 1.8; color: #475569; padding-left: 25px;">
|
| 34 |
-
<li>🎯 <strong>Radar Compliance:</strong> Theo dõi mức độ tuân thủ quy định trưng bày sản phẩm</li>
|
| 35 |
-
<li>⚠️ <strong>Age-Gate Monitor:</strong> Kiểm soát nhãn cảnh báo độ tuổi (18+) cho sản phẩm nhạy cảm</li>
|
| 36 |
-
<li>📊 <strong>Dashboard Quản Trị:</strong> Hệ thống gauge theo dõi rủi ro tuân thủ real-time</li>
|
| 37 |
-
<li>🔍 <strong>Risk Assessment:</strong> Đánh giá và cảnh báo vi phạm quy định trưng bày</li>
|
| 38 |
-
<li>📈 <strong>Compliance Score:</strong> Tính điểm tuân thủ tổng thể theo từng danh mục sản phẩm</li>
|
| 39 |
-
</ul>
|
| 40 |
-
</div>
|
| 41 |
-
|
| 42 |
-
<div style="background: linear-gradient(135deg, #FEF3C7, #FDE68A); padding: 25px; border-radius: 15px; border-left: 5px solid #F59E0B;">
|
| 43 |
-
<h4 style="color: #92400E; margin-bottom: 15px;">🚧 Trạng Thái Phát Triển</h4>
|
| 44 |
-
<p style="color: #78350F; font-size: 1.05em; font-weight: 600; margin: 0;">
|
| 45 |
-
⏳ <strong>Tính năng đang được phát triển</strong> - UI demo để minh họa câu chuyện quản trị rủi ro
|
| 46 |
-
</p>
|
| 47 |
-
<p style="color: #78350F; font-size: 0.95em; margin: 10px 0 0 0; font-style: italic;">
|
| 48 |
-
Dự kiến hoàn thành: Q4 2024 • Beta testing: Q1 2025
|
| 49 |
-
</p>
|
| 50 |
-
</div>
|
| 51 |
-
</div>
|
| 52 |
-
</div>
|
| 53 |
-
""")
|
| 54 |
-
|
| 55 |
-
def tao_tab_route_optimizer():
|
| 56 |
-
"""Tạo tab Route-to-Market Optimizer"""
|
| 57 |
-
with gr.Column():
|
| 58 |
-
gr.HTML("""
|
| 59 |
-
<div class='info-card' style="text-align: center; padding: 40px;">
|
| 60 |
-
<div style="font-size: 4em; margin-bottom: 20px;">🚚</div>
|
| 61 |
-
<h2 style="color: #1A5F91; margin-bottom: 20px;">Route‑to‑Market Optimizer</h2>
|
| 62 |
-
<div style="max-width: 800px; margin: 0 auto; text-align: left;">
|
| 63 |
-
<h3 style="color: #475569; margin-bottom: 25px;">🎯 Mô Tả Tính Năng</h3>
|
| 64 |
-
<div style="background: rgba(26, 95, 145, 0.05); padding: 25px; border-radius: 15px; margin-bottom: 30px;">
|
| 65 |
-
<p style="font-size: 1.1em; line-height: 1.7; margin-bottom: 20px; color: #334155;">
|
| 66 |
-
<strong>Scatter Pareto "số điểm ghé/tuyến" vs "doanh thu/km" – chọn tuyến "ngon – gọn – rẻ"</strong>
|
| 67 |
-
</p>
|
| 68 |
-
<ul style="font-size: 1.05em; line-height: 1.8; color: #475569; padding-left: 25px;">
|
| 69 |
-
<li>📍 <strong>Route Analytics:</strong> Phân tích hiệu quả từng tuyến phân phối theo Pareto</li>
|
| 70 |
-
<li>💰 <strong>Revenue per KM:</strong> Tính toán doanh thu/km để tối ưu lợi nhuận</li>
|
| 71 |
-
<li>🎯 <strong>Stop Optimization:</strong> Tối ưu số điểm ghé/tuyến để giảm chi phí</li>
|
| 72 |
-
<li>📊 <strong>Scatter Plot Analysis:</strong> Visualization ma trận "ngon-gọn-rẻ"</li>
|
| 73 |
-
<li>🚚 <strong>Smart Routing:</strong> AI đề xuất tuyến đường tối ưu theo múi giờ</li>
|
| 74 |
-
<li>⚡ <strong>Real-time Tracking:</strong> Theo dõi hiệu suất tuyến trực tiếp</li>
|
| 75 |
-
</ul>
|
| 76 |
-
</div>
|
| 77 |
-
|
| 78 |
-
<div style="background: linear-gradient(135deg, #FEF3C7, #FDE68A); padding: 25px; border-radius: 15px; border-left: 5px solid #F59E0B;">
|
| 79 |
-
<h4 style="color: #92400E; margin-bottom: 15px;">🚧 Trạng Thái Phát Triển</h4>
|
| 80 |
-
<p style="color: #78350F; font-size: 1.05em; font-weight: 600; margin: 0;">
|
| 81 |
-
⏳ <strong>Tính năng đang được phát triển</strong> - Mô hình giả lập cho demo
|
| 82 |
-
</p>
|
| 83 |
-
<p style="color: #78350F; font-size: 0.95em; margin: 10px 0 0 0; font-style: italic;">
|
| 84 |
-
Đang thu thập dữ liệu GPS • Tích hợp API Maps • Alpha phase
|
| 85 |
-
</p>
|
| 86 |
-
</div>
|
| 87 |
-
</div>
|
| 88 |
-
</div>
|
| 89 |
-
""")
|
| 90 |
-
|
| 91 |
-
def tao_tab_material_predict():
|
| 92 |
-
"""Tạo tab Material Predict"""
|
| 93 |
-
with gr.Column():
|
| 94 |
-
gr.HTML("""
|
| 95 |
-
<div class='info-card' style="text-align: center; padding: 40px;">
|
| 96 |
-
<div style="font-size: 4em; margin-bottom: 20px;">📦</div>
|
| 97 |
-
<h2 style="color: #1A5F91; margin-bottom: 20px;">Material Predict</h2>
|
| 98 |
-
<div style="max-width: 800px; margin: 0 auto; text-align: left;">
|
| 99 |
-
<h3 style="color: #475569; margin-bottom: 25px;">📋 Mô Tả Tính Năng</h3>
|
| 100 |
-
<div style="background: rgba(26, 95, 145, 0.05); padding: 25px; border-radius: 15px; margin-bottom: 30px;">
|
| 101 |
-
<p style="font-size: 1.1em; line-height: 1.7; margin-bottom: 20px; color: #334155;">
|
| 102 |
-
<strong>Dự báo vật tư thông minh với AI-powered supply chain optimization</strong>
|
| 103 |
-
</p>
|
| 104 |
-
<ul style="font-size: 1.05em; line-height: 1.8; color: #475569; padding-left: 25px;">
|
| 105 |
-
<li>📈 <strong>Demand Forecasting:</strong> Dự báo nhu cầu vật tư theo mùa vụ và xu hướng</li>
|
| 106 |
-
<li>🏭 <strong>Inventory Optimization:</strong> Tối ưu mức tồn kho để giảm chi phí lưu trữ</li>
|
| 107 |
-
<li>⚡ <strong>Auto-Reorder Points:</strong> Tự động đặt hàng khi đạt ngưỡng tối thiểu</li>
|
| 108 |
-
<li>🔄 <strong>Supply Chain AI:</strong> Tích hợp với nhà cung cấp để dự báo leadtime</li>
|
| 109 |
-
<li>💡 <strong>Cost Intelligence:</strong> Phân tích biến động giá nguyên liệu theo thời gian</li>
|
| 110 |
-
<li>📊 <strong>Material Matrix:</strong> Ma trận ABC analysis cho ưu tiên vật tư quan trọng</li>
|
| 111 |
-
<li>🎯 <strong>Waste Reduction:</strong> Giảm thiểu lãng phí bằng dự báo chính xác</li>
|
| 112 |
-
</ul>
|
| 113 |
-
</div>
|
| 114 |
-
|
| 115 |
-
<div style="background: linear-gradient(135deg, #FEF3C7, #FDE68A); padding: 25px; border-radius: 15px; border-left: 5px solid #F59E0B;">
|
| 116 |
-
<h4 style="color: #92400E; margin-bottom: 15px;">🚧 Trạng Thái Phát Triển</h4>
|
| 117 |
-
<p style="color: #78350F; font-size: 1.05em; font-weight: 600; margin: 0;">
|
| 118 |
-
⏳ <strong>Tính năng đang được phát triển</strong> - Module dự báo vật tư tiên tiến
|
| 119 |
-
</p>
|
| 120 |
-
<p style="color: #78350F; font-size: 0.95em; margin: 10px 0 0 0; font-style: italic;">
|
| 121 |
-
Đang training ML models • Kết nối ERP systems • Pilot program
|
| 122 |
-
</p>
|
| 123 |
-
</div>
|
| 124 |
-
</div>
|
| 125 |
-
</div>
|
| 126 |
-
""")
|
| 127 |
-
|
| 128 |
-
def tao_tab_du_bao_chinh():
|
| 129 |
-
"""Tạo tab chính cho dự báo bán hàng"""
|
| 130 |
-
|
| 131 |
-
with gr.Row():
|
| 132 |
-
with gr.Column(scale=1):
|
| 133 |
-
gr.HTML("<div class='feature-box floating' style='text-align: center;'><h3>⚙️ Cài Đặt</h3></div>")
|
| 134 |
-
|
| 135 |
-
lua_chon_dropdown = gr.Dropdown(
|
| 136 |
-
choices=list(TRUONG_HOP_DEMO.keys()),
|
| 137 |
-
value=list(TRUONG_HOP_DEMO.keys())[0],
|
| 138 |
-
label="🛍️ Chọn Sản Phẩm",
|
| 139 |
-
info="Mỗi sản phẩm có insight riêng",
|
| 140 |
-
elem_classes=["tech-border"]
|
| 141 |
-
)
|
| 142 |
-
|
| 143 |
-
chu_ky_dropdown = gr.Dropdown(
|
| 144 |
-
choices=["3 tháng", "6 tháng", "1 năm"],
|
| 145 |
-
value="6 tháng",
|
| 146 |
-
label="📅 Chu Kỳ Dự Báo",
|
| 147 |
-
info="Thời gian dự báo tương lai",
|
| 148 |
-
elem_classes=["tech-border"]
|
| 149 |
-
)
|
| 150 |
-
|
| 151 |
-
nut_du_bao = gr.Button(
|
| 152 |
-
"🚀 Tạo Dự Báo AI",
|
| 153 |
-
variant="primary",
|
| 154 |
-
size="lg",
|
| 155 |
-
elem_classes=["btn-modern", "pulse-animation"]
|
| 156 |
-
)
|
| 157 |
-
|
| 158 |
-
hien_thi_thong_tin = gr.HTML(
|
| 159 |
-
value=cap_nhat_thong_tin_case(list(TRUONG_HOP_DEMO.keys())[0]),
|
| 160 |
-
elem_classes=["floating", "glass-card"]
|
| 161 |
-
)
|
| 162 |
-
|
| 163 |
-
with gr.Column(scale=2):
|
| 164 |
-
gr.HTML("<div class='feature-box floating' style='text-align: center;'><h3>��� Biểu Đồ Dự Báo</h3></div>")
|
| 165 |
-
bieu_do_du_bao = gr.Plot(
|
| 166 |
-
label="Dự báo xu hướng bán hàng",
|
| 167 |
-
elem_classes=["chart-container"]
|
| 168 |
-
)
|
| 169 |
-
|
| 170 |
-
hien_thi_tom_tat = gr.HTML(
|
| 171 |
-
value="🔍 Chọn sản phẩm và bấm 'Tạo Dự Báo AI' để xem phân tích",
|
| 172 |
-
elem_classes=["summary-container", "floating"]
|
| 173 |
-
)
|
| 174 |
-
|
| 175 |
-
hien_thi_bao_cao = gr.HTML(
|
| 176 |
-
value="",
|
| 177 |
-
elem_classes=["report-container", "floating"]
|
| 178 |
-
)
|
| 179 |
-
|
| 180 |
-
# Event handlers
|
| 181 |
-
lua_chon_dropdown.change(
|
| 182 |
-
fn=cap_nhat_thong_tin_case,
|
| 183 |
-
inputs=[lua_chon_dropdown],
|
| 184 |
-
outputs=[hien_thi_thong_tin]
|
| 185 |
-
)
|
| 186 |
-
|
| 187 |
-
nut_du_bao.click(
|
| 188 |
-
fn=xu_ly_du_doan_voi_loading,
|
| 189 |
-
inputs=[lua_chon_dropdown, chu_ky_dropdown],
|
| 190 |
-
outputs=[bieu_do_du_bao, hien_thi_tom_tat]
|
| 191 |
-
)
|
| 192 |
-
|
| 193 |
-
return lua_chon_dropdown, bieu_do_du_bao, hien_thi_tom_tat, hien_thi_bao_cao, hien_thi_thong_tin
|
| 194 |
-
|
| 195 |
-
def tao_ung_dung_voi_tabs():
|
| 196 |
-
"""Tạo ứng dụng Gradio với tabs"""
|
| 197 |
-
|
| 198 |
-
with gr.Blocks(
|
| 199 |
-
title="🚀 Hệ Thống Dự Báo Bán Hàng AI - FoxAI",
|
| 200 |
-
theme=gr.themes.Soft(),
|
| 201 |
-
css=custom_css
|
| 202 |
-
) as demo:
|
| 203 |
-
|
| 204 |
-
# Header
|
| 205 |
-
gr.HTML(f"""
|
| 206 |
-
<div class="header-container">
|
| 207 |
-
<div style="text-align: center; margin-bottom: 20px;">
|
| 208 |
-
<img src="{FOXAI_LOGO_URL}" alt="FoxAI Logo" class="foxai-logo"/>
|
| 209 |
-
</div>
|
| 210 |
-
<div class="header-title">
|
| 211 |
-
🚀 HỆ THỐNG DỰ BÁO AI
|
| 212 |
-
</div>
|
| 213 |
-
<p style="font-size: 1.1em; color: rgba(255,255,255,0.95) !important; margin: 15px auto; font-weight: 500; line-height: 1.5; max-width: 600px; text-align: center;">
|
| 214 |
-
Phân tích thông minh với công nghệ <strong style="color: white !important;">FoxAI</strong>
|
| 215 |
-
</p>
|
| 216 |
-
<div class="system-status">
|
| 217 |
-
🟢 Hoạt động • 95.8% độ chính xác • Powered by FoxAI
|
| 218 |
-
</div>
|
| 219 |
-
</div>
|
| 220 |
-
""")
|
| 221 |
-
|
| 222 |
-
# Tabs
|
| 223 |
-
with gr.Tabs() as tabs:
|
| 224 |
-
with gr.TabItem("📈 Dự Báo Bán Hàng", elem_id="main-tab"):
|
| 225 |
-
components = tao_tab_du_bao_chinh()
|
| 226 |
-
|
| 227 |
-
with gr.TabItem("🧾 Compliance & Age‑Gate Radar", elem_id="compliance-tab"):
|
| 228 |
-
tao_tab_compliance()
|
| 229 |
-
|
| 230 |
-
with gr.TabItem("🚚 Route‑to‑Market Optimizer", elem_id="route-tab"):
|
| 231 |
-
tao_tab_route_optimizer()
|
| 232 |
-
|
| 233 |
-
with gr.TabItem("📦 Material Predict", elem_id="material-tab"):
|
| 234 |
-
tao_tab_material_predict()
|
| 235 |
-
|
| 236 |
-
# Footer
|
| 237 |
-
gr.HTML(f"""
|
| 238 |
-
<div class='info-card' style="margin-top: 30px; text-align: center;">
|
| 239 |
-
<div style="display: flex; align-items: center; justify-content: center; margin-bottom: 25px;">
|
| 240 |
-
<img src="{FOXAI_LOGO_URL}" alt="FoxAI" style="height: 40px; margin-right: 15px;"/>
|
| 241 |
-
<h3 style="color: #1A5F91; margin: 0;">💡 Hệ Thống FoxAI</h3>
|
| 242 |
-
</div>
|
| 243 |
-
|
| 244 |
-
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 20px; margin: 25px 0;">
|
| 245 |
-
<div style="text-align: center; padding: 15px; background: rgba(26, 95, 145, 0.05); border-radius: 10px;">
|
| 246 |
-
<div style="color: #334155; line-height: 1.8; font-weight: 500;">
|
| 247 |
-
🎯 Độ chính xác 95.8%<br/>
|
| 248 |
-
📅 Dự báo 3 tháng - 1 năm<br/>
|
| 249 |
-
🔄 Market intelligence<br/>
|
| 250 |
-
💼 Enterprise ready
|
| 251 |
-
</div>
|
| 252 |
-
</div>
|
| 253 |
-
</div>
|
| 254 |
-
|
| 255 |
-
<div style="text-align: center; margin: 25px 0; padding: 20px; background: linear-gradient(135deg, rgba(26, 95, 145, 0.1), rgba(139, 139, 139, 0.1)); border-radius: 15px; border: 2px solid #1A5F91;">
|
| 256 |
-
<p style="color: #1A5F91; font-weight: 700; margin: 0; font-size: 1.1em;">
|
| 257 |
-
🦊 <strong>Powered by FoxAI</strong> • 🇻🇳 Made in Vietnam • 🤖 Advanced AI
|
| 258 |
-
</p>
|
| 259 |
-
<p style="color: #334155; margin: 8px 0 0 0; font-size: 0.9em; font-weight: 500;">
|
| 260 |
-
YOUR TRUSTED AI PARTNER
|
| 261 |
-
</p>
|
| 262 |
-
</div>
|
| 263 |
-
</div>
|
| 264 |
-
""")
|
| 265 |
-
|
| 266 |
-
return demo
|
| 267 |
-
|
| 268 |
-
if __name__ == "__main__":
|
| 269 |
-
demo = tao_ung_dung_voi_tabs()
|
| 270 |
-
demo.launch(
|
| 271 |
-
share=True,
|
| 272 |
-
server_name="0.0.0.0",
|
| 273 |
-
server_port=7860,
|
| 274 |
-
show_error=True
|
| 275 |
-
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
app_with_tabs.py
DELETED
|
@@ -1,336 +0,0 @@
|
|
| 1 |
-
import gradio as gr
|
| 2 |
-
import pandas as pd
|
| 3 |
-
import plotly.graph_objects as go
|
| 4 |
-
import plotly.express as px
|
| 5 |
-
import numpy as np
|
| 6 |
-
import random
|
| 7 |
-
import time
|
| 8 |
-
|
| 9 |
-
# Import tất cả từ app.py gốc trừ phần Gradio interface
|
| 10 |
-
from app import *
|
| 11 |
-
|
| 12 |
-
def tao_tab_compliance():
|
| 13 |
-
"""Tạo tab Compliance & Age-Gate Radar"""
|
| 14 |
-
gr.HTML("""
|
| 15 |
-
<div class='info-card' style="text-align: center; padding: 40px;">
|
| 16 |
-
<div style="font-size: 4em; margin-bottom: 20px;">🧾</div>
|
| 17 |
-
<h2 style="color: #1A5F91; margin-bottom: 20px;">Compliance & Age‑Gate Radar</h2>
|
| 18 |
-
<div style="max-width: 800px; margin: 0 auto; text-align: left;">
|
| 19 |
-
<h3 style="color: #475569; margin-bottom: 25px;">📋 Mô Tả Tính Năng</h3>
|
| 20 |
-
<div style="background: rgba(26, 95, 145, 0.05); padding: 25px; border-radius: 15px; margin-bottom: 30px;">
|
| 21 |
-
<p style="font-size: 1.1em; line-height: 1.7; margin-bottom: 20px; color: #334155;">
|
| 22 |
-
<strong>Radar & Gauge tuân thủ chuẩn trưng bày/nhãn cảnh báo/age‑gate (18+)</strong>
|
| 23 |
-
</p>
|
| 24 |
-
<ul style="font-size: 1.05em; line-height: 1.8; color: #475569; padding-left: 25px;">
|
| 25 |
-
<li>🎯 <strong>Radar Compliance:</strong> Theo dõi mức độ tuân thủ quy định trưng bày sản phẩm</li>
|
| 26 |
-
<li>⚠️ <strong>Age-Gate Monitor:</strong> Kiểm soát nhãn cảnh báo độ tuổi (18+) cho sản phẩm nhạy cảm</li>
|
| 27 |
-
<li>📊 <strong>Dashboard Quản Trị:</strong> Hệ thống gauge theo dõi rủi ro tuân thủ real-time</li>
|
| 28 |
-
<li>🔍 <strong>Risk Assessment:</strong> Đánh giá và cảnh báo vi phạm quy định trưng bày</li>
|
| 29 |
-
<li>📈 <strong>Compliance Score:</strong> Tính điểm tuân thủ tổng thể theo từng danh mục sản phẩm</li>
|
| 30 |
-
</ul>
|
| 31 |
-
</div>
|
| 32 |
-
|
| 33 |
-
<div style="background: linear-gradient(135deg, #FEF3C7, #FDE68A); padding: 25px; border-radius: 15px; border-left: 5px solid #F59E0B;">
|
| 34 |
-
<h4 style="color: #92400E; margin-bottom: 15px;">🚧 Trạng Thái Phát Triển</h4>
|
| 35 |
-
<p style="color: #78350F; font-size: 1.05em; font-weight: 600; margin: 0;">
|
| 36 |
-
⏳ <strong>Tính năng đang được phát triển</strong> - UI demo để minh họa câu chuyện quản trị rủi ro
|
| 37 |
-
</p>
|
| 38 |
-
<p style="color: #78350F; font-size: 0.95em; margin: 10px 0 0 0; font-style: italic;">
|
| 39 |
-
Dự kiến hoàn thành: Q4 2024 • Beta testing: Q1 2025
|
| 40 |
-
</p>
|
| 41 |
-
</div>
|
| 42 |
-
</div>
|
| 43 |
-
</div>
|
| 44 |
-
""")
|
| 45 |
-
|
| 46 |
-
def tao_tab_route_optimizer():
|
| 47 |
-
"""Tạo tab Route-to-Market Optimizer"""
|
| 48 |
-
gr.HTML("""
|
| 49 |
-
<div class='info-card' style="text-align: center; padding: 40px;">
|
| 50 |
-
<div style="font-size: 4em; margin-bottom: 20px;">🚚</div>
|
| 51 |
-
<h2 style="color: #1A5F91; margin-bottom: 20px;">Route‑to‑Market Optimizer</h2>
|
| 52 |
-
<div style="max-width: 800px; margin: 0 auto; text-align: left;">
|
| 53 |
-
<h3 style="color: #475569; margin-bottom: 25px;">🎯 Mô Tả Tính Năng</h3>
|
| 54 |
-
<div style="background: rgba(26, 95, 145, 0.05); padding: 25px; border-radius: 15px; margin-bottom: 30px;">
|
| 55 |
-
<p style="font-size: 1.1em; line-height: 1.7; margin-bottom: 20px; color: #334155;">
|
| 56 |
-
<strong>Scatter Pareto "số điểm ghé/tuyến" vs "doanh thu/km" – chọn tuyến "ngon – gọn – rẻ"</strong>
|
| 57 |
-
</p>
|
| 58 |
-
<ul style="font-size: 1.05em; line-height: 1.8; color: #475569; padding-left: 25px;">
|
| 59 |
-
<li>📍 <strong>Route Analytics:</strong> Phân tích hiệu quả từng tuyến phân phối theo Pareto</li>
|
| 60 |
-
<li>💰 <strong>Revenue per KM:</strong> Tính toán doanh thu/km để tối ưu lợi nhuận</li>
|
| 61 |
-
<li>🎯 <strong>Stop Optimization:</strong> Tối ưu số điểm ghé/tuyến để giảm chi phí</li>
|
| 62 |
-
<li>📊 <strong>Scatter Plot Analysis:</strong> Visualization ma trận "ngon-gọn-rẻ"</li>
|
| 63 |
-
<li>🚚 <strong>Smart Routing:</strong> AI đề xuất tuyến đường tối ưu theo múi giờ</li>
|
| 64 |
-
<li>⚡ <strong>Real-time Tracking:</strong> Theo dõi hiệu suất tuyến trực tiếp</li>
|
| 65 |
-
</ul>
|
| 66 |
-
</div>
|
| 67 |
-
|
| 68 |
-
<div style="background: linear-gradient(135deg, #FEF3C7, #FDE68A); padding: 25px; border-radius: 15px; border-left: 5px solid #F59E0B;">
|
| 69 |
-
<h4 style="color: #92400E; margin-bottom: 15px;">🚧 Trạng Thái Phát Triển</h4>
|
| 70 |
-
<p style="color: #78350F; font-size: 1.05em; font-weight: 600; margin: 0;">
|
| 71 |
-
⏳ <strong>Tính năng đang được phát triển</strong> - Mô hình giả lập cho demo
|
| 72 |
-
</p>
|
| 73 |
-
<p style="color: #78350F; font-size: 0.95em; margin: 10px 0 0 0; font-style: italic;">
|
| 74 |
-
Đang thu thập dữ liệu GPS • Tích hợp API Maps • Alpha phase
|
| 75 |
-
</p>
|
| 76 |
-
</div>
|
| 77 |
-
</div>
|
| 78 |
-
</div>
|
| 79 |
-
""")
|
| 80 |
-
|
| 81 |
-
def tao_tab_material_predict():
|
| 82 |
-
"""Tạo tab Material Predict"""
|
| 83 |
-
gr.HTML("""
|
| 84 |
-
<div class='info-card' style="text-align: center; padding: 40px;">
|
| 85 |
-
<div style="font-size: 4em; margin-bottom: 20px;">📦</div>
|
| 86 |
-
<h2 style="color: #1A5F91; margin-bottom: 20px;">Material Predict</h2>
|
| 87 |
-
<div style="max-width: 800px; margin: 0 auto; text-align: left;">
|
| 88 |
-
<h3 style="color: #475569; margin-bottom: 25px;">📋 Mô Tả Tính Năng</h3>
|
| 89 |
-
<div style="background: rgba(26, 95, 145, 0.05); padding: 25px; border-radius: 15px; margin-bottom: 30px;">
|
| 90 |
-
<p style="font-size: 1.1em; line-height: 1.7; margin-bottom: 20px; color: #334155;">
|
| 91 |
-
<strong>Dự báo vật tư thông minh với AI-powered supply chain optimization</strong>
|
| 92 |
-
</p>
|
| 93 |
-
<ul style="font-size: 1.05em; line-height: 1.8; color: #475569; padding-left: 25px;">
|
| 94 |
-
<li>📈 <strong>Demand Forecasting:</strong> Dự báo nhu cầu vật tư theo mùa vụ và xu hướng</li>
|
| 95 |
-
<li>🏭 <strong>Inventory Optimization:</strong> Tối ưu mức tồn kho để giảm chi phí lưu trữ</li>
|
| 96 |
-
<li>⚡ <strong>Auto-Reorder Points:</strong> Tự động đặt hàng khi đạt ngưỡng tối thiểu</li>
|
| 97 |
-
<li>🔄 <strong>Supply Chain AI:</strong> Tích hợp với nhà cung cấp để dự báo leadtime</li>
|
| 98 |
-
<li>💡 <strong>Cost Intelligence:</strong> Phân tích biến động giá nguyên liệu theo thời gian</li>
|
| 99 |
-
<li>📊 <strong>Material Matrix:</strong> Ma trận ABC analysis cho ưu tiên vật tư quan trọng</li>
|
| 100 |
-
<li>🎯 <strong>Waste Reduction:</strong> Giảm thiểu lãng phí bằng dự báo chính xác</li>
|
| 101 |
-
</ul>
|
| 102 |
-
</div>
|
| 103 |
-
|
| 104 |
-
<div style="background: linear-gradient(135deg, #FEF3C7, #FDE68A); padding: 25px; border-radius: 15px; border-left: 5px solid #F59E0B;">
|
| 105 |
-
<h4 style="color: #92400E; margin-bottom: 15px;">🚧 Trạng Thái Phát Triển</h4>
|
| 106 |
-
<p style="color: #78350F; font-size: 1.05em; font-weight: 600; margin: 0;">
|
| 107 |
-
⏳ <strong>Tính năng đang được phát triển</strong> - Module dự báo vật tư tiên tiến
|
| 108 |
-
</p>
|
| 109 |
-
<p style="color: #78350F; font-size: 0.95em; margin: 10px 0 0 0; font-style: italic;">
|
| 110 |
-
Đang training ML models • Kết nối ERP systems • Pilot program
|
| 111 |
-
</p>
|
| 112 |
-
</div>
|
| 113 |
-
</div>
|
| 114 |
-
</div>
|
| 115 |
-
""")
|
| 116 |
-
|
| 117 |
-
def tao_tab_du_bao_chinh():
|
| 118 |
-
"""Tạo tab chính cho dự báo bán hàng"""
|
| 119 |
-
|
| 120 |
-
with gr.Row():
|
| 121 |
-
with gr.Column(scale=1):
|
| 122 |
-
gr.HTML("<div class='feature-box floating' style='text-align: center;'><h3>⚙️ Cài Đặt</h3></div>")
|
| 123 |
-
|
| 124 |
-
lua_chon_dropdown = gr.Dropdown(
|
| 125 |
-
choices=list(TRUONG_HOP_DEMO.keys()),
|
| 126 |
-
value=list(TRUONG_HOP_DEMO.keys())[0],
|
| 127 |
-
label="🛍️ Chọn Sản Phẩm",
|
| 128 |
-
info="Mỗi sản phẩm có insight riêng",
|
| 129 |
-
elem_classes=["tech-border"]
|
| 130 |
-
)
|
| 131 |
-
|
| 132 |
-
chu_ky_dropdown = gr.Dropdown(
|
| 133 |
-
choices=["3 tháng", "6 tháng", "1 năm"],
|
| 134 |
-
value="6 tháng",
|
| 135 |
-
label="📅 Chu Kỳ Dự Báo",
|
| 136 |
-
info="Thời gian dự báo tương lai",
|
| 137 |
-
elem_classes=["tech-border"]
|
| 138 |
-
)
|
| 139 |
-
|
| 140 |
-
nut_du_bao = gr.Button(
|
| 141 |
-
"🚀 Tạo Dự Báo AI",
|
| 142 |
-
variant="primary",
|
| 143 |
-
size="lg",
|
| 144 |
-
elem_classes=["btn-modern", "pulse-animation"]
|
| 145 |
-
)
|
| 146 |
-
|
| 147 |
-
hien_thi_thong_tin = gr.HTML(
|
| 148 |
-
value=cap_nhat_thong_tin_case(list(TRUONG_HOP_DEMO.keys())[0]),
|
| 149 |
-
elem_classes=["floating", "glass-card"]
|
| 150 |
-
)
|
| 151 |
-
|
| 152 |
-
with gr.Row():
|
| 153 |
-
with gr.Column():
|
| 154 |
-
gr.HTML("<div class='feature-box floating' style='text-align: center;'><h3>📈 Kết Quả Dự Báo</h3></div>")
|
| 155 |
-
|
| 156 |
-
che_do_xem = gr.Radio(
|
| 157 |
-
choices=[("📅 Theo Ngày", "ngày"), ("📆 Theo Tuần", "tháng"), ("🗓️ Theo Tháng", "năm")],
|
| 158 |
-
value="ngày",
|
| 159 |
-
label="📊 Chế Độ Hiển Thị",
|
| 160 |
-
info="Thay đổi cách hiển thị biểu đồ",
|
| 161 |
-
elem_classes=["tech-border"]
|
| 162 |
-
)
|
| 163 |
-
|
| 164 |
-
bieu_do_du_bao = gr.Plot(
|
| 165 |
-
label="Biểu Đồ Dự Báo Bán Hàng",
|
| 166 |
-
elem_classes=["plot-container", "glass-card", "neon-border"],
|
| 167 |
-
elem_id="chart-target"
|
| 168 |
-
)
|
| 169 |
-
|
| 170 |
-
loading_panel = gr.HTML(value="", elem_id="loading-panel")
|
| 171 |
-
|
| 172 |
-
with gr.Row():
|
| 173 |
-
with gr.Column(scale=1):
|
| 174 |
-
gr.HTML("<div class='feature-box floating' style='text-align: center;'><h3>📊 Thống Kê</h3></div>")
|
| 175 |
-
hien_thi_tom_tat = gr.HTML()
|
| 176 |
-
|
| 177 |
-
with gr.Column(scale=1):
|
| 178 |
-
gr.HTML("<div class='feature-box floating' style='text-align: center;'><h3>🎯 Chiến Lược AI</h3></div>")
|
| 179 |
-
|
| 180 |
-
nut_streaming = gr.Button(
|
| 181 |
-
"🤖 Tạo Chiến Lược AI (Streaming)",
|
| 182 |
-
variant="secondary",
|
| 183 |
-
size="sm",
|
| 184 |
-
elem_classes=["btn-modern"],
|
| 185 |
-
visible=False
|
| 186 |
-
)
|
| 187 |
-
|
| 188 |
-
hien_thi_bao_cao = gr.Markdown()
|
| 189 |
-
|
| 190 |
-
# Event handlers
|
| 191 |
-
def xu_ly_streaming(lua_chon_case):
|
| 192 |
-
if lua_chon_case is None:
|
| 193 |
-
return "# 🎯 CHIẾN LƯỢC ĐỀ XUẤT\n\n📊 **Chọn mặt hàng để tạo chiến lược**"
|
| 194 |
-
try:
|
| 195 |
-
for partial_text in tao_streaming_text(lua_chon_case):
|
| 196 |
-
yield partial_text
|
| 197 |
-
except Exception as e:
|
| 198 |
-
yield f"# ❌ Lỗi\n\n{str(e)}"
|
| 199 |
-
|
| 200 |
-
lua_chon_dropdown.change(
|
| 201 |
-
fn=lambda case: [cap_nhat_thong_tin_case(case), gr.update(visible=case is not None)],
|
| 202 |
-
inputs=[lua_chon_dropdown],
|
| 203 |
-
outputs=[hien_thi_thong_tin, nut_streaming]
|
| 204 |
-
)
|
| 205 |
-
|
| 206 |
-
evt0 = nut_du_bao.click(
|
| 207 |
-
fn=lambda: "",
|
| 208 |
-
outputs=[loading_panel]
|
| 209 |
-
)
|
| 210 |
-
|
| 211 |
-
evt1 = evt0.then(
|
| 212 |
-
fn=hien_loading_tung_buoc,
|
| 213 |
-
outputs=[loading_panel],
|
| 214 |
-
show_progress=False,
|
| 215 |
-
)
|
| 216 |
-
|
| 217 |
-
evt1.then(
|
| 218 |
-
fn=tinh_toan_ket_qua,
|
| 219 |
-
inputs=[lua_chon_dropdown, chu_ky_dropdown, che_do_xem],
|
| 220 |
-
outputs=[bieu_do_du_bao, hien_thi_tom_tat, hien_thi_bao_cao, loading_panel],
|
| 221 |
-
show_progress=False,
|
| 222 |
-
)
|
| 223 |
-
|
| 224 |
-
nut_streaming.click(
|
| 225 |
-
fn=xu_ly_streaming,
|
| 226 |
-
inputs=[lua_chon_dropdown],
|
| 227 |
-
outputs=[hien_thi_bao_cao],
|
| 228 |
-
show_progress=False
|
| 229 |
-
)
|
| 230 |
-
|
| 231 |
-
che_do_xem.change(
|
| 232 |
-
fn=lambda case, chu_ky, mode: [
|
| 233 |
-
tao_bieu_do_du_doan(case, chu_ky, mode) if case else tao_bieu_do_mac_dinh(),
|
| 234 |
-
tao_thong_tin_tom_tat(case, chu_ky, mode) if case else tao_tom_tat_mac_dinh()
|
| 235 |
-
],
|
| 236 |
-
inputs=[lua_chon_dropdown, chu_ky_dropdown, che_do_xem],
|
| 237 |
-
outputs=[bieu_do_du_bao, hien_thi_tom_tat]
|
| 238 |
-
)
|
| 239 |
-
|
| 240 |
-
return (lua_chon_dropdown, bieu_do_du_bao, hien_thi_tom_tat, hien_thi_bao_cao, hien_thi_thong_tin)
|
| 241 |
-
|
| 242 |
-
def tao_ung_dung_voi_tabs():
|
| 243 |
-
"""Tạo ứng dụng Gradio với tabs"""
|
| 244 |
-
|
| 245 |
-
with gr.Blocks(
|
| 246 |
-
title="🚀 Hệ Thống Dự Báo Bán Hàng AI - FoxAI",
|
| 247 |
-
theme=gr.themes.Soft(),
|
| 248 |
-
css=custom_css
|
| 249 |
-
) as demo:
|
| 250 |
-
|
| 251 |
-
# Header
|
| 252 |
-
gr.HTML(f"""
|
| 253 |
-
<div class="header-container">
|
| 254 |
-
<div style="text-align: center; margin-bottom: 20px;">
|
| 255 |
-
<img src="{FOXAI_LOGO_URL}" alt="FoxAI Logo" class="foxai-logo"/>
|
| 256 |
-
</div>
|
| 257 |
-
<div class="header-title">
|
| 258 |
-
🚀 HỆ THỐNG DỰ BÁO AI
|
| 259 |
-
</div>
|
| 260 |
-
<p style="font-size: 1.1em; color: rgba(255,255,255,0.95) !important; margin: 15px auto; font-weight: 500; line-height: 1.5; max-width: 600px; text-align: center;">
|
| 261 |
-
Phân tích thông minh với công nghệ <strong style="color: white !important;">FoxAI</strong>
|
| 262 |
-
</p>
|
| 263 |
-
<div class="system-status">
|
| 264 |
-
🟢 Hoạt động • 95.8% độ chính xác • Powered by FoxAI
|
| 265 |
-
</div>
|
| 266 |
-
</div>
|
| 267 |
-
""")
|
| 268 |
-
|
| 269 |
-
# Tabs
|
| 270 |
-
with gr.Tabs() as tabs:
|
| 271 |
-
with gr.TabItem("📈 Dự Báo Bán Hàng", elem_id="main-tab"):
|
| 272 |
-
components = tao_tab_du_bao_chinh()
|
| 273 |
-
lua_chon_dropdown, bieu_do_du_bao, hien_thi_tom_tat, hien_thi_bao_cao, hien_thi_thong_tin = components
|
| 274 |
-
|
| 275 |
-
with gr.TabItem("🧾 Compliance & Age‑Gate Radar", elem_id="compliance-tab"):
|
| 276 |
-
tao_tab_compliance()
|
| 277 |
-
|
| 278 |
-
with gr.TabItem("🚚 Route‑to‑Market Optimizer", elem_id="route-tab"):
|
| 279 |
-
tao_tab_route_optimizer()
|
| 280 |
-
|
| 281 |
-
with gr.TabItem("📦 Material Predict", elem_id="material-tab"):
|
| 282 |
-
tao_tab_material_predict()
|
| 283 |
-
|
| 284 |
-
# Auto load cho tab chính
|
| 285 |
-
demo.load(
|
| 286 |
-
fn=lambda: [
|
| 287 |
-
cap_nhat_thong_tin_case(list(TRUONG_HOP_DEMO.keys())[0]),
|
| 288 |
-
tao_bieu_do_mac_dinh(),
|
| 289 |
-
tao_tom_tat_mac_dinh(),
|
| 290 |
-
"""# 🎯 CHIẾN LƯỢC ĐỀ XUẤT
|
| 291 |
-
|
| 292 |
-
## 📊 **Sẵn Sàng Phân Tích**
|
| 293 |
-
|
| 294 |
-
**Nhấn 'Tạo Dự Báo AI' để xem phân tích chi tiết**
|
| 295 |
-
|
| 296 |
-
Hệ thống AI sẽ tạo chiến lược đề xuất với:
|
| 297 |
-
|
| 298 |
-
• **Phân tích xu hướng** thị trường
|
| 299 |
-
• **Insights chi tiết** từ dữ liệu
|
| 300 |
-
• **Khuyến nghị cụ thể** để tối ưa doanh thu
|
| 301 |
-
• **Roadmap hành động** rõ ràng
|
| 302 |
-
|
| 303 |
-
*🤖 Powered by FoxAI Intelligence*"""
|
| 304 |
-
],
|
| 305 |
-
outputs=[hien_thi_thong_tin, bieu_do_du_bao, hien_thi_tom_tat, hien_thi_bao_cao]
|
| 306 |
-
)
|
| 307 |
-
|
| 308 |
-
# Footer
|
| 309 |
-
gr.HTML(f"""
|
| 310 |
-
<div class='info-card' style="margin-top: 30px; text-align: center;">
|
| 311 |
-
<div style="display: flex; align-items: center; justify-content: center; margin-bottom: 25px;">
|
| 312 |
-
<img src="{FOXAI_LOGO_URL}" alt="FoxAI" style="height: 40px; margin-right: 15px;"/>
|
| 313 |
-
<h3 style="color: #1A5F91; margin: 0;">💡 Hệ Thống FoxAI</h3>
|
| 314 |
-
</div>
|
| 315 |
-
|
| 316 |
-
<div style="text-align: center; margin: 25px 0; padding: 20px; background: linear-gradient(135deg, rgba(26, 95, 145, 0.1), rgba(139, 139, 139, 0.1)); border-radius: 15px; border: 2px solid #1A5F91;">
|
| 317 |
-
<p style="color: #1A5F91; font-weight: 700; margin: 0; font-size: 1.1em;">
|
| 318 |
-
🦊 <strong>Powered by FoxAI</strong> • 🇻🇳 Made in Vietnam • 🤖 Advanced AI
|
| 319 |
-
</p>
|
| 320 |
-
<p style="color: #334155; margin: 8px 0 0 0; font-size: 0.9em; font-weight: 500;">
|
| 321 |
-
YOUR TRUSTED AI PARTNER
|
| 322 |
-
</p>
|
| 323 |
-
</div>
|
| 324 |
-
</div>
|
| 325 |
-
""")
|
| 326 |
-
|
| 327 |
-
return demo
|
| 328 |
-
|
| 329 |
-
if __name__ == "__main__":
|
| 330 |
-
demo = tao_ung_dung_voi_tabs()
|
| 331 |
-
demo.launch(
|
| 332 |
-
share=True,
|
| 333 |
-
server_name="0.0.0.0",
|
| 334 |
-
server_port=7860,
|
| 335 |
-
show_error=True
|
| 336 |
-
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|