本地部署 OpenManus 保姆级教程(Windows 版)
一、环境搭建
我的电脑是Windows 10版本,其他的没尝试,如果大家系统和我的不一致,请自行判断,基本上没什么大的出入啊。
openManus的Git地址:https://github.com/mannaandpoem/OpenManus
根据官网的两种安装推荐方式如下:
这里我使用第一只方式,虽然推荐了使用UV,但是我使用过,就不用第二种方式。
二、Anaconda下载
我电脑上没有安装:Anaconda,那就一并安装一下吧
这里推荐两种下载方式一是官网下载,二是镜像下载;官网下载太慢可选用镜像下载。
官网下载:https://www.anaconda.com/products/distribution
镜像下载:https://mirrors.bfsu.edu.cn/anaconda/archive/
我这里选择了Anaconda3-5.3.1-Windows-x86_64.exe这个镜像版本,大家随意啊。
具体Anaconda如何安装的,大家自行搜索啊,这里就不赘述了。
三、核心组件安装
为了方便不知道如何安装的,我也偷懒一下,也是直接使用deepseek帮我搞一下:
https://github.com/mannaandpoem/OpenManus
我在学习如何使用open-manus,但是下面的安装步骤,是在linux中运行的,我的电脑是window10 ,请把下面的操作步骤换成windows10中的步骤,让我一目了然
使用 conda
创建一个新的 conda 环境:
conda create -n open_manus python=3.12
conda activate open_manus
克隆存储库:
git clone https://github.com/mannaandpoem/OpenManus.git
cd OpenManus
安装依赖项:
pip install -r requirements.txt
为了方便大家快速搭建,直接贴了我的提示词,运行结果如下:
以下是为 Windows 10 系统适配的详细步骤(使用 Anaconda):
1. 安装前置工具
- 确保已安装 [Git for Windows](https://git-scm.com/download/win)
- 确保已安装 [Miniconda 或 Anaconda](https://docs.conda.io/en/latest/miniconda.html)
2. 打开 Anaconda Prompt(推荐)或 PowerShell
3. 创建 conda 环境
```powershell
conda create -n open_manus python=3.12 -y
conda activate open_manus
- 克隆仓库
git clone https://github.com/mannaandpoem/OpenManus.git
cd OpenManus
- 安装依赖
pip install -r requirements.txt
常见问题解决方案:
-
如果遇到环境激活问题:
- 在 PowerShell 中首次使用需执行:
conda init powershell
- 关闭后重新打开终端
- 在 PowerShell 中首次使用需执行:
-
如果缺少 C++ 编译工具(安装某些包时报错):
安装 Microsoft C++ Build Tools -
如果 Python 3.12 不可用:
conda create -n open_manus python=3.11
-
替代克隆方式(如果 git 不可用):
直接下载 ZIP:https://github.com/mannaandpoem/OpenManus/archive/refs/heads/main.zip
解压后进入目录执行后续步骤
至此已经本地已经安装完毕了。
四、服务配置与连接
找到Config文件夹,进去,重新复制一份config.toml文件
这里替换config文件配置:
# Global LLM configuration
[llm]
model = "Qwen/QwQ-32B"
base_url = "https://api.siliconflow.cn/v1"
api_key = "这里写你自己的Key"
max_tokens = 16384
temperature = 0.6
# Optional configuration for specific LLM models
[llm.vision]
model = "Qwen/Qwen2-VL-72B-Instruct"
base_url = "https://api.siliconflow.cn/v1"
api_key = "这里写你自己的Key"
这里我使用的硅基流动Key,他们家刚好有活动,注册就送你2000万Tokens,我们这边测试用,完全够了,薅羊毛地址是:https://cloud.siliconflow.cn/i/pCa1dBVX
大家有其他的Key,也是可以用,随自己的意愿。
配置完毕之后,接下来就是运行main.py
至此,流程基本已经开始跑起来了。
五、前端页面
由于是控制台我不喜欢,然后我又用deepseek帮我制作了html页面,便于我页面处理:
这里就写了2个文件
主要两个文件:app.py和templates/index.html
两个文件的详细代码如下:
app.py:
from flask import Flask, Response, request, jsonify, render_template
from flask_cors import CORS
import subprocess
import sys
import os
import signal
import threading
app = Flask(__name__)
CORS(app, resources={r"/*": {"origins": "*"}})
# 进程管理
process_lock = threading.Lock()
current_process = None
@app.route('/')
def index():
return render_template('index.html')
@app.route('/stream', methods=['GET', 'POST', 'OPTIONS'])
def stream_execute():
global current_process
# 处理预检请求
if request.method == 'OPTIONS':
return _build_preflight_response()
# 获取输入内容
idea = request.json.get('idea', '') if request.method == 'POST' else request.args.get('idea', '')
if not idea:
return Response("data: 错误:未提供输入\n\n", mimetype='text/event-stream')
# 终止已有进程
with process_lock:
if current_process and current_process.poll() is None:
current_process.terminate()
# 启动新进程
current_process = subprocess.Popen(
[sys.executable, '-u', 'main.py'],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
text=True,
bufsize=1,
universal_newlines=True,
creationflags=subprocess.CREATE_NEW_PROCESS_GROUP if os.name == 'nt' else 0
)
# 发送输入
current_process.stdin.write(idea + '\n')
current_process.stdin.flush()
# 流式响应
def generate():
while True:
line = current_process.stdout.readline()
if not line:
if current_process.poll() is not None:
break
continue
yield f"data: {line}\n\n"
yield "event: end\ndata: \n\n"
return Response(
generate(),
mimetype='text/event-stream',
headers={
'Access-Control-Allow-Origin': '*',
'Cache-Control': 'no-cache',
'X-Accel-Buffering': 'no'
}
)
def _build_preflight_response():
response = jsonify({'status': 'ok'})
response.headers.add("Access-Control-Allow-Origin", "*")
response.headers.add("Access-Control-Allow-Headers", "*")
response.headers.add("Access-Control-Allow-Methods", "*")
return response
@app.route('/stop', methods=['POST'])
def stop_execution():
global current_process
with process_lock:
if current_process and current_process.poll() is None:
current_process.terminate()
return jsonify({'status': 'stopped'})
return jsonify({'status': 'not running'}), 404
@app.after_request
def add_cors_headers(response):
response.headers['Access-Control-Allow-Origin'] = '*'
response.headers['Access-Control-Allow-Headers'] = 'Content-Type'
response.headers['Access-Control-Allow-Methods'] = 'GET, POST, PUT, DELETE, OPTIONS'
return response
if __name__ == '__main__':
app.run(port=5000, threaded=True)
index.html的页面代码如下:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>OpenManus 实时控制台</title>
<link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/5.3.0/css/bootstrap.min.css" rel="stylesheet">
<style>
#output {
background: #1e1e1e;
color: #d4d4d4;
padding: 20px;
border-radius: 5px;
font-family: 'Consolas', monospace;
height: 60vh;
overflow-y: auto;
white-space: pre-wrap;
}
.log-item {
margin: 5px 0;
padding: 3px 10px;
border-left: 3px solid #3c3c3c;
}
.loading {
position: fixed;
top: 20px;
right: 20px;
display: none;
}
</style>
</head>
<body>
<div class="container py-5">
<h1 class="text-primary mb-4">🚀 OpenManus 实时控制台</h1>
<div class="mb-4">
<textarea id="ideaInput" class="form-control bg-dark text-light"
rows="4" placeholder="输入您的创意(示例:分析特斯拉最近三个月的股价趋势并生成可视化报告)"></textarea>
</div>
<div class="d-flex gap-2 mb-4">
<button class="btn btn-success" onclick="startExecution()">开始执行</button>
<button class="btn btn-danger" onclick="stopExecution()">终止任务</button>
</div>
<div class="card bg-dark">
<div class="card-header text-light">实时输出</div>
<div id="output" class="card-body"></div>
</div>
<div id="loading" class="loading">
<div class="spinner-border text-primary" role="status">
<span class="visually-hidden">加载中...</span>
</div>
</div>
</div>
<script>
let eventSource = null;
function showLoading() {
document.getElementById('loading').style.display = 'block';
}
function hideLoading() {
document.getElementById('loading').style.display = 'none';
}
function clearOutput() {
document.getElementById('output').innerHTML = '';
}
function showError(message) {
const output = document.getElementById('output');
output.innerHTML += `<div class="text-danger">${message}</div>`;
}
function ansiToHtml(text) {
return text
.replace(/\x1B\[32m/g, '<span class="text-success">')
.replace(/\x1B\[31m/g, '<span class="text-danger">')
.replace(/\x1B\[0m/g, '</span>');
}
function startExecution() {
const idea = document.getElementById('ideaInput').value.trim();
if (!idea) return alert('请输入执行内容');
clearOutput();
showLoading();
// 先发送POST请求
fetch('http://localhost:5000/stream', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ idea: idea })
})
.then(response => {
if (!response.ok) {
throw new Error(`HTTP错误 ${response.status}`);
}
// 建立SSE连接
eventSource = new EventSource(`http://localhost:5000/stream?idea=${encodeURIComponent(idea)}`);
eventSource.onmessage = (e) => {
const formatted = ansiToHtml(e.data);
document.getElementById('output').innerHTML +=
`<div class="log-item">${formatted}</div>`;
// 自动滚动
const output = document.getElementById('output');
output.scrollTop = output.scrollHeight;
};
eventSource.onerror = (e) => {
console.error('SSE Error:', e);
hideLoading();
eventSource.close();
};
eventSource.addEventListener('end', () => {
hideLoading();
eventSource.close();
});
})
.catch(error => {
hideLoading();
showError(`请求失败: ${error.message}`);
});
}
function stopExecution() {
if (eventSource) {
eventSource.close();
hideLoading();
}
fetch('http://localhost:5000/stop', {
method: 'POST'
})
.then(response => {
if (response.ok) {
alert('已终止执行');
}
});
}
// 清理资源
window.addEventListener('beforeunload', () => {
if (eventSource) eventSource.close();
fetch('/stop', { method: 'POST' });
});
</script>
</body>
</html>
启动服务:
再打开一个powershell
启动服务,至此页面完成:浏览器直接访问:http://localhost:5000/
openmanus会按照步骤给你执行,自动处理,解放双手吧。
至此基本上就完成了。
我本地也是刚跑出来,大家遇到什么问题,欢迎可以互相套路。