Skip to content
Merged
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
58 changes: 24 additions & 34 deletions frontend/app/analyze/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,9 @@ export default function AnalysisResultsPage({
const [results, setResults] = useState<AnalysisResults | null>(null);
const [isAnalysisLoading, setIsAnalysisLoading] = useState(!conversationId);
const [diagramAnalysis, setDiagramAnalysis] = useState("");
const [analysisError, setAnalysisError] = useState("");
const [combinedMessages, setCombinedMessages] = useState<string[]>([]);
const [combinedMessages, setCombinedMessages] = useState<
{ role: "user" | "assistant"; content: string }[]
>([]);
const [biomodelData, setBiomodelData] = useState<BiomodelDetail | null>(null);
const [biomodelLoading, setBiomodelLoading] = useState(true);
const [showLoginDialog, setShowLoginDialog] = useState(false);
Expand Down Expand Up @@ -135,32 +136,15 @@ export default function AnalysisResultsPage({
// is already part of the stored history, no need to regenerate it.
if (conversationId) return;

// Diagram analyses are being precomputed and stored for all biomodels
// instead of generated on demand per request, so skip the /diagram
// call for now and show a placeholder instead.
const fetchDiagramAnalysis = async () => {
setIsAnalysisLoading(true);
setAnalysisError("");
try {
const token = await getAccessToken();
const apiUrl = process.env.NEXT_PUBLIC_API_URL;
const res = await fetch(`${apiUrl}/analyse/${id}/diagram`, {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
},
});

if (res.ok) {
const data = await res.json();
setDiagramAnalysis(data.response || "");
} else {
const errorData = await res.json();
setAnalysisError(errorData.detail || "Failed to analyze diagram.");
}
} catch (err) {
setAnalysisError("Failed to fetch diagram analysis.");
} finally {
setIsAnalysisLoading(false);
}
setDiagramAnalysis(
"AI generated summary/analysis of this biomodel will be displayed here.",
);
setIsAnalysisLoading(false);
};

const fetchAnalysis = async () => {
Expand Down Expand Up @@ -206,21 +190,27 @@ export default function AnalysisResultsPage({
// Create combined messages when analyses are ready
useEffect(() => {
if (diagramAnalysis || results?.aiAnalysis) {
const messageParts: string[] = [];
const newMessages: { role: "user" | "assistant"; content: string }[] = [];

if (diagramAnalysis) {
const diagramMessage = `# Diagram Analysis \n ${diagramAnalysis}`;
messageParts.push(diagramMessage);
newMessages.push({
role: "assistant",
content: `# Diagram Analysis \n ${diagramAnalysis}`,
});
}

if (results?.aiAnalysis) {
const aiMessage = `# Biomodel Analysis \n ${results.aiAnalysis}`;
messageParts.push(aiMessage);
if (prompt.trim()) {
newMessages.push({ role: "user", content: prompt });
}

const joined_messages = messageParts.join("\n\n");
if (results?.aiAnalysis) {
newMessages.push({
role: "assistant",
content: `# Biomodel Analysis \n ${results.aiAnalysis}`,
});
}

setCombinedMessages([joined_messages]);
setCombinedMessages(newMessages);
}
}, [diagramAnalysis, results?.aiAnalysis, id]);

Expand Down
30 changes: 7 additions & 23 deletions frontend/app/search/[bmid]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import {
Briefcase,
Cog,
} from "lucide-react";
import { getAccessToken, useUser } from "@auth0/nextjs-auth0/client";
import { useUser } from "@auth0/nextjs-auth0/client";
import { LoginRequiredDialog } from "@/components/login-required-dialog";
import { SignInOutButton } from "@/components/sign-in-out-button";
import { getOptionalAccessToken } from "@/lib/get-optional-access-token";
Expand Down Expand Up @@ -98,7 +98,6 @@ export default function BiomodelDetailPage() {
conversationId ? "analysis" : "overview",
);
const [diagramAnalysis, setDiagramAnalysis] = useState("");
const [analysisError, setAnalysisError] = useState("");
const [combinedMessages, setCombinedMessages] = useState<string[]>([]);
const [showLoginDialog, setShowLoginDialog] = useState(false);
const [diagramImageUrl, setDiagramImageUrl] = useState("");
Expand Down Expand Up @@ -205,28 +204,13 @@ export default function BiomodelDetailPage() {
if (diagramFetchTriggeredRef.current) return;
diagramFetchTriggeredRef.current = true;

// Diagram analyses are being precomputed and stored for all biomodels
// instead of generated on demand per request, so skip the /diagram
// call for now and show a placeholder instead.
const fetchDiagramAnalysis = async () => {
try {
const token = await getAccessToken();
const apiUrl = process.env.NEXT_PUBLIC_API_URL;
const res = await fetch(`${apiUrl}/analyse/${data.bmKey}/diagram`, {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
},
});

if (res.ok) {
const responseData = await res.json();
setDiagramAnalysis(responseData.response || "");
} else {
const errorData = await res.json();
setAnalysisError(errorData.detail || "Failed to analyze diagram.");
}
} catch (err) {
setAnalysisError("Failed to fetch diagram analysis.");
}
setDiagramAnalysis(
"AI generated summary/analysis of this biomodel will be displayed here.",
);
};

fetchDiagramAnalysis();
Expand Down
17 changes: 8 additions & 9 deletions frontend/components/ChatBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,10 @@ interface ChatParameters {
llmMode: string;
}

type SeedMessage = string | { role: "user" | "assistant"; content: string };

interface ChatBoxProps {
startMessage: string | string[];
startMessage: string | SeedMessage[];
quickActions: QuickAction[];
supplementalActions?: QuickAction[];
cardTitle: string;
Expand All @@ -61,12 +63,12 @@ interface ChatBoxProps {
}

// Pure helpers — no dependency on component state/props.
const createInitialMessages = (startMsg: string | string[]): Message[] => {
const createInitialMessages = (startMsg: string | SeedMessage[]): Message[] => {
if (Array.isArray(startMsg)) {
return startMsg.map((content, index) => ({
return startMsg.map((seed, index) => ({
id: (index + 1).toString(),
role: "assistant" as const,
content,
role: typeof seed === "string" ? ("assistant" as const) : seed.role,
content: typeof seed === "string" ? seed : seed.content,
timestamp: new Date(),
}));
} else if (startMsg) {
Expand Down Expand Up @@ -166,10 +168,7 @@ export const ChatBox: React.FC<ChatBoxProps> = ({
useEffect(() => {
if (boundConversationId) return;
if (!startMessage || isInitialLoading) return;
setLocalSeedMessages((prev) => {
if (prev.some((m) => m.role === "user")) return prev;
return createInitialMessages(startMessage);
});
setLocalSeedMessages(createInitialMessages(startMessage));
}, [startMessage, isInitialLoading, boundConversationId]);

const handleQuickAction = (action: QuickAction) => {
Expand Down
Loading