🐛 fix: use JSON object for video image reference (#14900)

This commit is contained in:
YuTengjing
2026-05-18 00:55:29 +08:00
committed by GitHub
parent f3f2bda880
commit 7e514ac3e3
3 changed files with 73 additions and 3 deletions
+40
View File
@@ -21,6 +21,46 @@ jobs:
- name: Checkout repository
uses: actions/checkout@v6
# Remind contributors when a non-release PR targets `main`.
# Day-to-day PRs should target `canary`; `main` is reserved for releases
# (see .agents/skills/version-release/SKILL.md). Allowed exceptions:
# - PR title matches `🚀 release: v{x.y.z}` (minor release)
# - head branch matches `hotfix/*` or `release/*` (patch release)
- name: Remind contributor if base branch is not canary
if: github.event.action == 'opened' && github.event.pull_request.base.ref == 'main'
env:
HEAD_REF: ${{ github.event.pull_request.head.ref }}
PR_TITLE: ${{ github.event.pull_request.title }}
PR_NUMBER: ${{ github.event.pull_request.number }}
GH_TOKEN: ${{ secrets.GH_TOKEN }}
run: |
if [[ "$HEAD_REF" == hotfix/* ]] || [[ "$HEAD_REF" == release/* ]]; then
echo "✅ Release/hotfix branch ($HEAD_REF) -> main is allowed"
exit 0
fi
if [[ "$PR_TITLE" =~ ^🚀[[:space:]]+release: ]]; then
echo "✅ Release-titled PR -> main is allowed"
exit 0
fi
echo "⚠️ Non-release PR targets main; posting reminder comment."
gh pr comment "$PR_NUMBER" --body "$(cat <<'EOF'
👋 Thanks for your contribution!
This PR currently targets the **`main`** branch, but `main` is reserved for release PRs only. Day-to-day development (features, fixes, refactors, docs, etc.) should target the **`canary`** branch.
### How to fix
On the PR page, click **Edit** next to the title, then change the base branch from `main` to `canary`.
### When targeting `main` is allowed
- PR title starts with `🚀 release: v{x.y.z}` (minor release)
- Head branch matches `hotfix/*` or `release/*` (patch release)
If your PR fits one of these cases, please ignore this message.
EOF
)"
- name: Check if author is a team member
id: check-team
run: |
@@ -19,6 +19,12 @@ const mockOptions: CreateVideoOptions = {
provider: 'openai',
};
const mockVllmOptions: CreateVideoOptions = {
apiKey: 'test-api-key',
baseURL: 'http://localhost:8000/v1',
provider: 'vllm',
};
beforeEach(() => {
vi.clearAllMocks();
});
@@ -95,7 +101,7 @@ describe('createOpenAICompatibleVideo', () => {
expect(body.size).toBe('1920x1080');
});
it('should include imageUrl as input_reference', async () => {
it('should include imageUrl as JSON input_reference object', async () => {
global.fetch = vi.fn().mockResolvedValueOnce({
ok: true,
json: async () => ({ id: 'video-task-img' }),
@@ -111,6 +117,26 @@ describe('createOpenAICompatibleVideo', () => {
await createOpenAICompatibleVideo(payload, mockOptions);
const body = JSON.parse((global.fetch as any).mock.calls[0][1].body);
expect(body.input_reference).toEqual({ image_url: 'https://example.com/image.jpg' });
});
it('should preserve string input_reference for non-OpenAI compatible providers', async () => {
global.fetch = vi.fn().mockResolvedValueOnce({
ok: true,
json: async () => ({ id: 'video-task-vllm-img' }),
});
const payload: CreateVideoPayload = {
model: 'vllm-omni',
params: {
prompt: 'Continue this scene',
imageUrl: 'https://example.com/image.jpg',
},
};
await createOpenAICompatibleVideo(payload, mockVllmOptions);
const body = JSON.parse((global.fetch as any).mock.calls[0][1].body);
expect(body.input_reference).toBe('https://example.com/image.jpg');
});
@@ -1,4 +1,5 @@
import createDebug from 'debug';
import { ModelProvider } from 'model-bank';
import type {
CreateVideoPayload,
@@ -115,7 +116,7 @@ export async function pollOpenAICompatibleVideoStatus(
* model: string,
* prompt: string,
* seconds?: string, // OpenAI Sora format (string type)
* input_reference?: string | object, // For image-to-video
* input_reference?: string | { image_url: string } | { file_id: string }, // For image-to-video
* }
*
* Creates a video generation task and returns immediately with inferenceId.
@@ -150,7 +151,10 @@ export async function createOpenAICompatibleVideo(
// Image-to-video support
if (imageUrl) {
body['input_reference'] = imageUrl;
// OpenAI JSON requests reject bare strings, for example:
// `input_reference: "https://example.com/image.jpg"`.
body['input_reference'] =
options.provider === ModelProvider.OpenAI ? { image_url: imageUrl } : imageUrl;
}
log('OpenAI-compatible video API request body: %O', body);