Spaces:
Running
Running
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]:
|