| import { lazy, Suspense } from "react"; |
| import { ResultTable } from "./ResultTable"; |
| import { DatabaseIcon, WindIcon } from "./icons"; |
| import type { ConversationMessage } from "./types"; |
|
|
| const AnalysisChart = lazy(() => |
| import("./AnalysisChart").then((module) => ({ |
| default: module.AnalysisChart, |
| })), |
| ); |
|
|
| export function ChatMessage({ message }: { message: ConversationMessage }) { |
| if (message.role === "user") { |
| return ( |
| <article className="message message--user"> |
| <div className="user-bubble">{message.content}</div> |
| </article> |
| ); |
| } |
|
|
| return ( |
| <article className={`message message--assistant ${message.error ? "has-error" : ""}`}> |
| <div className="assistant-avatar"> |
| <WindIcon /> |
| </div> |
| <div className="assistant-body"> |
| <div className="assistant-meta"> |
| <strong>VayuChat</strong> |
| <span>Gemini 3.5 Flash-Lite</span> |
| </div> |
| {message.error ? ( |
| <div className="answer-error" role="alert"> |
| <strong>Analysis stopped</strong> |
| <p>{message.error}</p> |
| </div> |
| ) : ( |
| <> |
| <p className="answer-lead">{message.result?.answer ?? message.content}</p> |
| {message.result?.key_points.length ? ( |
| <ul className="key-points"> |
| {message.result.key_points.map((point) => ( |
| <li key={point}>{point}</li> |
| ))} |
| </ul> |
| ) : null} |
| {message.result ? ( |
| <Suspense fallback={<div className="chart-loading" aria-hidden="true" />}> |
| <AnalysisChart result={message.result} /> |
| </Suspense> |
| ) : null} |
| {message.result ? <ResultTable result={message.result} /> : null} |
| {message.result?.method_note || message.result?.query ? ( |
| <details className="method-details"> |
| <summary> |
| <DatabaseIcon /> |
| How this was calculated |
| </summary> |
| {message.result.method_note ? <p>{message.result.method_note}</p> : null} |
| {message.result.query ? <pre>{message.result.query}</pre> : null} |
| </details> |
| ) : null} |
| </> |
| )} |
| </div> |
| </article> |
| ); |
| } |
|
|