Spaces:
Running
Running
File size: 3,344 Bytes
bc7e9cd db9635c bc7e9cd db9635c bc7e9cd db9635c bc7e9cd db9635c bc7e9cd db9635c bc7e9cd db9635c bc7e9cd db9635c bc7e9cd |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
<script lang="ts">
import { onMount, afterUpdate } from "svelte";
import gsap from "gsap";
import { StreamingToolCallParser, filterToolCalls } from "../../utils/tool-call-parser";
export let content: string;
export let streaming: boolean = false;
let textEl: HTMLDivElement;
let cursorEl: HTMLSpanElement;
let lastContentLength = 0;
let newContentEl: HTMLSpanElement;
let parser: StreamingToolCallParser | null = null;
// Initialize parser for streaming mode
$: {
if (streaming && !parser) {
parser = new StreamingToolCallParser();
} else if (!streaming && parser) {
parser = null;
}
}
// Filter content based on streaming state
$: filteredContent = (() => {
if (streaming && parser) {
// Use streaming parser to incrementally process content
parser.reset();
const result = parser.process(content);
return result.safeText;
} else {
// Use static filter for non-streaming content
return filterToolCalls(content);
}
})();
onMount(() => {
if (textEl && !streaming) {
gsap.fromTo(textEl,
{ opacity: 0, y: 3, scale: 0.99 },
{ opacity: 1, y: 0, scale: 1, duration: 0.3, ease: "power2.out" }
);
}
});
// Animate new characters appearing during streaming
afterUpdate(() => {
if (streaming && filteredContent.length > lastContentLength) {
const newChars = filteredContent.slice(lastContentLength);
if (newContentEl && newChars.length > 0) {
gsap.fromTo(newContentEl,
{ opacity: 0, scale: 0.95 },
{ opacity: 1, scale: 1, duration: 0.15, ease: "power2.out" }
);
}
lastContentLength = filteredContent.length;
}
if (!streaming) {
lastContentLength = 0;
}
});
$: if (streaming && cursorEl) {
gsap.to(cursorEl, {
opacity: 0.3,
duration: 0.6,
yoyo: true,
repeat: -1,
ease: "power2.inOut"
});
}
$: if (!streaming && cursorEl) {
gsap.killTweensOf(cursorEl);
gsap.to(cursorEl, {
opacity: 0,
duration: 0.3,
ease: "power2.out",
onComplete: () => {
// Small celebration pulse on complete
if (textEl) {
gsap.to(textEl, {
borderLeftColor: "rgba(76, 175, 80, 0.3)",
duration: 0.3,
yoyo: true,
repeat: 1,
ease: "power2.inOut"
});
}
}
});
}
</script>
<div class="text-renderer" bind:this={textEl}>
<span class="content">
{#if streaming && lastContentLength > 0}
{filteredContent.slice(0, lastContentLength)}
<span bind:this={newContentEl}>{filteredContent.slice(lastContentLength)}</span>
{:else}
{filteredContent}
{/if}
{#if streaming}<span class="cursor" bind:this={cursorEl}>▊</span>{/if}
</span>
</div>
<style>
.text-renderer {
padding: 0.125rem 0;
line-height: 1.6;
white-space: pre-wrap;
word-wrap: break-word;
}
.content {
color: rgba(251, 248, 244, 0.9);
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Monaco", "Menlo", monospace;
font-size: 0.875rem;
line-height: 1.6;
letter-spacing: 0.01em;
}
.cursor {
display: inline-block;
color: rgba(124, 152, 133, 0.7);
font-weight: 400;
margin-left: 1px;
}
</style> |