Add support for image input in model resources and enhance related configurations

- Introduce a new `support_image_input` field in model resources, allowing models to indicate support for image input.
- Update the backend models, schemas, and database seed scripts to accommodate the new field.
- Enhance the AssistantConfig and related routes to handle image input capabilities, ensuring proper validation and error handling.
- Modify the frontend components to include toggles for enabling visual understanding and filtering models based on image input support.
- Implement necessary adjustments in the voice preview and pipeline to integrate video stream handling alongside audio functionalities.
This commit is contained in:
Xin Wang
2026-07-07 19:41:45 +08:00
parent 32a52d318a
commit c5db918830
18 changed files with 411 additions and 116 deletions

View File

@@ -23,6 +23,11 @@ import { API_BASE, webrtcApi } from "@/lib/api";
export type VoicePreviewStatus = "idle" | "connecting" | "connected" | "failed";
type ConnectOptions = {
visionEnabled?: boolean;
videoStream?: MediaStream | null;
};
export type ChatMessage = {
id: string;
role: "user" | "assistant";
@@ -218,7 +223,7 @@ export function useVoicePreview(
[disconnect, fail],
);
const connect = useCallback(async () => {
const connect = useCallback(async (options: ConnectOptions = {}) => {
if (startingRef.current || pcRef.current || wsRef.current) return;
if (!assistantId) {
setError("请先保存助手,再开始语音预览。");
@@ -456,6 +461,11 @@ export function useVoicePreview(
} else {
pc.addTransceiver("audio", { direction: "recvonly" });
}
if (options.videoStream) {
options.videoStream
.getVideoTracks()
.forEach((track) => pc.addTrack(track, options.videoStream!));
}
// 4) 生成 offer 并发给后端(assistant_id 在 payload 顶层)
const offer = await pc.createOffer();
@@ -472,6 +482,7 @@ export function useVoicePreview(
sdp: localDescription.sdp,
type: localDescription.type,
assistant_id: assistantId,
vision_enabled: Boolean(options.visionEnabled),
},
}),
);
@@ -482,6 +493,17 @@ export function useVoicePreview(
}
}, [assistantId, fail, closeOnRemoteEnd, refreshDevices]);
const replaceVideoStream = useCallback(
async (videoStream: MediaStream | null) => {
const pc = pcRef.current;
if (!pc) return;
const sender = pc.getSenders().find((s) => s.track?.kind === "video");
if (!sender) return;
await sender.replaceTrack(videoStream?.getVideoTracks()[0] ?? null);
},
[],
);
// 选择麦克风:更新选择;若会话正在发送麦克风音频,则用 WebRTC replaceTrack
// 热切换轨道(无需重新协商),并把波形可视化重新接到新流。
// 未连接时仅记下选择,留待下次 connect 生效。
@@ -558,6 +580,7 @@ export function useVoicePreview(
selectDevice,
sendText,
connect,
replaceVideoStream,
disconnect,
audioRef,
};