Spaces:
Running
Running
Sami
commited on
Commit
Β·
dda6248
1
Parent(s):
2f8eb98
Sync changes - automated commit
Browse files
app.py
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
import streamlit as st
|
2 |
-
|
3 |
import os
|
4 |
from streamlit_extras.colored_header import colored_header
|
5 |
from streamlit_lottie import st_lottie
|
@@ -16,6 +16,9 @@ from pathlib import Path
|
|
16 |
import hashlib
|
17 |
import streamlit_file_browser as sfb
|
18 |
|
|
|
|
|
|
|
19 |
# Add retry decorator for API calls
|
20 |
@retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=4, max=10))
|
21 |
def load_lottieurl(url: str) -> Dict[str, Any]:
|
@@ -95,7 +98,7 @@ def init_session_state():
|
|
95 |
"uploaded_files": [],
|
96 |
"settings_open": False,
|
97 |
"messages": [],
|
98 |
-
"original_system_message":
|
99 |
"session_dir": None,
|
100 |
"last_request_time": time.time()
|
101 |
}
|
@@ -110,7 +113,7 @@ def init_session_state():
|
|
110 |
st.session_state.selected_model = st.session_state.settings["model"]
|
111 |
|
112 |
# Always reset interpreter for fresh session
|
113 |
-
|
114 |
|
115 |
# Apply initial settings
|
116 |
apply_interpreter_settings()
|
@@ -123,28 +126,28 @@ def init_session_state():
|
|
123 |
|
124 |
def apply_interpreter_settings():
|
125 |
"""Apply interpreter settings"""
|
126 |
-
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
interpreter.conversation_history = True # Force this to False
|
134 |
-
interpreter.os = st.session_state.settings["os_mode"]
|
135 |
|
136 |
-
# Set allowed paths
|
137 |
-
|
138 |
-
|
|
|
|
|
139 |
|
140 |
# Update system message
|
141 |
-
|
142 |
if st.session_state.settings["custom_instructions"]:
|
143 |
-
|
144 |
|
145 |
if st.session_state.settings["use_workspace"]:
|
146 |
workspace_path = get_session_folder()
|
147 |
-
|
148 |
|
149 |
class OutputController:
|
150 |
def __init__(self):
|
@@ -186,8 +189,8 @@ class OutputController:
|
|
186 |
# Move clear_chat_history outside main function
|
187 |
def clear_chat_history():
|
188 |
"""Completely reset the chat state"""
|
189 |
-
|
190 |
-
|
191 |
st.session_state.messages = [] # Clear UI message history
|
192 |
save_settings() # Ensure settings persist after clear
|
193 |
st.success("Chat history cleared!")
|
@@ -628,7 +631,7 @@ def handle_user_input(user_input: str):
|
|
628 |
response_placeholder = st.empty()
|
629 |
|
630 |
# Enhanced streaming with chunking
|
631 |
-
for chunk in
|
632 |
if isinstance(chunk, dict):
|
633 |
content = str(chunk.get('content', '')) # Convert content to string
|
634 |
chunk_type = chunk.get('type', 'message')
|
@@ -710,45 +713,62 @@ def handle_user_input(user_input: str):
|
|
710 |
|
711 |
# Add file handling functions
|
712 |
def get_session_folder() -> str:
|
713 |
-
"""Get or create the session folder
|
714 |
if not st.session_state.settings["use_workspace"]:
|
715 |
return "/"
|
716 |
|
717 |
try:
|
718 |
-
#
|
719 |
if st.session_state.get("session_dir"):
|
720 |
workspace_dir = Path(st.session_state.session_dir)
|
|
|
|
|
|
|
721 |
else:
|
722 |
# Use default workspace directory
|
723 |
-
workspace_dir = Path("autointerpreter-workspace")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
724 |
|
725 |
-
|
726 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
727 |
|
728 |
-
#
|
729 |
if not st.session_state.get("session_dir"):
|
730 |
timestamp = datetime.now(timezone.utc).strftime("%Y-%m-%d_%H_%M")
|
731 |
session_dir = workspace_dir / f"session-{timestamp}"
|
732 |
-
|
733 |
-
|
734 |
-
|
735 |
-
|
736 |
-
|
737 |
-
|
738 |
-
|
739 |
-
|
740 |
-
|
741 |
-
|
742 |
-
|
743 |
-
st.session_state.session_dir = str(workspace_dir)
|
744 |
-
st.session_state.uploaded_files = []
|
745 |
-
update_custom_instructions()
|
746 |
|
747 |
return st.session_state.session_dir
|
748 |
|
749 |
except Exception as e:
|
750 |
st.error(f"Error managing workspace: {str(e)}")
|
751 |
return "/"
|
|
|
752 |
def handle_file_upload(uploaded_files):
|
753 |
"""Enhanced file upload handling with better error handling and validation"""
|
754 |
if not uploaded_files:
|
@@ -877,11 +897,11 @@ def get_file_icon(file_type: str) -> str:
|
|
877 |
elif file_type.startswith('application/pdf'):
|
878 |
return "π"
|
879 |
elif file_type.startswith('application/json'):
|
880 |
-
return "
|
881 |
elif 'python' in file_type.lower():
|
882 |
return "π"
|
883 |
elif 'javascript' in file_type.lower():
|
884 |
-
return ""
|
885 |
elif 'spreadsheet' in file_type.lower():
|
886 |
return "π"
|
887 |
else:
|
@@ -889,75 +909,110 @@ def get_file_icon(file_type: str) -> str:
|
|
889 |
|
890 |
# Add audio track selection handler
|
891 |
def update_audio_track():
|
892 |
-
"""Update the selected audio track"""
|
893 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
894 |
|
895 |
def create_audio_player():
|
896 |
-
|
|
|
897 |
<div class="floating-audio">
|
898 |
-
<audio id="audio-player" controls loop style="width: 250px; height: 40px;"
|
899 |
-
onerror="handleAudioError()"
|
900 |
-
onloadeddata="handleAudioLoaded()">
|
901 |
<source id="audio-source" src="{audio_tracks[st.session_state.selected_audio_track]}" type="audio/mpeg">
|
902 |
Your browser does not support the audio element.
|
903 |
</audio>
|
904 |
<select id="audio-select" onchange="updateAudio(this.value)"
|
905 |
-
style="width: 100%; padding: 5px; border-radius: 5px;
|
906 |
-
{' '.join([f'<option value="{url}" {"selected" if name == st.session_state.selected_audio_track else ""}>{name}</option>'
|
907 |
for name, url in audio_tracks.items()])}
|
908 |
</select>
|
|
|
909 |
</div>
|
910 |
<script>
|
911 |
-
function
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
912 |
console.error('Audio playback error');
|
913 |
const player = document.getElementById('audio-player');
|
914 |
player.style.opacity = '0.5';
|
915 |
-
|
916 |
-
}
|
917 |
|
918 |
-
function handleAudioLoaded() {
|
919 |
const player = document.getElementById('audio-player');
|
920 |
player.style.opacity = '1';
|
921 |
-
|
922 |
-
}
|
923 |
|
924 |
-
function updateAudio(url) {
|
925 |
-
try {
|
926 |
-
|
927 |
-
|
928 |
-
|
929 |
-
|
930 |
-
|
931 |
-
|
932 |
-
|
933 |
-
|
934 |
-
|
935 |
-
|
936 |
-
|
937 |
-
|
938 |
-
|
|
|
|
|
939 |
console.error('Error updating audio:', error);
|
940 |
-
|
941 |
-
|
|
|
942 |
|
943 |
-
|
944 |
-
document.addEventListener('DOMContentLoaded', function() {{
|
945 |
const audioPlayer = document.getElementById('audio-player');
|
946 |
let retryCount = 0;
|
947 |
const maxRetries = 3;
|
948 |
|
949 |
-
audioPlayer.addEventListener('error', function() {
|
950 |
-
if (retryCount < maxRetries) {
|
951 |
-
setTimeout(() => {
|
952 |
console.log('Retrying audio load...');
|
|
|
953 |
audioPlayer.load();
|
954 |
retryCount++;
|
955 |
-
}
|
956 |
-
}
|
957 |
-
|
958 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
959 |
</script>
|
960 |
-
"""
|
|
|
|
|
|
|
961 |
|
962 |
def cleanup_old_sessions():
|
963 |
"""Clean up old session directories with improved error handling and format detection"""
|
@@ -1274,7 +1329,7 @@ def main():
|
|
1274 |
# System Message Settings
|
1275 |
st.text_area(
|
1276 |
"Default System Message",
|
1277 |
-
value=
|
1278 |
disabled=True,
|
1279 |
help="Base instructions for the AI assistant",
|
1280 |
height=100
|
|
|
1 |
import streamlit as st
|
2 |
+
import interpreter
|
3 |
import os
|
4 |
from streamlit_extras.colored_header import colored_header
|
5 |
from streamlit_lottie import st_lottie
|
|
|
16 |
import hashlib
|
17 |
import streamlit_file_browser as sfb
|
18 |
|
19 |
+
# Create interpreter instance
|
20 |
+
interpreter_instance = interpreter.Interpreter()
|
21 |
+
|
22 |
# Add retry decorator for API calls
|
23 |
@retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=4, max=10))
|
24 |
def load_lottieurl(url: str) -> Dict[str, Any]:
|
|
|
98 |
"uploaded_files": [],
|
99 |
"settings_open": False,
|
100 |
"messages": [],
|
101 |
+
"original_system_message": interpreter_instance.system_message,
|
102 |
"session_dir": None,
|
103 |
"last_request_time": time.time()
|
104 |
}
|
|
|
113 |
st.session_state.selected_model = st.session_state.settings["model"]
|
114 |
|
115 |
# Always reset interpreter for fresh session
|
116 |
+
interpreter_instance.reset()
|
117 |
|
118 |
# Apply initial settings
|
119 |
apply_interpreter_settings()
|
|
|
126 |
|
127 |
def apply_interpreter_settings():
|
128 |
"""Apply interpreter settings"""
|
129 |
+
interpreter_instance.api_key = st.session_state.settings["api_key"]
|
130 |
+
interpreter_instance.api_base = st.session_state.settings["api_base"]
|
131 |
+
interpreter_instance.model = st.session_state.settings["model"]
|
132 |
+
interpreter_instance.auto_run = st.session_state.settings["auto_run"]
|
133 |
+
interpreter_instance.temperature = 0.7
|
134 |
+
interpreter_instance.safe_mode = "off"
|
135 |
+
interpreter_instance.conversation_history = True # Force this to False
|
|
|
|
|
136 |
|
137 |
+
# Set allowed paths directly on interpreter
|
138 |
+
if st.session_state.settings["use_workspace"]:
|
139 |
+
interpreter_instance.allowed_paths = [get_session_folder()]
|
140 |
+
else:
|
141 |
+
interpreter_instance.allowed_paths = st.session_state.settings["allowed_paths"]
|
142 |
|
143 |
# Update system message
|
144 |
+
interpreter_instance.system_message = st.session_state.original_system_message
|
145 |
if st.session_state.settings["custom_instructions"]:
|
146 |
+
interpreter_instance.system_message += f"\n\nAdditional Instructions:\n{st.session_state.settings['custom_instructions']}"
|
147 |
|
148 |
if st.session_state.settings["use_workspace"]:
|
149 |
workspace_path = get_session_folder()
|
150 |
+
interpreter_instance.system_message += f"\n\nWorkspace Path: {workspace_path}\nYou can only access files in this workspace directory."
|
151 |
|
152 |
class OutputController:
|
153 |
def __init__(self):
|
|
|
189 |
# Move clear_chat_history outside main function
|
190 |
def clear_chat_history():
|
191 |
"""Completely reset the chat state"""
|
192 |
+
interpreter_instance.messages = [] # Clear interpreter's message history
|
193 |
+
interpreter_instance.reset() # Full reset of interpreter
|
194 |
st.session_state.messages = [] # Clear UI message history
|
195 |
save_settings() # Ensure settings persist after clear
|
196 |
st.success("Chat history cleared!")
|
|
|
631 |
response_placeholder = st.empty()
|
632 |
|
633 |
# Enhanced streaming with chunking
|
634 |
+
for chunk in interpreter_instance.chat(user_input, stream=True, display=False):
|
635 |
if isinstance(chunk, dict):
|
636 |
content = str(chunk.get('content', '')) # Convert content to string
|
637 |
chunk_type = chunk.get('type', 'message')
|
|
|
713 |
|
714 |
# Add file handling functions
|
715 |
def get_session_folder() -> str:
|
716 |
+
"""Get or create the session folder with improved error handling and validation"""
|
717 |
if not st.session_state.settings["use_workspace"]:
|
718 |
return "/"
|
719 |
|
720 |
try:
|
721 |
+
# Use custom workspace path if set
|
722 |
if st.session_state.get("session_dir"):
|
723 |
workspace_dir = Path(st.session_state.session_dir)
|
724 |
+
# Validate path is absolute and exists
|
725 |
+
if not workspace_dir.is_absolute():
|
726 |
+
workspace_dir = workspace_dir.resolve()
|
727 |
else:
|
728 |
# Use default workspace directory
|
729 |
+
workspace_dir = Path("autointerpreter-workspace").resolve()
|
730 |
+
|
731 |
+
# Validate and create directory
|
732 |
+
try:
|
733 |
+
# Check if path is writable
|
734 |
+
if workspace_dir.exists() and not os.access(str(workspace_dir), os.W_OK):
|
735 |
+
raise PermissionError(f"No write permission for {workspace_dir}")
|
736 |
+
|
737 |
+
workspace_dir.mkdir(parents=True, exist_ok=True, mode=0o755)
|
738 |
|
739 |
+
# Verify directory was created successfully
|
740 |
+
if not workspace_dir.is_dir():
|
741 |
+
raise OSError(f"Failed to create directory {workspace_dir}")
|
742 |
+
|
743 |
+
except (PermissionError, OSError) as e:
|
744 |
+
st.error(f"Error accessing workspace directory: {str(e)}")
|
745 |
+
# Fallback to temporary directory
|
746 |
+
import tempfile
|
747 |
+
workspace_dir = Path(tempfile.mkdtemp(prefix="autointerpreter-"))
|
748 |
+
st.warning(f"Using temporary workspace: {workspace_dir}")
|
749 |
|
750 |
+
# Create session directory if needed
|
751 |
if not st.session_state.get("session_dir"):
|
752 |
timestamp = datetime.now(timezone.utc).strftime("%Y-%m-%d_%H_%M")
|
753 |
session_dir = workspace_dir / f"session-{timestamp}"
|
754 |
+
try:
|
755 |
+
session_dir.mkdir(exist_ok=True, mode=0o755)
|
756 |
+
if not session_dir.is_dir():
|
757 |
+
raise OSError(f"Failed to create session directory {session_dir}")
|
758 |
+
|
759 |
+
st.session_state.session_dir = str(session_dir)
|
760 |
+
st.session_state.uploaded_files = []
|
761 |
+
update_custom_instructions()
|
762 |
+
except Exception as e:
|
763 |
+
st.error(f"Error creating session directory: {str(e)}")
|
764 |
+
return str(workspace_dir)
|
|
|
|
|
|
|
765 |
|
766 |
return st.session_state.session_dir
|
767 |
|
768 |
except Exception as e:
|
769 |
st.error(f"Error managing workspace: {str(e)}")
|
770 |
return "/"
|
771 |
+
|
772 |
def handle_file_upload(uploaded_files):
|
773 |
"""Enhanced file upload handling with better error handling and validation"""
|
774 |
if not uploaded_files:
|
|
|
897 |
elif file_type.startswith('application/pdf'):
|
898 |
return "π"
|
899 |
elif file_type.startswith('application/json'):
|
900 |
+
return "π"
|
901 |
elif 'python' in file_type.lower():
|
902 |
return "π"
|
903 |
elif 'javascript' in file_type.lower():
|
904 |
+
return "π"
|
905 |
elif 'spreadsheet' in file_type.lower():
|
906 |
return "π"
|
907 |
else:
|
|
|
909 |
|
910 |
# Add audio track selection handler
|
911 |
def update_audio_track():
|
912 |
+
"""Update the selected audio track with error handling"""
|
913 |
+
try:
|
914 |
+
new_track = st.session_state.audio_select
|
915 |
+
if new_track in audio_tracks:
|
916 |
+
st.session_state.selected_audio_track = new_track
|
917 |
+
save_settings() # Persist the audio track selection
|
918 |
+
else:
|
919 |
+
st.error(f"Invalid audio track selection: {new_track}")
|
920 |
+
# Fallback to default track
|
921 |
+
st.session_state.selected_audio_track = "Ambient"
|
922 |
+
except Exception as e:
|
923 |
+
st.error(f"Error updating audio track: {str(e)}")
|
924 |
+
st.session_state.selected_audio_track = "Ambient"
|
925 |
|
926 |
def create_audio_player():
|
927 |
+
"""Create a more robust audio player with error handling"""
|
928 |
+
return """
|
929 |
<div class="floating-audio">
|
930 |
+
<audio id="audio-player" controls loop preload="none" style="width: 250px; height: 40px;">
|
|
|
|
|
931 |
<source id="audio-source" src="{audio_tracks[st.session_state.selected_audio_track]}" type="audio/mpeg">
|
932 |
Your browser does not support the audio element.
|
933 |
</audio>
|
934 |
<select id="audio-select" onchange="updateAudio(this.value)"
|
935 |
+
style="width: 100%; padding: 5px; border-radius: 5px;">
|
936 |
+
{' '.join([f'<option value="{url}" {"selected" if name == st.session_state.selected_audio_track else ""}'>{name}</option>'
|
937 |
for name, url in audio_tracks.items()])}
|
938 |
</select>
|
939 |
+
<div id="audio-status" style="font-size: 0.8em; color: #666; text-align: center;"></div>
|
940 |
</div>
|
941 |
<script>
|
942 |
+
function setAudioStatus(message, isError = false) {
|
943 |
+
const status = document.getElementById('audio-status');
|
944 |
+
if (status) {
|
945 |
+
status.textContent = message;
|
946 |
+
status.style.color = isError ? '#dc2626' : '#666';
|
947 |
+
}
|
948 |
+
}
|
949 |
+
|
950 |
+
function handleAudioError() {
|
951 |
console.error('Audio playback error');
|
952 |
const player = document.getElementById('audio-player');
|
953 |
player.style.opacity = '0.5';
|
954 |
+
setAudioStatus('Error loading audio', true);
|
955 |
+
}
|
956 |
|
957 |
+
function handleAudioLoaded() {
|
958 |
const player = document.getElementById('audio-player');
|
959 |
player.style.opacity = '1';
|
960 |
+
setAudioStatus('Ready to play');
|
961 |
+
}
|
962 |
|
963 |
+
function updateAudio(url) {
|
964 |
+
try {
|
965 |
+
const audioPlayer = document.getElementById('audio-player');
|
966 |
+
const audioSource = document.getElementById('audio-source');
|
967 |
+
const wasPlaying = !audioPlayer.paused;
|
968 |
+
|
969 |
+
setAudioStatus('Loading...');
|
970 |
+
audioSource.src = url;
|
971 |
+
audioPlayer.load();
|
972 |
+
|
973 |
+
if (wasPlaying) {
|
974 |
+
audioPlayer.play().catch(error => {
|
975 |
+
console.error('Error playing audio:', error);
|
976 |
+
setAudioStatus('Playback error', true);
|
977 |
+
});
|
978 |
+
}
|
979 |
+
} catch (error) {
|
980 |
console.error('Error updating audio:', error);
|
981 |
+
setAudioStatus('Update error', true);
|
982 |
+
}
|
983 |
+
}
|
984 |
|
985 |
+
document.addEventListener('DOMContentLoaded', function() {
|
|
|
986 |
const audioPlayer = document.getElementById('audio-player');
|
987 |
let retryCount = 0;
|
988 |
const maxRetries = 3;
|
989 |
|
990 |
+
audioPlayer.addEventListener('error', function() {
|
991 |
+
if (retryCount < maxRetries) {
|
992 |
+
setTimeout(() => {
|
993 |
console.log('Retrying audio load...');
|
994 |
+
setAudioStatus('Retrying...');
|
995 |
audioPlayer.load();
|
996 |
retryCount++;
|
997 |
+
}, 1000 * retryCount);
|
998 |
+
} else {
|
999 |
+
setAudioStatus('Failed to load audio', true);
|
1000 |
+
}
|
1001 |
+
});
|
1002 |
+
|
1003 |
+
audioPlayer.addEventListener('playing', function() {
|
1004 |
+
setAudioStatus('Playing');
|
1005 |
+
});
|
1006 |
+
|
1007 |
+
audioPlayer.addEventListener('pause', function() {
|
1008 |
+
setAudioStatus('Paused');
|
1009 |
+
});
|
1010 |
+
});
|
1011 |
</script>
|
1012 |
+
""".format(
|
1013 |
+
audio_tracks=audio_tracks,
|
1014 |
+
st=st
|
1015 |
+
)
|
1016 |
|
1017 |
def cleanup_old_sessions():
|
1018 |
"""Clean up old session directories with improved error handling and format detection"""
|
|
|
1329 |
# System Message Settings
|
1330 |
st.text_area(
|
1331 |
"Default System Message",
|
1332 |
+
value=interpreter_instance.system_message,
|
1333 |
disabled=True,
|
1334 |
help="Base instructions for the AI assistant",
|
1335 |
height=100
|