NeuralAI / from-scratch /web_ui /tools_api.py
Subject-Emu-5259's picture
Push NeuralAI project files - training data, scripts, services, knowledge base
38b4eff verified
Raw
History Blame Contribute Delete
23.2 kB
# tools_api.py
#
# Flask API endpoints for NeuralAI tools
# - Code execution (Python, JavaScript)
# - File management
# - Web fetching
# - Database operations
# - Git operations
import json
import sys
import os
from pathlib import Path
from flask import Blueprint, jsonify, request
# Add tools to path
TOOLS_PATH = Path(__file__).resolve().parent.parent.parent / "tools"
if str(TOOLS_PATH) not in sys.path:
sys.path.insert(0, str(TOOLS_PATH))
try:
from code_sandbox import CodeSandbox
from file_manager import FileManager
from web_fetcher import WebFetcher
from db_connector import DatabaseConnector
from git_assistant import GitAssistant
TOOLS_AVAILABLE = True
except ImportError as e:
print(f"[Tools API] Import error: {e}")
TOOLS_AVAILABLE = False
CodeSandbox = None
FileManager = None
WebFetcher = None
DatabaseConnector = None
GitAssistant = None
# Create blueprint
tools_bp = Blueprint('tools', __name__, url_prefix='/api/tools')
# Initialize tools
if TOOLS_AVAILABLE:
sandbox = CodeSandbox()
file_mgr = FileManager(base_dir=str(Path(__file__).resolve().parent.parent.parent.parent))
web_fetcher = WebFetcher()
db_conn = DatabaseConnector()
git_helper = GitAssistant()
else:
sandbox = None
file_mgr = None
web_fetcher = None
db_conn = None
git_helper = None
# ========================================
# CODE EXECUTION
# ========================================
@tools_bp.route('/execute', methods=['POST'])
def execute_code():
"""Execute Python or JavaScript code."""
if not sandbox:
return jsonify({"error": "Code sandbox not available", "success": False}), 503
data = request.get_json(silent=True) or {}
code = data.get('code', '')
language = data.get('language', 'python').lower()
timeout = data.get('timeout', 30)
if not code:
return jsonify({"error": "No code provided", "success": False}), 400
if language == 'python':
result = sandbox.run_python(code, timeout=timeout)
elif language in ('javascript', 'js'):
result = sandbox.run_javascript(code, timeout=timeout)
else:
return jsonify({"error": f"Unsupported language: {language}", "success": False}), 400
return jsonify({
"success": result.get("success", False),
"output": result.get("output", ""),
"error": result.get("error", ""),
"exit_code": result.get("exit_code", -1),
"execution_time": result.get("execution_time", 0),
"language": language
})
@tools_bp.route('/execute/python', methods=['POST'])
def execute_python():
"""Execute Python code specifically."""
data = request.get_json(silent=True) or {}
data['language'] = 'python'
return execute_code()
@tools_bp.route('/execute/javascript', methods=['POST'])
def execute_javascript():
"""Execute JavaScript code specifically."""
data = request.get_json(silent=True) or {}
data['language'] = 'javascript'
return execute_code()
# ========================================
# FILE MANAGEMENT
# ========================================
@tools_bp.route('/files/list', methods=['POST'])
def list_files_tool():
"""List files in a directory."""
if not file_mgr:
return jsonify({"error": "File manager not available", "success": False}), 503
data = request.get_json(silent=True) or {}
path = data.get('path', '.')
result = file_mgr.list_dir(path)
return jsonify({
"success": result.get("success", True),
"path": path,
"directories": result.get("directories", []),
"files": result.get("files", [])
})
@tools_bp.route('/files/read', methods=['POST'])
def read_file_tool():
"""Read a file."""
if not file_mgr:
return jsonify({"error": "File manager not available", "success": False}), 503
data = request.get_json(silent=True) or {}
filepath = data.get('path', '')
if not filepath:
return jsonify({"error": "No path provided", "success": False}), 400
result = file_mgr.read_file(filepath)
return jsonify({
"success": result.get("success", False),
"content": result.get("content", ""),
"error": result.get("error", ""),
"path": filepath
})
@tools_bp.route('/files/write', methods=['POST'])
def write_file_tool():
"""Write content to a file."""
if not file_mgr:
return jsonify({"error": "File manager not available", "success": False}), 503
data = request.get_json(silent=True) or {}
filepath = data.get('path', '')
content = data.get('content', '')
if not filepath:
return jsonify({"error": "No path provided", "success": False}), 400
result = file_mgr.write_file(filepath, content)
return jsonify({
"success": result.get("success", False),
"path": filepath,
"bytes_written": result.get("bytes_written", 0),
"error": result.get("error", "")
})
@tools_bp.route('/files/search', methods=['POST'])
def search_files_tool():
"""Search for files by name or content."""
if not file_mgr:
return jsonify({"error": "File manager not available", "success": False}), 503
data = request.get_json(silent=True) or {}
query = data.get('query', '')
path = data.get('path', '.')
search_type = data.get('type', 'filename') # filename or content
if not query:
return jsonify({"error": "No search query provided", "success": False}), 400
if search_type == 'content':
result = file_mgr.search(query, path, search_content=True)
else:
result = file_mgr.search(query, path, search_content=False)
return jsonify({
"success": result.get("success", True),
"query": query,
"matches": result.get("matches", []),
"count": len(result.get("matches", []))
})
# ========================================
# WEB FETCHING
# ========================================
@tools_bp.route('/web/fetch', methods=['POST'])
def fetch_url_tool():
"""Fetch content from a URL."""
if not web_fetcher:
return jsonify({"error": "Web fetcher not available", "success": False}), 503
data = request.get_json(silent=True) or {}
url = data.get('url', '')
timeout = data.get('timeout', 30)
if not url:
return jsonify({"error": "No URL provided", "success": False}), 400
result = web_fetcher.fetch(url, timeout=timeout)
return jsonify({
"success": result.get("success", False),
"url": url,
"content": result.get("content", ""),
"title": result.get("title", ""),
"links": result.get("links", [])[:20], # Limit links
"error": result.get("error", "")
})
@tools_bp.route('/web/extract', methods=['POST'])
def extract_from_url():
"""Extract specific data from a URL."""
if not web_fetcher:
return jsonify({"error": "Web fetcher not available", "success": False}), 503
data = request.get_json(silent=True) or {}
url = data.get('url', '')
extract_type = data.get('extract', 'text') # text, links, meta, all
if not url:
return jsonify({"error": "No URL provided", "success": False}), 400
result = web_fetcher.fetch(url)
if not result.get("success"):
return jsonify({"success": False, "error": result.get("error", "Fetch failed")})
response = {"success": True, "url": url}
if extract_type in ('text', 'all'):
response['text'] = result.get('content', '')
if extract_type in ('links', 'all'):
response['links'] = result.get('links', [])
if extract_type in ('meta', 'all'):
response['meta'] = result.get('meta', {})
return jsonify(response)
# ========================================
# DATABASE OPERATIONS
# ========================================
@tools_bp.route('/db/query', methods=['POST'])
def query_database():
"""Execute a SQL query."""
if not db_conn:
return jsonify({"error": "Database connector not available", "success": False}), 503
data = request.get_json(silent=True) or {}
db_path = data.get('database', '')
query = data.get('query', '')
params = data.get('params', [])
if not query:
return jsonify({"error": "No query provided", "success": False}), 400
# Default to NeuralAI's database if not specified
if not db_path:
db_path = str(Path(__file__).resolve().parent / "neuralai.db")
result = db_conn.execute_query(db_path, query, params)
return jsonify({
"success": result.get("success", False),
"rows": result.get("rows", []),
"row_count": len(result.get("rows", [])),
"columns": result.get("columns", []),
"error": result.get("error", "")
})
@tools_bp.route('/db/schema', methods=['POST'])
def get_database_schema():
"""Get database schema."""
if not db_conn:
return jsonify({"error": "Database connector not available", "success": False}), 503
data = request.get_json(silent=True) or {}
db_path = data.get('database', '')
if not db_path:
db_path = str(Path(__file__).resolve().parent / "neuralai.db")
result = db_conn.get_schema(db_path)
return jsonify({
"success": result.get("success", False),
"tables": result.get("tables", []),
"error": result.get("error", "")
})
@tools_bp.route('/db/tables', methods=['POST'])
def list_tables():
"""List all tables in database."""
if not db_conn:
return jsonify({"error": "Database connector not available", "success": False}), 503
data = request.get_json(silent=True) or {}
db_path = data.get('database', '')
if not db_path:
db_path = str(Path(__file__).resolve().parent / "neuralai.db")
result = db_conn.list_tables(db_path)
return jsonify({
"success": result.get("success", False),
"tables": result.get("tables", []),
"error": result.get("error", "")
})
# ========================================
# GIT OPERATIONS
# ========================================
@tools_bp.route('/git/status', methods=['POST'])
def git_status():
"""Get git status."""
if not git_helper:
return jsonify({"error": "Git assistant not available", "success": False}), 503
data = request.get_json(silent=True) or {}
repo_path = data.get('path', '.')
result = git_helper.status(repo_path)
return jsonify({
"success": result.get("success", False),
"branch": result.get("branch", ""),
"staged": result.get("staged", []),
"modified": result.get("modified", []),
"untracked": result.get("untracked", []),
"ahead": result.get("ahead", 0),
"behind": result.get("behind", 0),
"error": result.get("error", "")
})
@tools_bp.route('/git/log', methods=['POST'])
def git_log():
"""Get git log."""
if not git_helper:
return jsonify({"error": "Git assistant not available", "success": False}), 503
data = request.get_json(silent=True) or {}
repo_path = data.get('path', '.')
limit = data.get('limit', 10)
result = git_helper.log(repo_path, limit=limit)
return jsonify({
"success": result.get("success", False),
"commits": result.get("commits", []),
"count": len(result.get("commits", [])),
"error": result.get("error", "")
})
@tools_bp.route('/git/diff', methods=['POST'])
def git_diff():
"""Get git diff."""
if not git_helper:
return jsonify({"error": "Git assistant not available", "success": False}), 503
data = request.get_json(silent=True) or {}
repo_path = data.get('path', '.')
staged = data.get('staged', False)
result = git_helper.diff(repo_path, staged=staged)
return jsonify({
"success": result.get("success", False),
"diff": result.get("diff", ""),
"error": result.get("error", "")
})
@tools_bp.route('/git/commit', methods=['POST'])
def git_commit():
"""Create a git commit."""
if not git_helper:
return jsonify({"error": "Git assistant not available", "success": False}), 503
data = request.get_json(silent=True) or {}
repo_path = data.get('path', '.')
message = data.get('message', '')
add_all = data.get('add_all', True)
if not message:
return jsonify({"error": "Commit message required", "success": False}), 400
result = git_helper.commit(repo_path, message, add_all=add_all)
return jsonify({
"success": result.get("success", False),
"commit_hash": result.get("commit_hash", ""),
"message": message,
"error": result.get("error", "")
})
@tools_bp.route('/git/push', methods=['POST'])
def git_push():
"""Push to remote."""
if not git_helper:
return jsonify({"error": "Git assistant not available", "success": False}), 503
data = request.get_json(silent=True) or {}
repo_path = data.get('path', '.')
remote = data.get('remote', 'origin')
branch = data.get('branch', None)
result = git_helper.push(repo_path, remote=remote, branch=branch)
return jsonify({
"success": result.get("success", False),
"output": result.get("output", ""),
"error": result.get("error", "")
})
@tools_bp.route('/git/branch', methods=['POST'])
def git_branch():
"""List or create branches."""
if not git_helper:
return jsonify({"error": "Git assistant not available", "success": False}), 503
data = request.get_json(silent=True) or {}
repo_path = data.get('path', '.')
action = data.get('action', 'list') # list, create, switch
branch_name = data.get('branch', '')
if action == 'list':
result = git_helper.list_branches(repo_path)
return jsonify({
"success": result.get("success", False),
"branches": result.get("branches", []),
"current": result.get("current", ""),
"error": result.get("error", "")
})
if action == 'create' and branch_name:
result = git_helper.create_branch(repo_path, branch_name)
return jsonify({
"success": result.get("success", False),
"branch": branch_name,
"error": result.get("error", "")
})
return jsonify({"error": "Invalid action or missing branch name", "success": False}), 400
# ========================================
# TOOL STATUS
# ========================================
@tools_bp.route('/status', methods=['GET'])
def tools_status():
"""Get status of all tools."""
return jsonify({
"available": TOOLS_AVAILABLE,
"tools": {
"code_sandbox": sandbox is not None,
"file_manager": file_mgr is not None,
"web_fetcher": web_fetcher is not None,
"database": db_conn is not None,
"git": git_helper is not None
}
})
# ========================================
# HELPER: Execute tool by name
# ========================================
def generate_code_with_model(prompt: str, language: str = "python") -> str:
"""
Use the local model to generate code based on a prompt.
Returns the generated code string.
"""
try:
# Import the model from neuralai_engine
from neuralai_engine import local_model, tokenizer
import torch
if local_model is None or tokenizer is None:
return None
# Build a code generation prompt
if language == "python":
system_prompt = f"""You are a Python code generator. Write clean, working Python code.
Rules:
- Only output the code, no explanations
- Use standard library when possible
- Handle edge cases
- The code should be complete and runnable
User request: {prompt}
Write the Python code:"""
else:
system_prompt = f"""You are a JavaScript code generator. Write clean, working JavaScript code.
Rules:
- Only output the code, no explanations
- Use modern JavaScript (ES6+)
- Handle edge cases
- The code should be complete and runnable
User request: {prompt}
Write the JavaScript code:"""
# Tokenize and generate
inputs = tokenizer(system_prompt, return_tensors="pt")
if torch.cuda.is_available():
inputs = {k: v.cuda() for k, v in inputs.items()}
with torch.no_grad():
outputs = local_model.generate(
**inputs,
max_new_tokens=256,
temperature=0.7,
do_sample=True,
pad_token_id=tokenizer.eos_token_id
)
generated = tokenizer.decode(outputs[0], skip_special_tokens=True)
# Extract just the code part (after the prompt)
if "Write the " in generated:
code_start = generated.rfind("Write the ")
code = generated[code_start + len(f"Write the {language} code:"):]
else:
code = generated
# Clean up - remove markdown code blocks if present
if "```" in code:
import re
code_match = re.search(r'```(?:python|javascript|js)?\s*([\s\S]*?)```', code)
if code_match:
code = code_match.group(1).strip()
return code.strip()
except Exception as e:
print(f"[Code Gen] Error: {e}")
return None
def execute_tool(tool_name: str, params: dict) -> dict:
"""
Execute a tool by name with given parameters.
Used by the chat router to dispatch tool calls.
"""
if not TOOLS_AVAILABLE:
return {"success": False, "error": "Tools not available"}
try:
if tool_name == "terminal":
# Terminal is handled separately via WebSocket
return {"success": False, "error": "Use Terminal tab for shell commands"}
# NEW: Code generation + execution
if tool_name == "code_gen":
prompt = params.get("prompt", params.get("query", "write a simple program"))
language = params.get("language", "python")
# First, generate code using the model
generated_code = generate_code_with_model(prompt, language)
if not generated_code:
# Fallback to template code if model fails
if language == "python":
generated_code = f'''# Generated Python code
# Request: {prompt}
def main():
print("Hello from NeuralAI!")
# Add your logic here
pass
if __name__ == "__main__":
main()
'''
else:
generated_code = f'''// Generated JavaScript code
// Request: {prompt}
function main() {{
console.log("Hello from NeuralAI!");
// Add your logic here
}}
main();
'''
# Now execute the generated code
if language == "python":
result = sandbox.run_python(generated_code, timeout=params.get("timeout", 30))
elif language in ("javascript", "js"):
result = sandbox.run_javascript(generated_code, timeout=params.get("timeout", 30))
else:
return {"success": False, "error": f"Unsupported language: {language}"}
# Return both the generated code and execution result
return {
"success": result.get("success", False),
"generated_code": generated_code,
"output": result.get("output", ""),
"error": result.get("error", ""),
"execution_time": result.get("execution_time", 0),
"language": language
}
if tool_name == "code_exec":
code = params.get("code", "")
language = params.get("language", "python")
timeout = params.get("timeout", 30)
if language == "python":
return sandbox.run_python(code, timeout=timeout)
elif language in ("javascript", "js"):
return sandbox.run_javascript(code, timeout=timeout)
else:
return {"success": False, "error": f"Unsupported language: {language}"}
if tool_name == "file_manager":
action = params.get("action", "list")
if action == "list":
return file_mgr.list_dir(params.get("path", "."))
elif action == "read":
return file_mgr.read_file(params.get("path", ""))
elif action == "write":
return file_mgr.write_file(params.get("path", ""), params.get("content", ""))
elif action == "search":
return file_mgr.search(params.get("query", ""), params.get("path", "."), search_content=False)
elif action == "search_content":
return file_mgr.search(params.get("query", ""), params.get("path", "."), search_content=True)
return {"success": False, "error": f"Unknown file action: {action}"}
if tool_name == "web_fetcher":
url = params.get("url", "")
return web_fetcher.fetch(url, timeout=params.get("timeout", 30))
if tool_name == "database":
db_path = params.get("database", str(Path(__file__).resolve().parent / "neuralai.db"))
query = params.get("query", "")
if query.lower().startswith(("select", "pragma")):
return db_conn.execute_query(db_path, query)
elif "schema" in params.get("action", "").lower():
return db_conn.get_schema(db_path)
elif "tables" in params.get("action", "").lower():
return db_conn.list_tables(db_path)
return db_conn.execute_query(db_path, query)
if tool_name == "git":
action = params.get("action", "status")
repo_path = params.get("path", ".")
# Create a new GitAssistant with the specified path
from git_assistant import GitAssistant as _GitAssistant
git = _GitAssistant(repo_path)
if action == "status":
return git.status()
elif action == "log":
return git.log(limit=params.get("limit", 10))
elif action == "diff":
return git.diff(staged=params.get("staged", False))
elif action == "commit":
return git.commit(params.get("message", ""), add_all=params.get("add_all", True))
elif action == "push":
return git.push(remote=params.get("remote", "origin"))
elif action == "branch":
return git.list_branches()
return {"success": False, "error": f"Unknown git action: {action}"}
return {"success": False, "error": f"Unknown tool: {tool_name}"}
except Exception as e:
return {"success": False, "error": str(e)}