Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 42 additions & 2 deletions app/api/parse-pdf/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ import type { ParsedPdfContent } from '@/lib/types/pdf';
import { createLogger } from '@/lib/logger';
import { apiError, apiSuccess } from '@/lib/server/api-response';
import { validateUrlForSSRF } from '@/lib/server/ssrf-guard';

export const runtime = 'nodejs';
export const dynamic = 'force-dynamic';

const log = createLogger('Parse PDF');

export async function POST(req: NextRequest) {
Expand All @@ -27,6 +31,10 @@ export async function POST(req: NextRequest) {
const providerId = formData.get('providerId') as PDFProviderId | null;
const apiKey = formData.get('apiKey') as string | null;
const baseUrl = formData.get('baseUrl') as string | null;
const cloudApiKey = formData.get('cloudApiKey') as string | null;
const cloudBaseUrl = formData.get('cloudBaseUrl') as string | null;
const localApiKey = formData.get('localApiKey') as string | null;
const localBaseUrl = formData.get('localBaseUrl') as string | null;

if (!pdfFile) {
return apiError('MISSING_REQUIRED_FIELD', 400, 'No PDF file provided');
Expand All @@ -37,7 +45,39 @@ export async function POST(req: NextRequest) {
pdfFileName = pdfFile?.name;
resolvedProviderId = effectiveProviderId;

const clientBaseUrl = baseUrl || undefined;
const resolveClientPdfConfig = () => {
const legacyBaseUrl = baseUrl?.trim() || '';
const legacyApiKey = apiKey?.trim() || '';

if (effectiveProviderId !== 'mineru') {
return {
clientBaseUrl: legacyBaseUrl || undefined,
clientApiKey: legacyApiKey || undefined,
};
}

const cloudUrl = cloudBaseUrl?.trim() || '';
const cloudKey = cloudApiKey?.trim() || '';
const localUrl = localBaseUrl?.trim() || '';
const localKey = localApiKey?.trim() || '';

// Prefer cloud when it is complete, then local, then legacy fallback.
if (cloudUrl && cloudKey) {
return { clientBaseUrl: cloudUrl, clientApiKey: cloudKey };
}
if (localUrl) {
return { clientBaseUrl: localUrl, clientApiKey: localKey || undefined };
}
if (cloudUrl) {
return { clientBaseUrl: cloudUrl, clientApiKey: cloudKey || undefined };
}
return {
clientBaseUrl: legacyBaseUrl || undefined,
clientApiKey: legacyApiKey || undefined,
};
};

const { clientBaseUrl, clientApiKey } = resolveClientPdfConfig();
if (clientBaseUrl && process.env.NODE_ENV === 'production') {
const ssrfError = validateUrlForSSRF(clientBaseUrl);
if (ssrfError) {
Expand All @@ -48,7 +88,7 @@ export async function POST(req: NextRequest) {
const config = {
providerId: effectiveProviderId,
apiKey: clientBaseUrl
? apiKey || ''
? clientApiKey || ''
: resolvePDFApiKey(effectiveProviderId, apiKey || undefined),
baseUrl: clientBaseUrl
? clientBaseUrl
Expand Down
70 changes: 66 additions & 4 deletions app/generation-preview/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,50 @@ import { StepVisualizer } from './components/visualizers';

const log = createLogger('GenerationPreview');

function resolveEffectivePdfConfig(
providerId?: string,
config?: {
apiKey?: string;
baseUrl?: string;
cloudApiKey?: string;
cloudBaseUrl?: string;
localApiKey?: string;
localBaseUrl?: string;
},
): { apiKey?: string; baseUrl?: string } {
if (!config) return {};

const legacyBaseUrl = config.baseUrl?.trim() || '';
const legacyApiKey = config.apiKey?.trim() || '';

if (providerId !== 'mineru') {
return {
apiKey: legacyApiKey || undefined,
baseUrl: legacyBaseUrl || undefined,
};
}

const cloudBaseUrl = config.cloudBaseUrl?.trim() || '';
const cloudApiKey = config.cloudApiKey?.trim() || '';
const localBaseUrl = config.localBaseUrl?.trim() || '';
const localApiKey = config.localApiKey?.trim() || '';

// Prefer cloud when complete, otherwise local, then legacy.
if (cloudBaseUrl && cloudApiKey) {
return { baseUrl: cloudBaseUrl, apiKey: cloudApiKey };
}
if (localBaseUrl) {
return { baseUrl: localBaseUrl, apiKey: localApiKey || undefined };
}
if (cloudBaseUrl) {
return { baseUrl: cloudBaseUrl, apiKey: cloudApiKey || undefined };
}
return {
baseUrl: legacyBaseUrl || undefined,
apiKey: legacyApiKey || undefined,
};
}

function GenerationPreviewContent() {
const router = useRouter();
const { t } = useI18n();
Expand Down Expand Up @@ -183,11 +227,29 @@ function GenerationPreviewContent() {
if (currentSession.pdfProviderId) {
parseFormData.append('providerId', currentSession.pdfProviderId);
}
if (currentSession.pdfProviderConfig?.apiKey?.trim()) {
parseFormData.append('apiKey', currentSession.pdfProviderConfig.apiKey);

const resolvedPdfConfig = resolveEffectivePdfConfig(
currentSession.pdfProviderId,
currentSession.pdfProviderConfig,
);
if (resolvedPdfConfig.apiKey) {
parseFormData.append('apiKey', resolvedPdfConfig.apiKey);
}
if (resolvedPdfConfig.baseUrl) {
parseFormData.append('baseUrl', resolvedPdfConfig.baseUrl);
}

if (currentSession.pdfProviderConfig?.cloudApiKey?.trim()) {
parseFormData.append('cloudApiKey', currentSession.pdfProviderConfig.cloudApiKey);
}
if (currentSession.pdfProviderConfig?.cloudBaseUrl?.trim()) {
parseFormData.append('cloudBaseUrl', currentSession.pdfProviderConfig.cloudBaseUrl);
}
if (currentSession.pdfProviderConfig?.localApiKey?.trim()) {
parseFormData.append('localApiKey', currentSession.pdfProviderConfig.localApiKey);
}
if (currentSession.pdfProviderConfig?.baseUrl?.trim()) {
parseFormData.append('baseUrl', currentSession.pdfProviderConfig.baseUrl);
if (currentSession.pdfProviderConfig?.localBaseUrl?.trim()) {
parseFormData.append('localBaseUrl', currentSession.pdfProviderConfig.localBaseUrl);
}

const parseResponse = await fetch('/api/parse-pdf', {
Expand Down
9 changes: 8 additions & 1 deletion app/generation-preview/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,14 @@ export interface GenerationSessionState {
pdfStorageKey?: string;
pdfFileName?: string;
pdfProviderId?: string;
pdfProviderConfig?: { apiKey?: string; baseUrl?: string };
pdfProviderConfig?: {
apiKey?: string;
baseUrl?: string;
cloudApiKey?: string;
cloudBaseUrl?: string;
localApiKey?: string;
localBaseUrl?: string;
};
// Web search context
researchContext?: string;
researchSources?: Array<{ title: string; url: string }>;
Expand Down
15 changes: 14 additions & 1 deletion app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,16 @@ function HomePage() {
let pdfStorageKey: string | undefined;
let pdfFileName: string | undefined;
let pdfProviderId: string | undefined;
let pdfProviderConfig: { apiKey?: string; baseUrl?: string } | undefined;
let pdfProviderConfig:
| {
apiKey?: string;
baseUrl?: string;
cloudApiKey?: string;
cloudBaseUrl?: string;
localApiKey?: string;
localBaseUrl?: string;
}
| undefined;

if (form.pdfFile) {
pdfStorageKey = await storePdfBlob(form.pdfFile);
Expand All @@ -283,6 +292,10 @@ function HomePage() {
pdfProviderConfig = {
apiKey: providerCfg.apiKey,
baseUrl: providerCfg.baseUrl,
cloudApiKey: providerCfg.cloudApiKey,
cloudBaseUrl: providerCfg.cloudBaseUrl,
localApiKey: providerCfg.localApiKey,
localBaseUrl: providerCfg.localBaseUrl,
};
}
}
Expand Down
Loading
Loading