refactor: share platform file and route helpers
This commit is contained in:
@@ -1,4 +1,8 @@
|
||||
import type { PlaygroundProtocol } from './modelTesterSession.js';
|
||||
import {
|
||||
buildConversationAcceptList,
|
||||
detectConversationFileKind,
|
||||
} from '../../../shared/conversationFileTypes.js';
|
||||
|
||||
export type ConversationFileTransportMode = 'native' | 'inline_only' | 'unsupported';
|
||||
|
||||
@@ -10,44 +14,13 @@ export type ConversationFileCapability = {
|
||||
reason: string;
|
||||
};
|
||||
|
||||
const DOCUMENT_ACCEPT_PARTS = ['.pdf', '.txt', '.md', '.markdown', '.json'] as const;
|
||||
const DOCUMENT_MIME_TYPES = new Set([
|
||||
'application/json',
|
||||
'application/pdf',
|
||||
'text/markdown',
|
||||
'text/plain',
|
||||
]);
|
||||
const DOCUMENT_EXTENSIONS = ['.json', '.md', '.markdown', '.pdf', '.txt'] as const;
|
||||
const IMAGE_EXTENSIONS = ['.avif', '.bmp', '.gif', '.jpeg', '.jpg', '.png', '.svg', '.webp'] as const;
|
||||
const AUDIO_EXTENSIONS = ['.aac', '.flac', '.m4a', '.mp3', '.ogg', '.wav', '.weba'] as const;
|
||||
|
||||
type ConversationFileDescriptor = {
|
||||
filename?: string | null;
|
||||
mimeType?: string | null;
|
||||
};
|
||||
|
||||
type ConversationFileKind = 'document' | 'image' | 'audio' | 'unknown';
|
||||
|
||||
const isSupportedMode = (mode: ConversationFileTransportMode): boolean => mode !== 'unsupported';
|
||||
|
||||
const normalizeName = (value: string | null | undefined): string => (value || '').trim().toLowerCase();
|
||||
|
||||
function detectKindFromFilename(filename: string): ConversationFileKind {
|
||||
if (!filename) return 'unknown';
|
||||
if (DOCUMENT_EXTENSIONS.some((extension) => filename.endsWith(extension))) return 'document';
|
||||
if (IMAGE_EXTENSIONS.some((extension) => filename.endsWith(extension))) return 'image';
|
||||
if (AUDIO_EXTENSIONS.some((extension) => filename.endsWith(extension))) return 'audio';
|
||||
return 'unknown';
|
||||
}
|
||||
|
||||
function resolveConversationFileKind(file: ConversationFileDescriptor): ConversationFileKind {
|
||||
const mimeType = normalizeName(file.mimeType);
|
||||
if (mimeType.startsWith('image/')) return 'image';
|
||||
if (mimeType.startsWith('audio/')) return 'audio';
|
||||
if (DOCUMENT_MIME_TYPES.has(mimeType)) return 'document';
|
||||
return detectKindFromFilename(normalizeName(file.filename));
|
||||
}
|
||||
|
||||
function buildSupportedTypeLabel(capability: ConversationFileCapability): string {
|
||||
const labels: string[] = [];
|
||||
if (isSupportedMode(capability.documentMode)) labels.push('PDF / TXT / Markdown / JSON');
|
||||
@@ -111,11 +84,11 @@ export function resolveConversationFileCapability(
|
||||
}
|
||||
|
||||
export function buildConversationFileAccept(capability: ConversationFileCapability): string {
|
||||
const parts: string[] = [];
|
||||
if (isSupportedMode(capability.documentMode)) parts.push(...DOCUMENT_ACCEPT_PARTS);
|
||||
if (isSupportedMode(capability.imageMode)) parts.push('image/*');
|
||||
if (isSupportedMode(capability.audioMode)) parts.push('audio/*');
|
||||
return parts.join(',');
|
||||
return buildConversationAcceptList({
|
||||
document: isSupportedMode(capability.documentMode),
|
||||
image: isSupportedMode(capability.imageMode),
|
||||
audio: isSupportedMode(capability.audioMode),
|
||||
});
|
||||
}
|
||||
|
||||
export function buildConversationFileHint(capability: ConversationFileCapability): string {
|
||||
@@ -147,7 +120,7 @@ export function isConversationUploadedFileSupported(
|
||||
capability: ConversationFileCapability,
|
||||
file: ConversationFileDescriptor,
|
||||
): boolean {
|
||||
const kind = resolveConversationFileKind(file);
|
||||
const kind = detectConversationFileKind(file);
|
||||
if (kind === 'document') return isSupportedMode(capability.documentMode);
|
||||
if (kind === 'image') return isSupportedMode(capability.imageMode);
|
||||
if (kind === 'audio') return isSupportedMode(capability.audioMode);
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { isTruthyFlag } from './accountConnection.js';
|
||||
|
||||
const FOCUS_SITE_ID_KEY = 'focusSiteId';
|
||||
const FOCUS_ANNOUNCEMENT_ID_KEY = 'focusAnnouncementId';
|
||||
const FOCUS_ACCOUNT_ID_KEY = 'focusAccountId';
|
||||
@@ -10,12 +12,6 @@ function normalizePositiveId(input: unknown): number | null {
|
||||
return value;
|
||||
}
|
||||
|
||||
function isTruthyFlag(value: string | null): boolean {
|
||||
if (!value) return false;
|
||||
const normalized = value.trim().toLowerCase();
|
||||
return normalized === '1' || normalized === 'true' || normalized === 'yes';
|
||||
}
|
||||
|
||||
export function buildSiteFocusPath(siteId: number): string {
|
||||
const normalizedId = normalizePositiveId(siteId);
|
||||
if (!normalizedId) return '/sites';
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { parseProxyLogMetadata } from '../../../shared/proxyLogMeta.js';
|
||||
|
||||
type ProxyLogPathMeta = {
|
||||
clientFamily: string | null;
|
||||
sessionId: string | null;
|
||||
@@ -8,20 +10,13 @@ type ProxyLogPathMeta = {
|
||||
|
||||
export function parseProxyLogPathMeta(message?: string): ProxyLogPathMeta {
|
||||
const raw = typeof message === 'string' ? message.trim() : '';
|
||||
const clientMatch = raw.match(/\[client:([^\]]+)\]/i);
|
||||
const sessionMatch = raw.match(/\[session:([^\]]+)\]/i);
|
||||
const downstreamMatch = raw.match(/\[downstream:([^\]]+)\]/i);
|
||||
const upstreamMatch = raw.match(/\[upstream:([^\]]+)\]/i);
|
||||
const stripped = raw.replace(
|
||||
/^\s*(?:\[(?:client|session|downstream|upstream):[^\]]+\]\s*)+/i,
|
||||
'',
|
||||
).trim();
|
||||
const parsed = parseProxyLogMetadata(raw);
|
||||
|
||||
return {
|
||||
clientFamily: clientMatch?.[1]?.trim() || null,
|
||||
sessionId: sessionMatch?.[1]?.trim() || null,
|
||||
downstreamPath: downstreamMatch?.[1]?.trim() || null,
|
||||
upstreamPath: upstreamMatch?.[1]?.trim() || null,
|
||||
errorMessage: stripped,
|
||||
clientFamily: parsed.clientKind,
|
||||
sessionId: parsed.sessionId,
|
||||
downstreamPath: parsed.downstreamPath,
|
||||
upstreamPath: parsed.upstreamPath,
|
||||
errorMessage: parsed.messageText,
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user