Really-amin commited on
Commit
21d8cd3
1 Parent(s): 2edf006

Upload 4 files

Browse files
Files changed (4) hide show
  1. admin_dashboard.py +186 -187
  2. admin_dashboard_filemanager.py +190 -107
  3. app.py +585 -305
  4. requests.txt +19 -0
admin_dashboard.py CHANGED
@@ -1,190 +1,189 @@
1
- import streamlit as st
2
- import subprocess
3
- import time
4
- import pandas as pd
5
- import plotly.express as px
6
- import random
7
- from datetime import datetime
8
- from sklearn.linear_model import LogisticRegression
9
- from sklearn.datasets import make_classification
10
- from sklearn.model_selection import train_test_split
11
- from sklearn.metrics import accuracy_score
12
-
13
- # کلاس برای یادگیری ماشین
14
- class MLEngine:
15
- def __init__(self):
16
- # ایجاد داده‌های آموزشی شبیه‌سازی شده
17
- self.X, self.y = make_classification(n_samples=1000, n_features=10, random_state=42)
18
- self.model = LogisticRegression()
19
- self.training_history = []
20
- self.last_update_time = None
21
- self.current_accuracy = 0
22
- self.total_interactions = 1234
23
- self.user_satisfaction = 95
24
-
25
- def train_model(self):
26
- """آموزش مدل و ذخیره دقت آن"""
27
- # تقسیم داده‌ها به مجموعه‌های آموزشی و آزمایشی
28
- X_train, X_test, y_train, y_test = train_test_split(self.X, self.y, test_size=0.2, random_state=42)
29
- self.model.fit(X_train, y_train)
30
-
31
- # پیش‌بینی و محاسبه دقت
32
- predictions = self.model.predict(X_test)
33
- accuracy = accuracy_score(y_test, predictions)
34
-
35
- # ذخیره دقت در تاریخچه آموزشی
36
- self.current_accuracy = accuracy * 100 # دقت به درصد
37
- self.training_history.append({"timestamp": datetime.now(), "accuracy": self.current_accuracy})
38
- self.last_update_time = datetime.now()
39
-
40
- def update_knowledge_base(self):
41
- """شبیه‌سازی به‌روزرسانی پایگاه دانش"""
42
- time.sleep(2) # شبیه‌سازی زمان به‌روزرسانی پایگاه دانش
43
- self.train_model() # آموزش مجدد مدل به عنوان بخشی از به‌روزرسانی
44
 
45
- def get_learning_stats(self):
46
- """برگرداندن آمار یادگیری شامل دقت و تاریخچه آموزشی"""
47
- return {
48
- "history": self.training_history,
49
- "currentAccuracy": self.current_accuracy,
50
- "totalInteractions": self.total_interactions,
51
- "userSatisfaction": self.user_satisfaction,
52
- "lastUpdate": self.last_update_time.strftime("%Y-%m-%d %H:%M:%S") if self.last_update_time else "No Update Yet"
53
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
54
 
55
- # ایجاد یک نمونه از کلاس MLEngine
56
- ml_engine = MLEngine()
57
- ml_engine.train_model() # آموزش اولیه مدل
58
-
59
- # تابع برای اجرای فایل `admin_dashboard_filemanager.py`
60
- def open_file_manager():
61
- """اجرای فایل مدیریت فایل‌ها و به‌روزرسانی پایگاه دانش"""
62
- try:
63
- # اجرای فایل `admin_dashboard_filemanager.py`
64
- subprocess.Popen(["python", "admin_dashboard_filemanager.py"])
65
- st.success("Knowledge Base update has been initiated successfully!")
66
- except Exception as e:
67
- st.error(f"Error while opening file manager: {e}")
68
-
69
- # CSS سفارشی برای طراحی گلس مورفیسم و نئومورفیسم
70
- CUSTOM_CSS = """
71
- <style>
72
- body {
73
- background: linear-gradient(135deg, #ece9e6, #ffffff);
74
- font-family: 'Arial', sans-serif;
75
- }
76
- .dashboard-container {
77
- max-width: 800px;
78
- margin: auto;
79
- padding: 20px;
80
- }
81
- .glass-card, .glass-button, .glass-chart {
82
- backdrop-filter: blur(10px); /* شفافیت پس‌زمینه */
83
- background: rgba(255, 255, 255, 0.15); /* پس‌زمینه شفاف */
84
- border-radius: 20px; /* گوشه‌های گرد */
85
- box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.15), -4px -4px 10px rgba(255, 255, 255, 0.7); /* سایه‌های نئومورفیسم */
86
- padding: 20px;
87
- margin: 15px 0;
88
- transition: all 0.3s ease;
89
- }
90
- .glass-card:hover, .glass-button:hover {
91
- box-shadow: 6px 6px 12px rgba(0, 0, 0, 0.2), -6px -6px 12px rgba(255, 255, 255, 0.5); /* افکت سایه هنگام هاور */
92
- transform: translateY(-5px); /* جابجایی جزئی */
93
- }
94
- .header {
95
- text-align: center;
96
- color: #333;
97
- font-size: 24px;
98
- font-weight: bold;
99
- padding: 10px 0;
100
- }
101
- .glass-button {
102
- display: inline-block;
103
- color: #ffffff;
104
- background: linear-gradient(135deg, #4a90e2, #50e3c2);
105
- border: none;
106
- font-size: 18px;
107
- cursor: pointer;
108
- text-align: center;
109
- width: 100%;
110
- padding: 10px 20px;
111
- margin-top: 10px;
112
- border-radius: 20px;
113
- box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.15), -4px -4px 10px rgba(255, 255, 255, 0.7); /* سایه‌های نئومورفیسم */
114
- transition: all 0.3s ease;
115
- }
116
- .glass-button:hover {
117
- background: linear-gradient(135deg, #50e3c2, #4a90e2); /* تغییر رنگ هنگام هاور */
118
- }
119
- .stat-card {
120
- text-align: center;
121
- color: #333;
122
- padding: 15px;
123
- }
124
- .stat-title {
125
- font-size: 16px;
126
- color: #666;
127
- }
128
- .stat-value {
129
- font-size: 26px;
130
- font-weight: bold;
131
- color: #4a90e2;
132
- }
133
- .glass-upload {
134
- background: rgba(255, 255, 255, 0.25); /* پس‌زمینه شفاف */
135
- border: 1px solid rgba(255, 255, 255, 0.3);
136
- border-radius: 20px;
137
- padding: 20px;
138
- box-shadow: inset 4px 4px 6px rgba(0, 0, 0, 0.1), inset -4px -4px 6px rgba(255, 255, 255, 0.5); /* سایه داخلی */
139
- }
140
- .icon {
141
- font-size: 24px;
142
- color: #4a90e2;
143
- margin-right: 8px;
144
- }
145
- </style>
146
- """
147
-
148
- # اعمال CSS سفارشی
149
- st.markdown(CUSTOM_CSS, unsafe_allow_html=True)
150
-
151
- # ساخت داشبورد
152
- st.markdown("<div class='dashboard-container'>", unsafe_allow_html=True)
153
- st.markdown("<div class='header'>Admin Dashboard</div>", unsafe_allow_html=True)
154
-
155
- # دکمه به‌روزرسانی پایگاه دانش با طراحی گلس مورفیسم
156
- if st.button("Update Knowledge Base"):
157
- ml_engine.update_knowledge_base()
158
- open_file_manager()
159
-
160
- # نمایش آمارها با طراحی نئومورفیسم
161
- st.subheader("Statistics")
162
- col1, col2, col3 = st.columns(3)
163
-
164
- # نمایش آمارهای فعلی مدل
165
- stats = ml_engine.get_learning_stats()
166
- col1.markdown(f"<div class='glass-card stat-card'><div class='stat-title'>📊 Accuracy</div><div class='stat-value'>{stats['currentAccuracy']:.2f}%</div></div>", unsafe_allow_html=True)
167
- col2.markdown(f"<div class='glass-card stat-card'><div class='stat-title'>👤 Total Interactions</div><div class='stat-value'>{stats['totalInteractions']}</div></div>", unsafe_allow_html=True)
168
- col3.markdown(f"<div class='glass-card stat-card'><div class='stat-title'>👍 User Satisfaction</div><div class='stat-value'>{stats['userSatisfaction']}%</div></div>", unsafe_allow_html=True)
169
-
170
- # نمودار روند یادگیری با طراحی شفاف (گلس مورفیسم)
171
- st.subheader("Learning Rate Trend")
172
- learning_df = pd.DataFrame([
173
- {"Date": stat["timestamp"], "Accuracy": stat["accuracy"]}
174
- for stat in stats["history"]
175
- ])
176
- fig = px.line(learning_df, x="Date", y="Accuracy", title="Learning Rate Over Time",
177
- template="plotly_white", markers=True)
178
- fig.update_traces(line=dict(color="#4a90e2", width=2))
179
- st.plotly_chart(fig, use_container_width=True)
180
-
181
- # آپلود فایل با طراحی نئومورفیسم
182
- st.subheader("Manage Files")
183
- st.markdown("<div class='glass-upload'>", unsafe_allow_html=True)
184
- uploaded_file = st.file_uploader("Upload Document", type=["txt", "pdf", "docx"])
185
- if uploaded_file:
186
- st.success("File uploaded successfully!")
187
- st.markdown("</div>", unsafe_allow_html=True)
188
-
189
- # پایان داشبورد
190
- st.markdown("</div>", unsafe_allow_html=True)
 
1
+ import React, { useState, useEffect } from 'react';
2
+ import { Card, CardHeader, CardTitle, CardContent } from '@/components/ui/card';
3
+ import { Button } from '@/components/ui/button';
4
+ import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer } from 'recharts';
5
+ import { Upload, RefreshCw, Users, BarChart2, ThumbsUp, Database } from 'lucide-react';
6
+ import { Alert, AlertDescription } from '@/components/ui/alert';
7
+
8
+ const AdminDashboard = () => {
9
+ const [stats, setStats] = useState({
10
+ accuracy: 95.5,
11
+ interactions: 1234,
12
+ satisfaction: 98,
13
+ lastUpdate: new Date().toLocaleString(),
14
+ averageResponseTime: 0.5,
15
+ totalQuestions: 3500
16
+ });
17
+
18
+ const [learningData, setLearningData] = useState([
19
+ { date: '2024-01', accuracy: 90 },
20
+ { date: '2024-02', accuracy: 92 },
21
+ { date: '2024-03', accuracy: 94 },
22
+ { date: '2024-04', accuracy: 95.5 }
23
+ ]);
24
+
25
+ const [isUpdating, setIsUpdating] = useState(false);
26
+ const [updateStatus, setUpdateStatus] = useState(null);
27
+
28
+ const updateKnowledgeBase = async () => {
29
+ setIsUpdating(true);
30
+ setUpdateStatus('درحال به‌روزرسانی پایگاه دانش...');
 
 
 
 
 
 
 
 
 
 
 
 
 
31
 
32
+ try {
33
+ // ارسال درخواست به‌روزرسانی به سرور
34
+ const response = await fetch('/api/update-knowledge-base', {
35
+ method: 'POST',
36
+ headers: {
37
+ 'Content-Type': 'application/json',
 
 
38
  }
39
+ });
40
+
41
+ if (response.ok) {
42
+ setUpdateStatus('به‌روزرسانی با موفقیت انجام شد');
43
+ setStats(prev => ({
44
+ ...prev,
45
+ lastUpdate: new Date().toLocaleString()
46
+ }));
47
+ } else {
48
+ throw new Error('خطا در به‌روزرسانی');
49
+ }
50
+ } catch (error) {
51
+ setUpdateStatus('خطا در به‌روزرسانی پایگاه دانش');
52
+ } finally {
53
+ setIsUpdating(false);
54
+ // پاک کردن پیام وضعیت بعد از 3 ثانیه
55
+ setTimeout(() => setUpdateStatus(null), 3000);
56
+ }
57
+ };
58
+
59
+ const handleFileUpload = async (event) => {
60
+ const file = event.target.files[0];
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
+ return (
83
+ <div className="min-h-screen bg-gradient-to-br from-gray-50 to-gray-100 p-8 rtl">
84
+ <div className="max-w-6xl mx-auto space-y-8">
85
+ {/* Header */}
86
+ <div className="text-center">
87
+ <h1 className="text-4xl font-bold text-gray-800 mb-4">پنل مدیریت</h1>
88
+ <p className="text-gray-600">آخرین به‌روزرسانی: {stats.lastUpdate}</p>
89
+ </div>
90
+
91
+ {/* Status Alert */}
92
+ {updateStatus && (
93
+ <Alert className="bg-white/30 backdrop-blur-lg">
94
+ <AlertDescription>{updateStatus}</AlertDescription>
95
+ </Alert>
96
+ )}
97
+
98
+ {/* Stats Cards */}
99
+ <div className="grid md:grid-cols-3 gap-6">
100
+ {/* Response Time Card */}
101
+ <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">
102
+ <div className="flex items-center justify-between">
103
+ <BarChart2 className="text-blue-500" size={24} />
104
+ <h3 className="text-lg font-semibold text-gray-700">زمان پاسخ‌دهی</h3>
105
+ </div>
106
+ <p className="text-3xl font-bold text-blue-600 mt-4">{stats.averageResponseTime}s</p>
107
+ </div>
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
+ <p className="text-3xl font-bold text-green-600 mt-4">{stats.totalQuestions}</p>
116
+ </div>
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
+ {/* Chart Section */}
129
+ <Card 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)]">
130
+ <CardHeader>
131
+ <CardTitle>روند یادگیری</CardTitle>
132
+ </CardHeader>
133
+ <CardContent>
134
+ <div className="h-64">
135
+ <ResponsiveContainer width="100%" height="100%">
136
+ <LineChart data={learningData}>
137
+ <CartesianGrid strokeDasharray="3 3" />
138
+ <XAxis dataKey="date" />
139
+ <YAxis domain={[80, 100]} />
140
+ <Tooltip />
141
+ <Line
142
+ type="monotone"
143
+ dataKey="accuracy"
144
+ stroke="#4F46E5"
145
+ strokeWidth={2}
146
+ dot={{ fill: '#4F46E5' }}
147
+ />
148
+ </LineChart>
149
+ </ResponsiveContainer>
150
+ </div>
151
+ </CardContent>
152
+ </Card>
153
+
154
+ {/* Actions Section */}
155
+ <div className="grid md:grid-cols-2 gap-6">
156
+ {/* Update Knowledge Base Button */}
157
+ <Button
158
+ onClick={updateKnowledgeBase}
159
+ disabled={isUpdating}
160
+ className="bg-gradient-to-r from-blue-500 to-indigo-600 text-white rounded-xl p-4 flex items-center justify-center gap-2 shadow-[5px_5px_20px_rgba(0,0,0,0.1)] transition-all duration-300 hover:shadow-[8px_8px_25px_rgba(0,0,0,0.12)] hover:transform hover:-translate-y-1"
161
+ >
162
+ <Database className={`w-5 h-5 ${isUpdating ? 'animate-spin' : ''}`} />
163
+ {isUpdating ? 'در حال به‌روزرسانی...' : 'به‌روزرسانی پایگاه دانش'}
164
+ </Button>
165
+
166
+ {/* File Upload Section */}
167
+ <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)]">
168
+ <div className="flex items-center justify-center w-full">
169
+ <label className="flex flex-col items-center justify-center w-full h-32 border-2 border-dashed rounded-xl border-gray-300 cursor-pointer bg-white/50 hover:bg-white/70 transition-all duration-300">
170
+ <div className="flex flex-col items-center justify-center pt-5 pb-6">
171
+ <Upload className="w-8 h-8 text-gray-500 mb-2" />
172
+ <p className="text-sm text-gray-500">برای آپلود فایل کلیک کنید</p>
173
+ </div>
174
+ <input
175
+ type="file"
176
+ className="hidden"
177
+ onChange={handleFileUpload}
178
+ accept=".txt,.pdf,.docx"
179
+ />
180
+ </label>
181
+ </div>
182
+ </div>
183
+ </div>
184
+ </div>
185
+ </div>
186
+ );
187
+ };
188
 
189
+ export default AdminDashboard;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
admin_dashboard_filemanager.py CHANGED
@@ -1,68 +1,78 @@
1
  import streamlit as st
2
  from pathlib import Path
3
  from datetime import datetime
4
- import shutil
5
  import zipfile
6
  from PIL import Image
7
  import time
8
 
9
- # تنظیمات صفحه
10
- st.set_page_config(page_title="مدیریت فایل‌ها", layout="centered", page_icon="📁")
 
 
 
 
 
11
 
12
- # CSS برای طراحی گلس مورفیسم و نئومورفیسم
13
- CUSTOM_CSS = """
14
  <style>
15
- body {
16
- font-family: 'Vazir', sans-serif;
17
- background: linear-gradient(135deg, #ece9e6, #ffffff);
18
- }
19
- .dashboard-container {
20
- max-width: 800px;
21
- margin: auto;
22
- padding: 20px;
23
- }
24
- .glass-card, .glass-button, .drag-drop {
25
- backdrop-filter: blur(10px);
26
- background: rgba(255, 255, 255, 0.15);
27
- border-radius: 20px;
28
- box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.15), -4px -4px 10px rgba(255, 255, 255, 0.7);
29
- padding: 20px;
30
- margin: 15px 0;
31
- transition: all 0.3s ease;
32
- }
33
- .glass-button {
34
- color: #ffffff;
35
- background: linear-gradient(135deg, #4a90e2, #50e3c2);
36
- border: none;
37
- font-size: 18px;
38
- cursor: pointer;
39
- width: 100%;
40
- padding: 10px 20px;
41
- margin-top: 10px;
42
- border-radius: 20px;
43
- transition: all 0.3s ease;
44
- }
45
- .glass-button:hover {
46
- background: linear-gradient(135deg, #50e3c2, #4a90e2);
47
- }
48
- .drag-drop {
49
- border: 2px dashed #4a90e2;
50
- padding: 40px;
51
- text-align: center;
52
- cursor: pointer;
53
- }
 
 
 
54
  </style>
55
- """
56
- st.markdown(CUSTOM_CSS, unsafe_allow_html=True)
57
 
 
58
  class FileManager:
59
  def __init__(self):
60
- self.root_path = Path('uploads')
61
  self.root_path.mkdir(exist_ok=True)
62
 
63
  def upload_file(self, file):
64
- """آپلود فایل با نوار پیشرفت"""
 
 
65
  dest_path = self.root_path / file.name
 
66
  with open(dest_path, "wb") as f:
67
  total_size = file.size
68
  chunk_size = 1024
@@ -71,75 +81,148 @@ class FileManager:
71
  data = file.read(chunk_size)
72
  f.write(data)
73
  bytes_read += len(data)
74
- st.progress(bytes_read / total_size)
75
- return f"فایل '{file.name}' با موفقیت آپلود شد."
 
 
 
 
 
76
 
77
  def list_files(self, file_type=None):
78
- """لیست فایل‌ها با فیلتر نوع فایل"""
79
- files = [f.name for f in self.root_path.iterdir() if f.is_file() and (not file_type or f.suffix == file_type)]
80
- return files
 
 
 
81
 
82
  def delete_file(self, filename):
83
  """حذف فایل"""
84
- path = self.root_path / filename
85
- if path.exists():
86
- path.unlink()
87
- return f"فایل '{filename}' حذف شد."
88
- return f"فایل '{filename}' یافت نشد."
 
 
 
89
 
90
  def preview_file(self, filename):
91
  """پیش‌نمایش فایل"""
92
  path = self.root_path / filename
93
- if path.suffix in ['.jpg', '.jpeg', '.png']:
94
- return Image.open(path)
95
- elif path.suffix == '.txt':
96
- with open(path, "r", encoding="utf-8") as f:
97
- return f.read(300)
98
- return "پیش‌نمایش در دسترس نیست."
 
 
 
99
 
100
  def compress_files(self, files):
101
- """فشرده‌سازی فایل‌ها"""
102
- zip_name = f"compressed_{datetime.now().strftime('%Y%m%d%H%M%S')}.zip"
103
- zip_path = self.root_path / zip_name
104
- with zipfile.ZipFile(zip_path, 'w') as zipf:
105
- for file in files:
106
- file_path = self.root_path / file
107
- zipf.write(file_path, file)
108
- st.progress((files.index(file) + 1) / len(files))
109
- return f"فایل‌ها با نام '{zip_name}' فشرده شدند."
110
-
111
- file_manager = FileManager()
112
-
113
- # آپلود فایل
114
- st.title("📁 مدیریت فایل‌ها")
115
- uploaded_file = st.file_uploader("فایل خود را آپلود کنید", type=["jpg", "jpeg", "png", "txt"], accept_multiple_files=False)
116
-
117
- if uploaded_file:
118
- st.write(file_manager.upload_file(uploaded_file))
119
-
120
- # لیست فایل‌ها و فیلتر نوع فایل
121
- st.subheader("فایل‌های آپلود شده")
122
- file_type = st.selectbox("نمایش فایل‌های:", ["همه", ".jpg", ".txt", ".png"], index=0)
123
- files = file_manager.list_files(None if file_type == "همه" else file_type)
124
-
125
- # نمایش منوی زمینه و عملیات‌ها
126
- for file in files:
127
- col1, col2, col3, col4 = st.columns([3, 1, 1, 1])
 
 
 
 
 
128
  with col1:
129
- if st.button(f"پیش‌نمایش {file}"):
130
- preview = file_manager.preview_file(file)
131
- if isinstance(preview, str):
132
- st.text(preview)
133
- else:
134
- st.image(preview)
 
 
 
 
135
  with col2:
136
- if st.button(f"حذف {file}"):
137
- st.write(file_manager.delete_file(file))
138
- with col3:
139
- st.download_button(label=f"دانلود {file}", data=open(file_manager.root_path / file, 'rb').read(), file_name=file)
140
-
141
- # فشرده‌سازی فایل‌ها
142
- st.subheader("فشرده‌سازی فایل‌��ا")
143
- selected_files = st.multiselect("فایل‌های موردنظر را انتخاب کنید", files)
144
- if st.button("فشرده‌سازی فایل‌ها"):
145
- st.write(file_manager.compress_files(selected_files))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
 
8
+ # Page configuration
9
+ st.set_page_config(
10
+ page_title="مدیریت فایل",
11
+ page_icon="📂",
12
+ layout="wide",
13
+ initial_sidebar_state="expanded"
14
+ )
15
 
16
+ # Custom CSS with Farsi font and modern theme
17
+ st.markdown("""
18
  <style>
19
+ @import url('https://fonts.googleapis.com/css2?family=Vazirmatn:wght@400;700&display=swap');
20
+ * {
21
+ font-family: 'Vazirmatn', sans-serif;
22
+ }
23
+ .main {
24
+ background-color: #f0f2f6;
25
+ }
26
+ .stButton>button {
27
+ width: 100%;
28
+ border-radius: 10px;
29
+ background-color: #4c78af;
30
+ color: white;
31
+ border: none;
32
+ padding: 0.5rem 1rem;
33
+ margin: 0.25rem 0;
34
+ transition: all 0.3s ease;
35
+ }
36
+ .stButton>button:hover {
37
+ background-color: #3a5d8f;
38
+ box-shadow: 0 4px 8px rgba(0,0,0,0.1);
39
+ }
40
+ .uploadedFile {
41
+ border: 2px dashed #4c78af;
42
+ border-radius: 10px;
43
+ padding: 1rem;
44
+ margin: 1rem 0;
45
+ }
46
+ .css-1d391kg {
47
+ padding: 1rem;
48
+ border-radius: 10px;
49
+ background-color: white;
50
+ box-shadow: 0 2px 4px rgba(0,0,0,0.05);
51
+ }
52
+ h1, h2, h3 {
53
+ color: #1e3d59;
54
+ }
55
+ .stProgress .st-bo {
56
+ background-color: #4c78af;
57
+ }
58
+ .stSelectbox, .stMultiSelect {
59
+ border-radius: 10px;
60
+ }
61
  </style>
62
+ """, unsafe_allow_html=True)
 
63
 
64
+ # FileManager class for file operations
65
  class FileManager:
66
  def __init__(self):
67
+ self.root_path = Path("uploads")
68
  self.root_path.mkdir(exist_ok=True)
69
 
70
  def upload_file(self, file):
71
+ """آپلود فایل با نمایش نوار پیشرفت"""
72
+ progress_text = st.empty()
73
+ progress_bar = st.progress(0)
74
  dest_path = self.root_path / file.name
75
+
76
  with open(dest_path, "wb") as f:
77
  total_size = file.size
78
  chunk_size = 1024
 
81
  data = file.read(chunk_size)
82
  f.write(data)
83
  bytes_read += len(data)
84
+ progress = bytes_read / total_size
85
+ progress_bar.progress(progress)
86
+ progress_text.text(f"در حال آپلود... {int(progress * 100)}%")
87
+
88
+ progress_text.empty()
89
+ progress_bar.empty()
90
+ return f"فایل '{file.name}' با موفقیت آپلود شد!"
91
 
92
  def list_files(self, file_type=None):
93
+ """لیست فایل‌ها با امکان فیلتر بر اساس نوع فایل"""
94
+ files = [
95
+ f.name for f in self.root_path.iterdir()
96
+ if f.is_file() and (not file_type or f.suffix.lower() == file_type.lower())
97
+ ]
98
+ return sorted(files)
99
 
100
  def delete_file(self, filename):
101
  """حذف فایل"""
102
+ try:
103
+ path = self.root_path / filename
104
+ if path.exists():
105
+ path.unlink()
106
+ return "success", f"فایل '{filename}' با موفقیت حذف شد"
107
+ return "error", f"فایل '{filename}' یافت نشد"
108
+ except Exception as e:
109
+ return "error", f"خطا در حذف فایل: {str(e)}"
110
 
111
  def preview_file(self, filename):
112
  """پیش‌نمایش فایل"""
113
  path = self.root_path / filename
114
+ try:
115
+ if path.suffix.lower() in ['.jpg', '.jpeg', '.png', '.gif']:
116
+ return Image.open(path)
117
+ elif path.suffix.lower() == '.txt':
118
+ with open(path, "r", encoding="utf-8") as f:
119
+ return f.read(500) + "\n...(ادامه دارد)" if path.stat().st_size > 500 else f.read()
120
+ return "پیش‌نمایش برای این نوع فایل در دسترس نیست"
121
+ except Exception as e:
122
+ return f"خطا در نمایش فایل: {str(e)}"
123
 
124
  def compress_files(self, files):
125
+ """فشرده‌سازی فایل‌های انتخاب شده به ZIP"""
126
+ if not files:
127
+ return "error", "لطفاً فایل‌هایی را برای فشرده‌سازی انتخاب کنید"
128
+
129
+ try:
130
+ zip_name = f"compressed_{datetime.now().strftime('%Y%m%d_%H%M%S')}.zip"
131
+ zip_path = self.root_path / zip_name
132
+ progress_text = st.empty()
133
+ progress_bar = st.progress(0)
134
+
135
+ with zipfile.ZipFile(zip_path, 'w') as zipf:
136
+ for i, file in enumerate(files, 1):
137
+ file_path = self.root_path / file
138
+ zipf.write(file_path, file)
139
+ progress = i / len(files)
140
+ progress_bar.progress(progress)
141
+ progress_text.text(f"در حال فشرده‌سازی... {int(progress * 100)}%")
142
+
143
+ progress_text.empty()
144
+ progress_bar.empty()
145
+ return "success", f"فایل‌ها با موفقیت فشرده‌سازی شد: '{zip_name}'"
146
+ except Exception as e:
147
+ return "error", f"خطا در فشرده‌سازی فایل‌ها: {str(e)}"
148
+
149
+ def main():
150
+ st.title("📂 مدیریت فایل پیشرفته")
151
+
152
+ file_manager = FileManager()
153
+
154
+ # Layout with two columns
155
+ col1, col2 = st.columns([2, 1])
156
+
157
  with col1:
158
+ st.subheader("📤 آپلود فایل")
159
+ uploaded_file = st.file_uploader(
160
+ "فایل خود را اینجا قرار دهید یا برای انتخاب کلیک کنید",
161
+ type=["jpg", "jpeg", "png", "gif", "txt"],
162
+ accept_multiple_files=False
163
+ )
164
+ if uploaded_file:
165
+ result = file_manager.upload_file(uploaded_file)
166
+ st.success(result)
167
+
168
  with col2:
169
+ st.subheader("🔍 فیلتر فایل‌ها")
170
+ file_type = st.selectbox(
171
+ "نمایش نوع فایل:",
172
+ ["همه", ".jpg", ".jpeg", ".png", ".gif", ".txt"],
173
+ index=0
174
+ )
175
+
176
+ # List of uploaded files
177
+ st.subheader("📁 فایل‌های آپلود شده")
178
+ files = file_manager.list_files(None if file_type == "همه" else file_type)
179
+
180
+ if not files:
181
+ st.info("هنوز فایلی آپلود نشده است")
182
+ else:
183
+ for file in files:
184
+ col1, col2, col3, col4 = st.columns([3, 1, 1, 1])
185
+
186
+ with col1:
187
+ if st.button(f"👁️ پیش‌نمایش {file}"):
188
+ preview = file_manager.preview_file(file)
189
+ if isinstance(preview, str):
190
+ st.text(preview)
191
+ else:
192
+ st.image(preview, use_column_width=True)
193
+
194
+ with col2:
195
+ if st.button(f"🗑️ حذف {file}"):
196
+ status, message = file_manager.delete_file(file)
197
+ if status == "success":
198
+ st.success(message)
199
+ else:
200
+ st.error(message)
201
+
202
+ with col3:
203
+ with open(file_manager.root_path / file, 'rb') as f:
204
+ st.download_button(
205
+ label=f"⬇️ دانلود",
206
+ data=f.read(),
207
+ file_name=file
208
+ )
209
+
210
+ # Compression section
211
+ st.subheader("🗜️ فشرده‌سازی فایل‌ها")
212
+ selected_files = st.multiselect(
213
+ "فایل‌های مورد نظر برای فشرده‌سازی را انتخاب کنید",
214
+ files
215
+ )
216
+
217
+ if st.button("📦 فشرده‌سازی فایل‌های انتخاب شده"):
218
+ if selected_files:
219
+ status, message = file_manager.compress_files(selected_files)
220
+ if status == "success":
221
+ st.success(message)
222
+ else:
223
+ st.error(message)
224
+ else:
225
+ st.warning("لطفاً فایل‌هایی برای فشرده‌سازی انتخاب کنید")
226
+
227
+ if __name__ == "__main__":
228
+ main()
app.py CHANGED
@@ -1,305 +1,585 @@
1
- import streamlit as st
2
- from datetime import datetime
3
- import time
4
- import random
5
-
6
- CUSTOM_CSS = """
7
- <style>
8
- @import url('https://fonts.googleapis.com/css2?family=Vazirmatn:wght@300;400;500;700&display=swap');
9
-
10
- :root {
11
- --primary-bg: #f0f2f5;
12
- --chat-bg: #ffffff;
13
- --primary-color: #2979ff;
14
- --secondary-color: #f50057;
15
- --text-primary: #262626;
16
- --text-secondary: #666666;
17
- }
18
-
19
- body {
20
- font-family: 'Vazirmatn', sans-serif !important;
21
- background-color: var(--primary-bg) !important;
22
- color: var(--text-primary);
23
- }
24
-
25
- .main-header {
26
- background: linear-gradient(135deg, var(--primary-color), var(--secondary-color));
27
- color: white;
28
- padding: 1rem;
29
- border-radius: 15px;
30
- margin-bottom: 2rem;
31
- box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
32
- text-align: center;
33
- }
34
-
35
- .chat-window {
36
- background: var(--chat-bg);
37
- border-radius: 20px;
38
- padding: 1.5rem;
39
- box-shadow: 0 8px 16px rgba(0, 0, 0, 0.1);
40
- max-height: 600px;
41
- overflow-y: auto;
42
- margin-bottom: 2rem;
43
- }
44
-
45
- .message {
46
- display: flex;
47
- margin-bottom: 1.5rem;
48
- animation: fadeIn 0.3s ease-in-out;
49
- }
50
-
51
- .message-content {
52
- max-width: 80%;
53
- padding: 1rem 1.5rem;
54
- border-radius: 15px;
55
- position: relative;
56
- }
57
-
58
- .user-message {
59
- justify-content: flex-end;
60
- }
61
-
62
- .user-message .message-content {
63
- background: var(--primary-color);
64
- color: white;
65
- border-bottom-right-radius: 5px;
66
- margin-left: auto;
67
- }
68
-
69
- .bot-message {
70
- justify-content: flex-start;
71
- }
72
-
73
- .bot-message .message-content {
74
- background: #f1f1f1;
75
- color: var(--text-primary);
76
- border-bottom-left-radius: 5px;
77
- }
78
-
79
- .timestamp {
80
- font-size: 0.75rem;
81
- color: var(--text-secondary);
82
- margin-top: 0.25rem;
83
- text-align: right;
84
- }
85
-
86
- .input-area {
87
- background: white;
88
- padding: 1rem;
89
- border-radius: 15px;
90
- box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
91
- margin-top: 1rem;
92
- }
93
-
94
- .stTextInput input {
95
- border: 2px solid #e0e0e0 !important;
96
- border-radius: 10px !important;
97
- padding: 0.75rem 1rem !important;
98
- font-size: 1rem !important;
99
- transition: all 0.3s ease;
100
- direction: rtl;
101
- }
102
-
103
- .stTextInput input:focus {
104
- border-color: var(--primary-color) !important;
105
- box-shadow: 0 0 0 2px rgba(41, 121, 255, 0.2) !important;
106
- }
107
-
108
- .stButton > button {
109
- background: var(--primary-color) !important;
110
- color: white !important;
111
- border-radius: 10px !important;
112
- padding: 0.75rem 2rem !important;
113
- font-family: 'Vazirmatn', sans-serif !important;
114
- font-weight: 500 !important;
115
- transition: all 0.3s ease !important;
116
- border: none !important;
117
- }
118
-
119
- .stButton > button:hover {
120
- transform: translateY(-2px);
121
- box-shadow: 0 4px 8px rgba(41, 121, 255, 0.3) !important;
122
- }
123
-
124
- .typing-indicator {
125
- padding: 1rem;
126
- background: #f1f1f1;
127
- border-radius: 10px;
128
- margin-bottom: 1rem;
129
- animation: pulse 1.5s infinite;
130
- }
131
-
132
- @keyframes fadeIn {
133
- from { opacity: 0; transform: translateY(10px); }
134
- to { opacity: 1; transform: translateY(0); }
135
- }
136
-
137
- @keyframes pulse {
138
- 0% { opacity: 0.5; }
139
- 50% { opacity: 1; }
140
- 100% { opacity: 0.5; }
141
- }
142
-
143
- .status-bar {
144
- background: rgba(255, 255, 255, 0.9);
145
- padding: 0.5rem 1rem;
146
- border-radius: 10px;
147
- margin-bottom: 1rem;
148
- display: flex;
149
- align-items: center;
150
- justify-content: space-between;
151
- font-size: 0.9rem;
152
- color: var(--text-secondary);
153
- }
154
-
155
- .prompt-suggestions {
156
- display: flex;
157
- gap: 0.5rem;
158
- flex-wrap: wrap;
159
- margin: 1rem 0;
160
- }
161
-
162
- .prompt-suggestion {
163
- background: #f1f1f1;
164
- padding: 0.5rem 1rem;
165
- border-radius: 20px;
166
- font-size: 0.9rem;
167
- cursor: pointer;
168
- transition: all 0.3s ease;
169
- }
170
-
171
- .prompt-suggestion:hover {
172
- background: var(--primary-color);
173
- color: white;
174
- }
175
- </style>
176
- """
177
-
178
- class EnhancedChatbot:
179
- def __init__(self):
180
- if 'messages' not in st.session_state:
181
- st.session_state.messages = []
182
- if 'last_activity' not in st.session_state:
183
- st.session_state.last_activity = datetime.now()
184
-
185
- def format_timestamp(self):
186
- return datetime.now().strftime("%H:%M")
187
-
188
- def get_bot_status(self):
189
- return "🟢 آنلاین" if (datetime.now() - st.session_state.last_activity).seconds < 300 else "🔴 آفلاین"
190
-
191
- def chat_response(self, message):
192
- if not message.strip():
193
- return
194
-
195
- # اضافه کردن پیام کاربر
196
- timestamp = self.format_timestamp()
197
- st.session_state.messages.append({
198
- "role": "user",
199
- "content": message,
200
- "timestamp": timestamp
201
- })
202
-
203
- # شبیه‌سازی تایپ کردن ربات
204
- with st.empty():
205
- for _ in range(3):
206
- time.sleep(0.5)
207
- st.write("در حال تایپ...")
208
-
209
- # پاسخ ربات
210
- responses = [
211
- "بله، متوجه شدم. چطور می‌تونم کمکتون کنم؟",
212
- "این موضوع جالبیه! می‌تونید بیشتر توضیح بدید؟",
213
- "من اینجا هستم تا به شما کمک کنم. سوال دیگه‌ای دارید؟",
214
- "اجازه بدید بیشتر در این مورد صحبت کنیم...",
215
- ]
216
-
217
- bot_response = random.choice(responses)
218
- st.session_state.messages.append({
219
- "role": "assistant",
220
- "content": bot_response,
221
- "timestamp": self.format_timestamp()
222
- })
223
-
224
- st.session_state.last_activity = datetime.now()
225
-
226
- def main():
227
- st.set_page_config(
228
- page_title="چت‌بات هوشمند | پشتیبانی آنلاین",
229
- page_icon="💬",
230
- layout="wide"
231
- )
232
-
233
- st.markdown(CUSTOM_CSS, unsafe_allow_html=True)
234
-
235
- # هدر اصلی
236
- st.markdown("""
237
- <div class="main-header">
238
- <h1>🤖 چت‌بات هوشمند</h1>
239
- <p>پاسخگوی 24 ساعته شما هستیم</p>
240
- </div>
241
- """, unsafe_allow_html=True)
242
-
243
- # ستون‌بندی صفحه
244
- col1, col2 = st.columns([3, 1])
245
-
246
- with col1:
247
- # نوار وضعیت
248
- st.markdown(f"""
249
- <div class="status-bar">
250
- <span>{chatbot.get_bot_status()}</span>
251
- <span>آخرین فعالیت: {chatbot.format_timestamp()}</span>
252
- </div>
253
- """, unsafe_allow_html=True)
254
-
255
- # پنجره چت
256
- st.markdown('<div class="chat-window">', unsafe_allow_html=True)
257
-
258
- for msg in st.session_state.messages:
259
- message_class = "user-message" if msg["role"] == "user" else "bot-message"
260
- st.markdown(f"""
261
- <div class="message {message_class}">
262
- <div class="message-content">
263
- {msg["content"]}
264
- <div class="timestamp">{msg["timestamp"]}</div>
265
- </div>
266
- </div>
267
- """, unsafe_allow_html=True)
268
-
269
- st.markdown('</div>', unsafe_allow_html=True)
270
-
271
- # بخش ورودی پیام
272
- st.markdown('<div class="input-area">', unsafe_allow_html=True)
273
-
274
- # پیشنهادات سریع
275
- suggestions = ["سلام", "درباره خدمات", "تماس با ما", "قیمت‌ها"]
276
- st.markdown('<div class="prompt-suggestions">', unsafe_allow_html=True)
277
- for suggestion in suggestions:
278
- st.markdown(f'<span class="prompt-suggestion">{suggestion}</span>', unsafe_allow_html=True)
279
- st.markdown('</div>', unsafe_allow_html=True)
280
-
281
- # ورودی پیام
282
- user_input = st.text_input("", placeholder="پیام خود را اینجا بنویسید...", key="user_input")
283
- if st.button("ارسال"):
284
- if user_input:
285
- chatbot.chat_response(user_input)
286
- st.experimental_rerun()
287
-
288
- st.markdown('</div>', unsafe_allow_html=True)
289
-
290
- # ستون اطلاعات جانبی
291
- with col2:
292
- st.markdown("""
293
- <div style="background: white; padding: 1rem; border-radius: 15px; box-shadow: 0 4px 6px rgba(0,0,0,0.1);">
294
- <h3>💡 راهنمای استفاده</h3>
295
- <ul>
296
- <li>برای شروع گفتگو کافیست پیام خود را تایپ کنید</li>
297
- <li>از پیشنهادات سریع بالای صفحه استفاده کنید</li>
298
- <li>پشتیبانی 24 ساعته در خدمت شماست</li>
299
- </ul>
300
- </div>
301
- """, unsafe_allow_html=True)
302
-
303
- if __name__ == "__main__":
304
- chatbot = EnhancedChatbot()
305
- main()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import time
3
+ import random
4
+ import json
5
+ from datetime import datetime
6
+ import os
7
+
8
+ # تنظیمات اصلی چت‌بات
9
+ ADMIN_USERNAME = "admin"
10
+ ADMIN_PASSWORD = "password"
11
+
12
+ # CSS بهبود یافته با انیمیشن‌ها و افکت‌های جدید
13
+ CUSTOM_CSS = """
14
+ <style>
15
+ @import url('https://fonts.googleapis.com/css2?family=Vazirmatn:wght@300;400;500;700&display=swap');
16
+ @import url('https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css');
17
+
18
+ :root {
19
+ --primary-color: #3b82f6;
20
+ --secondary-color: #6366f1;
21
+ --accent-color: #10b981;
22
+ --background-color: #f8fafc;
23
+ --chat-bg: #ffffff;
24
+ --user-message-bg: #e0e7ff;
25
+ --bot-message-bg: #f1f5f9;
26
+ --text-primary: #1e293b;
27
+ --text-secondary: #475569;
28
+ --border-color: #e2e8f0;
29
+ --error-color: #ef4444;
30
+ --success-color: #22c55e;
31
+ }
32
+
33
+ /* === انیمیشن‌های جدید === */
34
+ @keyframes slideIn {
35
+ from { transform: translateY(20px); opacity: 0; }
36
+ to { transform: translateY(0); opacity: 1; }
37
+ }
38
+
39
+ @keyframes pulse {
40
+ 0% { transform: scale(1); }
41
+ 50% { transform: scale(1.05); }
42
+ 100% { transform: scale(1); }
43
+ }
44
+
45
+ @keyframes fadeIn {
46
+ from { opacity: 0; }
47
+ to { opacity: 1; }
48
+ }
49
+
50
+ /* === استایل‌های اصلی === */
51
+ body {
52
+ font-family: 'Vazirmatn', sans-serif !important;
53
+ background-color: var(--background-color);
54
+ direction: rtl;
55
+ }
56
+
57
+ .chat-container {
58
+ max-width: 900px;
59
+ margin: 2rem auto;
60
+ background: var(--chat-bg);
61
+ border-radius: 1rem;
62
+ box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
63
+ animation: slideIn 0.5s ease-out;
64
+ }
65
+
66
+ .chat-header {
67
+ background: linear-gradient(to left, var(--primary-color), var(--secondary-color));
68
+ color: white;
69
+ padding: 1.5rem;
70
+ border-radius: 1rem 1rem 0 0;
71
+ text-align: center;
72
+ position: relative;
73
+ overflow: hidden;
74
+ }
75
+
76
+ .chat-header::before {
77
+ content: '';
78
+ position: absolute;
79
+ top: -50%;
80
+ left: -50%;
81
+ width: 200%;
82
+ height: 200%;
83
+ background: linear-gradient(
84
+ 45deg,
85
+ transparent 0%,
86
+ rgba(255, 255, 255, 0.1) 50%,
87
+ transparent 100%
88
+ );
89
+ animation: shine 3s infinite linear;
90
+ }
91
+
92
+ @keyframes shine {
93
+ from { transform: translateX(-100%) rotate(45deg); }
94
+ to { transform: translateX(100%) rotate(45deg); }
95
+ }
96
+
97
+ .chat-header h1 {
98
+ font-size: 1.75rem;
99
+ font-weight: 700;
100
+ margin: 0;
101
+ display: flex;
102
+ align-items: center;
103
+ justify-content: center;
104
+ gap: 0.75rem;
105
+ }
106
+
107
+ .chat-header h1 i {
108
+ animation: pulse 2s infinite;
109
+ }
110
+
111
+ .chat-messages {
112
+ height: 500px;
113
+ overflow-y: auto;
114
+ padding: 1.5rem;
115
+ background: var(--chat-bg);
116
+ scroll-behavior: smooth;
117
+ }
118
+
119
+ .message {
120
+ margin-bottom: 1rem;
121
+ max-width: 80%;
122
+ padding: 1rem;
123
+ border-radius: 0.75rem;
124
+ position: relative;
125
+ animation: fadeIn 0.3s ease-out;
126
+ transition: transform 0.2s;
127
+ }
128
+
129
+ .message:hover {
130
+ transform: translateY(-2px);
131
+ }
132
+
133
+ .message.user {
134
+ background: var(--user-message-bg);
135
+ margin-left: auto;
136
+ color: var(--text-primary);
137
+ box-shadow: 2px 2px 10px rgba(99, 102, 241, 0.1);
138
+ }
139
+
140
+ .message.bot {
141
+ background: var(--bot-message-bg);
142
+ margin-right: auto;
143
+ color: var(--text-primary);
144
+ box-shadow: 2px 2px 10px rgba(241, 245, 249, 0.3);
145
+ }
146
+
147
+ .message::before {
148
+ content: '';
149
+ position: absolute;
150
+ width: 0;
151
+ height: 0;
152
+ border: 8px solid transparent;
153
+ }
154
+
155
+ .message.user::before {
156
+ border-left-color: var(--user-message-bg);
157
+ right: -16px;
158
+ top: 50%;
159
+ transform: translateY(-50%);
160
+ }
161
+
162
+ .message.bot::before {
163
+ border-right-color: var(--bot-message-bg);
164
+ left: -16px;
165
+ top: 50%;
166
+ transform: translateY(-50%);
167
+ }
168
+
169
+ .chat-input {
170
+ padding: 1.5rem;
171
+ border-top: 1px solid var(--border-color);
172
+ display: flex;
173
+ gap: 1rem;
174
+ align-items: center;
175
+ background: rgba(255, 255, 255, 0.9);
176
+ backdrop-filter: blur(10px);
177
+ }
178
+
179
+ .chat-input input {
180
+ flex: 1;
181
+ padding: 0.75rem 1rem;
182
+ border: 2px solid var(--border-color);
183
+ border-radius: 0.5rem;
184
+ font-family: 'Vazirmatn', sans-serif;
185
+ font-size: 0.875rem;
186
+ transition: all 0.3s;
187
+ }
188
+
189
+ .chat-input input:focus {
190
+ outline: none;
191
+ border-color: var(--primary-color);
192
+ box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
193
+ }
194
+
195
+ .chat-input button {
196
+ background: var(--primary-color);
197
+ color: white;
198
+ border: none;
199
+ padding: 0.75rem 1.5rem;
200
+ border-radius: 0.5rem;
201
+ cursor: pointer;
202
+ display: flex;
203
+ align-items: center;
204
+ gap: 0.5rem;
205
+ transition: all 0.2s;
206
+ font-weight: 500;
207
+ }
208
+
209
+ .chat-input button:hover {
210
+ background: var(--secondary-color);
211
+ transform: translateY(-2px);
212
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
213
+ }
214
+
215
+ .chat-input button:active {
216
+ transform: translateY(0);
217
+ }
218
+
219
+ /* === قابلیت‌های جدید === */
220
+ .typing-indicator {
221
+ display: flex;
222
+ gap: 0.5rem;
223
+ padding: 1rem;
224
+ background: var(--bot-message-bg);
225
+ border-radius: 0.75rem;
226
+ width: fit-content;
227
+ margin-bottom: 1rem;
228
+ animation: fadeIn 0.3s;
229
+ }
230
+
231
+ .typing-dot {
232
+ width: 8px;
233
+ height: 8px;
234
+ background: var(--primary-color);
235
+ border-radius: 50%;
236
+ animation: typingDot 1s infinite;
237
+ }
238
+
239
+ .typing-dot:nth-child(2) { animation-delay: 0.2s; }
240
+ .typing-dot:nth-child(3) { animation-delay: 0.4s; }
241
+
242
+ @keyframes typingDot {
243
+ 0%, 100% { transform: translateY(0); }
244
+ 50% { transform: translateY(-5px); }
245
+ }
246
+
247
+ .quick-replies {
248
+ display: flex;
249
+ gap: 0.5rem;
250
+ flex-wrap: wrap;
251
+ margin-top: 1rem;
252
+ }
253
+
254
+ .quick-reply {
255
+ background: var(--accent-color);
256
+ color: white;
257
+ padding: 0.5rem 1rem;
258
+ border-radius: 2rem;
259
+ cursor: pointer;
260
+ transition: all 0.2s;
261
+ font-size: 0.875rem;
262
+ }
263
+
264
+ .quick-reply:hover {
265
+ transform: translateY(-2px);
266
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
267
+ }
268
+
269
+ /* === پنل مدیریت === */
270
+ .admin-panel {
271
+ background: white;
272
+ padding: 1.5rem;
273
+ border-radius: 0.75rem;
274
+ margin-bottom: 1rem;
275
+ box-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1);
276
+ }
277
+
278
+ .admin-panel h2 {
279
+ color: var(--text-primary);
280
+ font-size: 1.25rem;
281
+ margin-bottom: 1rem;
282
+ display: flex;
283
+ align-items: center;
284
+ gap: 0.5rem;
285
+ }
286
+
287
+ .admin-controls {
288
+ display: flex;
289
+ flex-direction: column;
290
+ gap: 1rem;
291
+ }
292
+
293
+ .admin-button {
294
+ display: flex;
295
+ align-items: center;
296
+ gap: 0.5rem;
297
+ padding: 0.75rem 1rem;
298
+ border-radius: 0.5rem;
299
+ cursor: pointer;
300
+ transition: all 0.2s;
301
+ border: none;
302
+ font-family: 'Vazirmatn', sans-serif;
303
+ font-weight: 500;
304
+ }
305
+
306
+ .admin-button.danger {
307
+ background: var(--error-color);
308
+ color: white;
309
+ }
310
+
311
+ .admin-button.success {
312
+ background: var(--success-color);
313
+ color: white;
314
+ }
315
+
316
+ .admin-button:hover {
317
+ transform: translateY(-2px);
318
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
319
+ }
320
+
321
+ .statistics {
322
+ background: white;
323
+ padding: 1rem;
324
+ border-radius: 0.5rem;
325
+ margin-top: 1rem;
326
+ }
327
+
328
+ .stat-item {
329
+ display: flex;
330
+ justify-content: space-between;
331
+ padding: 0.5rem 0;
332
+ border-bottom: 1px solid var(--border-color);
333
+ }
334
+
335
+ .stat-item:last-child {
336
+ border-bottom: none;
337
+ }
338
+ </style>
339
+ """
340
+
341
+ class EnhancedChatbot:
342
+ def __init__(self):
343
+ self.conversation_history = []
344
+ self.admin_logged_in = False
345
+ self.quick_replies = [
346
+ "بخشنامه‌های جدید",
347
+ "راهنمای استفاده",
348
+ "تماس با پشتیبانی",
349
+ "گزارش مشکل"
350
+ ]
351
+ self.stats = {
352
+ 'total_messages': 0,
353
+ 'user_messages': 0,
354
+ 'bot_messages': 0,
355
+ 'start_time': datetime.now()
356
+ }
357
+ self.load_responses()
358
+
359
+ def load_responses(self):
360
+ """بارگذاری پاسخ‌های از پیش تعریف شده"""
361
+ self.responses = {
362
+ 'greeting': [
363
+ "سلام! چطور می‌تونم کمکتون کنم؟",
364
+ "درود! من پاسخگوی هوشمند بخشنامه هستم. چه کمکی از دستم برمیاد؟",
365
+ "خوش آمدید! در خدمت شما هستم."
366
+ ],
367
+ 'help': [
368
+ "برای راهنمایی بیشتر می‌تونید از گزینه‌های سریع پایین استفاده کنید.",
369
+ "من می‌تونم در موارد زیر کمکتون کنم:\n- جستجوی بخشنامه‌ها\n- پاسخ به سوالات متداول\n- راهنمایی در مورد فرآیندها",
370
+ ],
371
+ 'unknown': [
372
+ "متوجه نشدم. می‌شه بیشتر توضیح بدید؟",
373
+ "می‌تونید سوالتون رو به شکل دیگه‌ای بپرسید؟",
374
+ "برای راهنمایی بهتر، لطفاً جزئیات بیشتری ارائه کنید."
375
+ ]
376
+ }
377
+
378
+ def chat_response(self, message):
379
+ """پردازش پیام کاربر و ارائه پاسخ هوشمند"""
380
+ self.stats['total_messages'] += 1
381
+ self.stats['user_messages'] += 1
382
+
383
+ # افزودن پیام کاربر
384
+ self.conversation_history.append({
385
+ 'type': 'user',
386
+ 'message': message,
387
+ 'timestamp': datetime.now().strftime("%H:%M")
388
+ })
389
+
390
+ # شبیه‌سازی تایپ کردن
391
+ time.sleep(1)
392
+
393
+ # انتخاب پاسخ مناسب
394
+ if any(word in message.lower() for word in ['سلام', 'درود', 'خوش آمدید']):
395
+ response = random.choice(self.responses['greeting'])
396
+ elif 'راهنمایی' in message.lower() or 'کمک' in message.lower():
397
+ response = random.choice(self.responses['help'])
398
+ else:
399
+ response = random.choice(self.responses['unknown'])
400
+
401
+ self.stats['bot_messages'] += 1
402
+
403
+ # افزودن پاسخ ربات
404
+ self.conversation_history.append({
405
+ 'type': 'bot',
406
+ 'message': response,
407
+ 'timestamp': datetime.now().strftime("%H:%M")
408
+ })
409
+
410
+ return self.conversation_history
411
+
412
+ def get_stats(self):
413
+ """دریافت آمار چت‌بات"""
414
+ uptime = datetime.now() - self.stats['start_time']
415
+ return {
416
+ 'total_messages': self.stats['total_messages'],
417
+ 'user_messages': self.stats['user_messages'],
418
+ 'bot_messages': self.stats['bot_messages'],
419
+ 'uptime': str(uptime).split('.')[0],
420
+ 'response_rate': f"{(self.stats['bot_messages'] / self.stats['user_messages'] * 100):.1f}%" if self.stats['user_messages'] > 0 else "0%"
421
+ }
422
+
423
+ # تنظیمات اولیه استریملیت
424
+ # ادامه کد قبلی...
425
+
426
+ # تنظیمات اولیه استریملیت
427
+ st.set_page_config(
428
+ page_title="پاسخگوی هوشمند بخشنامه",
429
+ page_icon="🤖",
430
+ layout="wide",
431
+ initial_sidebar_state="expanded"
432
+ )
433
+
434
+ # اعمال CSS
435
+ st.markdown(CUSTOM_CSS, unsafe_allow_html=True)
436
+
437
+ # ایجاد نمونه از چت‌بات
438
+ if 'chatbot' not in st.session_state:
439
+ st.session_state.chatbot = EnhancedChatbot()
440
+
441
+ # نمایش هدر اصلی
442
+ st.markdown("""
443
+ <div class="chat-container">
444
+ <div class="chat-header">
445
+ <h1>
446
+ <i class="fas fa-robot"></i>
447
+ پاسخگوی هوشمند بخشنامه
448
+ <span class="status-badge online">
449
+ <i class="fas fa-circle"></i>
450
+ </span>
451
+ </h1>
452
+ </div>
453
+ <div class="chat-messages" id="chat-messages">
454
+ """, unsafe_allow_html=True)
455
+
456
+ # نمایش پیام‌ها
457
+ for message in st.session_state.chatbot.conversation_history:
458
+ message_class = "user" if message['type'] == 'user' else "bot"
459
+ icon = "user" if message['type'] == 'user' else "robot"
460
+
461
+ st.markdown(f"""
462
+ <div class="message {message_class}">
463
+ <div class="message-header">
464
+ <i class="fas fa-{icon}"></i>
465
+ <span class="timestamp">{message['timestamp']}</span>
466
+ </div>
467
+ <div class="message-content">
468
+ {message['message']}
469
+ </div>
470
+ </div>
471
+ """, unsafe_allow_html=True)
472
+
473
+ # نمایش نشانگر تایپ کردن
474
+ if st.session_state.get('is_typing', False):
475
+ st.markdown("""
476
+ <div class="typing-indicator">
477
+ <div class="typing-dot"></div>
478
+ <div class="typing-dot"></div>
479
+ <div class="typing-dot"></div>
480
+ </div>
481
+ """, unsafe_allow_html=True)
482
+
483
+ # پاسخ‌های سریع
484
+ st.markdown("""
485
+ <div class="quick-replies">
486
+ """, unsafe_allow_html=True)
487
+
488
+ for reply in st.session_state.chatbot.quick_replies:
489
+ st.markdown(f"""
490
+ <div class="quick-reply" onclick="document.getElementById('user-input').value='{reply}'">
491
+ {reply}
492
+ </div>
493
+ """, unsafe_allow_html=True)
494
+
495
+ st.markdown("</div>", unsafe_allow_html=True)
496
+
497
+ # بخش ورودی پیام
498
+ col1, col2 = st.columns([4, 1])
499
+ with col1:
500
+ user_message = st.text_input(
501
+ "",
502
+ placeholder="پیام خود را بنویسید...",
503
+ key="user_message",
504
+ help="برای ارسال پیام، متن خود را وارد کرده و دکمه ارسال را بزنید"
505
+ )
506
+
507
+ with col2:
508
+ send_button = st.button(
509
+ "ارسال پیام",
510
+ key="send_button",
511
+ help="برای ارسال پیام کلیک کنید"
512
+ )
513
+
514
+ if send_button and user_message:
515
+ st.session_state['is_typing'] = True
516
+ st.session_state.chatbot.chat_response(user_message)
517
+ st.session_state['is_typing'] = False
518
+ st.experimental_rerun()
519
+
520
+ st.markdown("</div>", unsafe_allow_html=True)
521
+
522
+ # پنل مدیریت در سایدبار
523
+ with st.sidebar:
524
+ st.markdown("""
525
+ <div class="admin-panel">
526
+ <h2>
527
+ <i class="fas fa-cog"></i>
528
+ پنل مدیریت
529
+ </h2>
530
+ </div>
531
+ """, unsafe_allow_html=True)
532
+
533
+ if st.checkbox("نمایش آمار"):
534
+ stats = st.session_state.chatbot.get_stats()
535
+ st.markdown("""
536
+ <div class="statistics">
537
+ <h3>آمار سیستم</h3>
538
+ """, unsafe_allow_html=True)
539
+
540
+ for key, value in stats.items():
541
+ st.markdown(f"""
542
+ <div class="stat-item">
543
+ <span>{key}:</span>
544
+ <strong>{value}</strong>
545
+ </div>
546
+ """, unsafe_allow_html=True)
547
+
548
+ st.markdown("</div>", unsafe_allow_html=True)
549
+
550
+ if st.button("پاک کردن تاریخچه", key="clear_history"):
551
+ st.session_state.chatbot.conversation_history = []
552
+ st.experimental_rerun()
553
+
554
+ # تنظیمات ظاهری
555
+ st.markdown("### تنظیمات ظاهری")
556
+ font_size = st.slider("اندازه متن", 12, 20, 14)
557
+ st.markdown(f"""
558
+ <style>
559
+ .message {{ font-size: {font_size}px; }}
560
+ </style>
561
+ """, unsafe_allow_html=True)
562
+
563
+ # اضافه کردن اسکریپت‌های جاوااسکریپت برای عملکرد بهتر
564
+ st.markdown("""
565
+ <script>
566
+ // اسکرول خودکار به آخرین پیام
567
+ function scrollToBottom() {
568
+ const messages = document.querySelector('.chat-messages');
569
+ messages.scrollTop = messages.scrollHeight;
570
+ }
571
+
572
+ // اجرای اسکرول در لود صفحه
573
+ window.onload = scrollToBottom;
574
+
575
+ // مدیریت کلیدهای میانبر
576
+ document.addEventListener('keydown', function(event) {
577
+ if (event.key === 'Enter' && !event.shiftKey) {
578
+ const sendButton = document.querySelector('button:contains("ارسال پیام")');
579
+ if (sendButton) {
580
+ sendButton.click();
581
+ }
582
+ }
583
+ });
584
+ </script>
585
+ """, unsafe_allow_html=True)
requests.txt ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ requests
2
+ pandas
3
+ numpy
4
+ matplotlib
5
+ seaborn
6
+ scikit-learn
7
+ streamlit
8
+ plotly
9
+ transformers
10
+ flask
11
+ fastapi
12
+ opencv-python
13
+ beautifulsoup4
14
+ scrapy
15
+ sqlalchemy
16
+ tensorflow
17
+ torch
18
+ awsomefont
19
+ gradio