feat: editor and file tree
This commit is contained in:
parent
699c3c1dba
commit
e59cd2849b
@ -0,0 +1,30 @@
|
||||
import streamlit as st
|
||||
from pathlib import Path
|
||||
|
||||
WORKSPACE = Path("workspace")
|
||||
WORKSPACE.mkdir(exist_ok=True)
|
||||
|
||||
class FileManager:
|
||||
def __init__(self, base_path=Path("workspace")):
|
||||
self.base_path = Path(base_path)
|
||||
self.base_path.mkdir(exist_ok=True)
|
||||
|
||||
# read_file content
|
||||
|
||||
# save_file content
|
||||
|
||||
def get_file_tree(self):
|
||||
def build_tree(path: Path):
|
||||
|
||||
tree = {}
|
||||
|
||||
for item in sorted(path.iterdir()):
|
||||
if item.is_dir():
|
||||
tree[item.name] = build_tree(item)
|
||||
else:
|
||||
tree[item.name] = None
|
||||
return tree
|
||||
return build_tree(self.base_path)
|
||||
|
||||
if __name__ == "__main__":
|
||||
FileManager()
|
||||
@ -3,19 +3,30 @@ import streamlit as st
|
||||
def render_chat():
|
||||
st.subheader("Chat with AI Assistant")
|
||||
|
||||
if st.session_state.chat_history:
|
||||
for message in st.session_state.chat_history:
|
||||
st.markdown(f"**{message['role'].capitalize()}:** {message['content']}")
|
||||
chat_section = st.container()
|
||||
setup_section = st.container()
|
||||
|
||||
with chat_section:
|
||||
if st.session_state.chat_history:
|
||||
for message in st.session_state.chat_history:
|
||||
st.markdown(f"**{message['role'].capitalize()}:** {message['content']}")
|
||||
|
||||
user_input = st.text_input("Type your message here:", key="chat_input")
|
||||
|
||||
if st.button("Send", key="send_button") and user_input:
|
||||
st.session_state.chat_history.append({"role": "user", "content": user_input})
|
||||
# Here you would typically call your AI assistant to get a response
|
||||
# For demonstration, we'll just echo the user's message
|
||||
ai_response = f"Echo: {user_input}"
|
||||
st.session_state.chat_history.append({"role": "assistant", "content": ai_response})
|
||||
st.session_state.chat_input = "" # Clear input after sending
|
||||
|
||||
user_input = st.text_input("Type your message here:", key="chat_input")
|
||||
with setup_section:
|
||||
st.info("This is where you can set up your AI assistant. For now, this section is just a placeholder.")
|
||||
st.toggle("Use debug system prompt", key="use_system_prompt", value=True)
|
||||
|
||||
if st.button("Send", key="send_button") and user_input:
|
||||
st.session_state.chat_history.append({"role": "user", "content": user_input})
|
||||
# Here you would typically call your AI assistant to get a response
|
||||
# For demonstration, we'll just echo the user's message
|
||||
ai_response = f"Echo: {user_input}"
|
||||
st.session_state.chat_history.append({"role": "assistant", "content": ai_response})
|
||||
st.session_state.chat_input = "" # Clear input after sending
|
||||
# Here you could add options to configure the AI assistant, such as selecting a model, setting parameters, etc.
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
render_chat()
|
||||
@ -1,17 +1,65 @@
|
||||
import streamlit as st
|
||||
import streamlit_ace as st_ace
|
||||
from pathlib import Path
|
||||
from backend.managers.file_manager import FileManager
|
||||
|
||||
def render_editor():
|
||||
LANG_MAP = {
|
||||
".py": "python", ".tex": "latex", ".js": "javascript",
|
||||
".html": "html", ".css": "css", ".sh": "bash",
|
||||
".json": "json", ".yaml": "yaml", ".yml": "yaml"
|
||||
}
|
||||
|
||||
st.subheader("Code Editor")
|
||||
|
||||
if st.session_state.selected_file:
|
||||
st.text_area(
|
||||
"Edit your code here:",
|
||||
value=st.session_state.file_content,
|
||||
height=400,
|
||||
key="code_editor"
|
||||
)
|
||||
else:
|
||||
|
||||
if not st.session_state.open_files:
|
||||
st.info("Please select a file to edit.")
|
||||
return
|
||||
|
||||
fm = FileManager()
|
||||
|
||||
tab_names = [Path(f).name for f in st.session_state.open_files]
|
||||
tabs = st.tabs(tab_names)
|
||||
|
||||
for idx, file_path in enumerate(st.session_state.open_files):
|
||||
with tabs[idx]:
|
||||
st.session_state.active_file = file_path
|
||||
|
||||
if file_path not in st.session_state.files_content:
|
||||
st.session_state.files_content[file_path] = fm.read_file(file_path)
|
||||
|
||||
file_language = LANG_MAP.get(file_path.suffix, "text")
|
||||
|
||||
code = st_ace(
|
||||
value=st.session_state.files_content[file_path],
|
||||
language=file_language,
|
||||
theme="monokai",
|
||||
key=f"code_editor_{file_path}"
|
||||
)
|
||||
|
||||
st.session_state.files_content[file_path] = code
|
||||
|
||||
col1, col2 = st.columns([1, 1])
|
||||
with col1:
|
||||
if st.button("Save Changes", key=f"save_{file_path}"):
|
||||
fm.save_file(file_path, st.session_state.files_content[file_path])
|
||||
st.success("File saved successfully!")
|
||||
|
||||
with col2:
|
||||
if st.button("Close File", key=f"close_{file_path}"):
|
||||
st.session_state.open_files.remove(file_path)
|
||||
del st.session_state.files_content[file_path]
|
||||
st.success("File closed successfully!")
|
||||
|
||||
if st.session_state.active_file == file_path:
|
||||
st.session_state.active_file = (
|
||||
st.session_state.open_files[0]
|
||||
if st.session_state.open_files
|
||||
else None
|
||||
)
|
||||
|
||||
st.rerun() # Refresh the page to update the UI
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
render_editor()
|
||||
@ -1,4 +1,55 @@
|
||||
import streamlit as st
|
||||
from pathlib import Path
|
||||
from backend.managers.file_manager import FileManager
|
||||
|
||||
fm = FileManager()
|
||||
|
||||
def render_filetree(tree, parent_path=Path()):
|
||||
for name, content in sorted(tree.items()):
|
||||
full_path = parent_path / name
|
||||
|
||||
if isinstance(content, dict): # Directory
|
||||
with st.sidebar.expander(f"📁 {name}", expanded=False):
|
||||
render_filetree(content, full_path)
|
||||
else: # File
|
||||
cols= st.sidebar.columns([3, 1])
|
||||
with cols[0]:
|
||||
if st.sidebar.button(f"📄 {name}", key=str(full_path)):
|
||||
abs_path = fm.base_path / full_path
|
||||
|
||||
if str(abs_path) not in st.session_state.open_files:
|
||||
st.session_state.open_files.append(str(abs_path))
|
||||
|
||||
st.session_state.active_file = str(abs_path)
|
||||
|
||||
with cols[1]:
|
||||
show_options_key = f"show_options_{full_path}"
|
||||
if st.button("...", key=show_options_key):
|
||||
st.session_state[show_options_key] = not st.session_state.get(show_options_key, False)
|
||||
|
||||
if st.session_state.get(show_options_key, False):
|
||||
action = st.selectbox("", ["", "Rename", "Delete"], key=f"action_{full_path}", index=0)
|
||||
|
||||
if action == "Delete":
|
||||
st.warning("Are you sure you want to delete this file?")
|
||||
if st.button("Yes, delete file", key=f"confirm_delete_{full_path}"):
|
||||
try:
|
||||
(fm.base_path / full_path).unlink()
|
||||
st.experimental_rerun()
|
||||
except Exception as e:
|
||||
st.error(f"Error deleting file: {e}")
|
||||
|
||||
elif action == "Rename":
|
||||
new_name = st.text_input("New Name", key=f"rename_{full_path}")
|
||||
if "/" in new_name or "\\" in new_name:
|
||||
st.warning("Do not include slashes in names!")
|
||||
elif new_name:
|
||||
new_path = (fm.base_path / full_path.parent / new_name)
|
||||
try:
|
||||
(fm.base_path / full_path).rename(new_path)
|
||||
st.experimental_rerun()
|
||||
except Exception as e:
|
||||
st.error(f"Error renaming file: {e}")
|
||||
|
||||
def render_sidebar():
|
||||
st.sidebar.title("Navigation")
|
||||
@ -16,9 +67,36 @@ def render_sidebar():
|
||||
|
||||
with file_explorer_section:
|
||||
st.sidebar.subheader("File Explorer")
|
||||
st.sidebar.info("File Explorer functionality is not implemented yet.")
|
||||
# selected_file = st.sidebar.file_uploader("Upload a file", type=["py", "txt", "md"])
|
||||
tree = fm.get_file_tree()
|
||||
if not tree:
|
||||
st.sidebar.info("Workspace is empty.")
|
||||
else:
|
||||
render_filetree(tree)
|
||||
|
||||
st.sidebar.markdown("---")
|
||||
st.sidebar.write("Manage Files & Folders")
|
||||
|
||||
# Create Folder
|
||||
new_folder_name = st.sidebar.text_input("New Folder Name", key="new_folder_name")
|
||||
if "/" in new_folder_name or "\\" in new_folder_name:
|
||||
st.warning("Do not include slashes in names!")
|
||||
elif st.sidebar.button("Create Folder", key="create_folder") and new_folder_name:
|
||||
new_folder_path = fm.base_path / new_folder_name
|
||||
new_folder_path.mkdir(exist_ok=True)
|
||||
st.success(f"Folder '{new_folder_name}' created successfully!")
|
||||
st.experimental_rerun()
|
||||
|
||||
# Create File
|
||||
new_file_name = st.sidebar.text_input("New File Name", key="new_file_name")
|
||||
if "/" in new_file_name or "\\" in new_file_name:
|
||||
st.warning("Do not include slashes in names!")
|
||||
elif st.sidebar.button("Create File", key="create_file") and new_file_name:
|
||||
new_file_path = fm.base_path / new_file_name
|
||||
new_file_path.touch(exist_ok=True)
|
||||
st.success(f"File '{new_file_name}' created successfully!")
|
||||
st.experimental_rerun()
|
||||
|
||||
|
||||
|
||||
return choice
|
||||
|
||||
|
||||
@ -1,20 +1,27 @@
|
||||
import streamlit as st
|
||||
|
||||
def init_state():
|
||||
if "selected_file" not in st.session_state:
|
||||
st.session_state.selected_file = None
|
||||
# Editor state initialization
|
||||
if "open_files" not in st.session_state:
|
||||
st.session_state.open_files = []
|
||||
|
||||
if "file_content" not in st.session_state:
|
||||
st.session_state.file_content = ""
|
||||
if "files_content" not in st.session_state:
|
||||
st.session_state.files_content = {}
|
||||
|
||||
if "active_file" not in st.session_state:
|
||||
st.session_state.active_file = None
|
||||
|
||||
if "is_editing" not in st.session_state:
|
||||
st.session_state.is_editing = False
|
||||
|
||||
if "code_suggestions" not in st.session_state:
|
||||
st.session_state.code_suggestions = []
|
||||
|
||||
# Chat state initialization
|
||||
if "chat_history" not in st.session_state:
|
||||
st.session_state.chat_history = []
|
||||
|
||||
if "code_suggestions" not in st.session_state:
|
||||
st.session_state.code_suggestions = []
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
init_state()
|
||||
@ -18,3 +18,6 @@ pytest-cov>=4.0.0
|
||||
|
||||
# Development & Utilities
|
||||
python-dotenv>=1.0.0
|
||||
|
||||
#For code editor functionality
|
||||
streamlit-ace>=0.1.0
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user