Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -49,6 +49,39 @@ except ImportError:
|
|
| 49 |
ACE_EDITOR_AVAILABLE = False
|
| 50 |
logger.warning("streamlit-ace not available, falling back to standard text editor")
|
| 51 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 52 |
def ensure_packages():
|
| 53 |
required_packages = {
|
| 54 |
'manim': '0.17.3',
|
|
@@ -67,6 +100,7 @@ def ensure_packages():
|
|
| 67 |
'matplotlib': '3.5.0', # For Python script runner
|
| 68 |
'seaborn': '0.11.2', # For enhanced visualizations
|
| 69 |
'scipy': '1.7.3', # For scientific computations
|
|
|
|
| 70 |
}
|
| 71 |
|
| 72 |
with st.spinner("Checking required packages..."):
|
|
@@ -108,6 +142,8 @@ def ensure_packages():
|
|
| 108 |
import seaborn
|
| 109 |
elif package == 'scipy':
|
| 110 |
import scipy
|
|
|
|
|
|
|
| 111 |
except ImportError:
|
| 112 |
missing_packages[package] = version
|
| 113 |
|
|
@@ -202,19 +238,38 @@ def install_custom_packages(package_list):
|
|
| 202 |
return success, "\n".join(results)
|
| 203 |
|
| 204 |
@st.cache_resource(ttl=3600)
|
| 205 |
-
def init_ai_models():
|
| 206 |
try:
|
| 207 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 208 |
code_model = pipeline(
|
| 209 |
"text-generation",
|
| 210 |
-
model=
|
|
|
|
| 211 |
trust_remote_code=True
|
| 212 |
)
|
|
|
|
| 213 |
if code_model is None:
|
| 214 |
st.error("Failed to initialize code model")
|
| 215 |
return None
|
|
|
|
| 216 |
return {
|
| 217 |
"code_model": code_model,
|
|
|
|
| 218 |
"last_loaded": datetime.now().isoformat()
|
| 219 |
}
|
| 220 |
except Exception as e:
|
|
@@ -1494,6 +1549,8 @@ def main():
|
|
| 1494 |
"format_type": "mp4",
|
| 1495 |
"animation_speed": "Normal"
|
| 1496 |
}
|
|
|
|
|
|
|
| 1497 |
|
| 1498 |
# Page configuration with improved layout
|
| 1499 |
st.set_page_config(
|
|
@@ -1619,10 +1676,6 @@ def main():
|
|
| 1619 |
else:
|
| 1620 |
st.error("Failed to install required packages. Please try again.")
|
| 1621 |
st.stop()
|
| 1622 |
-
|
| 1623 |
-
# Initialize AI models if needed
|
| 1624 |
-
if st.session_state.ai_models is None or not check_model_freshness():
|
| 1625 |
-
st.session_state.ai_models = init_ai_models()
|
| 1626 |
|
| 1627 |
# Create main tabs
|
| 1628 |
tab_names = ["β¨ Editor", "π€ AI Assistant", "π LaTeX Formulas", "π¨ Assets", "ποΈ Timeline", "π Educational Export", "π Python Runner"]
|
|
@@ -1865,85 +1918,144 @@ class MyScene(Scene):
|
|
| 1865 |
with tabs[1]:
|
| 1866 |
st.markdown("### π€ AI Animation Assistant")
|
| 1867 |
|
| 1868 |
-
|
| 1869 |
-
|
| 1870 |
-
|
| 1871 |
-
st.markdown("####
|
| 1872 |
-
|
| 1873 |
-
|
| 1874 |
-
|
| 1875 |
-
|
| 1876 |
-
"
|
| 1877 |
-
"
|
| 1878 |
-
"
|
| 1879 |
-
"
|
| 1880 |
-
"
|
| 1881 |
-
"Illustrate the concept of integration with area under a curve"
|
| 1882 |
]
|
| 1883 |
|
| 1884 |
-
|
| 1885 |
-
"
|
| 1886 |
-
|
| 1887 |
-
)
|
| 1888 |
-
|
| 1889 |
-
prompt_value = selected_idea if selected_idea != "Select an idea..." else ""
|
| 1890 |
-
|
| 1891 |
-
code_input = st.text_area(
|
| 1892 |
-
"Your Prompt or Code",
|
| 1893 |
-
value=prompt_value,
|
| 1894 |
-
placeholder="Example: Create an animation that shows a circle morphing into a square while changing color from red to blue",
|
| 1895 |
-
height=150
|
| 1896 |
)
|
| 1897 |
|
| 1898 |
-
if
|
| 1899 |
-
|
| 1900 |
-
|
| 1901 |
-
|
| 1902 |
-
|
| 1903 |
-
|
| 1904 |
-
|
| 1905 |
-
st.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1906 |
|
| 1907 |
-
|
|
|
|
| 1908 |
|
| 1909 |
-
#
|
| 1910 |
-
if st.session_state.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1911 |
st.markdown("<div class='card'>", unsafe_allow_html=True)
|
| 1912 |
-
st.markdown("####
|
| 1913 |
-
st.
|
| 1914 |
|
| 1915 |
-
|
| 1916 |
-
|
| 1917 |
-
|
| 1918 |
-
|
| 1919 |
-
|
| 1920 |
-
|
| 1921 |
-
|
| 1922 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1923 |
|
| 1924 |
-
with col_ai2:
|
| 1925 |
-
if st.button("Render Preview", key="render_preview"):
|
| 1926 |
-
with st.spinner("Rendering preview..."):
|
| 1927 |
-
video_data, status = generate_manim_video(
|
| 1928 |
-
st.session_state.generated_code,
|
| 1929 |
-
"mp4",
|
| 1930 |
-
"480p", # Use lowest quality for preview
|
| 1931 |
-
ANIMATION_SPEEDS["Normal"]
|
| 1932 |
-
)
|
| 1933 |
-
|
| 1934 |
-
if video_data:
|
| 1935 |
-
st.video(video_data)
|
| 1936 |
-
st.download_button(
|
| 1937 |
-
label="Download Preview",
|
| 1938 |
-
data=video_data,
|
| 1939 |
-
file_name=f"manim_preview_{int(time.time())}.mp4",
|
| 1940 |
-
mime="video/mp4"
|
| 1941 |
-
)
|
| 1942 |
-
else:
|
| 1943 |
-
st.error(f"Failed to generate preview: {status}")
|
| 1944 |
st.markdown("</div>", unsafe_allow_html=True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1945 |
else:
|
| 1946 |
-
st.
|
| 1947 |
|
| 1948 |
# LATEX FORMULAS TAB
|
| 1949 |
with tabs[2]:
|
|
|
|
| 49 |
ACE_EDITOR_AVAILABLE = False
|
| 50 |
logger.warning("streamlit-ace not available, falling back to standard text editor")
|
| 51 |
|
| 52 |
+
# New functions for accessing secrets and password verification
|
| 53 |
+
def get_secret(secret_name):
|
| 54 |
+
"""Retrieve a secret from HuggingFace Spaces environment variables"""
|
| 55 |
+
secret_value = os.environ.get(secret_name)
|
| 56 |
+
if not secret_value:
|
| 57 |
+
logger.warning(f"Secret '{secret_name}' not found")
|
| 58 |
+
return None
|
| 59 |
+
return secret_value
|
| 60 |
+
|
| 61 |
+
def check_password():
|
| 62 |
+
"""Returns True if the user entered the correct password"""
|
| 63 |
+
# Get the password from secrets
|
| 64 |
+
correct_password = get_secret("password")
|
| 65 |
+
if not correct_password:
|
| 66 |
+
st.error("Admin password not configured in HuggingFace Spaces secrets")
|
| 67 |
+
return False
|
| 68 |
+
|
| 69 |
+
# Password input
|
| 70 |
+
if "password_entered" not in st.session_state:
|
| 71 |
+
st.session_state.password_entered = False
|
| 72 |
+
|
| 73 |
+
if not st.session_state.password_entered:
|
| 74 |
+
password = st.text_input("Enter password to access AI features", type="password")
|
| 75 |
+
if password:
|
| 76 |
+
if password == correct_password:
|
| 77 |
+
st.session_state.password_entered = True
|
| 78 |
+
return True
|
| 79 |
+
else:
|
| 80 |
+
st.error("Incorrect password")
|
| 81 |
+
return False
|
| 82 |
+
return False
|
| 83 |
+
return True
|
| 84 |
+
|
| 85 |
def ensure_packages():
|
| 86 |
required_packages = {
|
| 87 |
'manim': '0.17.3',
|
|
|
|
| 100 |
'matplotlib': '3.5.0', # For Python script runner
|
| 101 |
'seaborn': '0.11.2', # For enhanced visualizations
|
| 102 |
'scipy': '1.7.3', # For scientific computations
|
| 103 |
+
'huggingface_hub': '0.16.0', # For Hugging Face API
|
| 104 |
}
|
| 105 |
|
| 106 |
with st.spinner("Checking required packages..."):
|
|
|
|
| 142 |
import seaborn
|
| 143 |
elif package == 'scipy':
|
| 144 |
import scipy
|
| 145 |
+
elif package == 'huggingface_hub':
|
| 146 |
+
import huggingface_hub
|
| 147 |
except ImportError:
|
| 148 |
missing_packages[package] = version
|
| 149 |
|
|
|
|
| 238 |
return success, "\n".join(results)
|
| 239 |
|
| 240 |
@st.cache_resource(ttl=3600)
|
| 241 |
+
def init_ai_models(model_name=None):
|
| 242 |
try:
|
| 243 |
+
# Get the GitHub token from secrets
|
| 244 |
+
github_token = get_secret("github_token_api")
|
| 245 |
+
if not github_token:
|
| 246 |
+
st.error("GitHub API token not configured in HuggingFace Spaces secrets")
|
| 247 |
+
return None
|
| 248 |
+
|
| 249 |
+
# Use default model if none specified
|
| 250 |
+
if not model_name:
|
| 251 |
+
model_name = "deepseek-ai/deepseek-coder-1.3b-base"
|
| 252 |
+
|
| 253 |
+
with st.spinner(f"Loading AI model: {model_name} - this may take a moment..."):
|
| 254 |
+
# Configure the Hugging Face API with the token
|
| 255 |
+
from huggingface_hub import login
|
| 256 |
+
login(token=github_token)
|
| 257 |
+
|
| 258 |
+
# Now initialize the model with the token
|
| 259 |
code_model = pipeline(
|
| 260 |
"text-generation",
|
| 261 |
+
model=model_name,
|
| 262 |
+
token=github_token, # Pass the token for authentication
|
| 263 |
trust_remote_code=True
|
| 264 |
)
|
| 265 |
+
|
| 266 |
if code_model is None:
|
| 267 |
st.error("Failed to initialize code model")
|
| 268 |
return None
|
| 269 |
+
|
| 270 |
return {
|
| 271 |
"code_model": code_model,
|
| 272 |
+
"model_name": model_name,
|
| 273 |
"last_loaded": datetime.now().isoformat()
|
| 274 |
}
|
| 275 |
except Exception as e:
|
|
|
|
| 1549 |
"format_type": "mp4",
|
| 1550 |
"animation_speed": "Normal"
|
| 1551 |
}
|
| 1552 |
+
st.session_state.password_entered = False # Track password authentication
|
| 1553 |
+
st.session_state.custom_model = "deepseek-ai/deepseek-coder-1.3b-base" # Default model
|
| 1554 |
|
| 1555 |
# Page configuration with improved layout
|
| 1556 |
st.set_page_config(
|
|
|
|
| 1676 |
else:
|
| 1677 |
st.error("Failed to install required packages. Please try again.")
|
| 1678 |
st.stop()
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1679 |
|
| 1680 |
# Create main tabs
|
| 1681 |
tab_names = ["β¨ Editor", "π€ AI Assistant", "π LaTeX Formulas", "π¨ Assets", "ποΈ Timeline", "π Educational Export", "π Python Runner"]
|
|
|
|
| 1918 |
with tabs[1]:
|
| 1919 |
st.markdown("### π€ AI Animation Assistant")
|
| 1920 |
|
| 1921 |
+
# Check password before allowing access
|
| 1922 |
+
if check_password():
|
| 1923 |
+
# Model selection - only visible after authentication
|
| 1924 |
+
st.markdown("#### Model Selection")
|
| 1925 |
+
|
| 1926 |
+
# Predefined popular models
|
| 1927 |
+
popular_models = [
|
| 1928 |
+
"Select a predefined model...",
|
| 1929 |
+
"deepseek-ai/deepseek-coder-1.3b-base",
|
| 1930 |
+
"mistralai/Mistral-7B-Instruct-v0.2",
|
| 1931 |
+
"Phind/Phind-CodeLlama-34B-v2",
|
| 1932 |
+
"facebook/incoder-1B",
|
| 1933 |
+
"Salesforce/codegen2-1B",
|
|
|
|
| 1934 |
]
|
| 1935 |
|
| 1936 |
+
custom_model_option = st.radio(
|
| 1937 |
+
"Choose model option:",
|
| 1938 |
+
["Use predefined model", "Enter custom model name"]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1939 |
)
|
| 1940 |
|
| 1941 |
+
if custom_model_option == "Use predefined model":
|
| 1942 |
+
selected_model = st.selectbox(
|
| 1943 |
+
"Select a model:",
|
| 1944 |
+
options=popular_models
|
| 1945 |
+
)
|
| 1946 |
+
|
| 1947 |
+
if selected_model != "Select a predefined model...":
|
| 1948 |
+
st.session_state.custom_model = selected_model
|
| 1949 |
+
else:
|
| 1950 |
+
custom_model_name = st.text_input(
|
| 1951 |
+
"Enter custom model name/path:",
|
| 1952 |
+
value=st.session_state.custom_model,
|
| 1953 |
+
placeholder="e.g., organization/model-name"
|
| 1954 |
+
)
|
| 1955 |
+
|
| 1956 |
+
if custom_model_name:
|
| 1957 |
+
st.session_state.custom_model = custom_model_name
|
| 1958 |
|
| 1959 |
+
# Display currently selected model
|
| 1960 |
+
st.info(f"Currently selected model: {st.session_state.custom_model}")
|
| 1961 |
|
| 1962 |
+
# Only initialize models if password check passes and we have a model name
|
| 1963 |
+
if st.session_state.custom_model:
|
| 1964 |
+
model_changed = False
|
| 1965 |
+
|
| 1966 |
+
# Check if we need to reinitialize the model (if model changed)
|
| 1967 |
+
if (st.session_state.ai_models is not None and
|
| 1968 |
+
'model_name' in st.session_state.ai_models and
|
| 1969 |
+
st.session_state.ai_models['model_name'] != st.session_state.custom_model):
|
| 1970 |
+
model_changed = True
|
| 1971 |
+
|
| 1972 |
+
# Initialize model if needed
|
| 1973 |
+
if (st.session_state.ai_models is None or
|
| 1974 |
+
not check_model_freshness() or
|
| 1975 |
+
model_changed):
|
| 1976 |
+
st.session_state.ai_models = init_ai_models(st.session_state.custom_model)
|
| 1977 |
+
|
| 1978 |
+
if st.session_state.ai_models:
|
| 1979 |
+
# AI code generation
|
| 1980 |
st.markdown("<div class='card'>", unsafe_allow_html=True)
|
| 1981 |
+
st.markdown("#### Generate Animation from Description")
|
| 1982 |
+
st.write("Describe the animation you want to create, or provide partial code to complete.")
|
| 1983 |
|
| 1984 |
+
# Predefined animation ideas dropdown
|
| 1985 |
+
animation_ideas = [
|
| 1986 |
+
"Select an idea...",
|
| 1987 |
+
"Create a 3D animation showing a sphere morphing into a torus",
|
| 1988 |
+
"Show a visual proof of the Pythagorean theorem",
|
| 1989 |
+
"Visualize a Fourier transform converting a signal from time domain to frequency domain",
|
| 1990 |
+
"Create an animation explaining neural network forward propagation",
|
| 1991 |
+
"Illustrate the concept of integration with area under a curve"
|
| 1992 |
+
]
|
| 1993 |
+
|
| 1994 |
+
selected_idea = st.selectbox(
|
| 1995 |
+
"Try one of these ideas",
|
| 1996 |
+
options=animation_ideas
|
| 1997 |
+
)
|
| 1998 |
+
|
| 1999 |
+
prompt_value = selected_idea if selected_idea != "Select an idea..." else ""
|
| 2000 |
+
|
| 2001 |
+
code_input = st.text_area(
|
| 2002 |
+
"Your Prompt or Code",
|
| 2003 |
+
value=prompt_value,
|
| 2004 |
+
placeholder="Example: Create an animation that shows a circle morphing into a square while changing color from red to blue",
|
| 2005 |
+
height=150
|
| 2006 |
+
)
|
| 2007 |
+
|
| 2008 |
+
if st.button("Generate Animation Code", key="gen_ai_code"):
|
| 2009 |
+
if code_input:
|
| 2010 |
+
with st.spinner("AI is generating your animation code..."):
|
| 2011 |
+
response = suggest_code_completion(code_input, st.session_state.ai_models)
|
| 2012 |
+
if response:
|
| 2013 |
+
st.session_state.generated_code = response
|
| 2014 |
+
else:
|
| 2015 |
+
st.warning("Please enter a description or prompt first")
|
| 2016 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2017 |
st.markdown("</div>", unsafe_allow_html=True)
|
| 2018 |
+
|
| 2019 |
+
# AI generated code display and actions
|
| 2020 |
+
if st.session_state.generated_code:
|
| 2021 |
+
st.markdown("<div class='card'>", unsafe_allow_html=True)
|
| 2022 |
+
st.markdown("#### Generated Animation Code")
|
| 2023 |
+
st.code(st.session_state.generated_code, language="python")
|
| 2024 |
+
|
| 2025 |
+
col_ai1, col_ai2 = st.columns(2)
|
| 2026 |
+
with col_ai1:
|
| 2027 |
+
if st.button("Use This Code", key="use_gen_code"):
|
| 2028 |
+
st.session_state.code = st.session_state.generated_code
|
| 2029 |
+
st.session_state.temp_code = st.session_state.generated_code
|
| 2030 |
+
# Switch to Editor tab
|
| 2031 |
+
st.session_state.active_tab = 0
|
| 2032 |
+
st.rerun()
|
| 2033 |
+
|
| 2034 |
+
with col_ai2:
|
| 2035 |
+
if st.button("Render Preview", key="render_preview"):
|
| 2036 |
+
with st.spinner("Rendering preview..."):
|
| 2037 |
+
video_data, status = generate_manim_video(
|
| 2038 |
+
st.session_state.generated_code,
|
| 2039 |
+
"mp4",
|
| 2040 |
+
"480p", # Use lowest quality for preview
|
| 2041 |
+
ANIMATION_SPEEDS["Normal"]
|
| 2042 |
+
)
|
| 2043 |
+
|
| 2044 |
+
if video_data:
|
| 2045 |
+
st.video(video_data)
|
| 2046 |
+
st.download_button(
|
| 2047 |
+
label="Download Preview",
|
| 2048 |
+
data=video_data,
|
| 2049 |
+
file_name=f"manim_preview_{int(time.time())}.mp4",
|
| 2050 |
+
mime="video/mp4"
|
| 2051 |
+
)
|
| 2052 |
+
else:
|
| 2053 |
+
st.error(f"Failed to generate preview: {status}")
|
| 2054 |
+
st.markdown("</div>", unsafe_allow_html=True)
|
| 2055 |
+
else:
|
| 2056 |
+
st.warning("AI models failed to load. Generation features are unavailable.")
|
| 2057 |
else:
|
| 2058 |
+
st.info("Please enter the correct password to access AI features")
|
| 2059 |
|
| 2060 |
# LATEX FORMULAS TAB
|
| 2061 |
with tabs[2]:
|