feat(video): add retrieve video functionality for OpenAI

Implement video retrieval endpoint and integrate it through the API client stack. This enables fetching existing video resources from OpenAI's API.
This commit is contained in:
icarus 2025-10-12 00:52:09 +08:00
parent 9931856a1f
commit 5db5d69cec
5 changed files with 64 additions and 5 deletions

View File

@ -14,7 +14,7 @@ import { addSpan, endSpan } from '@renderer/services/SpanManagerService'
import { StartSpanParams } from '@renderer/trace/types/ModelSpanEntity'
import type { Assistant, GenerateImageParams, Model, Provider } from '@renderer/types'
import type { AiSdkModel, StreamTextParams } from '@renderer/types/aiCoreTypes'
import { CreateVideoParams, CreateVideoResult } from '@renderer/types/video'
import { CreateVideoParams, CreateVideoResult, RetrieveVideoParams, RetrieveVideoResult } from '@renderer/types/video'
import { buildClaudeCodeSystemModelMessage } from '@shared/anthropic'
import { type ImageModel, type LanguageModel, type Provider as AiSdkProvider, wrapLanguageModel } from 'ai'
@ -508,6 +508,13 @@ export default class ModernAiProvider {
return this.legacyProvider.createVideo(params)
}
/**
* We manually implement this method before aisdk supports it well
*/
public async retrieveVideo(params: RetrieveVideoParams): Promise<RetrieveVideoResult> {
return this.legacyProvider.retrieveVideo(params)
}
public getBaseURL(): string {
return this.legacyProvider.getBaseURL()
}

View File

@ -36,7 +36,7 @@ import {
OpenAIResponseSdkTool,
OpenAIResponseSdkToolCall
} from '@renderer/types/sdk'
import { CreateVideoParams } from '@renderer/types/video'
import { CreateVideoParams, RetrieveVideoParams } from '@renderer/types/video'
import { addImageFileToContents } from '@renderer/utils/formats'
import {
isSupportedToolUse,
@ -158,6 +158,11 @@ export class OpenAIResponseAPIClient extends OpenAIBaseClient<
return sdk.videos.create(params.params, params.options)
}
public async retrieveVideo(params: RetrieveVideoParams): Promise<OpenAI.Videos.Video> {
const sdk = await this.getSdkInstance()
return sdk.videos.retrieve(params.videoId, params.options)
}
private async handlePdfFile(file: FileMetadata): Promise<OpenAI.Responses.ResponseInputFile | undefined> {
if (file.size > 32 * MB) return undefined
try {

View File

@ -7,7 +7,7 @@ import { withSpanResult } from '@renderer/services/SpanManagerService'
import { StartSpanParams } from '@renderer/trace/types/ModelSpanEntity'
import type { GenerateImageParams, Model, Provider } from '@renderer/types'
import type { RequestOptions, SdkModel } from '@renderer/types/sdk'
import { CreateVideoParams, CreateVideoResult } from '@renderer/types/video'
import { CreateVideoParams, CreateVideoResult, RetrieveVideoParams, RetrieveVideoResult } from '@renderer/types/video'
import { isSupportedToolUse } from '@renderer/utils/mcp-tools'
import { AihubmixAPIClient } from './clients/aihubmix/AihubmixAPIClient'
@ -182,7 +182,23 @@ export default class AiProvider {
public async createVideo(params: CreateVideoParams): Promise<CreateVideoResult> {
if (this.apiClient instanceof OpenAIResponseAPIClient) {
return this.apiClient.createVideo(params)
const video = await this.apiClient.createVideo(params)
return {
type: 'openai',
video
}
} else {
throw new Error('Video generation is not supported by this provider')
}
}
public async retrieveVideo(params: RetrieveVideoParams): Promise<RetrieveVideoResult> {
if (this.apiClient instanceof OpenAIResponseAPIClient && params.type === 'openai') {
const video = await this.apiClient.retrieveVideo(params)
return {
type: 'openai',
video
}
} else {
throw new Error('Video generation is not supported by this provider')
}

View File

@ -16,7 +16,7 @@ import type { StreamTextParams } from '@renderer/types/aiCoreTypes'
import { type Chunk, ChunkType } from '@renderer/types/chunk'
import { Message } from '@renderer/types/newMessage'
import { SdkModel } from '@renderer/types/sdk'
import { CreateVideoParams, CreateVideoResult } from '@renderer/types/video'
import { CreateVideoParams, CreateVideoResult, RetrieveVideoParams, RetrieveVideoResult } from '@renderer/types/video'
import { removeSpecialCharactersForTopicName, uuid } from '@renderer/utils'
import { abortCompletion, readyToAbort } from '@renderer/utils/abortController'
import { isAbortError } from '@renderer/utils/error'
@ -403,6 +403,11 @@ export async function createVideo(params: CreateVideoParams): Promise<CreateVide
return ai.createVideo(params)
}
export async function retrieveVideo(params: RetrieveVideoParams): Promise<RetrieveVideoResult> {
const ai = new AiProviderNew(params.provider)
return ai.retrieveVideo(params)
}
export function hasApiKey(provider: Provider) {
if (!provider) return false
if (['ollama', 'lmstudio', 'vertexai', 'cherryai'].includes(provider.id)) return true

View File

@ -5,6 +5,7 @@ import { Provider } from './provider'
// Only OpenAI (Responses) is supported for now.
export type VideoEndpointType = 'openai'
// Create Video
interface CreateVideoBaseParams {
type: VideoEndpointType
provider: Provider
@ -28,3 +29,28 @@ export interface OpenAICreateVideoResult extends CreateVideoBaseResult {
}
export type CreateVideoResult = OpenAICreateVideoResult
// Retrieve Video
interface RetrieveVideoBaseParams {
type: VideoEndpointType
provider: Provider
}
export interface OpenAIRetrieveVideoParams extends RetrieveVideoBaseParams {
type: 'openai'
videoId: string
options?: OpenAI.RequestOptions
}
export type RetrieveVideoParams = OpenAIRetrieveVideoParams
interface RetrieveVideoBaseResult {
type: VideoEndpointType
}
export interface OpenAIRetrieveVideoResult extends RetrieveVideoBaseResult {
type: 'openai'
video: OpenAI.Videos.Video
}
export type RetrieveVideoResult = OpenAIRetrieveVideoResult