mirror of
https://github.com/gradio-app/gradio.git
synced 2025-01-30 11:00:11 +08:00
Revert chatbot styling (#8758)
* fix * fix * add changeset * add changeset * tests * Fix button panel (#8762) --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> Co-authored-by: Freddy Boulton <alfonsoboulton@gmail.com>
This commit is contained in:
parent
078663a3a4
commit
26cdd0ffe0
6
.changeset/nine-ways-sink.md
Normal file
6
.changeset/nine-ways-sink.md
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
"@gradio/chatbot": patch
|
||||||
|
"gradio": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
fix:Revert chatbot styling
|
@ -1 +1 @@
|
|||||||
{"cells": [{"cell_type": "markdown", "id": "302934307671667531413257853548643485645", "metadata": {}, "source": ["# Gradio Demo: chatbot_with_tools"]}, {"cell_type": "code", "execution_count": null, "id": "272996653310673477252411125948039410165", "metadata": {}, "outputs": [], "source": ["!pip install -q gradio "]}, {"cell_type": "code", "execution_count": null, "id": "288918539441861185822528903084949547379", "metadata": {}, "outputs": [], "source": ["import gradio as gr\n", "from gradio import ChatMessage\n", "import time\n", "\n", "def generate_response(history):\n", " history.append(ChatMessage(role=\"user\", content=\"What is the weather in San Francisco right now?\"))\n", " yield history\n", " time.sleep(0.25)\n", " history.append(ChatMessage(role=\"assistant\",\n", " content=\"In order to find the current weather in San Francisco, I will need to use my weather tool.\")\n", " )\n", " yield history\n", " time.sleep(0.25)\n", "\n", " history.append(ChatMessage(role=\"assistant\",\n", " content=\"API Error when connecting to weather service.\",\n", " metadata={\"title\": \"\ud83d\udca5 Error using tool 'Weather'\"})\n", " )\n", " yield history\n", " time.sleep(0.25)\n", "\n", " history.append(ChatMessage(role=\"assistant\",\n", " content=\"I will try again\",\n", " ))\n", " yield history\n", " time.sleep(0.25)\n", "\n", " history.append(ChatMessage(role=\"assistant\",\n", " content=\"Weather 72 degrees Fahrenheit with 20% chance of rain.\",\n", " metadata={\"title\": \"\ud83d\udee0\ufe0f Used tool 'Weather'\"}\n", " ))\n", " yield history\n", " time.sleep(0.25)\n", "\n", " history.append(ChatMessage(role=\"assistant\",\n", " content=\"Now that the API succeeded I can complete my task.\",\n", " ))\n", " yield history\n", " time.sleep(0.25)\n", "\n", " history.append(ChatMessage(role=\"assistant\",\n", " content=\"It's a sunny day in San Francisco with a current temperature of 72 degrees Fahrenheit and a 20% chance of rain. Enjoy the weather!\",\n", " ))\n", " yield history\n", "\n", "\n", "with gr.Blocks() as demo:\n", " chatbot = gr.Chatbot(type=\"messages\")\n", " button = gr.Button(\"Get San Francisco Weather\")\n", " button.click(generate_response, chatbot, chatbot)\n", "\n", "if __name__ == \"__main__\":\n", " demo.launch()\n"]}], "metadata": {}, "nbformat": 4, "nbformat_minor": 5}
|
{"cells": [{"cell_type": "markdown", "id": "302934307671667531413257853548643485645", "metadata": {}, "source": ["# Gradio Demo: chatbot_with_tools"]}, {"cell_type": "code", "execution_count": null, "id": "272996653310673477252411125948039410165", "metadata": {}, "outputs": [], "source": ["!pip install -q gradio "]}, {"cell_type": "code", "execution_count": null, "id": "288918539441861185822528903084949547379", "metadata": {}, "outputs": [], "source": ["import gradio as gr\n", "from gradio import ChatMessage\n", "import time\n", "\n", "\n", "def generate_response(history):\n", " history.append(\n", " ChatMessage(\n", " role=\"user\", content=\"What is the weather in San Francisco right now?\"\n", " )\n", " )\n", " yield history\n", " time.sleep(0.25)\n", " history.append(\n", " ChatMessage(\n", " role=\"assistant\",\n", " content=\"In order to find the current weather in San Francisco, I will need to use my weather tool.\",\n", " )\n", " )\n", " yield history\n", " time.sleep(0.25)\n", "\n", " history.append(\n", " ChatMessage(\n", " role=\"assistant\",\n", " content=\"API Error when connecting to weather service.\",\n", " metadata={\"title\": \"\ud83d\udca5 Error using tool 'Weather'\"},\n", " )\n", " )\n", " yield history\n", " time.sleep(0.25)\n", "\n", " history.append(\n", " ChatMessage(\n", " role=\"assistant\",\n", " content=\"I will try again\",\n", " )\n", " )\n", " yield history\n", " time.sleep(0.25)\n", "\n", " history.append(\n", " ChatMessage(\n", " role=\"assistant\",\n", " content=\"Weather 72 degrees Fahrenheit with 20% chance of rain.\",\n", " metadata={\"title\": \"\ud83d\udee0\ufe0f Used tool 'Weather'\"},\n", " )\n", " )\n", " yield history\n", " time.sleep(0.25)\n", "\n", " history.append(\n", " ChatMessage(\n", " role=\"assistant\",\n", " content=\"Now that the API succeeded I can complete my task.\",\n", " )\n", " )\n", " yield history\n", " time.sleep(0.25)\n", "\n", " history.append(\n", " ChatMessage(\n", " role=\"assistant\",\n", " content=\"It's a sunny day in San Francisco with a current temperature of 72 degrees Fahrenheit and a 20% chance of rain. Enjoy the weather!\",\n", " )\n", " )\n", " yield history\n", "\n", "\n", "def like(evt: gr.LikeData):\n", " print(\"User liked the response\")\n", " print(evt.index, evt.liked, evt.value)\n", "\n", "\n", "with gr.Blocks() as demo:\n", " chatbot = gr.Chatbot(type=\"messages\", height=500, show_copy_button=True)\n", " button = gr.Button(\"Get San Francisco Weather\")\n", " button.click(generate_response, chatbot, chatbot)\n", " chatbot.like(like)\n", "\n", "if __name__ == \"__main__\":\n", " demo.launch()\n"]}], "metadata": {}, "nbformat": 4, "nbformat_minor": 5}
|
@ -2,52 +2,81 @@ import gradio as gr
|
|||||||
from gradio import ChatMessage
|
from gradio import ChatMessage
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
|
||||||
def generate_response(history):
|
def generate_response(history):
|
||||||
history.append(ChatMessage(role="user", content="What is the weather in San Francisco right now?"))
|
history.append(
|
||||||
|
ChatMessage(
|
||||||
|
role="user", content="What is the weather in San Francisco right now?"
|
||||||
|
)
|
||||||
|
)
|
||||||
yield history
|
yield history
|
||||||
time.sleep(0.25)
|
time.sleep(0.25)
|
||||||
history.append(ChatMessage(role="assistant",
|
history.append(
|
||||||
content="In order to find the current weather in San Francisco, I will need to use my weather tool.")
|
ChatMessage(
|
||||||
|
role="assistant",
|
||||||
|
content="In order to find the current weather in San Francisco, I will need to use my weather tool.",
|
||||||
|
)
|
||||||
)
|
)
|
||||||
yield history
|
yield history
|
||||||
time.sleep(0.25)
|
time.sleep(0.25)
|
||||||
|
|
||||||
history.append(ChatMessage(role="assistant",
|
history.append(
|
||||||
|
ChatMessage(
|
||||||
|
role="assistant",
|
||||||
content="API Error when connecting to weather service.",
|
content="API Error when connecting to weather service.",
|
||||||
metadata={"title": "💥 Error using tool 'Weather'"})
|
metadata={"title": "💥 Error using tool 'Weather'"},
|
||||||
|
)
|
||||||
)
|
)
|
||||||
yield history
|
yield history
|
||||||
time.sleep(0.25)
|
time.sleep(0.25)
|
||||||
|
|
||||||
history.append(ChatMessage(role="assistant",
|
history.append(
|
||||||
|
ChatMessage(
|
||||||
|
role="assistant",
|
||||||
content="I will try again",
|
content="I will try again",
|
||||||
))
|
)
|
||||||
|
)
|
||||||
yield history
|
yield history
|
||||||
time.sleep(0.25)
|
time.sleep(0.25)
|
||||||
|
|
||||||
history.append(ChatMessage(role="assistant",
|
history.append(
|
||||||
|
ChatMessage(
|
||||||
|
role="assistant",
|
||||||
content="Weather 72 degrees Fahrenheit with 20% chance of rain.",
|
content="Weather 72 degrees Fahrenheit with 20% chance of rain.",
|
||||||
metadata={"title": "🛠️ Used tool 'Weather'"}
|
metadata={"title": "🛠️ Used tool 'Weather'"},
|
||||||
))
|
)
|
||||||
|
)
|
||||||
yield history
|
yield history
|
||||||
time.sleep(0.25)
|
time.sleep(0.25)
|
||||||
|
|
||||||
history.append(ChatMessage(role="assistant",
|
history.append(
|
||||||
|
ChatMessage(
|
||||||
|
role="assistant",
|
||||||
content="Now that the API succeeded I can complete my task.",
|
content="Now that the API succeeded I can complete my task.",
|
||||||
))
|
)
|
||||||
|
)
|
||||||
yield history
|
yield history
|
||||||
time.sleep(0.25)
|
time.sleep(0.25)
|
||||||
|
|
||||||
history.append(ChatMessage(role="assistant",
|
history.append(
|
||||||
|
ChatMessage(
|
||||||
|
role="assistant",
|
||||||
content="It's a sunny day in San Francisco with a current temperature of 72 degrees Fahrenheit and a 20% chance of rain. Enjoy the weather!",
|
content="It's a sunny day in San Francisco with a current temperature of 72 degrees Fahrenheit and a 20% chance of rain. Enjoy the weather!",
|
||||||
))
|
)
|
||||||
|
)
|
||||||
yield history
|
yield history
|
||||||
|
|
||||||
|
|
||||||
|
def like(evt: gr.LikeData):
|
||||||
|
print("User liked the response")
|
||||||
|
print(evt.index, evt.liked, evt.value)
|
||||||
|
|
||||||
|
|
||||||
with gr.Blocks() as demo:
|
with gr.Blocks() as demo:
|
||||||
chatbot = gr.Chatbot(type="messages")
|
chatbot = gr.Chatbot(type="messages", height=500, show_copy_button=True)
|
||||||
button = gr.Button("Get San Francisco Weather")
|
button = gr.Button("Get San Francisco Weather")
|
||||||
button.click(generate_response, chatbot, chatbot)
|
button.click(generate_response, chatbot, chatbot)
|
||||||
|
chatbot.like(like)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
demo.launch()
|
demo.launch()
|
||||||
|
@ -58,9 +58,11 @@ def set_cancel_events(
|
|||||||
|
|
||||||
root_block.set_event_trigger(
|
root_block.set_event_trigger(
|
||||||
triggers,
|
triggers,
|
||||||
fn=lambda: [Timer(active=False) for _ in timers_to_cancel]
|
fn=lambda: (
|
||||||
|
[Timer(active=False) for _ in timers_to_cancel]
|
||||||
if len(timers_to_cancel) > 1
|
if len(timers_to_cancel) > 1
|
||||||
else Timer(active=False),
|
else Timer(active=False)
|
||||||
|
),
|
||||||
inputs=None,
|
inputs=None,
|
||||||
outputs=timers_to_cancel,
|
outputs=timers_to_cancel,
|
||||||
show_api=False,
|
show_api=False,
|
||||||
|
@ -239,7 +239,7 @@ for (const msg_format of ["tuples", "messages"]) {
|
|||||||
await page.getByTestId("textbox").fill("hello");
|
await page.getByTestId("textbox").fill("hello");
|
||||||
await page.keyboard.press("Enter");
|
await page.keyboard.press("Enter");
|
||||||
await page.getByLabel("like", { exact: true }).click();
|
await page.getByLabel("like", { exact: true }).click();
|
||||||
await page.getByLabel("dislike").click();
|
await page.getByLabel("dislike", { exact: true }).click();
|
||||||
|
|
||||||
expect(await page.getByLabel("clicked dislike").count()).toEqual(1);
|
expect(await page.getByLabel("clicked dislike").count()).toEqual(1);
|
||||||
expect(await page.getByLabel("clicked like").count()).toEqual(0);
|
expect(await page.getByLabel("clicked like").count()).toEqual(0);
|
||||||
|
@ -124,6 +124,7 @@
|
|||||||
upload={gradio.client.upload}
|
upload={gradio.client.upload}
|
||||||
_fetch={gradio.client.fetch}
|
_fetch={gradio.client.fetch}
|
||||||
load_component={gradio.load_component}
|
load_component={gradio.load_component}
|
||||||
|
msg_format={type}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</Block>
|
</Block>
|
||||||
|
@ -4,19 +4,43 @@
|
|||||||
import type { FileData } from "@gradio/client";
|
import type { FileData } from "@gradio/client";
|
||||||
import DownloadIcon from "./Download.svelte";
|
import DownloadIcon from "./Download.svelte";
|
||||||
import { DownloadLink } from "@gradio/wasm/svelte";
|
import { DownloadLink } from "@gradio/wasm/svelte";
|
||||||
|
import type { NormalisedMessage, TextMessage } from "../types";
|
||||||
|
import { is_component_message } from "./utils";
|
||||||
|
|
||||||
export let likeable: boolean;
|
export let likeable: boolean;
|
||||||
export let show_copy_button: boolean;
|
export let show_copy_button: boolean;
|
||||||
export let show: boolean;
|
export let show: boolean;
|
||||||
export let message: Record<string, any>;
|
export let message: NormalisedMessage | NormalisedMessage[];
|
||||||
export let position: "right" | "left";
|
export let position: "right" | "left";
|
||||||
export let avatar: FileData | null;
|
export let avatar: FileData | null;
|
||||||
|
|
||||||
export let handle_action: (selected: string | null) => void;
|
export let handle_action: (selected: string | null) => void;
|
||||||
export let layout: "bubble" | "panel";
|
export let layout: "bubble" | "panel";
|
||||||
$: show_copy = show_copy_button && message && message?.type === "text";
|
|
||||||
|
function is_all_text(
|
||||||
|
message: NormalisedMessage[] | NormalisedMessage
|
||||||
|
): message is TextMessage[] | TextMessage {
|
||||||
|
return (
|
||||||
|
(Array.isArray(message) &&
|
||||||
|
message.every((m) => typeof m.content === "string")) ||
|
||||||
|
(!Array.isArray(message) && typeof message.content === "string")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function all_text(message: TextMessage[] | TextMessage): string {
|
||||||
|
if (Array.isArray(message)) {
|
||||||
|
return message.map((m) => m.content).join("\n");
|
||||||
|
}
|
||||||
|
return message.content;
|
||||||
|
}
|
||||||
|
|
||||||
|
$: message_text = is_all_text(message) ? all_text(message) : "";
|
||||||
|
|
||||||
|
$: show_copy = show_copy_button && message && is_all_text(message);
|
||||||
$: show_download =
|
$: show_download =
|
||||||
show_copy_button && (message?.value?.video?.url || message?.value?.url);
|
!Array.isArray(message) &&
|
||||||
|
is_component_message(message) &&
|
||||||
|
message.content.value.url;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if show}
|
{#if show}
|
||||||
@ -25,21 +49,19 @@
|
|||||||
null && 'with-avatar'}"
|
null && 'with-avatar'}"
|
||||||
>
|
>
|
||||||
{#if show_copy}
|
{#if show_copy}
|
||||||
<Copy value={message.value} />
|
<Copy value={message_text} />
|
||||||
{/if}
|
{/if}
|
||||||
{#if show_download}
|
{#if show_download && !Array.isArray(message) && is_component_message(message)}
|
||||||
<DownloadLink
|
<DownloadLink
|
||||||
href={message?.value?.video?.url || message?.value?.url}
|
href={message?.content?.value.url}
|
||||||
download={message?.value?.video?.orig_name ||
|
download={message.content.value.orig_name || "image"}
|
||||||
message.value.orig_name ||
|
|
||||||
"image"}
|
|
||||||
>
|
>
|
||||||
<span class="icon-wrap">
|
<span class="icon-wrap">
|
||||||
<DownloadIcon />
|
<DownloadIcon />
|
||||||
</span>
|
</span>
|
||||||
</DownloadLink>
|
</DownloadLink>
|
||||||
{/if}
|
{/if}
|
||||||
{#if likeable && position === "left"}
|
{#if likeable}
|
||||||
<LikeDislike {handle_action} padded={show_copy || show_download} />
|
<LikeDislike {handle_action} padded={show_copy || show_download} />
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
@ -54,36 +76,34 @@
|
|||||||
.icon-wrap:hover {
|
.icon-wrap:hover {
|
||||||
color: var(--body-text-color);
|
color: var(--body-text-color);
|
||||||
}
|
}
|
||||||
.message-buttons-right,
|
|
||||||
.message-buttons-left {
|
.message-buttons {
|
||||||
border-radius: var(--radius-md);
|
border-radius: var(--radius-md);
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
bottom: 0;
|
|
||||||
height: var(--size-7);
|
height: var(--size-7);
|
||||||
align-self: self-end;
|
align-self: self-end;
|
||||||
/* position: absolute; */
|
margin: 0px calc(var(--spacing-xl) * 3);
|
||||||
bottom: -15px;
|
|
||||||
margin: 2px;
|
|
||||||
padding-left: 5px;
|
padding-left: 5px;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
padding-bottom: var(--spacing-xl);
|
padding-bottom: var(--spacing-xl);
|
||||||
padding: var(--spacing-md) 2px;
|
padding: var(--spacing-md) var(--spacing-md);
|
||||||
|
border: 1px solid var(--border-color-primary);
|
||||||
|
background: var(--border-color-secondary);
|
||||||
|
gap: var(--spacing-md);
|
||||||
}
|
}
|
||||||
.message-buttons-left {
|
.message-buttons-left {
|
||||||
align-self: start;
|
align-self: start;
|
||||||
left: 0px;
|
left: 0px;
|
||||||
}
|
}
|
||||||
.message-buttons-right {
|
|
||||||
right: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.panel.message-buttons-left,
|
.panel.message-buttons-left,
|
||||||
.panel.message-buttons-right {
|
.panel.message-buttons-right {
|
||||||
margin: 10px 0 2px 0;
|
margin: 10px 0 2px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.message-buttons {
|
/* .message-buttons {
|
||||||
left: 0px;
|
left: 0px;
|
||||||
right: 0px;
|
right: 0px;
|
||||||
top: unset;
|
top: unset;
|
||||||
@ -92,9 +112,13 @@
|
|||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 0px;
|
gap: 0px;
|
||||||
}
|
} */
|
||||||
|
|
||||||
.message-buttons :global(> *) {
|
.message-buttons :global(> *) {
|
||||||
margin-right: 7px;
|
margin-right: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.with-avatar {
|
||||||
|
margin-left: calc(var(--spacing-xl) * 4 + 31px);
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { format_chat_for_sharing } from "./utils";
|
import { format_chat_for_sharing, is_component_message } from "./utils";
|
||||||
import type { NormalisedMessage } from "../types";
|
import type { NormalisedMessage } from "../types";
|
||||||
import { Gradio, copy } from "@gradio/utils";
|
import { Gradio, copy } from "@gradio/utils";
|
||||||
|
|
||||||
@ -92,6 +92,8 @@
|
|||||||
export let layout: "bubble" | "panel" = "bubble";
|
export let layout: "bubble" | "panel" = "bubble";
|
||||||
export let placeholder: string | null = null;
|
export let placeholder: string | null = null;
|
||||||
export let upload: Client["upload"];
|
export let upload: Client["upload"];
|
||||||
|
export let msg_format: "tuples" | "messages" = "tuples";
|
||||||
|
|
||||||
let target = document.querySelector("div.gradio-container");
|
let target = document.querySelector("div.gradio-container");
|
||||||
|
|
||||||
let div: HTMLDivElement;
|
let div: HTMLDivElement;
|
||||||
@ -172,6 +174,8 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$: groupedMessages = value && group_messages(value);
|
||||||
|
|
||||||
function handle_select(i: number, message: NormalisedMessage): void {
|
function handle_select(i: number, message: NormalisedMessage): void {
|
||||||
dispatch("select", {
|
dispatch("select", {
|
||||||
index: message.index,
|
index: message.index,
|
||||||
@ -184,11 +188,27 @@
|
|||||||
message: NormalisedMessage,
|
message: NormalisedMessage,
|
||||||
selected: string | null
|
selected: string | null
|
||||||
): void {
|
): void {
|
||||||
|
if (msg_format === "tuples") {
|
||||||
dispatch("like", {
|
dispatch("like", {
|
||||||
index: message.index,
|
index: message.index,
|
||||||
value: message.content,
|
value: message.content,
|
||||||
liked: selected === "like"
|
liked: selected === "like"
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
if (!groupedMessages) return;
|
||||||
|
|
||||||
|
const message_group = groupedMessages[i];
|
||||||
|
const [first, last] = [
|
||||||
|
message_group[0],
|
||||||
|
message_group[message_group.length - 1]
|
||||||
|
];
|
||||||
|
|
||||||
|
dispatch("like", {
|
||||||
|
index: [first.index, last.index] as [number, number],
|
||||||
|
value: message_group.map((m) => m.content),
|
||||||
|
liked: selected === "like"
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function get_message_label_data(message: NormalisedMessage): string {
|
function get_message_label_data(message: NormalisedMessage): string {
|
||||||
@ -209,12 +229,6 @@
|
|||||||
return `a component of type ${message.content.component ?? "unknown"}`;
|
return `a component of type ${message.content.component ?? "unknown"}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function is_component_message(
|
|
||||||
message: NormalisedMessage
|
|
||||||
): message is ComponentMessage {
|
|
||||||
return message.type === "component";
|
|
||||||
}
|
|
||||||
|
|
||||||
function group_messages(
|
function group_messages(
|
||||||
messages: NormalisedMessage[]
|
messages: NormalisedMessage[]
|
||||||
): NormalisedMessage[][] {
|
): NormalisedMessage[][] {
|
||||||
@ -223,6 +237,10 @@
|
|||||||
let currentRole: MessageRole | null = null;
|
let currentRole: MessageRole | null = null;
|
||||||
|
|
||||||
for (const message of messages) {
|
for (const message of messages) {
|
||||||
|
if (msg_format === "tuples") {
|
||||||
|
currentRole = null;
|
||||||
|
}
|
||||||
|
|
||||||
if (!(message.role === "assistant" || message.role === "user")) {
|
if (!(message.role === "assistant" || message.role === "user")) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -266,8 +284,7 @@
|
|||||||
aria-live="polite"
|
aria-live="polite"
|
||||||
>
|
>
|
||||||
<div class="message-wrap" use:copy>
|
<div class="message-wrap" use:copy>
|
||||||
{#if value !== null && value.length > 0}
|
{#if value !== null && value.length > 0 && groupedMessages !== null}
|
||||||
{@const groupedMessages = group_messages(value)}
|
|
||||||
{#each groupedMessages as messages, i}
|
{#each groupedMessages as messages, i}
|
||||||
{@const role = messages[0].role === "user" ? "user" : "bot"}
|
{@const role = messages[0].role === "user" ? "user" : "bot"}
|
||||||
{@const avatar_img = avatar_images[role === "user" ? 0 : 1]}
|
{@const avatar_img = avatar_images[role === "user" ? 0 : 1]}
|
||||||
@ -297,7 +314,10 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
<div class="flex-wrap">
|
<div
|
||||||
|
class="flex-wrap {role} "
|
||||||
|
class:component-wrap={messages[0].type === "component"}
|
||||||
|
>
|
||||||
{#each messages as message, thought_index}
|
{#each messages as message, thought_index}
|
||||||
{@const msg_type = messages[0].type}
|
{@const msg_type = messages[0].type}
|
||||||
<div
|
<div
|
||||||
@ -385,20 +405,20 @@
|
|||||||
{/if}
|
{/if}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<LikeButtons
|
<LikeButtons
|
||||||
show={role === "bot" && (likeable || show_copy_button)}
|
show={likeable || show_copy_button}
|
||||||
handle_action={(selected) => handle_like(i, message, selected)}
|
handle_action={(selected) => handle_like(i, messages[0], selected)}
|
||||||
{likeable}
|
{likeable}
|
||||||
{show_copy_button}
|
{show_copy_button}
|
||||||
{message}
|
message={msg_format === "tuples" ? messages[0] : messages}
|
||||||
position={role === "user" ? "right" : "left"}
|
position={role === "user" ? "right" : "left"}
|
||||||
avatar={avatar_img}
|
avatar={avatar_img}
|
||||||
{layout}
|
{layout}
|
||||||
/>
|
/>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{/each}
|
|
||||||
{#if pending_message}
|
{#if pending_message}
|
||||||
<Pending {layout} />
|
<Pending {layout} />
|
||||||
{/if}
|
{/if}
|
||||||
@ -430,7 +450,6 @@
|
|||||||
.bubble-wrap {
|
.bubble-wrap {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
|
||||||
height: 100%;
|
height: 100%;
|
||||||
padding-top: var(--spacing-xxl);
|
padding-top: var(--spacing-xxl);
|
||||||
}
|
}
|
||||||
@ -475,16 +494,7 @@
|
|||||||
|
|
||||||
.message-bubble-border {
|
.message-bubble-border {
|
||||||
border-width: 1px;
|
border-width: 1px;
|
||||||
border-radius: var(--radius-lg);
|
border-radius: var(--radius-md);
|
||||||
}
|
|
||||||
|
|
||||||
.bubble .user {
|
|
||||||
border-width: 1px;
|
|
||||||
border-radius: var(--radius-xl);
|
|
||||||
align-self: flex-start;
|
|
||||||
border-bottom-right-radius: 0;
|
|
||||||
|
|
||||||
box-shadow: var(--shadow-drop-lg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.user {
|
.user {
|
||||||
@ -502,11 +512,30 @@
|
|||||||
white-space: pre-line;
|
white-space: pre-line;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bubble .user {
|
.flex-wrap.user {
|
||||||
|
border-width: 1px;
|
||||||
|
border-radius: var(--radius-md);
|
||||||
align-self: flex-start;
|
align-self: flex-start;
|
||||||
border-bottom-right-radius: 0;
|
border-bottom-right-radius: 0;
|
||||||
|
box-shadow: var(--shadow-drop);
|
||||||
|
align-self: flex-start;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
padding: var(--spacing-sm) var(--spacing-xl);
|
padding: var(--spacing-sm) var(--spacing-xl);
|
||||||
|
border-color: var(--border-color-accent-subdued);
|
||||||
|
background-color: var(--color-accent-soft);
|
||||||
|
}
|
||||||
|
|
||||||
|
:not(.component-wrap).flex-wrap.bot {
|
||||||
|
border-width: 1px;
|
||||||
|
border-radius: var(--radius-lg);
|
||||||
|
align-self: flex-start;
|
||||||
|
border-bottom-left-radius: 0;
|
||||||
|
box-shadow: var(--shadow-drop);
|
||||||
|
align-self: flex-start;
|
||||||
|
text-align: right;
|
||||||
|
padding: var(--spacing-sm) var(--spacing-xl);
|
||||||
|
border-color: var(--border-color-primary);
|
||||||
|
background-color: var(--background-fill-secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.panel .user :global(*) {
|
.panel .user :global(*) {
|
||||||
@ -518,11 +547,6 @@
|
|||||||
border-color: var(--border-color-primary);
|
border-color: var(--border-color-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.bubble .user {
|
|
||||||
border-color: var(--border-color-accent-subdued);
|
|
||||||
background-color: var(--color-accent-soft);
|
|
||||||
}
|
|
||||||
|
|
||||||
.message-row {
|
.message-row {
|
||||||
display: flex;
|
display: flex;
|
||||||
/* flex-direction: column; */
|
/* flex-direction: column; */
|
||||||
@ -534,6 +558,7 @@
|
|||||||
}
|
}
|
||||||
.message-row.bubble {
|
.message-row.bubble {
|
||||||
margin: calc(var(--spacing-xl) * 3);
|
margin: calc(var(--spacing-xl) * 3);
|
||||||
|
margin-bottom: var(--spacing-xl);
|
||||||
}
|
}
|
||||||
|
|
||||||
.with_avatar.message-row.panel {
|
.with_avatar.message-row.panel {
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
export let handle_action: (selected: string | null) => void;
|
export let handle_action: (selected: string | null) => void;
|
||||||
export let padded = false;
|
export let padded = false;
|
||||||
|
export let position: "right" | "left" = "left";
|
||||||
|
|
||||||
let selected: "like" | "dislike" | null = null;
|
let selected: "like" | "dislike" | null = null;
|
||||||
</script>
|
</script>
|
||||||
@ -18,15 +19,13 @@
|
|||||||
aria-label={selected === "dislike" ? "clicked dislike" : "dislike"}
|
aria-label={selected === "dislike" ? "clicked dislike" : "dislike"}
|
||||||
class:padded
|
class:padded
|
||||||
class:selected={selected === "dislike"}
|
class:selected={selected === "dislike"}
|
||||||
class="dislike-button"
|
class="dislike-button {position}"
|
||||||
>
|
>
|
||||||
<span>
|
|
||||||
{#if selected === "dislike"}
|
{#if selected === "dislike"}
|
||||||
<ThumbDownActive />
|
<ThumbDownActive />
|
||||||
{:else}
|
{:else}
|
||||||
<ThumbDownDefault />
|
<ThumbDownDefault />
|
||||||
{/if}
|
{/if}
|
||||||
</span>
|
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
@ -39,13 +38,11 @@
|
|||||||
aria-label={selected === "like" ? "clicked like" : "like"}
|
aria-label={selected === "like" ? "clicked like" : "like"}
|
||||||
class:selected={selected === "like"}
|
class:selected={selected === "like"}
|
||||||
>
|
>
|
||||||
<span>
|
|
||||||
{#if selected === "like"}
|
{#if selected === "like"}
|
||||||
<ThumbUpActive />
|
<ThumbUpActive />
|
||||||
{:else}
|
{:else}
|
||||||
<ThumbUpDefault />
|
<ThumbUpDefault />
|
||||||
{/if}
|
{/if}
|
||||||
</span>
|
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
@ -55,11 +52,6 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
margin-right: 7px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
span {
|
|
||||||
display: inline-block;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
button:hover,
|
button:hover,
|
||||||
@ -72,8 +64,4 @@
|
|||||||
.selected:hover {
|
.selected:hover {
|
||||||
color: var(--color-accent);
|
color: var(--color-accent);
|
||||||
}
|
}
|
||||||
|
|
||||||
.like-button {
|
|
||||||
transform: translateY(0px);
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
@ -30,18 +30,24 @@
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
max-width: max-content;
|
max-width: max-content;
|
||||||
background: var(--color-accent-soft);
|
background: var(--color-accent-soft);
|
||||||
|
border: 1px solid var(--border-color-accent-subdued);
|
||||||
|
font-size: 0.8em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 8px;
|
padding: 3px 6px;
|
||||||
color: var(--body-text-color);
|
color: var(--body-text-color);
|
||||||
opacity: 0.8;
|
opacity: 0.8;
|
||||||
}
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
padding: 8px;
|
padding: 4px 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content :global(*) {
|
||||||
|
font-size: 0.8em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.title-text {
|
.title-text {
|
||||||
|
@ -156,3 +156,9 @@ export function normalise_tuples(
|
|||||||
});
|
});
|
||||||
return msg.filter((message) => message != null) as NormalisedMessage[];
|
return msg.filter((message) => message != null) as NormalisedMessage[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function is_component_message(
|
||||||
|
message: NormalisedMessage
|
||||||
|
): message is ComponentMessage {
|
||||||
|
return message.type === "component";
|
||||||
|
}
|
||||||
|
@ -18,7 +18,7 @@ export interface Message {
|
|||||||
role: MessageRole;
|
role: MessageRole;
|
||||||
metadata: Metadata;
|
metadata: Metadata;
|
||||||
content: string | FileData | ComponentData;
|
content: string | FileData | ComponentData;
|
||||||
index: [number, number] | number;
|
index: number | [number, number];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TextMessage extends Message {
|
export interface TextMessage extends Message {
|
||||||
|
Loading…
Reference in New Issue
Block a user