Spaces:
Sleeping
Sleeping
Really-amin
commited on
Commit
•
7da6612
1
Parent(s):
6e501ad
Upload 7 files
Browse files- admin_dashboard.py +402 -177
- app.py +77 -239
- banking_assistant.py +469 -0
- banking_model.py +146 -0
- filemanager.py +394 -0
- ml_banking_model.py +141 -0
- requirements.txt +12 -5
admin_dashboard.py
CHANGED
@@ -1,189 +1,414 @@
|
|
1 |
-
import
|
2 |
-
import
|
3 |
-
import
|
4 |
-
import
|
5 |
-
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
}
|
53 |
-
|
54 |
-
|
55 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
56 |
}
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
if (!file) return;
|
62 |
-
|
63 |
-
const formData = new FormData();
|
64 |
-
formData.append('file', file);
|
65 |
-
|
66 |
-
try {
|
67 |
-
const response = await fetch('/api/upload-document', {
|
68 |
-
method: 'POST',
|
69 |
-
body: formData
|
70 |
-
});
|
71 |
-
|
72 |
-
if (response.ok) {
|
73 |
-
setUpdateStatus('فایل با موفقیت آپلود شد');
|
74 |
-
} else {
|
75 |
-
throw new Error('خطا در آپلود فایل');
|
76 |
-
}
|
77 |
-
} catch (error) {
|
78 |
-
setUpdateStatus('خطا در آپلود فایل');
|
79 |
}
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
89 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
90 |
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
|
|
|
|
|
|
|
|
|
|
105 |
</div>
|
106 |
-
<
|
107 |
-
|
108 |
-
|
109 |
-
{/* Questions Card */}
|
110 |
-
<div className="bg-white/30 backdrop-blur-lg rounded-2xl p-6 shadow-[5px_5px_20px_rgba(0,0,0,0.1),-5px_-5px_20px_rgba(255,255,255,0.8)] transition-all duration-300 hover:shadow-[8px_8px_25px_rgba(0,0,0,0.12),-8px_-8px_25px_rgba(255,255,255,0.9)] hover:transform hover:-translate-y-1">
|
111 |
-
<div className="flex items-center justify-between">
|
112 |
-
<Users className="text-green-500" size={24} />
|
113 |
-
<h3 className="text-lg font-semibold text-gray-700">تعداد سوالات</h3>
|
114 |
</div>
|
115 |
-
<
|
116 |
-
|
117 |
-
|
118 |
-
{/* Accuracy Card */}
|
119 |
-
<div className="bg-white/30 backdrop-blur-lg rounded-2xl p-6 shadow-[5px_5px_20px_rgba(0,0,0,0.1),-5px_-5px_20px_rgba(255,255,255,0.8)] transition-all duration-300 hover:shadow-[8px_8px_25px_rgba(0,0,0,0.12),-8px_-8px_25px_rgba(255,255,255,0.9)] hover:transform hover:-translate-y-1">
|
120 |
-
<div className="flex items-center justify-between">
|
121 |
-
<ThumbsUp className="text-purple-500" size={24} />
|
122 |
-
<h3 className="text-lg font-semibold text-gray-700">دقت پاسخگویی</h3>
|
123 |
</div>
|
124 |
-
<p className="text-3xl font-bold text-purple-600 mt-4">{stats.accuracy}%</p>
|
125 |
-
</div>
|
126 |
</div>
|
|
|
|
|
127 |
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
<
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
|
144 |
-
|
145 |
-
|
146 |
-
|
147 |
-
|
148 |
-
|
149 |
-
|
150 |
-
|
151 |
-
|
152 |
-
|
153 |
-
|
154 |
-
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
-
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
|
167 |
-
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
-
|
177 |
-
|
178 |
-
|
179 |
-
|
180 |
-
|
181 |
-
|
182 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
183 |
</div>
|
184 |
-
</div>
|
185 |
</div>
|
186 |
-
|
187 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
188 |
|
189 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import streamlit as st
|
2 |
+
import plotly.graph_objects as go
|
3 |
+
import plotly.express as px
|
4 |
+
import numpy as np
|
5 |
+
from datetime import datetime, timedelta
|
6 |
+
|
7 |
+
import streamlit as st
|
8 |
+
import pandas as pd
|
9 |
+
from pathlib import Path
|
10 |
+
|
11 |
+
# تنظیمات صفحه
|
12 |
+
st.set_page_config(
|
13 |
+
page_title="داشبورد مدیریت",
|
14 |
+
page_icon="👤",
|
15 |
+
layout="wide"
|
16 |
+
)
|
17 |
+
|
18 |
+
# استایلهای داشبورد
|
19 |
+
st.markdown("""
|
20 |
+
<style>
|
21 |
+
@import url('https://fonts.googleapis.com/css2?family=Vazirmatn:wght@400;700&display=swap');
|
22 |
+
|
23 |
+
* {
|
24 |
+
font-family: 'Vazirmatn', sans-serif;
|
25 |
+
direction: rtl;
|
26 |
+
}
|
27 |
+
|
28 |
+
.dashboard-container {
|
29 |
+
background: white;
|
30 |
+
border-radius: 15px;
|
31 |
+
padding: 25px;
|
32 |
+
margin: 20px 0;
|
33 |
+
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
|
34 |
+
}
|
35 |
+
|
36 |
+
.stat-card {
|
37 |
+
background: linear-gradient(135deg, #6B73FF 0%, #000DFF 100%);
|
38 |
+
color: white;
|
39 |
+
padding: 20px;
|
40 |
+
border-radius: 10px;
|
41 |
+
margin: 10px;
|
42 |
+
text-align: center;
|
43 |
+
}
|
44 |
+
|
45 |
+
.file-upload {
|
46 |
+
border: 2px dashed #ccc;
|
47 |
+
padding: 20px;
|
48 |
+
border-radius: 10px;
|
49 |
+
text-align: center;
|
50 |
+
margin: 20px 0;
|
51 |
+
transition: all 0.3s ease;
|
52 |
+
}
|
53 |
+
|
54 |
+
.file-upload:hover {
|
55 |
+
border-color: #2196F3;
|
56 |
+
}
|
57 |
+
|
58 |
+
.action-button {
|
59 |
+
background: #2196F3;
|
60 |
+
color: white;
|
61 |
+
padding: 10px 20px;
|
62 |
+
border: none;
|
63 |
+
border-radius: 5px;
|
64 |
+
cursor: pointer;
|
65 |
+
transition: all 0.3s ease;
|
66 |
}
|
67 |
+
|
68 |
+
.action-button:hover {
|
69 |
+
background: #1976D2;
|
70 |
+
transform: scale(1.05);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
71 |
}
|
72 |
+
|
73 |
+
.file-list {
|
74 |
+
margin-top: 20px;
|
75 |
+
}
|
76 |
+
|
77 |
+
.file-item {
|
78 |
+
display: flex;
|
79 |
+
justify-content: space-between;
|
80 |
+
align-items: center;
|
81 |
+
padding: 15px;
|
82 |
+
background: #f5f5f5;
|
83 |
+
border-radius: 8px;
|
84 |
+
margin: 10px 0;
|
85 |
+
}
|
86 |
+
|
87 |
+
.delete-button {
|
88 |
+
background: #ff4444;
|
89 |
+
color: white;
|
90 |
+
padding: 5px 15px;
|
91 |
+
border: none;
|
92 |
+
border-radius: 5px;
|
93 |
+
cursor: pointer;
|
94 |
+
}
|
95 |
+
|
96 |
+
.delete-button:hover {
|
97 |
+
background: #cc0000;
|
98 |
+
}
|
99 |
+
</style>
|
100 |
+
""", unsafe_allow_html=True)
|
101 |
+
|
102 |
+
# هدر داشبورد
|
103 |
+
st.title("🎛️ داشبورد مدیریت")
|
104 |
+
|
105 |
+
# آمار کلی
|
106 |
+
col1, col2, col3 = st.columns(3)
|
107 |
+
with col1:
|
108 |
+
st.markdown("""
|
109 |
+
<div class="stat-card">
|
110 |
+
<h2>۱۲۳</h2>
|
111 |
+
<p>تعداد فایلها</p>
|
112 |
+
</div>
|
113 |
+
""", unsafe_allow_html=True)
|
114 |
+
|
115 |
+
with col2:
|
116 |
+
st.markdown("""
|
117 |
+
<div class="stat-card">
|
118 |
+
<h2>۴۵۶</h2>
|
119 |
+
<p>تعداد پرسشها</p>
|
120 |
</div>
|
121 |
+
""", unsafe_allow_html=True)
|
122 |
+
|
123 |
+
with col3:
|
124 |
+
st.markdown("""
|
125 |
+
<div class="stat-card">
|
126 |
+
<h2>۷۸۹</h2>
|
127 |
+
<p>پاسخهای موفق</p>
|
128 |
+
</div>
|
129 |
+
""", unsafe_allow_html=True)
|
130 |
|
131 |
+
# بخش آپلود فایل
|
132 |
+
st.markdown("""
|
133 |
+
<div class="dashboard-container">
|
134 |
+
<h3>📤 آپلود فایل جدید</h3>
|
135 |
+
<div class="file-upload">
|
136 |
+
<p>فایل خود را اینجا رها کنید یا کلیک کنید</p>
|
137 |
+
<input type="file" accept=".csv,.json,.txt">
|
138 |
+
</div>
|
139 |
+
</div>
|
140 |
+
""", unsafe_allow_html=True)
|
141 |
+
|
142 |
+
# لیست فایلها
|
143 |
+
st.markdown("""
|
144 |
+
<div class="dashboard-container">
|
145 |
+
<h3>📁 مدیریت فایلها</h3>
|
146 |
+
<div class="file-list">
|
147 |
+
<div class="file-item">
|
148 |
+
<span>banking_data.csv</span>
|
149 |
+
<button class="delete-button">حذف</button>
|
150 |
</div>
|
151 |
+
<div class="file-item">
|
152 |
+
<span>customer_qa.json</span>
|
153 |
+
<button class="delete-button">حذف</button>
|
|
|
|
|
|
|
|
|
|
|
154 |
</div>
|
155 |
+
<div class="file-item">
|
156 |
+
<span>training_data.txt</span>
|
157 |
+
<button class="delete-button">حذف</button>
|
|
|
|
|
|
|
|
|
|
|
158 |
</div>
|
|
|
|
|
159 |
</div>
|
160 |
+
</div>
|
161 |
+
""", unsafe_allow_html=True)
|
162 |
|
163 |
+
# تنظیمات مدل
|
164 |
+
st.markdown("""
|
165 |
+
<div class="dashboard-container">
|
166 |
+
<h3>⚙️ تنظیمات مدل</h3>
|
167 |
+
<div style="margin: 20px 0;">
|
168 |
+
<label>دمای مدل:</label>
|
169 |
+
<input type="range" min="0" max="100" value="70">
|
170 |
+
</div>
|
171 |
+
<div style="margin: 20px 0;">
|
172 |
+
<label>حداکثر طول پاسخ:</label>
|
173 |
+
<input type="number" value="512">
|
174 |
+
</div>
|
175 |
+
<button class="action-button">ذخیره تنظیمات</button>
|
176 |
+
</div>
|
177 |
+
""", unsafe_allow_html=True)
|
178 |
+
|
179 |
+
if __name__ == "__main__":
|
180 |
+
st.markdown("""
|
181 |
+
<script>
|
182 |
+
// اضافه کردن عملکرد به دکمهها
|
183 |
+
document.querySelectorAll('.delete-button').forEach(button => {
|
184 |
+
button.addEventListener('click', function() {
|
185 |
+
if (confirm('آیا از حذف این فایل اطمینان دارید؟')) {
|
186 |
+
this.closest('.file-item').remove();
|
187 |
+
}
|
188 |
+
});
|
189 |
+
});
|
190 |
+
</script>
|
191 |
+
""", unsafe_allow_html=True)
|
192 |
+
|
193 |
+
# اضافه کردن بخش نمودارها
|
194 |
+
st.markdown("""
|
195 |
+
<div class="dashboard-container">
|
196 |
+
<h3>📊 تحلیل عملکرد مدل</h3>
|
197 |
+
</div>
|
198 |
+
""", unsafe_allow_html=True)
|
199 |
+
|
200 |
+
# نمودار نرخ یادگیری
|
201 |
+
col1, col2 = st.columns(2)
|
202 |
+
with col1:
|
203 |
+
# نمودار نرخ یادگیری
|
204 |
+
dates = [datetime.now() - timedelta(days=x) for x in range(30)]
|
205 |
+
learning_rate = [0.001 * np.exp(-x/10) for x in range(30)]
|
206 |
+
|
207 |
+
fig_learning = go.Figure()
|
208 |
+
fig_learning.add_trace(go.Scatter(
|
209 |
+
x=dates,
|
210 |
+
y=learning_rate,
|
211 |
+
mode='lines+markers',
|
212 |
+
name='نرخ یادگیری',
|
213 |
+
line=dict(color='#2196F3', width=3)
|
214 |
+
))
|
215 |
+
fig_learning.update_layout(
|
216 |
+
title='نرخ یادگیری در طول زمان',
|
217 |
+
xaxis_title='تاریخ',
|
218 |
+
yaxis_title='نرخ یادگیری',
|
219 |
+
template='plotly_white',
|
220 |
+
dir='rtl'
|
221 |
+
)
|
222 |
+
st.plotly_chart(fig_learning, use_container_width=True)
|
223 |
+
|
224 |
+
with col2:
|
225 |
+
# نمودار دقت مدل
|
226 |
+
accuracy_data = np.linspace(0.7, 0.95, 30)
|
227 |
+
fig_accuracy = go.Figure()
|
228 |
+
fig_accuracy.add_trace(go.Scatter(
|
229 |
+
x=dates,
|
230 |
+
y=accuracy_data,
|
231 |
+
mode='lines+markers',
|
232 |
+
name='دقت مدل',
|
233 |
+
line=dict(color='#4CAF50', width=3)
|
234 |
+
))
|
235 |
+
fig_accuracy.update_layout(
|
236 |
+
title='پیشرفت دقت مدل',
|
237 |
+
xaxis_title='تاریخ',
|
238 |
+
yaxis_title='دقت',
|
239 |
+
template='plotly_white',
|
240 |
+
dir='rtl'
|
241 |
+
)
|
242 |
+
st.plotly_chart(fig_accuracy, use_container_width=True)
|
243 |
+
|
244 |
+
# نمودار پاسخهای صحیح و غلط
|
245 |
+
labels = ['پاسخهای صحیح', 'پاسخهای غلط']
|
246 |
+
values = [85, 15]
|
247 |
+
fig_pie = go.Figure(data=[go.Pie(
|
248 |
+
labels=labels,
|
249 |
+
values=values,
|
250 |
+
hole=.3,
|
251 |
+
marker_colors=['#4CAF50', '#f44336']
|
252 |
+
)])
|
253 |
+
fig_pie.update_layout(title='نسبت پاسخهای صحیح به غلط')
|
254 |
+
st.plotly_chart(fig_pie, use_container_width=True)
|
255 |
+
|
256 |
+
# چتبات آموزش سریع
|
257 |
+
st.markdown("""
|
258 |
+
<div class="dashboard-container">
|
259 |
+
<h3>🤖 آموزش سریع با چتبات</h3>
|
260 |
+
<div class="chat-trainer">
|
261 |
+
<input type="text" placeholder="دستور آموزشی خود را وارد کنید..." class="trainer-input">
|
262 |
+
<button class="action-button">ارسال دستور</button>
|
263 |
</div>
|
|
|
264 |
</div>
|
265 |
+
""", unsafe_allow_html=True)
|
266 |
+
|
267 |
+
# دکمه دسترسی به نالج بیس
|
268 |
+
st.markdown("""
|
269 |
+
<div class="dashboard-container">
|
270 |
+
<h3>📚 مدیریت نالج بیس</h3>
|
271 |
+
<button class="action-button" onclick="window.open('/filemanager.py')">
|
272 |
+
<i class="fas fa-folder-open"></i>
|
273 |
+
دسترسی به فایل منیجر
|
274 |
+
</button>
|
275 |
+
</div>
|
276 |
+
""", unsafe_allow_html=True)
|
277 |
+
|
278 |
+
# اضافه کردن استایلهای جدید
|
279 |
+
st.markdown("""
|
280 |
+
<style>
|
281 |
+
.chat-trainer {
|
282 |
+
display: flex;
|
283 |
+
gap: 10px;
|
284 |
+
margin: 20px 0;
|
285 |
+
}
|
286 |
+
|
287 |
+
.trainer-input {
|
288 |
+
flex: 1;
|
289 |
+
padding: 12px;
|
290 |
+
border: 2px solid #f0f0f0;
|
291 |
+
border-radius: 8px;
|
292 |
+
font-size: 14px;
|
293 |
+
}
|
294 |
+
|
295 |
+
.plotly-chart {
|
296 |
+
background: white;
|
297 |
+
border-radius: 10px;
|
298 |
+
padding: 15px;
|
299 |
+
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
|
300 |
+
}
|
301 |
+
</style>
|
302 |
+
""", unsafe_allow_html=True)
|
303 |
+
# اضافه کردن نمودار هیتمپ برای نمایش ماتریس خطا
|
304 |
+
confusion_matrix = np.array([
|
305 |
+
[850, 50],
|
306 |
+
[30, 70]
|
307 |
+
])
|
308 |
+
|
309 |
+
fig_heatmap = px.imshow(
|
310 |
+
confusion_matrix,
|
311 |
+
labels=dict(x="پیشبینی", y="مقدار واقعی"),
|
312 |
+
x=['مثبت', 'منفی'],
|
313 |
+
y=['مثبت', 'منفی'],
|
314 |
+
color_continuous_scale="RdBu",
|
315 |
+
title="ماتریس خطا"
|
316 |
+
)
|
317 |
+
fig_heatmap.update_layout(
|
318 |
+
template='plotly_white',
|
319 |
+
dir='rtl',
|
320 |
+
width=600,
|
321 |
+
height=500
|
322 |
+
)
|
323 |
+
|
324 |
+
# نمودار روند زمانی با قابلیت فیلتر
|
325 |
+
training_metrics = pd.DataFrame({
|
326 |
+
'تاریخ': pd.date_range(start='2023-01-01', periods=100),
|
327 |
+
'دقت': np.random.normal(0.85, 0.05, 100).cumsum()/100,
|
328 |
+
'recall': np.random.normal(0.80, 0.05, 100).cumsum()/100,
|
329 |
+
'f1_score': np.random.normal(0.82, 0.05, 100).cumsum()/100
|
330 |
+
})
|
331 |
+
|
332 |
+
fig_metrics = px.line(
|
333 |
+
training_metrics,
|
334 |
+
x='تاریخ',
|
335 |
+
y=['دقت', 'recall', 'f1_score'],
|
336 |
+
title='روند معیارهای ارزیابی',
|
337 |
+
labels={'value': 'مقدار', 'variable': 'معیار'},
|
338 |
+
template='plotly_white'
|
339 |
+
)
|
340 |
+
fig_metrics.update_layout(
|
341 |
+
showlegend=True,
|
342 |
+
legend_title_text='معیارها',
|
343 |
+
hovermode='x unified',
|
344 |
+
updatemenus=[
|
345 |
+
dict(
|
346 |
+
buttons=list([
|
347 |
+
dict(
|
348 |
+
args=[{"visible": [True, True, True]}],
|
349 |
+
label="همه",
|
350 |
+
method="restyle"
|
351 |
+
),
|
352 |
+
dict(
|
353 |
+
args=[{"visible": [True, False, False]}],
|
354 |
+
label="دقت",
|
355 |
+
method="restyle"
|
356 |
+
),
|
357 |
+
dict(
|
358 |
+
args=[{"visible": [False, True, False]}],
|
359 |
+
label="Recall",
|
360 |
+
method="restyle"
|
361 |
+
),
|
362 |
+
dict(
|
363 |
+
args=[{"visible": [False, False, True]}],
|
364 |
+
label="F1 Score",
|
365 |
+
method="restyle"
|
366 |
+
)
|
367 |
+
]),
|
368 |
+
direction="down",
|
369 |
+
showactive=True,
|
370 |
+
x=0.1,
|
371 |
+
y=1.1
|
372 |
+
)
|
373 |
+
]
|
374 |
+
)
|
375 |
+
|
376 |
+
# نمودار توزیع خطا
|
377 |
+
errors = np.random.normal(0, 1, 1000)
|
378 |
+
fig_dist = px.histogram(
|
379 |
+
errors,
|
380 |
+
nbins=50,
|
381 |
+
title='توزیع خطای پیشبینی',
|
382 |
+
labels={'value': 'خطا', 'count': 'تعداد'},
|
383 |
+
template='plotly_white'
|
384 |
+
)
|
385 |
+
fig_dist.update_layout(
|
386 |
+
bargap=0.1,
|
387 |
+
showlegend=False
|
388 |
+
)
|
389 |
+
|
390 |
+
# اضافه کردن کنترلهای تعاملی
|
391 |
+
st.sidebar.markdown("## تنظیمات نمودارها")
|
392 |
+
time_range = st.sidebar.slider(
|
393 |
+
"بازه زمانی (روز)",
|
394 |
+
min_value=7,
|
395 |
+
max_value=100,
|
396 |
+
value=30
|
397 |
+
)
|
398 |
+
|
399 |
+
metric_threshold = st.sidebar.number_input(
|
400 |
+
"آستانه دقت",
|
401 |
+
min_value=0.0,
|
402 |
+
max_value=1.0,
|
403 |
+
value=0.8,
|
404 |
+
step=0.05
|
405 |
+
)
|
406 |
|
407 |
+
# نمایش نمودارها با چینش جدید
|
408 |
+
col1, col2 = st.columns(2)
|
409 |
+
with col1:
|
410 |
+
st.plotly_chart(fig_metrics, use_container_width=True)
|
411 |
+
st.plotly_chart(fig_heatmap, use_container_width=True)
|
412 |
+
with col2:
|
413 |
+
st.plotly_chart(fig_dist, use_container_width=True)
|
414 |
+
st.plotly_chart(fig_pie, use_container_width=True)
|
app.py
CHANGED
@@ -1,239 +1,77 @@
|
|
1 |
-
import streamlit as st
|
2 |
-
import
|
3 |
-
import
|
4 |
-
from
|
5 |
-
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
.
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
.
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
.
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
.
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
.
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
color: #888;
|
79 |
-
margin-top: 5px;
|
80 |
-
text-align: right;
|
81 |
-
}
|
82 |
-
|
83 |
-
.quick-replies {
|
84 |
-
display: flex;
|
85 |
-
flex-wrap: wrap;
|
86 |
-
gap: 10px;
|
87 |
-
margin-top: 15px;
|
88 |
-
}
|
89 |
-
|
90 |
-
.quick-reply {
|
91 |
-
background: #4a90e2;
|
92 |
-
color: white;
|
93 |
-
padding: 8px 16px;
|
94 |
-
border-radius: 15px;
|
95 |
-
cursor: pointer;
|
96 |
-
font-weight: 500;
|
97 |
-
transition: background 0.3s ease;
|
98 |
-
}
|
99 |
-
|
100 |
-
.quick-reply:hover {
|
101 |
-
background: #357ab7;
|
102 |
-
}
|
103 |
-
|
104 |
-
.chat-input {
|
105 |
-
display: flex;
|
106 |
-
gap: 10px;
|
107 |
-
align-items: center;
|
108 |
-
padding: 20px;
|
109 |
-
background: #f8fafc;
|
110 |
-
}
|
111 |
-
|
112 |
-
.chat-input input[type="text"] {
|
113 |
-
flex-grow: 1;
|
114 |
-
padding: 10px;
|
115 |
-
border-radius: 5px;
|
116 |
-
border: 1px solid #ddd;
|
117 |
-
font-size: 1rem;
|
118 |
-
}
|
119 |
-
|
120 |
-
.chat-input button {
|
121 |
-
background: #4a90e2;
|
122 |
-
color: white;
|
123 |
-
padding: 10px 20px;
|
124 |
-
border: none;
|
125 |
-
border-radius: 5px;
|
126 |
-
cursor: pointer;
|
127 |
-
transition: background 0.3s;
|
128 |
-
}
|
129 |
-
|
130 |
-
.chat-input button:hover {
|
131 |
-
background: #357ab7;
|
132 |
-
}
|
133 |
-
|
134 |
-
.admin-panel {
|
135 |
-
background: #ffffff;
|
136 |
-
border-radius: 10px;
|
137 |
-
padding: 20px;
|
138 |
-
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
139 |
-
margin-bottom: 20px;
|
140 |
-
}
|
141 |
-
|
142 |
-
.statistics {
|
143 |
-
padding: 10px 0;
|
144 |
-
border-bottom: 1px solid #ddd;
|
145 |
-
}
|
146 |
-
|
147 |
-
</style>
|
148 |
-
""", unsafe_allow_html=True)
|
149 |
-
|
150 |
-
# دادههای اولیه
|
151 |
-
if 'conversation_history' not in st.session_state:
|
152 |
-
st.session_state.conversation_history = []
|
153 |
-
|
154 |
-
if 'is_typing' not in st.session_state:
|
155 |
-
st.session_state.is_typing = False
|
156 |
-
|
157 |
-
quick_replies = ["راهنمای استفاده", "تماس با پشتیبانی", "گزارش مشکل", "بخشنامههای جدید"]
|
158 |
-
|
159 |
-
# توابع چتبات
|
160 |
-
def get_bot_response(user_message):
|
161 |
-
time.sleep(1) # شبیهسازی تایپ کردن
|
162 |
-
return random.choice(["سلام! چطور میتونم کمک کنم؟", "لطفاً سوال خود را مطرح کنید.", "در خدمت شما هستم."])
|
163 |
-
|
164 |
-
def add_message(sender, message):
|
165 |
-
st.session_state.conversation_history.append({
|
166 |
-
'sender': sender,
|
167 |
-
'message': message,
|
168 |
-
'timestamp': datetime.now().strftime("%H:%M")
|
169 |
-
})
|
170 |
-
|
171 |
-
# هدر
|
172 |
-
st.markdown("""
|
173 |
-
<div class="header">
|
174 |
-
<h2>چتبات هوشمند</h2>
|
175 |
-
<div class="status">آنلاین</div>
|
176 |
-
</div>
|
177 |
-
""", unsafe_allow_html=True)
|
178 |
-
|
179 |
-
# نمایش پیامها
|
180 |
-
st.markdown("<div class='chat-container'><div class='chat-messages'>", unsafe_allow_html=True)
|
181 |
-
for message in st.session_state.conversation_history:
|
182 |
-
sender_class = "user" if message['sender'] == "user" else "bot"
|
183 |
-
st.markdown(f"""
|
184 |
-
<div class='message {sender_class}'>
|
185 |
-
<div>{message['message']}</div>
|
186 |
-
<div class='timestamp'>{message['timestamp']}</div>
|
187 |
-
</div>
|
188 |
-
""", unsafe_allow_html=True)
|
189 |
-
st.markdown("</div></div>", unsafe_allow_html=True)
|
190 |
-
|
191 |
-
# پاسخهای سریع
|
192 |
-
st.markdown("<div class='quick-replies'>", unsafe_allow_html=True)
|
193 |
-
for reply in quick_replies:
|
194 |
-
if st.button(reply):
|
195 |
-
add_message("user", reply)
|
196 |
-
bot_response = get_bot_response(reply)
|
197 |
-
add_message("bot", bot_response)
|
198 |
-
st.experimental_rerun()
|
199 |
-
st.markdown("</div>", unsafe_allow_html=True)
|
200 |
-
|
201 |
-
# ورودی کاربر
|
202 |
-
st.markdown("<div class='chat-input'>", unsafe_allow_html=True)
|
203 |
-
user_message = st.text_input("", placeholder="پیام خود را وارد کنید...", label_visibility="collapsed")
|
204 |
-
send_button = st.button("ارسال")
|
205 |
-
|
206 |
-
if send_button and user_message:
|
207 |
-
add_message("user", user_message)
|
208 |
-
st.session_state.is_typing = True
|
209 |
-
bot_response = get_bot_response(user_message)
|
210 |
-
add_message("bot", bot_response)
|
211 |
-
st.session_state.is_typing = False
|
212 |
-
st.experimental_rerun()
|
213 |
-
|
214 |
-
st.markdown("</div>", unsafe_allow_html=True)
|
215 |
-
|
216 |
-
# پنل مدیریت در سایدبار
|
217 |
-
with st.sidebar:
|
218 |
-
st.markdown("<div class='admin-panel'><h3>پنل مدیریت</h3>", unsafe_allow_html=True)
|
219 |
-
|
220 |
-
# نمایش آمار
|
221 |
-
total_messages = len(st.session_state.conversation_history)
|
222 |
-
user_messages = sum(1 for msg in st.session_state.conversation_history if msg['sender'] == 'user')
|
223 |
-
bot_messages = total_messages - user_messages
|
224 |
-
|
225 |
-
st.markdown(f"""
|
226 |
-
<div class="statistics">پیامهای کل: {total_messages}</div>
|
227 |
-
<div class="statistics">پیامهای کاربر: {user_messages}</div>
|
228 |
-
<div class="statistics">پیامهای ربات: {bot_messages}</div>
|
229 |
-
""", unsafe_allow_html=True)
|
230 |
-
|
231 |
-
# دکمه پاک کردن تاریخچه
|
232 |
-
if st.button("پاک کردن تاریخچه"):
|
233 |
-
st.session_state.conversation_history = []
|
234 |
-
st.experimental_rerun()
|
235 |
-
|
236 |
-
# تنظیمات ظاهری
|
237 |
-
st.markdown("### تنظیمات ظاهری")
|
238 |
-
font_size = st.slider("اندازه فونت", 12, 20, 14)
|
239 |
-
st.markdown(f"<style>.message {{ font-size: {font_size}px; }}</style>", unsafe_allow_html=True)
|
|
|
1 |
+
import streamlit as st
|
2 |
+
from admin_dashboard import AdminDashboard
|
3 |
+
from banking_assistant import BankingAssistant
|
4 |
+
from banking_model import BankingModelTrainer
|
5 |
+
from ml_banking_model import MLBankingEngine
|
6 |
+
|
7 |
+
class BankingSystem:
|
8 |
+
def __init__(self):
|
9 |
+
self.ml_engine = MLBankingEngine()
|
10 |
+
self.model_trainer = BankingModelTrainer()
|
11 |
+
self.assistant = BankingAssistant()
|
12 |
+
self.admin = AdminDashboard()
|
13 |
+
self.setup_page_config()
|
14 |
+
self.initialize_session_state()
|
15 |
+
|
16 |
+
def setup_page_config(self):
|
17 |
+
st.set_page_config(
|
18 |
+
page_title="سیستم بانکداری هوشمند",
|
19 |
+
page_icon="🏦",
|
20 |
+
layout="wide",
|
21 |
+
initial_sidebar_state="expanded"
|
22 |
+
)
|
23 |
+
|
24 |
+
def initialize_session_state(self):
|
25 |
+
if 'theme' not in st.session_state:
|
26 |
+
st.session_state.theme = 'light'
|
27 |
+
if 'user_role' not in st.session_state:
|
28 |
+
st.session_state.user_role = 'user'
|
29 |
+
if 'authenticated' not in st.session_state:
|
30 |
+
st.session_state.authenticated = False
|
31 |
+
|
32 |
+
def render_login(self):
|
33 |
+
st.markdown("""
|
34 |
+
<div style='text-align: center; padding: 50px;'>
|
35 |
+
<h1>🏦 سیستم بانکداری هوشمند</h1>
|
36 |
+
<p>لطفا وارد شوید</p>
|
37 |
+
</div>
|
38 |
+
""", unsafe_allow_html=True)
|
39 |
+
|
40 |
+
col1, col2, col3 = st.columns([1,2,1])
|
41 |
+
with col2:
|
42 |
+
username = st.text_input("نام کاربری")
|
43 |
+
password = st.text_input("رمز عبور", type="password")
|
44 |
+
|
45 |
+
if st.button("ورود"):
|
46 |
+
if username == "admin" and password == "admin":
|
47 |
+
st.session_state.user_role = 'admin'
|
48 |
+
st.session_state.authenticated = True
|
49 |
+
st.experimental_rerun()
|
50 |
+
elif username and password:
|
51 |
+
st.session_state.user_role = 'user'
|
52 |
+
st.session_state.authenticated = True
|
53 |
+
st.experimental_rerun()
|
54 |
+
|
55 |
+
def render_header(self):
|
56 |
+
st.markdown("""
|
57 |
+
<div style='display: flex; justify-content: space-between; align-items: center; padding: 1rem; background: white; box-shadow: 0 2px 4px rgba(0,0,0,0.1);'>
|
58 |
+
<h2>🏦 سیستم بانکداری هوشمند</h2>
|
59 |
+
<div>
|
60 |
+
<button onclick='logout()'>خروج</button>
|
61 |
+
</div>
|
62 |
+
</div>
|
63 |
+
""", unsafe_allow_html=True)
|
64 |
+
|
65 |
+
def main(self):
|
66 |
+
if not st.session_state.authenticated:
|
67 |
+
self.render_login()
|
68 |
+
else:
|
69 |
+
self.render_header()
|
70 |
+
if st.session_state.user_role == 'admin':
|
71 |
+
self.admin.render_dashboard()
|
72 |
+
else:
|
73 |
+
self.assistant.render_chat_interface()
|
74 |
+
|
75 |
+
if __name__ == "__main__":
|
76 |
+
system = BankingSystem()
|
77 |
+
system.main()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
banking_assistant.py
ADDED
@@ -0,0 +1,469 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import streamlit as st
|
2 |
+
import sqlite3
|
3 |
+
import random
|
4 |
+
from datetime import datetime
|
5 |
+
import pandas as pd
|
6 |
+
import plotly.express as px
|
7 |
+
from pathlib import Path
|
8 |
+
|
9 |
+
# تنظیمات اولیه دیتابیس
|
10 |
+
class DatabaseManager:
|
11 |
+
def __init__(self):
|
12 |
+
self.conn = sqlite3.connect('banking_assistant.db')
|
13 |
+
self.create_tables()
|
14 |
+
|
15 |
+
def create_tables(self):
|
16 |
+
c = self.conn.cursor()
|
17 |
+
# جدول مکالمات
|
18 |
+
c.execute('''
|
19 |
+
CREATE TABLE IF NOT EXISTS conversations (
|
20 |
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
21 |
+
user_message TEXT,
|
22 |
+
assistant_response TEXT,
|
23 |
+
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
|
24 |
+
feedback INTEGER DEFAULT 0
|
25 |
+
)
|
26 |
+
''')
|
27 |
+
|
28 |
+
# جدول پایگاه دانش
|
29 |
+
c.execute('''
|
30 |
+
CREATE TABLE IF NOT EXISTS knowledge_base (
|
31 |
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
32 |
+
question TEXT,
|
33 |
+
answer TEXT,
|
34 |
+
category TEXT,
|
35 |
+
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
36 |
+
)
|
37 |
+
''')
|
38 |
+
|
39 |
+
# جدول تنظیمات
|
40 |
+
c.execute('''
|
41 |
+
CREATE TABLE IF NOT EXISTS settings (
|
42 |
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
43 |
+
theme TEXT DEFAULT 'light',
|
44 |
+
language TEXT DEFAULT 'fa',
|
45 |
+
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
46 |
+
)
|
47 |
+
''')
|
48 |
+
self.conn.commit()
|
49 |
+
|
50 |
+
# تنظیمات استایل و تم
|
51 |
+
THEMES = {
|
52 |
+
'light': {
|
53 |
+
'bg_color': '#e0e5ec',
|
54 |
+
'text_color': '#333',
|
55 |
+
'shadow': '9px 9px 16px #b8b9be, -9px -9px 16px #ffffff'
|
56 |
+
},
|
57 |
+
'dark': {
|
58 |
+
'bg_color': '#2d3436',
|
59 |
+
'text_color': '#fff',
|
60 |
+
'shadow': '9px 9px 16px #1a1d1e, -9px -9px 16px #404b4d'
|
61 |
+
},
|
62 |
+
'blue': {
|
63 |
+
'bg_color': '#e3f2fd',
|
64 |
+
'text_color': '#1976d2',
|
65 |
+
'shadow': '9px 9px 16px #c1cdd4, -9px -9px 16px #ffffff'
|
66 |
+
}
|
67 |
+
}
|
68 |
+
def load_custom_styles(theme='light'):
|
69 |
+
return f"""
|
70 |
+
<style>
|
71 |
+
@import url('https://fonts.googleapis.com/css2?family=Vazirmatn:wght@100;200;300;400;500;600;700;800;900&display=swap');
|
72 |
+
|
73 |
+
/* تنظیمات پایه */
|
74 |
+
* {{
|
75 |
+
font-family: 'Vazirmatn', sans-serif;
|
76 |
+
direction: rtl;
|
77 |
+
transition: all 0.3s ease;
|
78 |
+
}}
|
79 |
+
|
80 |
+
body {{
|
81 |
+
background: {THEMES[theme]['bg_color']};
|
82 |
+
color: {THEMES[theme]['text_color']};
|
83 |
+
}}
|
84 |
+
|
85 |
+
/* هدر اصلی */
|
86 |
+
.main-header {{
|
87 |
+
background: {THEMES[theme]['bg_color']};
|
88 |
+
padding: 2rem;
|
89 |
+
border-radius: 25px;
|
90 |
+
box-shadow: {THEMES[theme]['shadow']};
|
91 |
+
margin-bottom: 2rem;
|
92 |
+
text-align: center;
|
93 |
+
position: relative;
|
94 |
+
overflow: hidden;
|
95 |
+
}}
|
96 |
+
|
97 |
+
.main-header::before {{
|
98 |
+
content: '';
|
99 |
+
position: absolute;
|
100 |
+
top: -50%;
|
101 |
+
left: -50%;
|
102 |
+
width: 200%;
|
103 |
+
height: 200%;
|
104 |
+
background: linear-gradient(
|
105 |
+
45deg,
|
106 |
+
transparent 0%,
|
107 |
+
rgba(255, 255, 255, 0.1) 50%,
|
108 |
+
transparent 100%
|
109 |
+
);
|
110 |
+
animation: shine 3s infinite;
|
111 |
+
}}
|
112 |
+
|
113 |
+
/* باکس چت */
|
114 |
+
.chat-container {{
|
115 |
+
background: {THEMES[theme]['bg_color']};
|
116 |
+
border-radius: 20px;
|
117 |
+
padding: 2rem;
|
118 |
+
margin: 1rem 0;
|
119 |
+
box-shadow: {THEMES[theme]['shadow']};
|
120 |
+
max-height: 70vh;
|
121 |
+
overflow-y: auto;
|
122 |
+
scroll-behavior: smooth;
|
123 |
+
}}
|
124 |
+
|
125 |
+
/* پیامها */
|
126 |
+
.message {{
|
127 |
+
margin: 1rem 0;
|
128 |
+
padding: 1rem;
|
129 |
+
border-radius: 15px;
|
130 |
+
position: relative;
|
131 |
+
animation: messageSlide 0.3s ease-out;
|
132 |
+
}}
|
133 |
+
|
134 |
+
.message.user {{
|
135 |
+
background: linear-gradient(135deg, #0073e6 0%, #0056b3 100%);
|
136 |
+
color: white;
|
137 |
+
margin-left: 2rem;
|
138 |
+
box-shadow: 0 4px 15px rgba(0, 115, 230, 0.2);
|
139 |
+
}}
|
140 |
+
|
141 |
+
.message.assistant {{
|
142 |
+
background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
|
143 |
+
color: #343a40;
|
144 |
+
margin-right: 2rem;
|
145 |
+
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
|
146 |
+
}}
|
147 |
+
|
148 |
+
/* ورودی چت */
|
149 |
+
.chat-input-container {{
|
150 |
+
background: {THEMES[theme]['bg_color']};
|
151 |
+
padding: 1.5rem;
|
152 |
+
border-radius: 15px;
|
153 |
+
box-shadow: {THEMES[theme]['shadow']};
|
154 |
+
margin-top: 1rem;
|
155 |
+
display: flex;
|
156 |
+
align-items: center;
|
157 |
+
gap: 1rem;
|
158 |
+
}}
|
159 |
+
|
160 |
+
.chat-input {{
|
161 |
+
flex: 1;
|
162 |
+
padding: 1rem;
|
163 |
+
border: none;
|
164 |
+
border-radius: 10px;
|
165 |
+
background: rgba(255, 255, 255, 0.1);
|
166 |
+
backdrop-filter: blur(10px);
|
167 |
+
color: {THEMES[theme]['text_color']};
|
168 |
+
font-size: 1rem;
|
169 |
+
transition: all 0.3s ease;
|
170 |
+
}}
|
171 |
+
|
172 |
+
.chat-input:focus {{
|
173 |
+
outline: none;
|
174 |
+
box-shadow: 0 0 0 3px rgba(0, 115, 230, 0.3);
|
175 |
+
}}
|
176 |
+
|
177 |
+
/* دکمهها */
|
178 |
+
.button {{
|
179 |
+
padding: 0.8rem 1.5rem;
|
180 |
+
border: none;
|
181 |
+
border-radius: 10px;
|
182 |
+
background: linear-gradient(135deg, #0073e6 0%, #0056b3 100%);
|
183 |
+
color: white;
|
184 |
+
cursor: pointer;
|
185 |
+
transition: all 0.3s ease;
|
186 |
+
font-weight: 500;
|
187 |
+
display: flex;
|
188 |
+
align-items: center;
|
189 |
+
gap: 0.5rem;
|
190 |
+
}}
|
191 |
+
|
192 |
+
.button:hover {{
|
193 |
+
transform: translateY(-2px);
|
194 |
+
box-shadow: 0 5px 15px rgba(0, 115, 230, 0.3);
|
195 |
+
}}
|
196 |
+
|
197 |
+
.button:active {{
|
198 |
+
transform: translateY(0);
|
199 |
+
}}
|
200 |
+
|
201 |
+
/* انیمیشنها */
|
202 |
+
@keyframes messageSlide {{
|
203 |
+
from {{
|
204 |
+
opacity: 0;
|
205 |
+
transform: translateY(20px);
|
206 |
+
}}
|
207 |
+
to {{
|
208 |
+
opacity: 1;
|
209 |
+
transform: translateY(0);
|
210 |
+
}}
|
211 |
+
}}
|
212 |
+
|
213 |
+
@keyframes shine {{
|
214 |
+
0% {{
|
215 |
+
transform: translateX(-100%) rotate(45deg);
|
216 |
+
}}
|
217 |
+
100% {{
|
218 |
+
transform: translateX(100%) rotate(45deg);
|
219 |
+
}}
|
220 |
+
}}
|
221 |
+
|
222 |
+
/* اسکرولبار سفارشی */
|
223 |
+
::-webkit-scrollbar {{
|
224 |
+
width: 8px;
|
225 |
+
}}
|
226 |
+
|
227 |
+
::-webkit-scrollbar-track {{
|
228 |
+
background: {THEMES[theme]['bg_color']};
|
229 |
+
}}
|
230 |
+
|
231 |
+
::-webkit-scrollbar-thumb {{
|
232 |
+
background: #0073e6;
|
233 |
+
border-radius: 4px;
|
234 |
+
}}
|
235 |
+
|
236 |
+
::-webkit-scrollbar-thumb:hover {{
|
237 |
+
background: #0056b3;
|
238 |
+
}}
|
239 |
+
</style>
|
240 |
+
"""
|
241 |
+
class BankingAssistant:
|
242 |
+
def __init__(self):
|
243 |
+
self.db = DatabaseManager()
|
244 |
+
self.model = BankingModel() # اضافه کردن مدل
|
245 |
+
if 'theme' not in st.session_state:
|
246 |
+
st.session_state.theme = 'light'
|
247 |
+
if 'messages' not in st.session_state:
|
248 |
+
st.session_state.messages = []
|
249 |
+
self.add_message('assistant', """
|
250 |
+
👋 سلام! من دستیار هوشمند بانکی شما هستم.
|
251 |
+
|
252 |
+
میتوانم در موارد زیر به شما کمک کنم:
|
253 |
+
📊 مشاهده وضعیت حساب
|
254 |
+
💳 انتقال وجه
|
255 |
+
📝 درخواست تسهیلات
|
256 |
+
🏦 اطلاعات شعب
|
257 |
+
|
258 |
+
چطور میتوانم کمکتان کنم؟
|
259 |
+
""")
|
260 |
+
|
261 |
+
def add_message(self, role, content):
|
262 |
+
timestamp = datetime.now().strftime("%H:%M")
|
263 |
+
st.session_state.messages.append({
|
264 |
+
'role': role,
|
265 |
+
'content': content,
|
266 |
+
'timestamp': timestamp
|
267 |
+
})
|
268 |
+
|
269 |
+
# ذخیره در دیتابیس
|
270 |
+
if role == 'user':
|
271 |
+
self.db.conn.execute(
|
272 |
+
'INSERT INTO conversations (user_message, timestamp) VALUES (?, ?)',
|
273 |
+
(content, timestamp)
|
274 |
+
)
|
275 |
+
else:
|
276 |
+
self.db.conn.execute(
|
277 |
+
'UPDATE conversations SET assistant_response = ? WHERE id = last_insert_rowid()',
|
278 |
+
(content,)
|
279 |
+
)
|
280 |
+
self.db.conn.commit()
|
281 |
+
|
282 |
+
def render_chat_interface(self):
|
283 |
+
st.markdown(load_custom_styles(st.session_state.theme), unsafe_allow_html=True)
|
284 |
+
|
285 |
+
# هدر اصلی
|
286 |
+
st.markdown("""
|
287 |
+
<div class="main-header">
|
288 |
+
<h1>🏦 دستیار هوشمند بانکی</h1>
|
289 |
+
<p>پاسخگوی 24 ساعته شما</p>
|
290 |
+
</div>
|
291 |
+
""", unsafe_allow_html=True)
|
292 |
+
|
293 |
+
# باکس چت
|
294 |
+
st.markdown('<div class="chat-container">', unsafe_allow_html=True)
|
295 |
+
|
296 |
+
for msg in st.session_state.messages:
|
297 |
+
class_name = "user" if msg['role'] == 'user' else "assistant"
|
298 |
+
st.markdown(f"""
|
299 |
+
<div class="message {class_name}">
|
300 |
+
{msg['content']}
|
301 |
+
<small style="position: absolute; bottom: 5px; {'right' if class_name == 'user' else 'left'}: 10px; opacity: 0.7;">
|
302 |
+
{msg['timestamp']}
|
303 |
+
</small>
|
304 |
+
</div>
|
305 |
+
""", unsafe_allow_html=True)
|
306 |
+
|
307 |
+
st.markdown('</div>', unsafe_allow_html=True)
|
308 |
+
|
309 |
+
# باکس ورودی
|
310 |
+
st.markdown("""
|
311 |
+
<div class="chat-input-container">
|
312 |
+
<button class="action-button">🎤</button>
|
313 |
+
<input type="text" class="chat-input" placeholder="پیام خود را بنویسید...">
|
314 |
+
<button class="button">
|
315 |
+
<span>ارسال</span>
|
316 |
+
<span>➤</span>
|
317 |
+
</button>
|
318 |
+
</div>
|
319 |
+
""", unsafe_allow_html=True)
|
320 |
+
|
321 |
+
|
322 |
+
class AdminDashboard:
|
323 |
+
def __init__(self, db_manager):
|
324 |
+
self.db = db_manager
|
325 |
+
|
326 |
+
def render_dashboard(self):
|
327 |
+
st.markdown("""
|
328 |
+
<div class="admin-header">
|
329 |
+
<h2>🔐 پنل مدیریت</h2>
|
330 |
+
</div>
|
331 |
+
""", unsafe_allow_html=True)
|
332 |
+
|
333 |
+
# نمودارهای تحلیلی
|
334 |
+
col1, col2 = st.columns(2)
|
335 |
+
|
336 |
+
with col1:
|
337 |
+
self.render_conversation_stats()
|
338 |
+
|
339 |
+
with col2:
|
340 |
+
self.render_feedback_chart()
|
341 |
+
|
342 |
+
# مدیریت پایگاه دانش
|
343 |
+
st.markdown("""
|
344 |
+
<div class="admin-section">
|
345 |
+
<h3>📚 مدیریت پایگاه دانش</h3>
|
346 |
+
</div>
|
347 |
+
""", unsafe_allow_html=True)
|
348 |
+
|
349 |
+
# افزودن دانش جدید
|
350 |
+
with st.expander("➕ افزودن مورد جدید"):
|
351 |
+
category = st.selectbox(
|
352 |
+
"دستهبندی",
|
353 |
+
["عمومی", "حسابها", "تسهیلات", "کارت", "شعب"]
|
354 |
+
)
|
355 |
+
question = st.text_area("سوال")
|
356 |
+
answer = st.text_area("پاسخ")
|
357 |
+
|
358 |
+
if st.button("ذخیره"):
|
359 |
+
self.db.conn.execute(
|
360 |
+
'INSERT INTO knowledge_base (question, answer, category) VALUES (?, ?, ?)',
|
361 |
+
(question, answer, category)
|
362 |
+
)
|
363 |
+
self.db.conn.commit()
|
364 |
+
st.success("✅ با موفقیت ذخیره شد")
|
365 |
+
|
366 |
+
def render_conversation_stats(self):
|
367 |
+
# دریافت آمار مکالمات
|
368 |
+
df = pd.read_sql_query("""
|
369 |
+
SELECT
|
370 |
+
date(timestamp) as date,
|
371 |
+
COUNT(*) as count
|
372 |
+
FROM conversations
|
373 |
+
GROUP BY date(timestamp)
|
374 |
+
ORDER BY date DESC
|
375 |
+
LIMIT 7
|
376 |
+
""", self.db.conn)
|
377 |
+
|
378 |
+
fig = px.line(
|
379 |
+
df,
|
380 |
+
x='date',
|
381 |
+
y='count',
|
382 |
+
title='آمار مکالمات 7 روز اخیر',
|
383 |
+
labels={'count': 'تعداد مکالمات', 'date': 'تاریخ'}
|
384 |
+
)
|
385 |
+
|
386 |
+
fig.update_layout(
|
387 |
+
font_family="Vazirmatn",
|
388 |
+
plot_bgcolor='rgba(0,0,0,0)',
|
389 |
+
paper_bgcolor='rgba(0,0,0,0)',
|
390 |
+
)
|
391 |
+
|
392 |
+
st.plotly_chart(fig)
|
393 |
+
|
394 |
+
def render_feedback_chart(self):
|
395 |
+
# نمودار بازخوردها
|
396 |
+
df = pd.read_sql_query("""
|
397 |
+
SELECT
|
398 |
+
feedback,
|
399 |
+
COUNT(*) as count
|
400 |
+
FROM conversations
|
401 |
+
WHERE feedback != 0
|
402 |
+
GROUP BY feedback
|
403 |
+
""", self.db.conn)
|
404 |
+
|
405 |
+
fig = px.pie(
|
406 |
+
df,
|
407 |
+
values='count',
|
408 |
+
names='feedback',
|
409 |
+
title='نمودار بازخوردها',
|
410 |
+
color_discrete_sequence=px.colors.sequential.Blues
|
411 |
+
)
|
412 |
+
|
413 |
+
fig.update_layout(
|
414 |
+
font_family="Vazirmatn",
|
415 |
+
plot_bgcolor='rgba(0,0,0,0)',
|
416 |
+
paper_bgcolor='rgba(0,0,0,0)',
|
417 |
+
)
|
418 |
+
|
419 |
+
st.plotly_chart(fig)
|
420 |
+
|
421 |
+
def main():
|
422 |
+
st.set_page_config(
|
423 |
+
page_title="دستیار هوشمند بانکی",
|
424 |
+
page_icon="🏦",
|
425 |
+
layout="wide",
|
426 |
+
initial_sidebar_state="expanded"
|
427 |
+
)
|
428 |
+
|
429 |
+
assistant = BankingAssistant()
|
430 |
+
|
431 |
+
# منوی کناری
|
432 |
+
with st.sidebar:
|
433 |
+
st.markdown("### ⚙️ تنظیمات")
|
434 |
+
theme = st.selectbox(
|
435 |
+
"انتخاب تم",
|
436 |
+
options=['light', 'dark', 'blue'],
|
437 |
+
index=['light', 'dark', 'blue'].index(st.session_state.theme)
|
438 |
+
)
|
439 |
+
|
440 |
+
if theme != st.session_state.theme:
|
441 |
+
st.session_state.theme = theme
|
442 |
+
st.experimental_rerun()
|
443 |
+
|
444 |
+
if st.button("🔐 ورود مدیر"):
|
445 |
+
st.session_state.show_login = True
|
446 |
+
|
447 |
+
# نمایش فرم لاگین
|
448 |
+
if st.session_state.get('show_login', False):
|
449 |
+
with st.form("login_form"):
|
450 |
+
username = st.text_input("نام کاربری")
|
451 |
+
password = st.text_input("رمز عبور", type="password")
|
452 |
+
|
453 |
+
if st.form_submit_button("ورود"):
|
454 |
+
if username == "admin" and password == "admin": # در حالت واقعی باید امنتر باشد
|
455 |
+
st.session_state.admin_logged_in = True
|
456 |
+
st.session_state.show_login = False
|
457 |
+
st.experimental_rerun()
|
458 |
+
else:
|
459 |
+
st.error("نام کاربری یا رمز عبور اشتباه است")
|
460 |
+
|
461 |
+
# نمایش داشبورد مدیر
|
462 |
+
if st.session_state.get('admin_logged_in', False):
|
463 |
+
admin = AdminDashboard(assistant.db)
|
464 |
+
admin.render_dashboard()
|
465 |
+
else:
|
466 |
+
assistant.render_chat_interface()
|
467 |
+
|
468 |
+
if __name__ == "__main__":
|
469 |
+
main()
|
banking_model.py
ADDED
@@ -0,0 +1,146 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import pandas as pd
|
2 |
+
import torch
|
3 |
+
from transformers import (
|
4 |
+
AutoModelForCausalLM,
|
5 |
+
AutoTokenizer,
|
6 |
+
TrainingArguments,
|
7 |
+
Trainer,
|
8 |
+
DataCollatorForLanguageModeling
|
9 |
+
)
|
10 |
+
from datasets import Dataset
|
11 |
+
import json
|
12 |
+
from pathlib import Path
|
13 |
+
|
14 |
+
class BankingModelTrainer:
|
15 |
+
def __init__(
|
16 |
+
self,
|
17 |
+
base_model_name="meta-llama/Llama-2-13b-chat-hf",
|
18 |
+
output_dir="./fine_tuned_model",
|
19 |
+
max_length=512
|
20 |
+
):
|
21 |
+
self.base_model_name = base_model_name
|
22 |
+
self.output_dir = Path(output_dir)
|
23 |
+
self.max_length = max_length
|
24 |
+
self.device = "cuda" if torch.cuda.is_available() else "cpu"
|
25 |
+
|
26 |
+
# تنظیمات مدل Llama-2
|
27 |
+
model_config = {
|
28 |
+
"device_map": "auto",
|
29 |
+
"torch_dtype": torch.bfloat16,
|
30 |
+
"low_cpu_mem_usage": True,
|
31 |
+
"max_memory": {0: "10GB"},
|
32 |
+
"load_in_8bit": True
|
33 |
+
}
|
34 |
+
|
35 |
+
# تنظیمات اولیه مدل و توکنایزر
|
36 |
+
self.tokenizer = AutoTokenizer.from_pretrained(base_model_name)
|
37 |
+
self.model = AutoModelForCausalLM.from_pretrained(
|
38 |
+
base_model_name,
|
39 |
+
**model_config
|
40 |
+
)
|
41 |
+
|
42 |
+
def prepare_data(self, data_path):
|
43 |
+
# خواندن دیتا از فایل
|
44 |
+
if data_path.endswith('.csv'):
|
45 |
+
df = pd.read_csv(data_path)
|
46 |
+
elif data_path.endswith('.json'):
|
47 |
+
with open(data_path, 'r', encoding='utf-8') as f:
|
48 |
+
data = json.load(f)
|
49 |
+
df = pd.DataFrame(data)
|
50 |
+
else:
|
51 |
+
raise ValueError("فرمت فایل باید CSV یا JSON باشد")
|
52 |
+
|
53 |
+
# پردازش و آمادهسازی دیتا
|
54 |
+
def prepare_examples(examples):
|
55 |
+
conversations = []
|
56 |
+
for q, a in zip(examples['question'], examples['answer']):
|
57 |
+
# فرمت Llama-2 برای مکالمه
|
58 |
+
conv = f"[INST] {q} [/INST] {a}"
|
59 |
+
conversations.append(conv)
|
60 |
+
|
61 |
+
# توکنایز کردن با تنظیمات Llama-2
|
62 |
+
encodings = self.tokenizer(
|
63 |
+
conversations,
|
64 |
+
truncation=True,
|
65 |
+
padding=True,
|
66 |
+
max_length=self.max_length,
|
67 |
+
return_tensors="pt"
|
68 |
+
)
|
69 |
+
|
70 |
+
return encodings
|
71 |
+
|
72 |
+
dataset = Dataset.from_pandas(df)
|
73 |
+
tokenized_dataset = dataset.map(
|
74 |
+
prepare_examples,
|
75 |
+
batched=True,
|
76 |
+
remove_columns=dataset.column_names
|
77 |
+
)
|
78 |
+
|
79 |
+
return tokenized_dataset
|
80 |
+
|
81 |
+
def train(self, dataset, epochs=3, batch_size=4):
|
82 |
+
training_args = TrainingArguments(
|
83 |
+
output_dir=str(self.output_dir),
|
84 |
+
num_train_epochs=epochs,
|
85 |
+
per_device_train_batch_size=batch_size,
|
86 |
+
gradient_accumulation_steps=4,
|
87 |
+
save_steps=500,
|
88 |
+
logging_steps=100,
|
89 |
+
learning_rate=2e-5, # کاهش نرخ یادگیری برای Llama-2
|
90 |
+
warmup_steps=100,
|
91 |
+
fp16=True, # فعال کردن fp16 برای Llama-2
|
92 |
+
save_total_limit=2,
|
93 |
+
logging_dir=str(self.output_dir / "logs"),
|
94 |
+
gradient_checkpointing=True # فعال کردن gradient checkpointing
|
95 |
+
)
|
96 |
+
|
97 |
+
data_collator = DataCollatorForLanguageModeling(
|
98 |
+
tokenizer=self.tokenizer,
|
99 |
+
mlm=False
|
100 |
+
)
|
101 |
+
|
102 |
+
trainer = Trainer(
|
103 |
+
model=self.model,
|
104 |
+
args=training_args,
|
105 |
+
train_dataset=dataset,
|
106 |
+
data_collator=data_collator
|
107 |
+
)
|
108 |
+
|
109 |
+
trainer.train()
|
110 |
+
|
111 |
+
self.model.save_pretrained(self.output_dir)
|
112 |
+
self.tokenizer.save_pretrained(self.output_dir)
|
113 |
+
|
114 |
+
def generate_response(self, prompt):
|
115 |
+
# فرمت Llama-2 برای پرامپت
|
116 |
+
formatted_prompt = f"[INST] {prompt} [/INST]"
|
117 |
+
inputs = self.tokenizer.encode(
|
118 |
+
formatted_prompt,
|
119 |
+
return_tensors="pt"
|
120 |
+
).to(self.device)
|
121 |
+
|
122 |
+
outputs = self.model.generate(
|
123 |
+
inputs,
|
124 |
+
max_length=self.max_length,
|
125 |
+
num_return_sequences=1,
|
126 |
+
temperature=0.7,
|
127 |
+
top_p=0.9,
|
128 |
+
do_sample=True,
|
129 |
+
pad_token_id=self.tokenizer.eos_token_id,
|
130 |
+
repetition_penalty=1.2 # اضافه کردن جریمه تکرار
|
131 |
+
)
|
132 |
+
|
133 |
+
response = self.tokenizer.decode(
|
134 |
+
outputs[0],
|
135 |
+
skip_special_tokens=True
|
136 |
+
)
|
137 |
+
# حذف پرامپت از پاسخ
|
138 |
+
response = response.replace(formatted_prompt, "").strip()
|
139 |
+
return response
|
140 |
+
|
141 |
+
if __name__ == "__main__":
|
142 |
+
trainer = BankingModelTrainer()
|
143 |
+
dataset = trainer.prepare_data("banking_qa.json")
|
144 |
+
trainer.train(dataset)
|
145 |
+
response = trainer.generate_response("شرایط وام مسکن چیست؟")
|
146 |
+
print(response)
|
filemanager.py
ADDED
@@ -0,0 +1,394 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import streamlit as st
|
2 |
+
from pathlib import Path
|
3 |
+
from datetime import datetime
|
4 |
+
import zipfile
|
5 |
+
from PIL import Image
|
6 |
+
import time
|
7 |
+
import humanize
|
8 |
+
|
9 |
+
# تنظیمات صفحه
|
10 |
+
st.set_page_config(
|
11 |
+
page_title="سیستم مدیریت فایل",
|
12 |
+
page_icon="💼",
|
13 |
+
layout="wide",
|
14 |
+
initial_sidebar_state="expanded"
|
15 |
+
)
|
16 |
+
|
17 |
+
# استایلهای سفارشی با تم چتبات
|
18 |
+
CUSTOM_CSS = """
|
19 |
+
<style>
|
20 |
+
/* فونت و تنظیمات پایه */
|
21 |
+
@import url('https://fonts.googleapis.com/css2?family=Vazirmatn:wght@400;700&display=swap');
|
22 |
+
|
23 |
+
* {
|
24 |
+
font-family: 'Vazirmatn', sans-serif;
|
25 |
+
direction: rtl;
|
26 |
+
}
|
27 |
+
|
28 |
+
/* کانتینر اصلی */
|
29 |
+
.main-container {
|
30 |
+
max-width: 1200px;
|
31 |
+
margin: 0 auto;
|
32 |
+
padding: 2rem;
|
33 |
+
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
|
34 |
+
border-radius: 20px;
|
35 |
+
box-shadow: 0 8px 32px rgba(31, 38, 135, 0.15);
|
36 |
+
}
|
37 |
+
|
38 |
+
/* کارت فایل */
|
39 |
+
.file-card {
|
40 |
+
background: white;
|
41 |
+
border-radius: 15px;
|
42 |
+
padding: 1.5rem;
|
43 |
+
margin: 1rem 0;
|
44 |
+
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
|
45 |
+
transition: all 0.3s ease;
|
46 |
+
animation: slideIn 0.3s ease-out;
|
47 |
+
}
|
48 |
+
|
49 |
+
.file-card:hover {
|
50 |
+
transform: translateY(-5px);
|
51 |
+
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15);
|
52 |
+
}
|
53 |
+
|
54 |
+
/* دکمههای عملیات */
|
55 |
+
.action-button {
|
56 |
+
background: #2196F3;
|
57 |
+
color: white;
|
58 |
+
border: none;
|
59 |
+
border-radius: 10px;
|
60 |
+
padding: 0.8rem 1.2rem;
|
61 |
+
cursor: pointer;
|
62 |
+
transition: all 0.3s ease;
|
63 |
+
display: flex;
|
64 |
+
align-items: center;
|
65 |
+
gap: 0.5rem;
|
66 |
+
}
|
67 |
+
|
68 |
+
.action-button:hover {
|
69 |
+
background: #1976D2;
|
70 |
+
transform: scale(1.05);
|
71 |
+
}
|
72 |
+
|
73 |
+
/* ناحیه آپلود */
|
74 |
+
.upload-area {
|
75 |
+
border: 2px dashed #2196F3;
|
76 |
+
border-radius: 15px;
|
77 |
+
padding: 2rem;
|
78 |
+
text-align: center;
|
79 |
+
background: rgba(255, 255, 255, 0.9);
|
80 |
+
cursor: pointer;
|
81 |
+
transition: all 0.3s ease;
|
82 |
+
}
|
83 |
+
|
84 |
+
.upload-area:hover {
|
85 |
+
border-color: #1976D2;
|
86 |
+
background: rgba(255, 255, 255, 1);
|
87 |
+
}
|
88 |
+
|
89 |
+
/* نوار پیشرفت */
|
90 |
+
.progress-bar {
|
91 |
+
height: 4px;
|
92 |
+
background: #e0e0e0;
|
93 |
+
border-radius: 2px;
|
94 |
+
overflow: hidden;
|
95 |
+
margin: 1rem 0;
|
96 |
+
}
|
97 |
+
|
98 |
+
.progress-fill {
|
99 |
+
height: 100%;
|
100 |
+
background: #2196F3;
|
101 |
+
width: 0%;
|
102 |
+
animation: fillProgress 2s ease-out forwards;
|
103 |
+
}
|
104 |
+
|
105 |
+
/* انیمیشنها */
|
106 |
+
@keyframes slideIn {
|
107 |
+
from {
|
108 |
+
opacity: 0;
|
109 |
+
transform: translateY(20px);
|
110 |
+
}
|
111 |
+
to {
|
112 |
+
opacity: 1;
|
113 |
+
transform: translateY(0);
|
114 |
+
}
|
115 |
+
}
|
116 |
+
|
117 |
+
@keyframes fillProgress {
|
118 |
+
from { width: 0%; }
|
119 |
+
to { width: 100%; }
|
120 |
+
}
|
121 |
+
|
122 |
+
/* فیلتر و جستجو */
|
123 |
+
.search-box {
|
124 |
+
display: flex;
|
125 |
+
gap: 1rem;
|
126 |
+
margin-bottom: 2rem;
|
127 |
+
}
|
128 |
+
|
129 |
+
.search-input {
|
130 |
+
flex: 1;
|
131 |
+
padding: 0.8rem 1.2rem;
|
132 |
+
border: 2px solid #e0e0e0;
|
133 |
+
border-radius: 10px;
|
134 |
+
font-size: 1rem;
|
135 |
+
transition: all 0.3s ease;
|
136 |
+
}
|
137 |
+
|
138 |
+
.search-input:focus {
|
139 |
+
border-color: #2196F3;
|
140 |
+
outline: none;
|
141 |
+
}
|
142 |
+
|
143 |
+
/* پیامهای اطلاعرسانی */
|
144 |
+
.info-message {
|
145 |
+
background: rgba(33, 150, 243, 0.1);
|
146 |
+
border-left: 4px solid #2196F3;
|
147 |
+
padding: 1rem;
|
148 |
+
border-radius: 0 10px 10px 0;
|
149 |
+
margin: 1rem 0;
|
150 |
+
}
|
151 |
+
</style>
|
152 |
+
"""
|
153 |
+
|
154 |
+
st.markdown(CUSTOM_CSS, unsafe_allow_html=True)
|
155 |
+
|
156 |
+
class FileManager:
|
157 |
+
def __init__(self):
|
158 |
+
self.root_path = Path("uploads")
|
159 |
+
self.root_path.mkdir(exist_ok=True)
|
160 |
+
|
161 |
+
def get_file_info(self, filename):
|
162 |
+
"""دریافت اطلاعات کامل فایل"""
|
163 |
+
path = self.root_path / filename
|
164 |
+
stats = path.stat()
|
165 |
+
return {
|
166 |
+
'size': humanize.naturalsize(stats.st_size),
|
167 |
+
'modified': datetime.fromtimestamp(stats.st_mtime).strftime('%Y/%m/%d %H:%M'),
|
168 |
+
'type': path.suffix[1:].upper(),
|
169 |
+
'icon': self._get_file_icon(path.suffix)
|
170 |
+
}
|
171 |
+
|
172 |
+
def _get_file_icon(self, suffix):
|
173 |
+
"""انتخاب آیکون مناسب برای هر نوع فایل"""
|
174 |
+
icons = {
|
175 |
+
'.txt': '📄',
|
176 |
+
'.pdf': '📕',
|
177 |
+
'.jpg': '🖼️',
|
178 |
+
'.jpeg': '🖼️',
|
179 |
+
'.png': '🖼️',
|
180 |
+
'.gif': '🎞️',
|
181 |
+
'.zip': '📦',
|
182 |
+
'.mp3': '🎵',
|
183 |
+
'.mp4': '🎥',
|
184 |
+
'.doc': '📘',
|
185 |
+
'.docx': '📘',
|
186 |
+
'.xls': '📊',
|
187 |
+
'.xlsx': '📊',
|
188 |
+
}
|
189 |
+
return icons.get(suffix.lower(), '📎')
|
190 |
+
|
191 |
+
def upload_file(self, file):
|
192 |
+
"""آپلود فایل با نمایش پیشرفت"""
|
193 |
+
try:
|
194 |
+
progress_text = st.empty()
|
195 |
+
progress_bar = st.progress(0)
|
196 |
+
|
197 |
+
dest_path = self.root_path / file.name
|
198 |
+
total_size = file.size
|
199 |
+
|
200 |
+
with open(dest_path, "wb") as f:
|
201 |
+
bytes_data = file.getbuffer()
|
202 |
+
f.write(bytes_data)
|
203 |
+
|
204 |
+
# شبیهسازی پیشرفت آپلود
|
205 |
+
for i in range(100):
|
206 |
+
time.sleep(0.01)
|
207 |
+
progress = (i + 1) / 100
|
208 |
+
progress_bar.progress(progress)
|
209 |
+
progress_text.text(f"در حال آپلود... {int(progress * 100)}%")
|
210 |
+
|
211 |
+
progress_text.empty()
|
212 |
+
progress_bar.empty()
|
213 |
+
|
214 |
+
return "success", f"✅ فایل '{file.name}' با موفقیت آپلود شد"
|
215 |
+
except Exception as e:
|
216 |
+
return "error", f"❌ خطا در آپلود فایل: {str(e)}"
|
217 |
+
|
218 |
+
def list_files(self, search_term="", file_type=None):
|
219 |
+
"""لیست فایلها با قابلیت جستجو و فیلتر"""
|
220 |
+
files = []
|
221 |
+
for f in self.root_path.iterdir():
|
222 |
+
if f.is_file():
|
223 |
+
if file_type and file_type != "همه" and f.suffix.lower() != file_type.lower():
|
224 |
+
continue
|
225 |
+
if search_term and search_term.lower() not in f.name.lower():
|
226 |
+
continue
|
227 |
+
files.append(f.name)
|
228 |
+
return sorted(files)
|
229 |
+
|
230 |
+
def preview_file(self, filename):
|
231 |
+
"""پیشنمایش پیشرفته فایل"""
|
232 |
+
try:
|
233 |
+
path = self.root_path / filename
|
234 |
+
if path.suffix.lower() in ['.jpg', '.jpeg', '.png', '.gif']:
|
235 |
+
img = Image.open(path)
|
236 |
+
return "image", img
|
237 |
+
elif path.suffix.lower() == '.txt':
|
238 |
+
with open(path, "r", encoding="utf-8") as f:
|
239 |
+
content = f.read(1000)
|
240 |
+
if len(content) >= 1000:
|
241 |
+
content += "\n...[ادامه متن]"
|
242 |
+
return "text", content
|
243 |
+
return "unsupported", "⚠️ پیشنمایش برای این نوع فایل در دسترس نیست"
|
244 |
+
except Exception as e:
|
245 |
+
return "error", f"❌ خطا در نمایش فایل: {str(e)}"
|
246 |
+
|
247 |
+
def compress_files(self, files):
|
248 |
+
"""فشردهسازی فایلها با نمایش پیشرفت"""
|
249 |
+
try:
|
250 |
+
if not files:
|
251 |
+
return "error", "⚠️ لطفاً حداقل یک فایل انتخاب کنید"
|
252 |
+
|
253 |
+
zip_name = f"compressed_{datetime.now().strftime('%Y%m%d_%H%M%S')}.zip"
|
254 |
+
zip_path = self.root_path / zip_name
|
255 |
+
|
256 |
+
progress_text = st.empty()
|
257 |
+
progress_bar = st.progress(0)
|
258 |
+
|
259 |
+
with zipfile.ZipFile(zip_path, 'w') as zipf:
|
260 |
+
for i, file in enumerate(files, 1):
|
261 |
+
file_path = self.root_path / file
|
262 |
+
zipf.write(file_path, file)
|
263 |
+
progress = i / len(files)
|
264 |
+
progress_bar.progress(progress)
|
265 |
+
progress_text.text(f"در حال فشردهسازی... {int(progress * 100)}%")
|
266 |
+
|
267 |
+
progress_text.empty()
|
268 |
+
progress_bar.empty()
|
269 |
+
|
270 |
+
return "success", f"✅ فایلها با موفقیت در '{zip_name}' فشرده شدند"
|
271 |
+
except Exception as e:
|
272 |
+
return "error", f"❌ خطا در فشردهسازی: {str(e)}"
|
273 |
+
|
274 |
+
def main():
|
275 |
+
st.markdown('<div class="main-container">', unsafe_allow_html=True)
|
276 |
+
st.title("💼 سیستم مدیریت فایل پیشرفته")
|
277 |
+
|
278 |
+
file_manager = FileManager()
|
279 |
+
|
280 |
+
# بخش آپلود فایل
|
281 |
+
st.markdown("""
|
282 |
+
<div class="upload-area">
|
283 |
+
<h3>📤 آپلود فایل</h3>
|
284 |
+
<p>فایل خود را اینجا رها کنید یا کلیک کنید</p>
|
285 |
+
<div class="progress-bar">
|
286 |
+
<div class="progress-fill"></div>
|
287 |
+
</div>
|
288 |
+
</div>
|
289 |
+
""", unsafe_allow_html=True)
|
290 |
+
|
291 |
+
uploaded_file = st.file_uploader(
|
292 |
+
"",
|
293 |
+
type=["jpg", "jpeg", "png", "gif", "txt", "pdf", "doc", "docx", "xls", "xlsx", "mp3", "mp4", "zip"],
|
294 |
+
accept_multiple_files=False
|
295 |
+
)
|
296 |
+
|
297 |
+
if uploaded_file:
|
298 |
+
status, message = file_manager.upload_file(uploaded_file)
|
299 |
+
if status == "success":
|
300 |
+
st.success(message)
|
301 |
+
else:
|
302 |
+
st.error(message)
|
303 |
+
|
304 |
+
# بخش جستجو و فیلتر
|
305 |
+
col1, col2 = st.columns([2, 1])
|
306 |
+
with col1:
|
307 |
+
search_term = st.text_input("🔍 جستجوی فایل", placeholder="نام فایل را وارد کنید...")
|
308 |
+
with col2:
|
309 |
+
file_type = st.selectbox(
|
310 |
+
"📁 نوع فایل",
|
311 |
+
["همه", ".jpg", ".jpeg", ".png", ".gif", ".txt", ".pdf", ".doc", ".docx", ".xls", ".xlsx", ".mp3", ".mp4", ".zip"]
|
312 |
+
)
|
313 |
+
|
314 |
+
# نمایش لیست فایلها
|
315 |
+
files = file_manager.list_files(search_term, file_type)
|
316 |
+
|
317 |
+
if not files:
|
318 |
+
st.markdown("""
|
319 |
+
<div class="info-message">
|
320 |
+
📭 هیچ فایلی یافت نشد
|
321 |
+
</div>
|
322 |
+
""", unsafe_allow_html=True)
|
323 |
+
else:
|
324 |
+
for file in files:
|
325 |
+
file_info = file_manager.get_file_info(file)
|
326 |
+
|
327 |
+
with st.container():
|
328 |
+
st.markdown(f"""
|
329 |
+
<div class="file-card">
|
330 |
+
<div style="display: flex; justify-content: space-between; align-items: center;">
|
331 |
+
<div>
|
332 |
+
<h3>{file_info['icon']} {file}</h3>
|
333 |
+
<p>اندازه: {file_info['size']} | نوع: {file_info['type']} | آخرین تغییر: {file_info['modified']}</p>
|
334 |
+
</div>
|
335 |
+
</div>
|
336 |
+
</div>
|
337 |
+
""", unsafe_allow_html=True)
|
338 |
+
|
339 |
+
col1, col2, col3, col4 = st.columns([1, 1, 1, 1])
|
340 |
+
|
341 |
+
with col1:
|
342 |
+
if st.button("👁️ نمایش", key=f"preview_{file}"):
|
343 |
+
preview_type, preview_content = file_manager.preview_file(file)
|
344 |
+
if preview_type == "image":
|
345 |
+
st.image(preview_content, use_column_width=True)
|
346 |
+
elif preview_type == "text":
|
347 |
+
st.text(preview_content)
|
348 |
+
else:
|
349 |
+
st.warning(preview_content)
|
350 |
+
|
351 |
+
with col2:
|
352 |
+
if st.button("🗑️ حذف", key=f"delete_{file}"):
|
353 |
+
if st.session_state.get('admin_logged_in', False):
|
354 |
+
status, message = file_manager.delete_file(file)
|
355 |
+
st.success(message) if status == "success" else st.error(message)
|
356 |
+
else:
|
357 |
+
st.error("⛔ فقط مدیر میتواند فایلها را حذف کند")
|
358 |
+
|
359 |
+
with col3:
|
360 |
+
with open(file_manager.root_path / file, 'rb') as f:
|
361 |
+
st.download_button(
|
362 |
+
"⬇️ دانلود",
|
363 |
+
f.read(),
|
364 |
+
file_name=file,
|
365 |
+
key=f"download_{file}"
|
366 |
+
)
|
367 |
+
|
368 |
+
# بخش فشردهسازی
|
369 |
+
st.markdown("""
|
370 |
+
<div class="file-card">
|
371 |
+
<h3>🗜️ فشردهسازی فایلها</h3>
|
372 |
+
</div>
|
373 |
+
""", unsafe_allow_html=True)
|
374 |
+
|
375 |
+
selected_files = st.multiselect(
|
376 |
+
"فایلهای مورد نظر را انتخاب کنید",
|
377 |
+
files,
|
378 |
+
key="compress_files"
|
379 |
+
)
|
380 |
+
|
381 |
+
if st.button("📦 ساخت فایل ZIP"):
|
382 |
+
if selected_files:
|
383 |
+
status, message = file_manager.compress_files(selected_files)
|
384 |
+
if status == "success":
|
385 |
+
st.success(message)
|
386 |
+
else:
|
387 |
+
st.error(message)
|
388 |
+
else:
|
389 |
+
st.warning("⚠️ لطفاً حداقل یک فایل انتخاب کنید")
|
390 |
+
|
391 |
+
st.markdown('</div>', unsafe_allow_html=True)
|
392 |
+
|
393 |
+
if __name__ == "__main__":
|
394 |
+
main()
|
ml_banking_model.py
ADDED
@@ -0,0 +1,141 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
from pathlib import Path
|
3 |
+
import torch
|
4 |
+
from transformers import AutoModelForCausalLM, AutoTokenizer, TrainingArguments, Trainer
|
5 |
+
from peft import LoraConfig, get_peft_model
|
6 |
+
import pandas as pd
|
7 |
+
from datasets import Dataset
|
8 |
+
import json
|
9 |
+
import psutil
|
10 |
+
import time
|
11 |
+
from datetime import datetime
|
12 |
+
import onnx
|
13 |
+
import onnxruntime
|
14 |
+
from functools import lru_cache
|
15 |
+
import logging
|
16 |
+
from typing import Dict, List, Optional
|
17 |
+
|
18 |
+
class BankingModel:
|
19 |
+
def __init__(self):
|
20 |
+
# تنظیم لاگر
|
21 |
+
self._setup_logging()
|
22 |
+
|
23 |
+
# ساخت پوشهها
|
24 |
+
self.base_dir = Path.cwd()
|
25 |
+
self.dirs = {
|
26 |
+
'model': self.base_dir / "trained_model",
|
27 |
+
'data': self.base_dir / "data",
|
28 |
+
'logs': self.base_dir / "logs",
|
29 |
+
'backup': self.base_dir / "backups",
|
30 |
+
'cache': self.base_dir / "cache",
|
31 |
+
'reports': self.base_dir / "reports"
|
32 |
+
}
|
33 |
+
|
34 |
+
for dir_path in self.dirs.values():
|
35 |
+
dir_path.mkdir(exist_ok=True)
|
36 |
+
|
37 |
+
# تنظیمات مدل برای CPU
|
38 |
+
self.model_name = "meta-llama/Llama-2-13b-chat-hf"
|
39 |
+
self.tokenizer = AutoTokenizer.from_pretrained(self.model_name)
|
40 |
+
|
41 |
+
# بهینهسازی برای CPU
|
42 |
+
self.model = AutoModelForCausalLM.from_pretrained(
|
43 |
+
self.model_name,
|
44 |
+
device_map='cpu',
|
45 |
+
torch_dtype=torch.float32,
|
46 |
+
low_cpu_mem_usage=True
|
47 |
+
)
|
48 |
+
|
49 |
+
# تنظیمات LoRA
|
50 |
+
self._setup_lora()
|
51 |
+
|
52 |
+
# مقداردهی کش
|
53 |
+
self.response_cache = {}
|
54 |
+
|
55 |
+
# شروع مانیتورینگ
|
56 |
+
self.start_monitoring()
|
57 |
+
|
58 |
+
def _setup_logging(self):
|
59 |
+
"""راهاندازی سیستم لاگینگ"""
|
60 |
+
logging.basicConfig(
|
61 |
+
filename=f'logs/model_{datetime.now().strftime("%Y%m%d")}.log',
|
62 |
+
level=logging.INFO,
|
63 |
+
format='%(asctime)s - %(levelname)s - %(message)s'
|
64 |
+
)
|
65 |
+
self.logger = logging.getLogger(__name__)
|
66 |
+
|
67 |
+
def _setup_lora(self):
|
68 |
+
"""تنظیم LoRA برای CPU"""
|
69 |
+
self.lora_config = LoraConfig(
|
70 |
+
r=8, # کاهش برای CPU
|
71 |
+
lora_alpha=16,
|
72 |
+
target_modules=["q_proj", "v_proj"],
|
73 |
+
lora_dropout=0.05,
|
74 |
+
bias="none",
|
75 |
+
task_type="CAUSAL_LM"
|
76 |
+
)
|
77 |
+
self.model = get_peft_model(self.model, self.lora_config)
|
78 |
+
|
79 |
+
@lru_cache(maxsize=1000)
|
80 |
+
def cached_predict(self, text: str) -> str:
|
81 |
+
"""پیشبینی با استفاده از کش"""
|
82 |
+
return self.predict(text)
|
83 |
+
|
84 |
+
def create_backup(self):
|
85 |
+
"""ایجاد نسخه پشتیبان"""
|
86 |
+
backup_time = datetime.now().strftime("%Y%m%d_%H%M%S")
|
87 |
+
backup_path = self.dirs['backup'] / f"model_backup_{backup_time}"
|
88 |
+
self.save_model(backup_path)
|
89 |
+
self.logger.info(f"Backup created at {backup_path}")
|
90 |
+
|
91 |
+
def monitor_resources(self) -> Dict:
|
92 |
+
"""مانیتورینگ منابع سیستم"""
|
93 |
+
cpu_percent = psutil.cpu_percent(interval=1)
|
94 |
+
memory = psutil.virtual_memory()
|
95 |
+
return {
|
96 |
+
'cpu_usage': cpu_percent,
|
97 |
+
'memory_used': memory.percent,
|
98 |
+
'memory_available': memory.available / (1024 * 1024 * 1024) # GB
|
99 |
+
}
|
100 |
+
|
101 |
+
def start_monitoring(self):
|
102 |
+
"""شروع مانیتورینگ مداوم"""
|
103 |
+
self.monitoring_data = []
|
104 |
+
self.monitoring_start_time = time.time()
|
105 |
+
|
106 |
+
def log_performance(self, input_text: str, response: str, response_time: float):
|
107 |
+
"""ثبت عملکرد مدل"""
|
108 |
+
performance_data = {
|
109 |
+
'timestamp': datetime.now().isoformat(),
|
110 |
+
'input_length': len(input_text),
|
111 |
+
'response_length': len(response),
|
112 |
+
'response_time': response_time,
|
113 |
+
'resources': self.monitor_resources()
|
114 |
+
}
|
115 |
+
|
116 |
+
with open(self.dirs['reports'] / 'performance.jsonl', 'a') as f:
|
117 |
+
f.write(json.dumps(performance_data) + '\n')
|
118 |
+
|
119 |
+
def export_to_onnx(self):
|
120 |
+
"""تبدیل مدل به ONNX برای اجرای سریعتر"""
|
121 |
+
dummy_input = self.tokenizer("test input", return_tensors="pt")
|
122 |
+
onnx_path = self.dirs['model'] / "model.onnx"
|
123 |
+
|
124 |
+
torch.onnx.export(
|
125 |
+
self.model,
|
126 |
+
(dummy_input['input_ids'],),
|
127 |
+
onnx_path,
|
128 |
+
opset_version=12,
|
129 |
+
input_names=['input_ids'],
|
130 |
+
output_names=['output']
|
131 |
+
)
|
132 |
+
self.logger.info(f"Model exported to ONNX at {onnx_path}")
|
133 |
+
|
134 |
+
def generate_report(self) -> Dict:
|
135 |
+
"""تولید گزارش عملکرد"""
|
136 |
+
with open(self.dirs['reports'] / 'performance.jsonl', 'r') as f:
|
137 |
+
data = [json.loads(line) for line in f]
|
138 |
+
|
139 |
+
return {
|
140 |
+
'total_requests': len(data),
|
141 |
+
'avg_response_time': sum(d['response_time'] for d in
|
requirements.txt
CHANGED
@@ -1,5 +1,12 @@
|
|
1 |
-
|
2 |
-
transformers
|
3 |
-
|
4 |
-
|
5 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
torch==2.1.0
|
2 |
+
transformers==4.35.0
|
3 |
+
peft==0.5.0
|
4 |
+
bitsandbytes==0.41.0
|
5 |
+
accelerate==0.24.0
|
6 |
+
datasets==2.14.0
|
7 |
+
pandas==2.1.0
|
8 |
+
scikit-learn==1.3.0
|
9 |
+
sentencepiece==0.1.99
|
10 |
+
pytest==7.4.2
|
11 |
+
black==23.9.1
|
12 |
+
flake8==6.1.0
|