diff --git a/host_ollama.py b/host_ollama.py
index bdabb0f..68a1619 100644
--- a/host_ollama.py
+++ b/host_ollama.py
@@ -1,113 +1,150 @@
#!/usr/bin/env python3
"""
-Ollama 本地镜像服务器
-功能:
-1. 自动检测并Host下载的镜像目录
-2. 提供文件浏览和下载接口
-3. 自动生成友好的下载页面
+Ollama 本地镜像服务器 - 增强版
+新增功能:
+1. 同时托管 ollama_releases 和 install.sh
+2. 自动生成安装指引
+3. 显示本机IP方便局域网访问
"""
import os
import sys
+import socket
from http.server import HTTPServer, SimpleHTTPRequestHandler
from pathlib import Path
import threading
import webbrowser
-MIRROR_DIR = "ollama_releases" # 与mirror_ollama.sh保持一致
+MIRROR_DIR = "ollama_releases"
+INSTALL_SCRIPT = "install.sh"
PORT = 8000
class OllamaRequestHandler(SimpleHTTPRequestHandler):
- """自定义请求处理器,增强目录浏览功能"""
+ """自定义请求处理器,支持多目录托管"""
- def __init__(self, *args, **kwargs):
- super().__init__(*args, directory=MIRROR_DIR, **kwargs)
+ def translate_path(self, path):
+ # 优先检查是否是install.sh
+ if path.endswith('/' + INSTALL_SCRIPT) or path == '/' + INSTALL_SCRIPT:
+ return os.path.abspath(INSTALL_SCRIPT)
+
+ # 默认处理镜像目录
+ path = path.split('?',1)[0]
+ path = path.split('#',1)[0]
+ return os.path.abspath(os.path.join(MIRROR_DIR, path.lstrip('/')))
def list_directory(self, path):
"""生成增强型目录列表页面"""
try:
- items = []
- for item in Path(path).iterdir():
+ # 特殊处理根目录
+ if os.path.abspath(path) == os.path.abspath(MIRROR_DIR):
+ return self.generate_index_page(path)
+ return super().list_directory(path)
+ except Exception as e:
+ self.send_error(500, f"服务器错误: {str(e)}")
+
+ def generate_index_page(self, path):
+ """生成带安装指引的首页"""
+ local_ip = get_local_ip()
+ install_url = f"http://{local_ip}:{self.server.server_port}/{INSTALL_SCRIPT}"
+
+ items = []
+ for item in Path(path).iterdir():
+ if item.is_file():
mtime = item.stat().st_mtime
size = item.stat().st_size
items.append((item.name, mtime, size))
-
- # 按版本号排序(降序)
- items.sort(key=lambda x: x[0], reverse=True)
-
- # 生成HTML
- html = ["
Ollama 本地镜像"]
- html.append("")
- html.append("Ollama 本地镜像库
")
- html.append(f"当前目录: {path}
")
- html.append("| 文件名 | 大小 | 修改时间 |
")
-
- for name, mtime, size in items:
- human_size = f"{size/1024/1024:.1f} MB" if size > 1024*1024 else f"{size/1024:.1f} KB"
- html.append(
- f'| {name} | '
- f'{human_size} | '
- f'{mtime:.0f} |
'
- )
-
- html.append("
")
- self.send_response(200)
- self.send_header("Content-type", "text/html; charset=utf-8")
- self.end_headers()
- self.wfile.write("\n".join(html).encode('utf-8'))
-
- except Exception as e:
- self.send_error(500, f"服务器错误: {str(e)}")
+
+ items.sort(key=lambda x: x[0], reverse=True)
+
+ html = [
+ "Ollama 本地镜像",
+ "",
+ f"Ollama 本地镜像库
",
+ f"",
+ "
📌 安装指引
",
+ f"
在其他机器上执行以下命令安装:
",
+ f"
curl -sSL {install_url} | sudo bash",
+ f"
",
+ "📂 可用文件列表
",
+ "| 文件名 | 大小 | 修改时间 |
"
+ ]
+
+ for name, mtime, size in items:
+ human_size = f"{size/1024/1024:.1f} MB" if size > 1024*1024 else f"{size/1024:.1f} KB"
+ html.append(
+ f'| {name} | '
+ f'{human_size} | '
+ f'{mtime:.0f} |
'
+ )
+
+ html.append("
")
+
+ self.send_response(200)
+ self.send_header("Content-type", "text/html; charset=utf-8")
+ self.end_headers()
+ self.wfile.write("\n".join(html).encode('utf-8'))
+
+def get_local_ip():
+ """获取本机局域网IP"""
+ try:
+ s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+ s.connect(("8.8.8.8", 80))
+ ip = s.getsockname()[0]
+ s.close()
+ return ip
+ except:
+ return "localhost"
def start_server(port=PORT):
"""启动HTTP服务器"""
+ local_ip = get_local_ip()
server_address = ('', port)
httpd = HTTPServer(server_address, OllamaRequestHandler)
print(f"\n🎯 Ollama 本地镜像服务已启动")
- print(f"👉 访问地址: http://localhost:{port}")
+ print(f"👉 本机访问: http://localhost:{port}")
+ print(f"👉 局域网访问: http://{local_ip}:{port}")
print(f"📁 镜像目录: {os.path.abspath(MIRROR_DIR)}")
- print("🛑 按 Ctrl+C 停止服务\n")
+ print(f"📜 安装脚本: {os.path.abspath(INSTALL_SCRIPT)}")
+ print("\n🔧 安装命令:")
+ print(f" curl -sSL http://{local_ip}:{port}/{INSTALL_SCRIPT} | sudo bash")
+ print("\n🛑 按 Ctrl+C 停止服务\n")
try:
httpd.serve_forever()
except KeyboardInterrupt:
print("\n服务器已停止")
-def ensure_mirror_dir():
- """确保镜像目录存在"""
+def check_files():
+ """检查必要文件是否存在"""
if not os.path.exists(MIRROR_DIR):
os.makedirs(MIRROR_DIR)
- print(f"创建镜像目录: {MIRROR_DIR}")
+ print(f"⚠️ 创建空镜像目录: {MIRROR_DIR}")
+ print("请先运行 mirror_ollama.sh 下载文件")
+
+ if not os.path.exists(INSTALL_SCRIPT):
+ print(f"❌ 错误: {INSTALL_SCRIPT} 不存在")
+ print("请确保安装脚本与host_ollama.py在同一目录")
return False
return True
-def open_browser():
- """自动打开浏览器"""
- import time
- time.sleep(1)
- webbrowser.open(f"http://localhost:{PORT}")
-
if __name__ == '__main__':
- # 检查并获取端口参数
- port = PORT
- if len(sys.argv) > 1:
- try:
- port = int(sys.argv[1])
- except ValueError:
- print("错误: 端口号必须是数字")
- sys.exit(1)
+ port = int(sys.argv[1]) if len(sys.argv) > 1 else PORT
- if not ensure_mirror_dir():
- print("⚠️ 注意: 镜像目录为空,请先运行 mirror_ollama.sh 下载文件")
+ if not check_files():
+ sys.exit(1)
# 自动打开浏览器
- threading.Thread(target=open_browser, daemon=True).start()
+ threading.Thread(
+ target=webbrowser.open,
+ args=(f"http://localhost:{port}",),
+ daemon=True
+ ).start()
- # 启动服务器
start_server(port)
\ No newline at end of file