Spaces:
Runtime error
Runtime error
J.B-Lin commited on
Commit ·
2e7d8b3
1
Parent(s): e7b9546
清理临时文件
Browse files- _check_hf.py +0 -28
- _get_modal_url.py +0 -12
- _install_modal.py +0 -64
- _setup_rtm.py +0 -180
_check_hf.py
DELETED
|
@@ -1,28 +0,0 @@
|
|
| 1 |
-
import urllib.request, json
|
| 2 |
-
|
| 3 |
-
url = "https://huggingface.co/api/models/openbmb/MiniCPM-o-4_5-gguf"
|
| 4 |
-
r = urllib.request.urlopen(url)
|
| 5 |
-
d = json.load(r)
|
| 6 |
-
|
| 7 |
-
print("=== All GGUF files in repo (with sizes) ===")
|
| 8 |
-
for s in sorted(d.get("siblings", []), key=lambda x: x["rfilename"]):
|
| 9 |
-
fname = s["rfilename"]
|
| 10 |
-
if fname.endswith(".gguf"):
|
| 11 |
-
# Try different size fields
|
| 12 |
-
size_bytes = s.get("size", 0) or s.get("lfs", {}).get("size", 0)
|
| 13 |
-
if size_bytes > 0:
|
| 14 |
-
size_gb = size_bytes / 1024 / 1024 / 1024
|
| 15 |
-
size_mb = size_bytes / 1024 / 1024
|
| 16 |
-
if size_gb >= 1:
|
| 17 |
-
print(f" {fname}: {size_gb:.1f} GB")
|
| 18 |
-
else:
|
| 19 |
-
print(f" {fname}: {size_mb:.0f} MB")
|
| 20 |
-
else:
|
| 21 |
-
# Print raw keys for debugging
|
| 22 |
-
print(f" {fname}: (unknown size, keys: {list(s.keys())})")
|
| 23 |
-
|
| 24 |
-
print("\n=== Raw data for one file (debug) ===")
|
| 25 |
-
for s in d.get("siblings", []):
|
| 26 |
-
if s["rfilename"].endswith(".gguf"):
|
| 27 |
-
print(json.dumps(s, indent=2))
|
| 28 |
-
break
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
_get_modal_url.py
DELETED
|
@@ -1,12 +0,0 @@
|
|
| 1 |
-
import urllib.request
|
| 2 |
-
import json
|
| 3 |
-
|
| 4 |
-
url = "https://pypi.org/pypi/modal/json"
|
| 5 |
-
data = json.loads(urllib.request.urlopen(url, timeout=15).read())
|
| 6 |
-
latest = data["info"]["version"]
|
| 7 |
-
print(f"LATEST_VERSION={latest}")
|
| 8 |
-
for f in data["releases"][latest]:
|
| 9 |
-
if f["filename"].endswith(".whl") and ("none-any" in f["filename"] or "py3-none" in f["filename"]):
|
| 10 |
-
print(f"WHEEL_URL={f['url']}")
|
| 11 |
-
print(f"FILENAME={f['filename']}")
|
| 12 |
-
break
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
_install_modal.py
DELETED
|
@@ -1,64 +0,0 @@
|
|
| 1 |
-
"""Download and install modal wheel using Python's urllib (which works)"""
|
| 2 |
-
import urllib.request
|
| 3 |
-
import json
|
| 4 |
-
import subprocess
|
| 5 |
-
import sys
|
| 6 |
-
import os
|
| 7 |
-
|
| 8 |
-
os.chdir(os.path.dirname(os.path.abspath(__file__)))
|
| 9 |
-
|
| 10 |
-
# Step 1: Get latest modal wheel URL
|
| 11 |
-
print("Step 1: Fetching modal version info...")
|
| 12 |
-
url = "https://pypi.org/pypi/modal/json"
|
| 13 |
-
data = json.loads(urllib.request.urlopen(url, timeout=15).read())
|
| 14 |
-
latest = data["info"]["version"]
|
| 15 |
-
print(f" Latest version: {latest}")
|
| 16 |
-
|
| 17 |
-
wheel_url = None
|
| 18 |
-
wheel_filename = None
|
| 19 |
-
for f in data["releases"][latest]:
|
| 20 |
-
if f["filename"].endswith(".whl") and ("none-any" in f["filename"] or "py3-none" in f["filename"]):
|
| 21 |
-
wheel_url = f["url"]
|
| 22 |
-
wheel_filename = f["filename"]
|
| 23 |
-
break
|
| 24 |
-
|
| 25 |
-
if not wheel_url:
|
| 26 |
-
print("ERROR: Could not find suitable wheel")
|
| 27 |
-
sys.exit(1)
|
| 28 |
-
|
| 29 |
-
print(f" Wheel URL: {wheel_url}")
|
| 30 |
-
|
| 31 |
-
# Step 2: Download wheel
|
| 32 |
-
print(f"Step 2: Downloading {wheel_filename}...")
|
| 33 |
-
urllib.request.urlretrieve(wheel_url, wheel_filename)
|
| 34 |
-
size_mb = os.path.getsize(wheel_filename) / (1024 * 1024)
|
| 35 |
-
print(f" Downloaded: {wheel_filename} ({size_mb:.1f} MB)")
|
| 36 |
-
|
| 37 |
-
# Step 3: Install wheel with pip
|
| 38 |
-
print("Step 3: Installing modal and dependencies...")
|
| 39 |
-
# Also need dependencies: grpcio, protobuf, etc.
|
| 40 |
-
# Let pip resolve dependencies from online (it might still fail for some)
|
| 41 |
-
# But at least the main wheel is local
|
| 42 |
-
result = subprocess.run(
|
| 43 |
-
[sys.executable, "-m", "pip", "install", "--index-url", "https://pypi.org/simple/", wheel_filename],
|
| 44 |
-
capture_output=True,
|
| 45 |
-
text=True,
|
| 46 |
-
timeout=120,
|
| 47 |
-
)
|
| 48 |
-
print(result.stdout)
|
| 49 |
-
if result.returncode != 0:
|
| 50 |
-
print("STDERR:", result.stderr)
|
| 51 |
-
# Try without index (offline install, may miss deps)
|
| 52 |
-
print("Trying offline install (may miss dependencies)...")
|
| 53 |
-
result2 = subprocess.run(
|
| 54 |
-
[sys.executable, "-m", "pip", "install", "--no-deps", "--no-index", wheel_filename],
|
| 55 |
-
capture_output=True,
|
| 56 |
-
text=True,
|
| 57 |
-
timeout=60,
|
| 58 |
-
)
|
| 59 |
-
print(result2.stdout)
|
| 60 |
-
if result2.returncode != 0:
|
| 61 |
-
print("STDERR:", result2.stderr)
|
| 62 |
-
sys.exit(1)
|
| 63 |
-
|
| 64 |
-
print("DONE! Modal installed successfully.")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
_setup_rtm.py
DELETED
|
@@ -1,180 +0,0 @@
|
|
| 1 |
-
"""设置RTM指令 - 使用Python脚本避免PowerShell转义问题"""
|
| 2 |
-
import json, subprocess, sys
|
| 3 |
-
|
| 4 |
-
PY = r"C:\Users\Andre\miniconda3\envs\trader_stable\python.exe"
|
| 5 |
-
RTM = r"C:\Users\Andre\.qclaw\workspace\skills\research-task-manager\scripts\research_task_manager.py"
|
| 6 |
-
DB = r"C:\Users\Andre\codes\LJB\hackthon\for_qclaw_llamacpp\PregoPal\rtm_task.json"
|
| 7 |
-
|
| 8 |
-
def rtm(*args):
|
| 9 |
-
cmd = [PY, RTM, "--db", DB] + list(args)
|
| 10 |
-
result = subprocess.run(cmd, capture_output=True, text=True)
|
| 11 |
-
print(result.stdout)
|
| 12 |
-
if result.returncode != 0:
|
| 13 |
-
print("STDERR:", result.stderr)
|
| 14 |
-
return result.returncode
|
| 15 |
-
|
| 16 |
-
# Step 1.1: Phase1
|
| 17 |
-
instructions_1_1 = """Phase1: 部署本地llama-server并验证全双工API
|
| 18 |
-
|
| 19 |
-
目标:启动llama-server并验证MiniCPM-o 4.5的语音输入/输出功能正常工作。
|
| 20 |
-
|
| 21 |
-
参考文档:
|
| 22 |
-
1. 官方README: https://www.modelscope.cn/models/OpenBMB/MiniCPM-o-4_5/files - 全双工架构说明
|
| 23 |
-
2. 本地部署经验: C:\\Users\\Andre\\codes\\LJB\\hackthon\\for_qclaw_llamacpp\\PregoPal\\docs\\本地部署经验.md
|
| 24 |
-
3. 官方部署例程: C:\\Users\\Andre\\codes\\LJB\\hackthon\\MiniCPM-V-CookBook\\deployment\\llama.cpp\\minicpm-o4_5_llamacpp_zh.md
|
| 25 |
-
4. 全双工后端参考: C:\\Users\\Andre\\codes\\LJB\\hackthon\\MiniCPM-V-CookBook\\demo\\web_demo\\WebRTC_Demo\\omini_backend_code\\code\\voice_chat\\omni_stream.py
|
| 26 |
-
|
| 27 |
-
关键资源位置:
|
| 28 |
-
- llama-server: C:\\Users\\Andre\\codes\\LJB\\llama.cpp-omni\\build\\bin\\Release\\llama-server.exe
|
| 29 |
-
- 模型文件: C:\\Users\\Andre\\codes\\LJB\\llama.cpp-omni\\models\\(Q4_K_M + vision/audio/tts/projector)
|
| 30 |
-
- PregoPal源码: C:\\Users\\Andre\\codes\\LJB\\hackthon\\for_qclaw_llamacpp\\PregoPal\\
|
| 31 |
-
|
| 32 |
-
步骤:
|
| 33 |
-
1. 确认llama-server.exe编译OK(含CUDA支持)
|
| 34 |
-
2. 确认所有5个模型文件完整
|
| 35 |
-
3. 启动llama-server:-m Q4_K_M --mmproj vision --mmproj audio --mmproj tts --mmproj projector -c 16384 --host 127.0.0.1 --port 8081
|
| 36 |
-
4. 验证API端点:/health /v1/chat/completions /omni/streaming_prefill /omni/streaming_generate
|
| 37 |
-
5. 测试文本推理,验证响应正常
|
| 38 |
-
6. 检查显存使用,确保4060Ti 16GB不超限
|
| 39 |
-
"""
|
| 40 |
-
|
| 41 |
-
rtm("update", "--id", "1.1", "--instructions", json.dumps(instructions_1_1, ensure_ascii=False))
|
| 42 |
-
|
| 43 |
-
# Step 1.2: Phase2
|
| 44 |
-
instructions_1_2 = """Phase2: 实现VoiceProcessor ASR和TTS音频输出
|
| 45 |
-
|
| 46 |
-
目标:让PregoPal能接收语音输入(ASR)和输出语音回复(TTS)。
|
| 47 |
-
|
| 48 |
-
参考文档:
|
| 49 |
-
- C:\\Users\\Andre\\codes\\LJB\\hackthon\\MiniCPM-V-CookBook\\inference\\speech2text_zh.md
|
| 50 |
-
- C:\\Users\\Andre\\codes\\LJB\\hackthon\\MiniCPM-V-CookBook\\inference\\text2speech_zh.md
|
| 51 |
-
- C:\\Users\\Andre\\codes\\LJB\\hackthon\\MiniCPM-V-CookBook\\demo\\web_demo\\gradio\\server\\models\\minicpmo4_5.py
|
| 52 |
-
|
| 53 |
-
MiniCPM-o 4.5原生支持语音输入/输出(通过音频tokenizer),但llama-server模式下:
|
| 54 |
-
方案A:使用llama-server的/v1/audio/transcriptions端点(类似Whisper)
|
| 55 |
-
方案B:使用本地Whisper-medium进行ASR + MiniCPM-o进行文本对话 + TTS
|
| 56 |
-
方案C:使用llama.cpp-omni的omni流式接口直接传入音频流
|
| 57 |
-
|
| 58 |
-
关键问题:
|
| 59 |
-
1. MiniCPM-o 4.5的GGUF版本是否支持/v1/audio端点?
|
| 60 |
-
2. 如果不支持,需要调研本地Whisper方案
|
| 61 |
-
3. TTS输出:MiniCPM-o自带的TTS能力(tts-mmproj)是否可用?
|
| 62 |
-
|
| 63 |
-
依赖:
|
| 64 |
-
- core/voice_processor.py需要实现transcribe(audio_path) -> str
|
| 65 |
-
- core/model_loader.py需要暴露TTS接口
|
| 66 |
-
"""
|
| 67 |
-
|
| 68 |
-
rtm("update", "--id", "1.2", "--instructions", json.dumps(instructions_1_2, ensure_ascii=False))
|
| 69 |
-
|
| 70 |
-
# Step 1.3: Phase3
|
| 71 |
-
instructions_1_3 = """Phase3: 改造ConversationManager接入MiniCPM-o 4.5 API
|
| 72 |
-
|
| 73 |
-
目标:将PregoPal的对话管理模块与实际模型连接起来。
|
| 74 |
-
|
| 75 |
-
参考:
|
| 76 |
-
- core/conversation_manager.py(当前占位)
|
| 77 |
-
- core/model_loader.py(当前已封装Modal API客户端)
|
| 78 |
-
- modal_deploy/client.py(MiniCPMClient实现参考)
|
| 79 |
-
|
| 80 |
-
需要改造的内容:
|
| 81 |
-
1. ConversationManager.build_system_prompt() - 构建包含孕期营养专业知识的系统提示词
|
| 82 |
-
2. ConversationManager.switch_mode() - 支持task/chat模式切换
|
| 83 |
-
3. ConversationManager.set_speaker() - 设置声纹识别出的当前说话人
|
| 84 |
-
4. ConversationManager.parse_response() - 解析AI回复,提取[EXTRACT_DIET]等标记
|
| 85 |
-
5. ModelLoader支持本地llama-server的OpenAI兼容API调用(替换Modal远程调用)
|
| 86 |
-
6. 集成DietExtractor的提取标记到对话流程中
|
| 87 |
-
|
| 88 |
-
关键设计决策:
|
| 89 |
-
- 系统提示词应该包含哪些内容?(孕期营养知识、对话规则、输出格式)
|
| 90 |
-
- 对话历史如何管理?(context window限制16384)
|
| 91 |
-
- 如何切换本地模式vs Modal远程模式?
|
| 92 |
-
"""
|
| 93 |
-
|
| 94 |
-
rtm("update", "--id", "1.3", "--instructions", json.dumps(instructions_1_3, ensure_ascii=False))
|
| 95 |
-
|
| 96 |
-
# Step 1.4: Phase4
|
| 97 |
-
instructions_1_4 = """Phase4: 实现start_voice_session全双工语音对话闭环
|
| 98 |
-
|
| 99 |
-
目标:让用户点击语音按钮后,实现"语音输入→ASR转写→AI思考→TTS输出"的完整闭环。
|
| 100 |
-
|
| 101 |
-
参考:
|
| 102 |
-
- MiniCPM-V-CookBook的Gradio demo: server/models/minicpmo4_5.py(包含ChatBot类实现)
|
| 103 |
-
- 全双工WebSocket/流式���现: omini_backend_code/code/voice_chat/omni_stream.py
|
| 104 |
-
- PregoPal当前占位: ui/app_builder.py中的start_voice_session()
|
| 105 |
-
|
| 106 |
-
Gradio语音交互方案:
|
| 107 |
-
方案A: Gradio内置Audio组件(gr.Audio(source="microphone") + gr.Audio(output))
|
| 108 |
-
方案B: 使用WebRTC + 自定义JS组件实现低延迟语音流
|
| 109 |
-
方案C: 使用FastAPI WebSocket + Gradio前端组合
|
| 110 |
-
|
| 111 |
-
关键步骤:
|
| 112 |
-
1. 改造ui/app_builder.py中的语音按钮,使其实际调用AIModel
|
| 113 |
-
2. 实现语音输入→ASR→AI→TTS→语音输出的串行流程
|
| 114 |
-
3. 使用gr.Stream或gr.load streaming模式实现实时反馈
|
| 115 |
-
4. 显示AI思考状态(thinking状态)
|
| 116 |
-
|
| 117 |
-
注意:Gradio的gr.Audio组件默认是点击录音→上传→处理→输出的模式,不是实时流。
|
| 118 |
-
如果要实现真正的"全双工",需要使用自定义JS组件 + WebSocket。
|
| 119 |
-
"""
|
| 120 |
-
|
| 121 |
-
rtm("update", "--id", "1.4", "--instructions", json.dumps(instructions_1_4, ensure_ascii=False))
|
| 122 |
-
|
| 123 |
-
# Step 1.5: Phase5
|
| 124 |
-
instructions_1_5 = """Phase5: 集成PregoPal业务逻辑
|
| 125 |
-
|
| 126 |
-
目标:将AI对话能力与PregoPal的完整业务管线串联起来。
|
| 127 |
-
|
| 128 |
-
完整的对话处理管线:
|
| 129 |
-
1. 用户语音输入 → 声纹识别(modules/voiceprint.py) → 识别说话人
|
| 130 |
-
2. ASR转写文本 → 进入ConversationManager
|
| 131 |
-
3. AI思考回复(含孕期营养知识)
|
| 132 |
-
4. AI回复中包含[EXTRACT_DIET][EXTRACT_RECIPE][EXTRACT_PREFERENCE][EXTRACT_WEIGHT][EXTRACT_MEMORY]等标记
|
| 133 |
-
5. DietExtractor.extract_all(reply)提取结构化数据
|
| 134 |
-
6. 结构化数据自动存储到diet_logger/family_manager
|
| 135 |
-
7. NutritionAnalyzer进行实时营养分析
|
| 136 |
-
8. TTS输出AI回复语音
|
| 137 |
-
9. 更新首页简报卡片
|
| 138 |
-
|
| 139 |
-
需要修改的模块:
|
| 140 |
-
- start_voice_session() - 串联整个管线
|
| 141 |
-
- voiceprint.py的identify_speaker - 从当前音频提取说话人
|
| 142 |
-
- MealRecommender - 使用AI推荐而不是随机模板
|
| 143 |
-
- NutritionAnalyzer - 对接DRIs标准
|
| 144 |
-
"""
|
| 145 |
-
|
| 146 |
-
rtm("update", "--id", "1.5", "--instructions", json.dumps(instructions_1_5, ensure_ascii=False))
|
| 147 |
-
|
| 148 |
-
# Step 1.6: Phase6
|
| 149 |
-
instructions_1_6 = """Phase6: 端到端测试与性能优化
|
| 150 |
-
|
| 151 |
-
目标:确保全双工语音交互在4060Ti 16GB上流畅运行。
|
| 152 |
-
|
| 153 |
-
测试清单:
|
| 154 |
-
1. 文本对话测试 - 10轮连续对话,验证上下文保持
|
| 155 |
-
2. 语音输入测试 - 不同噪音环境下的ASR准确率
|
| 156 |
-
3. 声纹识别测试 - 多家庭成员识别准确率
|
| 157 |
-
4. 营养分析测试 - 验证DRIs对比正确性
|
| 158 |
-
5. 内存测试 - 显存/内存泄漏检测
|
| 159 |
-
6. 响应时间测试 - 语音输入→TTS输出延迟
|
| 160 |
-
7. 并发测试 - 单用户连续对话稳定性
|
| 161 |
-
|
| 162 |
-
优化方向:
|
| 163 |
-
1. 模型量化级别:Q4_K_M vs Q8_0 vs F16
|
| 164 |
-
2. n_ctx上下文长度:4096 vs 8192 vs 16384
|
| 165 |
-
3. batch_size调整
|
| 166 |
-
4. 是否启用flash_attn
|
| 167 |
-
5. 长对话历史裁剪策略
|
| 168 |
-
6. GPU offloading层数(-ngl参数)
|
| 169 |
-
|
| 170 |
-
性能指标目标:
|
| 171 |
-
- 文本推理延迟: <3秒(首token)
|
| 172 |
-
- ASR延迟: <1秒(3秒语音)
|
| 173 |
-
- TTS延迟: <2秒(50字以内)
|
| 174 |
-
- 全双工轮询: <5秒/轮
|
| 175 |
-
- 显存占用: <14GB(留2GB余量)
|
| 176 |
-
"""
|
| 177 |
-
|
| 178 |
-
rtm("update", "--id", "1.6", "--instructions", json.dumps(instructions_1_6, ensure_ascii=False))
|
| 179 |
-
|
| 180 |
-
print("RTM 指令设置完成!")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|