Spaces:
Runtime error
Runtime error
Update app.py
Browse files
app.py
CHANGED
@@ -75,6 +75,77 @@ if HF_TOKEN:
|
|
75 |
logger.error(f"Attempt {attempt + 1} failed to initialize Hugging Face API: {str(e)}")
|
76 |
time.sleep(2 ** attempt)
|
77 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
78 |
# ========== LEARNING STYLE QUIZ ==========
|
79 |
class LearningStyleQuiz:
|
80 |
def __init__(self):
|
@@ -1582,77 +1653,6 @@ class EnhancedTeachingAssistant:
|
|
1582 |
# Initialize teaching assistant
|
1583 |
teaching_assistant = EnhancedTeachingAssistant()
|
1584 |
|
1585 |
-
# ========== UTILITY FUNCTIONS ==========
|
1586 |
-
class DataEncryptor:
|
1587 |
-
def __init__(self, key: str):
|
1588 |
-
self.cipher = Fernet(key.encode())
|
1589 |
-
|
1590 |
-
def encrypt(self, data: str) -> str:
|
1591 |
-
return self.cipher.encrypt(data.encode()).decode()
|
1592 |
-
|
1593 |
-
def decrypt(self, encrypted_data: str) -> str:
|
1594 |
-
return self.cipher.decrypt(encrypted_data.encode()).decode()
|
1595 |
-
|
1596 |
-
encryptor = DataEncryptor(ENCRYPTION_KEY)
|
1597 |
-
|
1598 |
-
def generate_session_token() -> str:
|
1599 |
-
alphabet = string.ascii_letters + string.digits
|
1600 |
-
return ''.join(secrets.choice(alphabet) for _ in range(SESSION_TOKEN_LENGTH))
|
1601 |
-
|
1602 |
-
def sanitize_input(text: str) -> str:
|
1603 |
-
if not text:
|
1604 |
-
return ""
|
1605 |
-
text = html.escape(text.strip())
|
1606 |
-
text = re.sub(r'<[^>]*>', '', text)
|
1607 |
-
text = re.sub(r'[^\w\s\-.,!?@#\$%^&*()+=]', '', text)
|
1608 |
-
return text
|
1609 |
-
|
1610 |
-
def validate_name(name: str) -> str:
|
1611 |
-
name = name.strip()
|
1612 |
-
if not name:
|
1613 |
-
raise ValueError("Name cannot be empty.")
|
1614 |
-
if len(name) > 100:
|
1615 |
-
raise ValueError("Name is too long (maximum 100 characters).")
|
1616 |
-
if any(c.isdigit() for c in name):
|
1617 |
-
raise ValueError("Name cannot contain numbers.")
|
1618 |
-
return name
|
1619 |
-
|
1620 |
-
def validate_age(age: Union[int, float, str]) -> int:
|
1621 |
-
try:
|
1622 |
-
age_int = int(age)
|
1623 |
-
if not MIN_AGE <= age_int <= MAX_AGE:
|
1624 |
-
raise ValueError(f"Age must be between {MIN_AGE} and {MAX_AGE}.")
|
1625 |
-
return age_int
|
1626 |
-
except (ValueError, TypeError):
|
1627 |
-
raise ValueError("Please enter a valid age number.")
|
1628 |
-
|
1629 |
-
def validate_file(file_obj) -> None:
|
1630 |
-
if not file_obj:
|
1631 |
-
raise ValueError("Please upload a file first")
|
1632 |
-
|
1633 |
-
file_ext = os.path.splitext(file_obj.name)[1].lower()
|
1634 |
-
if file_ext not in ALLOWED_FILE_TYPES:
|
1635 |
-
raise ValueError(f"Invalid file type. Allowed types: {', '.join(ALLOWED_FILE_TYPES)}")
|
1636 |
-
|
1637 |
-
file_size = os.path.getsize(file_obj.name) / (1024 * 1024)
|
1638 |
-
if file_size > MAX_FILE_SIZE_MB:
|
1639 |
-
raise ValueError(f"File too large. Maximum size is {MAX_FILE_SIZE_MB}MB.")
|
1640 |
-
|
1641 |
-
def remove_sensitive_info(text: str) -> str:
|
1642 |
-
patterns = [
|
1643 |
-
(r'\b\d{3}-\d{2}-\d{4}\b', '[REDACTED-SSN]'),
|
1644 |
-
(r'\b\d{6,9}\b', '[ID]'),
|
1645 |
-
(r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b', '[EMAIL]'),
|
1646 |
-
(r'\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b', '[IP]'),
|
1647 |
-
(r'\b[A-Z][a-z]+ [A-Z][a-z]+\b', '[NAME]'),
|
1648 |
-
(r'\b\d{3}\) \d{3}-\d{4}\b', '[PHONE]'),
|
1649 |
-
(r'\b\d{1,5} [A-Z][a-z]+ [A-Z][a-z]+, [A-Z]{2} \d{5}\b', '[ADDRESS]')
|
1650 |
-
]
|
1651 |
-
|
1652 |
-
for pattern, replacement in patterns:
|
1653 |
-
text = re.sub(pattern, replacement, text)
|
1654 |
-
return text
|
1655 |
-
|
1656 |
# ========== GRADIO INTERFACE ==========
|
1657 |
def create_enhanced_interface():
|
1658 |
with gr.Blocks(theme=gr.themes.Soft(), title="Student Learning Assistant") as app:
|
|
|
75 |
logger.error(f"Attempt {attempt + 1} failed to initialize Hugging Face API: {str(e)}")
|
76 |
time.sleep(2 ** attempt)
|
77 |
|
78 |
+
# ========== UTILITY FUNCTIONS ==========
|
79 |
+
class DataEncryptor:
|
80 |
+
def __init__(self, key: str):
|
81 |
+
self.cipher = Fernet(key.encode())
|
82 |
+
|
83 |
+
def encrypt(self, data: str) -> str:
|
84 |
+
return self.cipher.encrypt(data.encode()).decode()
|
85 |
+
|
86 |
+
def decrypt(self, encrypted_data: str) -> str:
|
87 |
+
return self.cipher.decrypt(encrypted_data.encode()).decode()
|
88 |
+
|
89 |
+
encryptor = DataEncryptor(ENCRYPTION_KEY)
|
90 |
+
|
91 |
+
def generate_session_token() -> str:
|
92 |
+
alphabet = string.ascii_letters + string.digits
|
93 |
+
return ''.join(secrets.choice(alphabet) for _ in range(SESSION_TOKEN_LENGTH))
|
94 |
+
|
95 |
+
def sanitize_input(text: str) -> str:
|
96 |
+
if not text:
|
97 |
+
return ""
|
98 |
+
text = html.escape(text.strip())
|
99 |
+
text = re.sub(r'<[^>]*>', '', text)
|
100 |
+
text = re.sub(r'[^\w\s\-.,!?@#\$%^&*()+=]', '', text)
|
101 |
+
return text
|
102 |
+
|
103 |
+
def validate_name(name: str) -> str:
|
104 |
+
name = name.strip()
|
105 |
+
if not name:
|
106 |
+
raise ValueError("Name cannot be empty.")
|
107 |
+
if len(name) > 100:
|
108 |
+
raise ValueError("Name is too long (maximum 100 characters).")
|
109 |
+
if any(c.isdigit() for c in name):
|
110 |
+
raise ValueError("Name cannot contain numbers.")
|
111 |
+
return name
|
112 |
+
|
113 |
+
def validate_age(age: Union[int, float, str]) -> int:
|
114 |
+
try:
|
115 |
+
age_int = int(age)
|
116 |
+
if not MIN_AGE <= age_int <= MAX_AGE:
|
117 |
+
raise ValueError(f"Age must be between {MIN_AGE} and {MAX_AGE}.")
|
118 |
+
return age_int
|
119 |
+
except (ValueError, TypeError):
|
120 |
+
raise ValueError("Please enter a valid age number.")
|
121 |
+
|
122 |
+
def validate_file(file_obj) -> None:
|
123 |
+
if not file_obj:
|
124 |
+
raise ValueError("Please upload a file first")
|
125 |
+
|
126 |
+
file_ext = os.path.splitext(file_obj.name)[1].lower()
|
127 |
+
if file_ext not in ALLOWED_FILE_TYPES:
|
128 |
+
raise ValueError(f"Invalid file type. Allowed types: {', '.join(ALLOWED_FILE_TYPES)}")
|
129 |
+
|
130 |
+
file_size = os.path.getsize(file_obj.name) / (1024 * 1024)
|
131 |
+
if file_size > MAX_FILE_SIZE_MB:
|
132 |
+
raise ValueError(f"File too large. Maximum size is {MAX_FILE_SIZE_MB}MB.")
|
133 |
+
|
134 |
+
def remove_sensitive_info(text: str) -> str:
|
135 |
+
patterns = [
|
136 |
+
(r'\b\d{3}-\d{2}-\d{4}\b', '[REDACTED-SSN]'),
|
137 |
+
(r'\b\d{6,9}\b', '[ID]'),
|
138 |
+
(r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b', '[EMAIL]'),
|
139 |
+
(r'\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b', '[IP]'),
|
140 |
+
(r'\b[A-Z][a-z]+ [A-Z][a-z]+\b', '[NAME]'),
|
141 |
+
(r'\b\d{3}\) \d{3}-\d{4}\b', '[PHONE]'),
|
142 |
+
(r'\b\d{1,5} [A-Z][a-z]+ [A-Z][a-z]+, [A-Z]{2} \d{5}\b', '[ADDRESS]')
|
143 |
+
]
|
144 |
+
|
145 |
+
for pattern, replacement in patterns:
|
146 |
+
text = re.sub(pattern, replacement, text)
|
147 |
+
return text
|
148 |
+
|
149 |
# ========== LEARNING STYLE QUIZ ==========
|
150 |
class LearningStyleQuiz:
|
151 |
def __init__(self):
|
|
|
1653 |
# Initialize teaching assistant
|
1654 |
teaching_assistant = EnhancedTeachingAssistant()
|
1655 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1656 |
# ========== GRADIO INTERFACE ==========
|
1657 |
def create_enhanced_interface():
|
1658 |
with gr.Blocks(theme=gr.themes.Soft(), title="Student Learning Assistant") as app:
|