Repository navigation
feat: support exact 17k+5 frame durations for vLLM-Omni #334
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,6 +5,7 @@ | |
| from pydantic import BaseModel, ConfigDict, Field, StrictInt, model_validator | ||
|
|
||
| from opendirector.domain.projects import ProjectError | ||
| from opendirector.domain.rule_facts import duration_matches | ||
| from opendirector.domain.minimax_models import MINIMAX_MODELS, minimax_capabilities | ||
| from opendirector.domain.kling_models import kling_capabilities | ||
| from opendirector.domain.bigmodel_video import cogvideo_capabilities, validate_cogvideo_outputs | ||
|
|
@@ -97,6 +98,8 @@ def capability_fields(config, rules): | |
| validate_cogvideo_outputs(capabilities) | ||
| if rules['profile'] == 'kling-official': | ||
| validate_kling_outputs(capabilities, config['modelId']) | ||
| if config.get('kind') == 'video' and config.get('protocol') == 'vllm_omni': | ||
| rules['fractionalDuration'] = True | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 范围建议收紧到 H3。这里只要 kind=='video' 且 protocol=='vllm_omni' 就把 fractionalDuration 置真,于是 standard-video(通用 vLLM-Omni 视频)和 fasth3-omni 也会走区间判定。配合 rule_facts.duration_matches 的 min(durations) <= x <= max(durations),一个只声明离散时长的普通 vLLM-Omni 模型(例如 durations 为 [4,8])会接受并原样下发 4–8 之间任意小数,前端时长控件也会退化成自由滑杆;本 PR 的浏览器用例正是把稀疏时长 fixture 从 vllm_omni 改到 volcengine 才保住离散行为。若非确认所有受支持的 vllm_omni 视频模型都能处理任意秒数,建议改成 rules['profile'] in {'vllm-omni-h3','fasth3-omni'} 时才置真,或引入显式的每模型能力位。 |
||
| rules['videoCapabilities'] = capabilities | ||
| rules['outputResolutions'] = [item['resolution'] for item in capabilities['outputs']] if capabilities else [] | ||
| return rules | ||
|
|
@@ -153,9 +156,10 @@ def check_video_config(kind, protocol, adapter, capabilities): | |
|
|
||
| def validate_video_duration(config, seconds, resolution=None): | ||
| from opendirector.domain.input_rules import input_rules | ||
| capabilities = input_rules(config).get('videoCapabilities') | ||
| rules = input_rules(config) | ||
| capabilities = rules.get('videoCapabilities') | ||
| if capabilities: | ||
| choices = [item for item in capabilities['outputs'] | ||
| if not resolution or resolution in {'auto', '自动'} or item['resolution'] == resolution.upper()] | ||
| if not any(seconds in item['durations'] for item in choices): | ||
| if not any(duration_matches(seconds, item['durations'], rules.get('fractionalDuration', False)) for item in choices): | ||
| raise ProjectError('当前模型的分辨率与时长组合不受支持,请重新选择;未提交生成。') | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -179,7 +179,9 @@ async def generate(self, config, task, submitted, *, result_ready=None): | |
| files.append(('input_references' if fast else 'input_reference', (meta['name'], data, image_type(data) if source_kind == 'image' else meta['type']))) | ||
| parameters = task['parameters'] | ||
| form = {'model': config['modelId'], 'prompt': prepared['prompt']} | ||
| if 'duration' in parameters: form['seconds'] = format(parameters['duration'], 'g') | ||
| if 'duration' in parameters: | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. FastH3 的小数时长实际不会走这里设置的 form['seconds']:本块的写入会紧接着被 fast 分支的 form.update({'seconds': str(parameters.get('seconds','5')), ...}) 覆盖,而视频 task 参数里没有 'seconds' 键(只有 'duration',见 creation_generation.py 的 _parameters),因此 FastH3 恒定提交 seconds=5,真实时长只经 extra_params.duration(float,见第 191 行)下发。它是否生效取决于服务端是否读 extra_params.duration,PR 描述也承认该路径未验证;而 UI 已对 FastH3 打开小数输入。建议补一条真实 FastH3 的 wire/集成断言或明确标注此限制;第 184 行对 standard-video 有效,但对 fast 分支是死代码,可考虑仅在非 fast 时执行以更清晰。 |
||
| seconds = parameters['duration'] | ||
| form['seconds'] = str(int(seconds)) if float(seconds).is_integer() else str(seconds) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. form['seconds'] 从 format(seconds,'g')(6 位有效数字)改为 str(seconds) 后会输出 4.458333333333333 这类全精度串——这正是精确性所需(H3 的精确帧走 num_frames,不受影响),但标准 vLLM-Omni 服务端能否解析全精度小数尚未验证。建议确认后端对全精度浮点的接受度,必要时固定到某个足够精度。 |
||
| if 'size' in parameters: form['size'] = parameters['size'] | ||
| if fast: | ||
| form.update({ | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,7 +9,9 @@ export function DurationControl({ | |
| disabled, | ||
| onChange, | ||
| scale, | ||
| fractional = false, | ||
| }: { | ||
| fractional?: boolean; | ||
| values: readonly number[]; | ||
| value: number; | ||
| disabled: boolean; | ||
|
|
@@ -52,14 +54,14 @@ export function DurationControl({ | |
| const hint = (seconds: number) => | ||
| seconds <= minimum || seconds >= maximum | ||
| ? limit | ||
| : !values.includes(seconds) | ||
| : !fractional && !values.includes(seconds) | ||
| ? t("canvasNodes.duration.unsupported", { | ||
| values: values.join(t("canvasNodes.duration.separator")), | ||
| }) | ||
| : ""; | ||
| const choose = (seconds: number) => { | ||
| if (!Number.isFinite(seconds) || !values.length || disabled) return; | ||
| const allowed = values.reduce((nearest, candidate) => | ||
| const allowed = fractional ? Math.max(minimum, Math.min(maximum, seconds)) : values.reduce((nearest, candidate) => | ||
| Math.abs(candidate - seconds) < Math.abs(nearest - seconds) | ||
| ? candidate | ||
| : nearest, | ||
|
|
@@ -97,7 +99,7 @@ export function DurationControl({ | |
| aria-label={t("canvasNodes.duration.aria")} | ||
| min={min} | ||
| max={max} | ||
| step={1} | ||
| step={fractional ? "any" : 1} | ||
| disabled={disabled || values.length <= 1} | ||
| value={Math.max(min, Math.min(max, value))} | ||
| aria-valuetext={t("canvasNodes.duration.value", { value })} | ||
|
|
@@ -109,6 +111,7 @@ export function DurationControl({ | |
| if (event.buttons === 1) pointerHint(event); | ||
| }} | ||
| onKeyDown={(event) => { | ||
| if (fractional) return; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 小数时长下有几处小问题:(1) 第 114 行 if (fractional) return; 直接禁用了滑杆的 Home/End/方向键步进;(2) 第 103/155 行 disabled={disabled || values.length <= 1} 在单值配置下会连数字输入一起禁掉,用户无法录入小数;(3) 第 54–61 行 hint() 在取值恰为 min/max 时仍返回 limit 提示(此时其实合法)。建议:fractional 时保留键盘步进或统一交给数字输入;单值时仍允许数字输入(仅禁用滑杆);边界取值不再提示 limit。 |
||
| const index = Math.max(0, values.indexOf(value)); | ||
| const next = | ||
| event.key === "Home" | ||
|
|
@@ -142,9 +145,10 @@ export function DurationControl({ | |
| <input | ||
| type="number" | ||
| aria-label={t("canvasNodes.duration.exactAria")} | ||
| title={fractional ? t("generation.duration.fractionalHint") : undefined} | ||
| min={minimum} | ||
| max={maximum} | ||
| step={1} | ||
| step={fractional ? "any" : 1} | ||
| aria-description={limit} | ||
| aria-describedby={notice ? noticeId : undefined} | ||
| value={draft} | ||
|
|
@@ -154,7 +158,7 @@ export function DurationControl({ | |
| setDraft(next); | ||
| // Persist a complete valid number immediately, so dismissing the | ||
| // popover cannot discard it before a native blur is delivered. | ||
| if (next.trim() && values.includes(Number(next))) | ||
| if (next.trim() && Number.isFinite(Number(next)) && (values.includes(Number(next)) || fractional && Number(next) >= minimum && Number(next) <= maximum)) | ||
| choose(Number(next)); | ||
| }} | ||
| onBlur={commit} | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
区间判定只取 min/max,和 H3 实际可达帧不一致:h3_frames(vllm_omni.py)把阶数 steps 夹在 [6,20],对应 107–345 帧、24fps 即 4.458–14.375s;但这里按配置 durations 的 [min,max](H3 预设为 4–15)放行,于是端点 4s/15s 会分别被静默输出为 4.458s/14.375s,用户选区间端点时实际时长偏差最大。建议要么把可接受区间与实际可达帧对齐,要么在 UI 回显 h3_frames 对齐后的实际时长(目前仅靠用户指南提示「拼接前核对实际时长」)。