Merge branch 'main' of gitlab.com:soapbox-pub/ditto

This commit is contained in:
Alex Gleason
2026-04-16 17:17:47 -05:00
5 changed files with 432 additions and 201 deletions
+38 -7
View File
@@ -1,10 +1,11 @@
import { useState, useRef, useCallback, useEffect } from 'react';
import { Send, Bot } from 'lucide-react';
import { Send } from 'lucide-react';
import { useQuery } from '@tanstack/react-query';
import { Link } from 'react-router-dom';
import { ScrollArea } from '@/components/ui/scroll-area';
import { DorkThinking } from '@/components/DorkThinking';
import { useShakespeare, type ChatMessage } from '@/hooks/useShakespeare';
import { useShakespeare, useShakespeareCredits, type ChatMessage } from '@/hooks/useShakespeare';
import { useCurrentUser } from '@/hooks/useCurrentUser';
import { cn } from '@/lib/utils';
@@ -19,6 +20,7 @@ const conversationCache = new Map<string, ChatMessage[]>();
export function AIChatWidget() {
const { user } = useCurrentUser();
const { sendStreamingMessage, getAvailableModels, isLoading, isAuthenticated } = useShakespeare();
const hasCredits = useShakespeareCredits();
// Fetch available models and select the cheapest as default
const { data: defaultModelId } = useQuery({
@@ -35,6 +37,7 @@ export function AIChatWidget() {
staleTime: 10 * 60_000,
enabled: !!user,
});
const cacheKey = user?.pubkey ?? '';
const [messages, setMessages] = useState<ChatMessage[]>(() => conversationCache.get(cacheKey) ?? []);
const [input, setInput] = useState('');
@@ -90,9 +93,37 @@ export function AIChatWidget() {
if (!user || !isAuthenticated) {
return (
<div className="flex flex-col items-center gap-2 py-4 px-2 text-center">
<Bot className="size-8 text-muted-foreground" />
<p className="text-xs text-muted-foreground">Log in to chat with AI</p>
<div className="flex flex-col items-center gap-3 py-6 px-3 text-center">
<pre className="text-xl font-mono text-primary leading-none">{'<[o_o]>'}</pre>
<p className="text-xs text-muted-foreground">Log in to chat with Dork</p>
</div>
);
}
// Show credits CTA when the user has no credits (hasCredits === false).
// While loading (hasCredits === undefined) we fall through to the chat UI.
if (hasCredits === false) {
return (
<div className="flex flex-col items-center gap-3 py-6 px-3 text-center">
<pre className="text-xl font-mono text-primary leading-none">{'<[o_o]>'}</pre>
<p className="text-xs text-muted-foreground leading-relaxed">
Grab some credits on{' '}
<a
href="https://shakespeare.diy"
target="_blank"
rel="noopener noreferrer"
className="text-primary hover:underline"
>
Shakespeare
</a>
{' '}to chat with Dork.
</p>
<Link
to="/ai-chat"
className="text-xs font-medium text-primary hover:underline"
>
Open AI Chat
</Link>
</div>
);
}
@@ -103,8 +134,8 @@ export function AIChatWidget() {
<ScrollArea ref={scrollRef} className="flex-1 min-h-0">
<div className="space-y-3 p-2">
{messages.length === 0 && !streamingContent && (
<div className="flex flex-col items-center gap-2 py-6 text-center">
<Bot className="size-6 text-muted-foreground/50" />
<div className="flex flex-col items-center gap-3 py-6 text-center">
<pre className="text-xl font-mono text-primary leading-none">{'<[o_o]>'}</pre>
<p className="text-xs text-muted-foreground">Ask me anything...</p>
</div>
)}