Skip to content

Commit

Permalink
improve path logic
Browse files Browse the repository at this point in the history
  • Loading branch information
bigsk1 committed Jul 25, 2024
1 parent b0c7835 commit 1816f76
Show file tree
Hide file tree
Showing 6 changed files with 281 additions and 273 deletions.
20 changes: 6 additions & 14 deletions automode_logic.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,15 @@
import json
import logging
from typing import AsyncGenerator
from anthropic import Anthropic
from pydantic import BaseModel
from fastapi import HTTPException
from config import PROJECTS_DIR, CLAUDE_MODEL
from config import PROJECTS_DIR, CLAUDE_MODEL, anthropic_client


# Set up logging
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)

# Initialize Anthropic client
anthropic_client = Anthropic(api_key=os.getenv("ANTHROPIC_API_KEY"))

#CLAUDE_MODEL = os.getenv("CLAUDE_MODEL", "claude-3-5-sonnet-20240620")
#PROJECTS_DIR = "projects"

SEARCH_PROVIDER = os.getenv("SEARCH_PROVIDER", "SEARXNG")

class SSEMessage(BaseModel):
Expand All @@ -43,18 +36,17 @@ class AutomodeRequest(BaseModel):

def create_folder(path):
try:
if not os.path.exists(path):
os.makedirs(path)
return f"Folder created: {path}"
full_path = os.path.join(PROJECTS_DIR, path)
os.makedirs(full_path, exist_ok=True)
return f"Folder created: {full_path}"
except Exception as e:
logger.error(f"Error creating folder: {str(e)}", exc_info=True)
return f"Error creating folder: {str(e)}"

def create_file(path: str, content: str = "") -> str:
try:
full_path = os.path.join(path)
if not os.path.exists(os.path.dirname(full_path)):
os.makedirs(os.path.dirname(full_path))
full_path = os.path.join(PROJECTS_DIR, path)
os.makedirs(os.path.dirname(full_path), exist_ok=True)
with open(full_path, 'w') as file:
file.write(content)
return f"File created: {full_path}"
Expand Down
137 changes: 74 additions & 63 deletions backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,15 @@
from pydantic import BaseModel
from dotenv import load_dotenv
from automode_logic import AutomodeRequest, start_automode_logic
from config import PROJECTS_DIR, UPLOADS_DIR, SEARCH_PROVIDER, CLAUDE_MODEL
from config import PROJECTS_DIR, UPLOADS_DIR, SEARCH_PROVIDER, CLAUDE_MODEL, anthropic_client
from shared_utils import (
anthropic_client, system_prompt,
perform_search, encode_image_to_base64, create_folder, create_file,
read_file, list_files, list_files_frontend, delete_file, read_file_frontend, delete_file_frontend, create_file_frontend,
write_to_file_frontend, create_folder_frontend, write_to_file
system_prompt, perform_search, encode_image_to_base64, create_folder, create_file,
read_file, list_files, delete_file, write_to_file
)

load_dotenv()


app = FastAPI()

api_router = APIRouter()
Expand Down Expand Up @@ -152,62 +151,56 @@ async def wrapper(*args, **kwargs):
async def create_project(request: ProjectRequest, path: str):
try:
project_name = f"{request.template.lower()}_project"
project_path = os.path.join(PROJECTS_DIR, path, project_name)
project_path = os.path.join(PROJECTS_DIR, path, project_name).replace('\\', '/')
os.makedirs(project_path, exist_ok=True)

if request.template == "react":
create_file(os.path.join(project_path, "package.json"), '{"name": "react-app", "version": "1.0.0"}')
create_file(os.path.join(project_path, "src/App.js"), 'import React from "react";\n\nfunction App() {\n return <div>Hello, React!</div>;\n}\n\nexport default App;')
create_file(os.path.join(project_path, "package.json").replace('\\', '/'), '{"name": "react-app", "version": "1.0.0"}')
create_file(os.path.join(project_path, "src/App.js").replace('\\', '/'), 'import React from "react";\n\nfunction App() {\n return <div>Hello, React!</div>;\n}\n\nexport default App;')
elif request.template == "node":
create_file(os.path.join(project_path, "package.json"), '{"name": "node-app", "version": "1.0.0"}')
create_file(os.path.join(project_path, "index.js"), 'console.log("Hello, Node.js!");')
create_file(os.path.join(project_path, "package.json").replace('\\', '/'), '{"name": "node-app", "version": "1.0.0"}')
create_file(os.path.join(project_path, "index.js").replace('\\', '/'), 'console.log("Hello, Node.js!");')
elif request.template == "python":
create_file(os.path.join(project_path, "main.py"), 'print("Hello, Python!")')
create_file(os.path.join(project_path, "requirements.txt"), '')
create_file(os.path.join(project_path, "main.py").replace('\\', '/'), 'print("Hello, Python!")')
create_file(os.path.join(project_path, "requirements.txt").replace('\\', '/'), '')
else:
raise ValueError(f"Unknown project template: {request.template}")

return {"message": f"{request.template} project created successfully at {os.path.relpath(project_path, PROJECTS_DIR)}"}
return {"message": f"{request.template} project created successfully at {os.path.relpath(project_path, PROJECTS_DIR).replace('\\', '/')}"}
except Exception as e:
logger.error(f"Error creating project: {str(e)}", exc_info=True)
raise HTTPException(status_code=500, detail=f"Error creating project: {str(e)}")


@app.get("/list_files")
@safe_path_operation
async def get_file_list(path: str = Query(...)):
logger.debug(f"Received path: {path}")
files = list_files_frontend(path)
if not files and path:
raise HTTPException(status_code=404, detail="Directory not found")
return {"files": files, "currentDirectory": path}


@app.post("/create_folder")
@safe_path_operation
async def create_folder_endpoint(path: str = Query(...)):
result = create_folder_frontend(path)
if "Error" in result:
raise HTTPException(status_code=500, detail=result)
return {"message": result}
try:
result = create_folder(path)
logger.info(f"Folder created: {path}")
return {"message": result}
except Exception as e:
logger.error(f"Error creating folder: {str(e)}", exc_info=True)
raise HTTPException(status_code=500, detail=str(e))

@app.post("/create_file")
@safe_path_operation
async def create_file_endpoint(path: str = Query(...), content: str = ""):
logger.debug(f"Received path: {path}")
result = create_file_frontend(path, content)
if "Error" in result:
raise HTTPException(status_code=500, detail=result)
return {"message": result}
try:
result = create_file(path, content)
logger.info(f"File created: {path}")
return {"message": result}
except Exception as e:
logger.error(f"Error creating file: {str(e)}", exc_info=True)
raise HTTPException(status_code=500, detail=str(e))

@app.get("/read_file")
#@safe_path_operation
async def read_file_endpoint(path: str = Query(...)):
logger.debug(f"Received path: {path}")
content = read_file_frontend(path)
if "Error" in content:
raise HTTPException(status_code=404, detail=content)
return {"content": content}
try:
content = read_file(path)
logger.info(f"File read: {path}")
return {"content": content}
except Exception as e:
logger.error(f"Error reading file: {str(e)}", exc_info=True)
raise HTTPException(status_code=404, detail=str(e))

@app.post("/write_file")
async def write_file_endpoint(request: Request, path: str = Query(...)):
Expand All @@ -224,22 +217,36 @@ async def write_file_endpoint(request: Request, path: str = Query(...)):
if not content:
raise HTTPException(status_code=422, detail="Content is required")

result = write_to_file_frontend(path, content)
logger.debug(f"Path: {path}, Content: {content}")
result = write_to_file(path, content)
if "Error" in result:
raise HTTPException(status_code=500, detail=result)
return JSONResponse(content={"message": result})
except Exception as e:
logger.error(f"Error in write_file_endpoint: {str(e)}", exc_info=True)
raise HTTPException(status_code=500, detail="Internal Server Error")



@app.get("/list_files")
async def list_files_endpoint(path: str = Query(".")):
try:
files = list_files(path)
return {"files": files, "currentDirectory": path}
except Exception as e:
logger.error(f"Error listing files: {str(e)}", exc_info=True)
raise HTTPException(status_code=500, detail=str(e))

@app.delete("/delete_file")
@safe_path_operation
async def delete_file_endpoint(path: str = Query(...)):
logger.debug(f"Received path: {path}")
result = delete_file_frontend(path)
if "Error" in result:
raise HTTPException(status_code=404, detail=result)
return {"message": result}
try:
result = delete_file(path)
logger.info(f"File deleted: {path}")
return {"message": result}
except Exception as e:
logger.error(f"Error deleting file: {str(e)}", exc_info=True)
raise HTTPException(status_code=500, detail=str(e))


@app.post("/upload")
async def upload_file(file: UploadFile = File(...)):
Expand Down Expand Up @@ -267,17 +274,18 @@ async def analyze_image(file: UploadFile = File(...)):
logger.debug(f"Received file: {file.filename}, content_type: {file.content_type}")
contents = await file.read()
logger.debug(f"File contents read, length: {len(contents)} bytes")

encoded_image = encode_image_to_base64(contents)
logger.debug(f"Image encoded, length: {len(encoded_image)}")

if encoded_image.startswith("Error encoding image:"):
raise ValueError(encoded_image)


logger.debug(f"Image encoded, length: {len(encoded_image)}")

analysis_result = anthropic_client.messages.create(
model=CLAUDE_MODEL,
max_tokens=1000,
system=system_prompt, # Use system parameter instead of including it in messages
system=system_prompt,
messages=[
{
"role": "user",
Expand All @@ -286,7 +294,7 @@ async def analyze_image(file: UploadFile = File(...)):
"type": "image",
"source": {
"type": "base64",
"media_type": file.content_type,
"media_type": "image/jpeg",
"data": encoded_image
}
},
Expand Down Expand Up @@ -321,15 +329,15 @@ async def search(query: SearchQuery):
# Chat endpoint
@app.post("/chat")
async def chat(request: ChatRequest):
global conversation_history #automode
global conversation_history
try:
message = request.message
conversation_history.append({"role": "user", "content": message})

logger.info(f"Sending message to AI: {message}")
response = anthropic_client.messages.create(
model=CLAUDE_MODEL,
max_tokens=4096, # Adjust this value if necessary
max_tokens=4096,
system=system_prompt,
messages=conversation_history,
tools=tools
Expand All @@ -347,20 +355,19 @@ async def chat(request: ChatRequest):
tool_input = content.input
logger.info(f"Tool used: {tool_name}, Input: {tool_input}")
tool_result = execute_tool(tool_name, tool_input)
response_content += f"\nTool used: {tool_name}\nTool result: {tool_result}\n"
if tool_result['success']:
response_content += f"\nTool used: {tool_name}\nTool result: {tool_result['result']}\n"
else:
response_content += f"\nTool used: {tool_name}\nTool error: {tool_result['error']}\n"
logger.info(f"Tool result: {tool_result}")
# Add a follow-up message based on the tool used
if tool_name == "read_file" and "The file is empty." in tool_result:
response_content += "\nIt seems the file is empty. Would you like to add some content to it?"
elif tool_name == "write_to_file":
response_content += "\nI have successfully written the content to the file. Is there anything else you would like to do?"

conversation_history.append({"role": "assistant", "content": response_content})
return {"response": response_content}
except Exception as e:
logger.error(f"Error in chat endpoint: {str(e)}", exc_info=True)
raise HTTPException(status_code=500, detail=str(e))


@api_router.get("/download_projects")
async def download_projects():
if not os.path.exists(PROJECTS_DIR):
Expand Down Expand Up @@ -621,6 +628,7 @@ async def pip_install(request: CommandRequest):
def execute_tool(tool_name, tool_input):
try:
logger.debug(f"Executing tool: {tool_name} with input: {tool_input}")
result = None
if tool_name == "create_folder":
result = create_folder(tool_input["path"])
elif tool_name == "create_file":
Expand All @@ -629,19 +637,22 @@ def execute_tool(tool_name, tool_input):
result = write_to_file(tool_input["path"], tool_input["content"])
elif tool_name == "read_file":
result = read_file(tool_input["path"])
if result.startswith("File not found:") or result.startswith("Error reading file:"):
return {"success": False, "error": result}
elif tool_name == "list_files":
result = list_files(tool_input["path"])
elif tool_name == "delete_file":
result = delete_file(tool_input["path"])
elif tool_name == "search":
result = perform_search(tool_input["query"])
else:
result = f"Unknown tool: {tool_name}"
return {"success": False, "error": f"Unknown tool: {tool_name}"}

logger.debug(f"Tool result: {result}")
return result
return {"success": True, "result": result}
except Exception as e:
logger.error(f"Error executing tool {tool_name}: {str(e)}", exc_info=True)
return f"Error executing tool {tool_name}: {str(e)}"
return {"success": False, "error": f"Error executing tool {tool_name}: {str(e)}"}


if __name__ == "__main__":
Expand Down
37 changes: 25 additions & 12 deletions config.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,36 @@
import os
from anthropic import Anthropic
from tavily import TavilyClient
from dotenv import load_dotenv


load_dotenv()

PROJECTS_DIR = os.path.abspath("projects")
if not os.path.exists(PROJECTS_DIR):
os.makedirs(PROJECTS_DIR)

UPLOADS_DIR = os.path.join(PROJECTS_DIR, "uploads")
if not os.path.exists(UPLOADS_DIR):
os.makedirs(UPLOADS_DIR)

SEARCH_PROVIDER = os.getenv("SEARCH_PROVIDER", "SEARXNG").upper()
TAVILY_API_KEY = os.getenv("TAVILY_API_KEY", None)

SEARXNG_URL = os.getenv("SEARXNG_URL", None)

TAVILY_API_KEY = os.getenv("TAVILY_API_KEY", None)

CLAUDE_MODEL = os.getenv("CLAUDE_MODEL", "claude-3-5-sonnet-20240620")

SEARCH_RESULTS_LIMIT = int(os.getenv('SEARXNG_RESULTS', '5'))


SEARCH_PROVIDER = os.getenv("SEARCH_PROVIDER", "SEARXNG").upper()


tavily_client = TavilyClient(api_key=TAVILY_API_KEY)

# Initialize Tavily client if needed
if SEARCH_PROVIDER == "TAVILY":
from tavily import TavilyClient
tavily_client = TavilyClient(api_key=TAVILY_API_KEY)


anthropic_client = Anthropic(api_key=os.getenv("ANTHROPIC_API_KEY"))

PROJECTS_DIR = os.path.abspath("projects")
if not os.path.exists(PROJECTS_DIR):
os.makedirs(PROJECTS_DIR)

UPLOADS_DIR = os.path.join(PROJECTS_DIR, "uploads")
if not os.path.exists(UPLOADS_DIR):
os.makedirs(UPLOADS_DIR)
Loading

0 comments on commit 1816f76

Please sign in to comment.