Sami commited on
Commit
dda6248
Β·
1 Parent(s): 2f8eb98

Sync changes - automated commit

Browse files
Files changed (1) hide show
  1. app.py +140 -85
app.py CHANGED
@@ -1,5 +1,5 @@
1
  import streamlit as st
2
- from interpreter import interpreter
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": interpreter.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
- interpreter.reset()
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
- interpreter.llm.api_key = st.session_state.settings["api_key"]
127
- interpreter.llm.api_base = st.session_state.settings["api_base"]
128
- interpreter.llm.model = st.session_state.settings["model"]
129
- interpreter.auto_run = st.session_state.settings["auto_run"]
130
- interpreter.llm.temperature = 0.7
131
- interpreter.llm.repetition_penalty = 1.2
132
- interpreter.safe_mode = "off"
133
- interpreter.conversation_history = True # Force this to False
134
- interpreter.os = st.session_state.settings["os_mode"]
135
 
136
- # Set allowed paths
137
- interpreter.computer.allowed_paths = [get_session_folder()] if st.session_state.settings["use_workspace"] else \
138
- st.session_state.settings["allowed_paths"]
 
 
139
 
140
  # Update system message
141
- interpreter.system_message = st.session_state.original_system_message
142
  if st.session_state.settings["custom_instructions"]:
143
- interpreter.system_message += f"\n\nAdditional Instructions:\n{st.session_state.settings['custom_instructions']}"
144
 
145
  if st.session_state.settings["use_workspace"]:
146
  workspace_path = get_session_folder()
147
- interpreter.system_message += f"\n\nWorkspace Path: {workspace_path}\nYou can only access files in this workspace directory."
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
- interpreter.messages = [] # Clear interpreter's message history
190
- interpreter.reset() # Full reset of interpreter
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 interpreter.chat(user_input, stream=True, display=False):
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 for file uploads with proper error handling"""
714
  if not st.session_state.settings["use_workspace"]:
715
  return "/"
716
 
717
  try:
718
- # If a custom workspace path is set, use it
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
- # Create directory if it doesn't exist
726
- workspace_dir.mkdir(parents=True, exist_ok=True, mode=0o755)
 
 
 
 
 
 
 
 
727
 
728
- # If no session directory is set, create one
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
- session_dir.mkdir(exist_ok=True, mode=0o755)
733
- st.session_state.session_dir = str(session_dir)
734
- st.session_state.uploaded_files = []
735
- update_custom_instructions()
736
-
737
- # Verify the workspace directory exists and is accessible
738
- if not workspace_dir.exists():
739
- st.error(f"Workspace directory not found: {workspace_dir}")
740
- # Create a new default workspace
741
- workspace_dir = Path("autointerpreter-workspace")
742
- workspace_dir.mkdir(parents=True, exist_ok=True, mode=0o755)
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
- st.session_state.selected_audio_track = st.session_state.audio_select
 
 
 
 
 
 
 
 
 
 
 
894
 
895
  def create_audio_player():
896
- return f"""
 
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; border: 1px solid var(--border-color);">
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 handleAudioError() {{
 
 
 
 
 
 
 
 
912
  console.error('Audio playback error');
913
  const player = document.getElementById('audio-player');
914
  player.style.opacity = '0.5';
915
- player.title = 'Error loading audio';
916
- }}
917
 
918
- function handleAudioLoaded() {{
919
  const player = document.getElementById('audio-player');
920
  player.style.opacity = '1';
921
- player.title = '';
922
- }}
923
 
924
- function updateAudio(url) {{
925
- try {{
926
- const audioPlayer = document.getElementById('audio-player');
927
- const audioSource = document.getElementById('audio-source');
928
- const wasPlaying = !audioPlayer.paused;
929
- audioSource.src = url;
930
- audioPlayer.load();
931
- if (wasPlaying) {{
932
- const playPromise = audioPlayer.play();
933
- if (playPromise !== undefined) {{
934
- playPromise.catch(error => {{
935
- console.error('Error playing audio:', error);
936
- }});
937
- }}
938
- }} catch (error) {{
 
 
939
  console.error('Error updating audio:', error);
940
- }}
941
- }}
 
942
 
943
- // Add auto-retry for failed audio loads
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
- }}, 1000 * retryCount);
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=interpreter.system_message,
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