Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

| Skill | Description | License |
|-------|-------------|---------|
| `mimo-v2-5-omni` | MiMo V2.5 multimodal understanding. Supports image, video, and audio analysis including OCR, video content analysis, and audio transcription. | MIT |
| `mimo-v2-5-tts` | MiMo V2.5 TTS voice synthesis. Supports preset voices, voice design, voice cloning, emotion styles, dialects, and singing. Supports natural language control, Director Mode, and audio tag control. | MIT |

## Installation
Expand Down
1 change: 1 addition & 0 deletions README_zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

| Skill | 描述 | 许可证 |
|-------|------|--------|
| `mimo-v2-5-omni` | MiMo V2.5 多模态理解。支持图片、视频、音频分析,包括 OCR、视频内容分析、音频转录。 | MIT |
| `mimo-v2-5-tts` | MiMo V2.5 TTS 语音合成。支持预置音色、音色设计、音色克隆、情绪风格、方言、唱歌。支持自然语言控制、导演模式、音频标签控制。 | MIT |

## 安装
Expand Down
88 changes: 88 additions & 0 deletions skills/mimo-v2-5-omni/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
---
name: mimo-v2-5-omni
description: "MiMo V2.5 多模态理解。使用小米 MiMo V2.5 模型进行图片、视频、音频的理解与分析。当需要识别图片内容、分析截图、OCR 文字提取、视频内容分析、音频转录、或用户发送了图片/视频/音频文件时激活此 skill。"
license: MIT
metadata:
version: 0.1.0
---

# MiMo Omni

使用小米 MiMo V2.5 模型进行多模态理解。支持图片、视频、音频三种媒体类型,支持本地文件和 URL 输入。

脚本目录:`$SKILLS_PATH/mimo-v2-5-omni/scripts/`

> **`$SKILLS_PATH` 说明:** skills 目录路径,因部署环境而异。

## 能力概览

| 类型 | 支持格式 | 说明 |
|------|---------|------|
| **图片理解** | jpg, png, gif, webp, bmp | 图片描述、OCR、分类、对比 |
| **视频理解** | mp4, webm, avi, mov | 视频内容分析、画面描述、关键信息提取 |
| **音频理解** | mp3, wav, flac, ogg, m4a | 语音转录、音频内容分析 |

## 环境依赖

| 环境变量 | 说明 | 必需 |
|---------|------|------|
| `MIMO_API_KEY` | MiMo API 密钥(MiMo 开放平台获取) | 是 |

| 依赖 | 说明 | 必需 |
|------|------|------|
| `python3` | 运行脚本 | 是 |
| `openai` | `pip install openai` | 是 |

## 用法

### 图片理解

```bash
python3 $SKILLS_PATH/mimo-v2-5-omni/scripts/mimo_omni.py image /path/to/photo.jpg --prompt "描述这张图片的内容"
```

### 视频理解

```bash
python3 $SKILLS_PATH/mimo-v2-5-omni/scripts/mimo_omni.py video /path/to/video.mp4 --prompt "总结这个视频的内容"
```

### 音频理解

```bash
python3 $SKILLS_PATH/mimo-v2-5-omni/scripts/mimo_omni.py audio /path/to/audio.mp3 --prompt "转录这段音频"
```

### URL 输入

```bash
python3 $SKILLS_PATH/mimo-v2-5-omni/scripts/mimo_omni.py image "https://example.com/photo.jpg" --prompt "这是什么?"
```

### 视频参数

```bash
python3 $SKILLS_PATH/mimo-v2-5-omni/scripts/mimo_omni.py video /path/to/video.mp4 \
--prompt "描述视频内容" \
--fps 5 \
--resolution high
```

## 使用场景

| 场景 | 类型 | 提示词示例 |
|------|------|-----------|
| 图片描述 | image | "描述这张图片的内容" |
| OCR 文字提取 | image | "提取图片中的所有文字,保持原始格式" |
| 截图分析 | image | "分析这张截图,说明界面上有什么" |
| 视频内容总结 | video | "总结这个视频的主要内容" |
| 视频数据提取 | video | "提取视频中出现的所有数据和文字" |
| 语音转录 | audio | "完整转录这段音频中说的每一句话" |
| 音频分析 | audio | "分析这段音频的内容和情绪" |

## 注意事项

- 大文件(视频/音频)处理时间较长,超时设为 300 秒
- URL 输入需确保链接可公开访问
- 视频默认抽帧率 2fps,可通过 `--fps` 调整
- 音频建议先用 ffmpeg 转为 wav 格式以获得最佳效果
155 changes: 155 additions & 0 deletions skills/mimo-v2-5-omni/scripts/mimo_omni.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
#!/usr/bin/env python3
"""MiMo Omni — 多模态理解(图片/视频/音频)。

模型: mimo-v2.5
支持: 图片理解、视频理解、音频理解

Requires:
pip install openai
export MIMO_API_KEY=...
"""

import argparse
import base64
import mimetypes
import os
import sys
from pathlib import Path

from openai import OpenAI


def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(description="MiMo V2.5 多模态理解")
parser.add_argument(
"type",
choices=["image", "video", "audio"],
help="媒体类型: image / video / audio",
)
parser.add_argument(
"input",
help="文件路径或 URL",
)
parser.add_argument(
"--prompt",
required=True,
help="文本提示",
)
parser.add_argument(
"--fps",
type=int,
default=2,
help="视频抽帧率 (仅 video 类型,默认 2)",
)
parser.add_argument(
"--resolution",
default="default",
help="视频分辨率 (仅 video 类型,默认 default)",
)
parser.add_argument(
"--max-tokens",
type=int,
default=4096,
help="最大输出 token 数 (默认 4096)",
)
return parser.parse_args()


def build_client() -> OpenAI:
api_key = os.environ.get("MIMO_API_KEY")
if not api_key:
print("MIMO_API_KEY is not set", file=sys.stderr)
sys.exit(1)
return OpenAI(api_key=api_key, base_url="https://api.xiaomimimo.com/v1")


def load_media(media_type: str, file_input: str) -> dict:
"""根据类型和输入方式构建 content block。"""
is_url = file_input.startswith("http://") or file_input.startswith("https://")

if media_type == "image":
if is_url:
return {"type": "image_url", "image_url": {"url": file_input}}
path = _resolve_path(file_input)
mime = _guess_mime(path, "image/png")
b64 = _read_base64(path)
return {"type": "image_url", "image_url": {"url": f"data:{mime};base64,{b64}"}}

if media_type == "video":
if is_url:
return {
"type": "video_url",
"video_url": {"url": file_input},
"fps": 2,
"media_resolution": "default",
}
path = _resolve_path(file_input)
mime = _guess_mime(path, "video/mp4")
b64 = _read_base64(path)
return {
"type": "video_url",
"video_url": {"url": f"data:{mime};base64,{b64}"},
"fps": 2,
"media_resolution": "default",
}

if media_type == "audio":
if is_url:
return {"type": "input_audio", "input_audio": {"data": file_input}}
path = _resolve_path(file_input)
mime = _guess_mime(path, "audio/wav")
b64 = _read_base64(path)
return {"type": "input_audio", "input_audio": {"data": f"data:{mime};base64,{b64}"}}

print(f"Unknown media type: {media_type}", file=sys.stderr)
sys.exit(1)


def _resolve_path(file_input: str) -> Path:
path = Path(file_input).resolve()
if not path.is_file():
print(f"File not found: {path}", file=sys.stderr)
sys.exit(1)
return path


def _guess_mime(path: Path, default: str) -> str:
mime, _ = mimetypes.guess_type(str(path))
return mime or default


def _read_base64(path: Path) -> str:
with open(path, "rb") as f:
return base64.b64encode(f.read()).decode()


def main() -> None:
args = parse_args()
client = build_client()

media_block = load_media(args.type, args.input)

completion = client.chat.completions.create(
model="mimo-v2.5",
max_tokens=args.max_tokens,
messages=[
{
"role": "user",
"content": [
media_block,
{"type": "text", "text": args.prompt},
],
}
],
)

message = completion.choices[0].message
if message.content:
print(message.content)
else:
print("No content in response", file=sys.stderr)
sys.exit(1)


if __name__ == "__main__":
main()