diff --git a/app.py b/app.py index 2e1959a..0649402 100644 --- a/app.py +++ b/app.py @@ -1,9 +1,12 @@ import asyncio import threading +import tomllib import uuid import webbrowser from datetime import datetime +from functools import partial from json import dumps +from pathlib import Path from fastapi import Body, FastAPI, HTTPException, Request from fastapi.middleware.cors import CORSMiddleware @@ -135,7 +138,7 @@ async def run_task(task_id: str, prompt: str): async def __call__(self, message): import re - # 提取 - 后面的内容 + # Extract - Subsequent Content cleaned_message = re.sub(r"^.*? - ", "", message) event_type = "log" @@ -244,12 +247,32 @@ async def generic_exception_handler(request: Request, exc: Exception): ) -def open_local_browser(): - webbrowser.open_new_tab("http://localhost:5172") +def open_local_browser(config): + webbrowser.open_new_tab(f"http://{config['host']}:{config['port']}") + + +def load_config(): + try: + config_path = Path(__file__).parent / "config" / "config.toml" + + with open(config_path, "rb") as f: + config = tomllib.load(f) + + return {"host": config["server"]["host"], "port": config["server"]["port"]} + except FileNotFoundError: + raise RuntimeError( + "Configuration file not found, please check if config/fig.toml exists" + ) + except KeyError as e: + raise RuntimeError( + f"The configuration file is missing necessary fields: {str(e)}" + ) if __name__ == "__main__": import uvicorn - threading.Timer(3, open_local_browser).start() - uvicorn.run(app, host="localhost", port=5172) + config = load_config() + open_with_config = partial(open_local_browser, config) + threading.Timer(3, open_with_config).start() + uvicorn.run(app, host=config["host"], port=config["port"]) diff --git a/config/config.example.toml b/config/config.example.toml index c1d51f0..e1a0d8b 100644 --- a/config/config.example.toml +++ b/config/config.example.toml @@ -20,3 +20,8 @@ temperature = 0.0 model = "claude-3-5-sonnet" base_url = "https://api.openai.com/v1" api_key = "sk-..." + +# Server configuration +[server] +host = "localhost" +port = 5172 diff --git a/run.bat b/run.bat index 23bf078..d9272db 100644 --- a/run.bat +++ b/run.bat @@ -2,15 +2,41 @@ setlocal cd /d %~dp0 -call venv\Scripts\activate.bat +set "VENV_DIR=%~dp0venv" +set "PYTHON_PATH=%VENV_DIR%\python.exe" -echo Trying to sync with GitHub repository... -git pull origin front-end || ( - echo Failed to sync with GitHub, skipping update... +where git >nul 2>&1 +if !errorlevel! == 0 ( + echo Trying to sync with GitHub repository... + git pull origin front-end 2>&1 || echo Failed to sync with GitHub, skipping update... +) else ( + echo Git not detected, skipping code synchronization +) + +if not exist "%VENV_DIR%\" ( + echo Virtual environment not found, initializing installation... + python -m venv "%VENV_DIR%" || ( + echo Failed to create virtual environment, please install Python 3.12 first + pause + exit /b 1 + ) + call "%VENV_DIR%\Scripts\activate.bat" + pip install -r requirements.txt || ( + echo Dependency installation failed, please check requirements. txt + pause + exit /b 1 + ) ) echo Starting Python application... -python app.py +if not exist "%PYTHON_PATH%" ( + echo Error: Python executable file does not exist in %PYTHON_PATH% + echo Please try deleting the venv folder and running the script again + pause + exit /b 1 +) + +"%PYTHON_PATH%" "%~dp0app.py" pause endlocal diff --git a/static/main.js b/static/main.js index c219d20..9bfd2f3 100644 --- a/static/main.js +++ b/static/main.js @@ -38,6 +38,7 @@ function createTask() { } setupSSE(data.task_id); loadHistory(); + promptInput.value = ''; }) .catch(error => { container.innerHTML = `
${lastResultContent}-
${lastResultContent}+
${content}-
${content}+ ${fileInteractionHtml} +
${content}+
${content}+
+#This is the result of Python code simulation run +#The actual operational results may vary + +# Running ${filePath.split('/').pop()}... +print("Hello from Python Simulated environment!") + +# Code execution completed ++ `; + outputDiv.appendChild(resultElement); + }) + .catch(error => { + console.error('Error loading Python file:', error); + const outputDiv = modal.querySelector('.python-output'); + outputDiv.innerHTML = `Error loading file: ${error.message}`; + }); +} + document.addEventListener('DOMContentLoaded', () => { loadHistory(); @@ -304,4 +522,19 @@ document.addEventListener('DOMContentLoaded', () => { document.getElementById('prompt-input').focus(); }); } + + // Add keyboard event listener to close modal boxes + document.addEventListener('keydown', (e) => { + if (e.key === 'Escape') { + const imageModal = document.getElementById('image-modal'); + if (imageModal && imageModal.classList.contains('active')) { + imageModal.classList.remove('active'); + } + + const pythonModal = document.getElementById('python-modal'); + if (pythonModal && pythonModal.classList.contains('active')) { + pythonModal.classList.remove('active'); + } + } + }); }); diff --git a/static/style.css b/static/style.css index 5aaec28..51c60ee 100644 --- a/static/style.css +++ b/static/style.css @@ -181,7 +181,6 @@ button:hover { display: flex; flex-direction: column; gap: 10px; - padding: 15px; width: 100%; max-height: calc(100vh - 200px); overflow-y: auto; @@ -270,7 +269,7 @@ button:hover { .step-item pre { padding: 10px; border-radius: 4px; - margin: 10px 0; + margin-left: 20px; overflow-x: hidden; font-family: 'Courier New', monospace; font-size: 0.9em; @@ -300,6 +299,176 @@ button:hover { } } +/* Step division line style */ +.step-divider { + display: flex; + align-items: center; + width: 100%; + margin: 15px 0; + position: relative; +} + +.step-circle { + width: 36px; + height: 36px; + border-radius: 50%; + background-color: var(--primary-color); + color: white; + display: flex; + align-items: center; + justify-content: center; + font-weight: bold; + font-size: 1.2em; + box-shadow: 0 2px 5px rgba(0,0,0,0.2); + z-index: 2; + flex-shrink: 0; +} + +/* File interaction style */ +.file-interaction { + margin-top: 15px; + padding: 10px; + border-radius: 6px; + background-color: #f5f7fa; + border: 1px solid var(--border-color); +} + +.download-link { + display: inline-block; + padding: 8px 16px; + background-color: var(--primary-color); + color: white; + text-decoration: none; + border-radius: 4px; + font-size: 0.9em; + transition: background-color 0.2s; +} + +.download-link:hover { + background-color: var(--primary-hover); +} + +.preview-image { + max-width: 100%; + max-height: 200px; + margin-bottom: 10px; + border-radius: 4px; + cursor: pointer; + transition: transform 0.2s; +} + +.preview-image:hover { + transform: scale(1.02); +} + +.audio-player { + display: flex; + flex-direction: column; + gap: 10px; +} + +.audio-player audio { + width: 100%; + margin-bottom: 10px; +} + +.run-button { + display: inline-block; + padding: 8px 16px; + background-color: var(--success-color); + color: white; + border: none; + border-radius: 4px; + cursor: pointer; + font-size: 0.9em; + margin-right: 10px; + transition: background-color 0.2s; +} + +.run-button:hover { + background-color: #218838; +} + +/* Full screen image modal box */ +.image-modal { + display: none; + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0.8); + z-index: 1000; + justify-content: center; + align-items: center; +} + +.image-modal.active { + display: flex; +} + +.modal-content { + max-width: 90%; + max-height: 90%; +} + +.close-modal { + position: absolute; + top: 20px; + right: 30px; + color: white; + font-size: 30px; + cursor: pointer; +} + +/* Python runs simulation modal boxes */ +.python-modal { + display: none; + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0.8); + z-index: 1000; + justify-content: center; + align-items: center; +} + +.python-modal.active { + display: flex; +} + +.python-console { + width: 80%; + height: 80%; + background-color: #1e1e1e; + color: #f8f8f8; + border-radius: 8px; + padding: 15px; + font-family: 'Courier New', monospace; + overflow: auto; +} + +.python-output { + white-space: pre-wrap; + line-height: 1.5; +} + +.step-line { + flex-grow: 1; + height: 2px; + background-color: var(--border-color); + margin-left: 10px; +} + +.step-info { + margin-left: 15px; + font-weight: bold; + color: var(--text-light); + font-size: 0.9em; +} + .step-item strong { display: block; margin-bottom: 8px;