Add renderMessage func

This commit is contained in:
braginini
2026-03-16 19:19:29 +01:00
parent cca4af2ee0
commit 6226ff8e82
3 changed files with 31 additions and 17 deletions
+4 -1
View File
@@ -8,7 +8,7 @@ import React, {
useState,
} from "react";
import type { ExplainContext, ExplainEvent } from "../types";
import AIChatBot from "./AIChatBot";
import AIChatBot, { type MessageRenderer } from "./AIChatBot";
import AIFloatingButton from "./AIFloatingButton";
import * as S from "./styles";
@@ -44,6 +44,7 @@ type AIAssistantProviderProps = {
subtitle?: string;
onExplain?: (event: ExplainEvent) => void;
showChat?: boolean;
renderMessage?: MessageRenderer;
};
/**
@@ -125,6 +126,7 @@ export default function AIAssistantProvider({
subtitle,
onExplain,
showChat = true,
renderMessage,
}: AIAssistantProviderProps) {
const [isChatOpen, setIsChatOpen] = useState(false);
const [initialQuery, setInitialQuery] = useState("");
@@ -309,6 +311,7 @@ export default function AIAssistantProvider({
apiKey={apiKey}
title={title}
subtitle={subtitle}
renderMessage={renderMessage}
/>
</>
)}
+26 -16
View File
@@ -12,6 +12,8 @@ import React, { useCallback, useEffect, useRef, useState } from "react";
import type { Message } from "../types";
import * as S from "./styles";
export type MessageRenderer = (message: Message) => React.ReactNode;
type Props = {
open: boolean;
onClose: () => void;
@@ -20,6 +22,7 @@ type Props = {
apiKey?: string;
title?: string;
subtitle?: string;
renderMessage?: MessageRenderer;
};
async function fetchAIResponse(
@@ -54,6 +57,25 @@ async function fetchAIResponse(
return data.reply;
}
function defaultRenderMessage(msg: Message): React.ReactNode {
return msg.content.split("\n").map((line, i) => (
<React.Fragment key={i}>
{line
.split(/(\*\*[^*]+\*\*)/)
.map((part, j) =>
part.startsWith("**") && part.endsWith("**") ? (
<strong key={j} style={S.messageBold}>
{part.slice(2, -2)}
</strong>
) : (
<React.Fragment key={j}>{part}</React.Fragment>
),
)}
{i < msg.content.split("\n").length - 1 && <br />}
</React.Fragment>
));
}
export default function AIChatBot({
open,
onClose,
@@ -62,6 +84,7 @@ export default function AIChatBot({
apiKey,
title = "AI Assistant",
subtitle = "Ask anything",
renderMessage,
}: Props) {
const [messages, setMessages] = useState<Message[]>([]);
const [input, setInput] = useState("");
@@ -244,22 +267,9 @@ export default function AIChatBot({
</div>
)}
<div style={S.messageBubble(msg.role === "user")}>
{msg.content.split("\n").map((line, i) => (
<React.Fragment key={i}>
{line
.split(/(\*\*[^*]+\*\*)/)
.map((part, j) =>
part.startsWith("**") && part.endsWith("**") ? (
<strong key={j} style={S.messageBold}>
{part.slice(2, -2)}
</strong>
) : (
<React.Fragment key={j}>{part}</React.Fragment>
),
)}
{i < msg.content.split("\n").length - 1 && <br />}
</React.Fragment>
))}
{renderMessage
? renderMessage(msg)
: defaultRenderMessage(msg)}
</div>
{msg.role === "user" && (
<div style={S.messageAvatar(true)}>
+1
View File
@@ -1,4 +1,5 @@
export { default as AIAssistantProvider, useAIAssistant } from "./AIAssistantProvider";
export { default as AIChatBot } from "./AIChatBot";
export type { MessageRenderer } from "./AIChatBot";
export { default as AIFloatingButton } from "./AIFloatingButton";
export type { Message, ExplainContext, ExplainEvent } from "../types";