Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,23 @@ import globals from 'globals';
import tseslint from 'typescript-eslint';

import importPlugin from 'eslint-plugin-import';
import reactHooksPlugin from 'eslint-plugin-react-hooks';

export default tseslint.config(
{
ignores: ['dist'],
ignores: ['**/node_modules/**', '**/build/**', '**/dist/**'],
},
{
name: 'default',
extends: [js.configs.recommended, ...tseslint.configs.recommended],
files: ['packages/**/src/**/*.ts'],
files: ['**/*.{js,mjs,cjs,ts,jsx,tsx}'],
languageOptions: {
ecmaVersion: 2020,
globals: globals.browser,
},
plugins: {
import: importPlugin,
'react-hooks': reactHooksPlugin,
},
settings: {
react: {
Expand Down Expand Up @@ -93,6 +95,8 @@ export default tseslint.config(
'@typescript-eslint/no-empty-object-type': 'off',
'@typescript-eslint/no-empty-generator-function': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'react-hooks/rules-of-hooks': 'error',
'react-hooks/exhaustive-deps': 'error',
},
},
);
4 changes: 3 additions & 1 deletion examples/nextjs-ai-chatbot/app/api/chats/[id]/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ import { createConfigFromEnv } from '@stream-io/ai-sdk-storage/dist/utils';

const storage = createStreamStorageClient(createConfigFromEnv());

export async function GET(req: Request, { params }: any) {

export async function GET(_req: Request, { params }: any) {
const { id } = await params;
try {
return NextResponse.json(
await storage.streamStorage.getChannelMessages(id),
);
// eslint-disable-next-line @typescript-eslint/no-unused-vars
} catch (error) {
return NextResponse.json([], { status: 404 });
}
Expand Down
2 changes: 1 addition & 1 deletion examples/nextjs-ai-chatbot/app/api/transcribe/route.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { NextRequest } from 'next/server';
import type { NextRequest } from 'next/server';
import { experimental_transcribe as transcribe } from 'ai';
import { openai } from '@ai-sdk/openai';

Expand Down
18 changes: 9 additions & 9 deletions examples/nextjs-ai-chatbot/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import 'animate.css';
import './globals.css';
import Sidebar from '@/components/sidebar';
import Composer from '@/components/composer';
import { LayoutProps } from '@/types';
import type { LayoutProps } from '@/types';
import { AppProvider } from '@/contexts/app';

const geistSans = Geist({
Expand All @@ -24,20 +24,20 @@ export const metadata: Metadata = {

export default function RootLayout({ children }: LayoutProps) {
return (
<html lang="en" data-theme="dim">
<html lang='en' data-theme='dim'>
<body
className={`${geistSans.variable} ${geistMono.variable} antialiased prose`}
>
<AppProvider>
<div className="grid grid-cols-1 md:grid-cols-[300px_auto] h-screen w-screen">
<div className="bg-base-200 px-5 py-2 md:relative absolute top-0 bottom-0 translate-x-[-100%] md:translate-x-0 transition-all duration-300">
<div className='grid grid-cols-1 md:grid-cols-[300px_auto] h-screen w-screen'>
<div className='bg-base-200 px-5 py-2 md:relative absolute top-0 bottom-0 translate-x-[-100%] md:translate-x-0 transition-all duration-300'>
<Sidebar />
</div>
<div className="flex flex-col h-full relative px-5">
<div className="w-full mx-auto flex flex-col h-[100vh] gap-2">
<div className="flex-1 overflow-y-auto">{children}</div>
<div className="flex-shrink-0 pb-5">
<div className="max-w-3xl mx-auto">
<div className='flex flex-col h-full relative px-5'>
<div className='w-full mx-auto flex flex-col h-[100vh] gap-2'>
<div className='flex-1 overflow-y-auto'>{children}</div>
<div className='flex-shrink-0 pb-5'>
<div className='max-w-3xl mx-auto'>
<Composer />
</div>
</div>
Expand Down
9 changes: 4 additions & 5 deletions examples/nextjs-ai-chatbot/components/composer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,9 @@ import { MODELS } from '@/utils/models';
import {
ArrowUpIcon,
ImageIcon,
Mic,
MicIcon,
MicOffIcon,
Paperclip,
SpeakerIcon,
XIcon,
} from 'lucide-react';
import { useEffect, useRef, useState } from 'react';
Expand All @@ -19,7 +17,7 @@ import { useTranscriber } from '@/hooks/usetranscribe';
export default function Composer() {
const [isActive, setIsActive] = useState(false);
const [input, setInput] = useState('');
const [files, setFiles] = useState<FileList[] | undefined>(undefined);
const [files, setFiles] = useState<File[] | undefined>(undefined);
const fileInputRef = useRef<HTMLInputElement>(null);
const { isListening, transcript, start, stop } = useTranscriber();

Expand Down Expand Up @@ -53,6 +51,7 @@ export default function Composer() {

useEffect(() => {
if (transcript) {
// eslint-disable-next-line
handleSubmit({
preventDefault: () => {},
target: { value: transcript },
Expand All @@ -75,6 +74,7 @@ export default function Composer() {
: 'outline-transparent'
}`}
>
{}
{[...(files || [])]?.map((file: any, index) => (
<div key={`attachment-${index}`} className="badge badge-sm mb-2">
<ImageIcon className="w-3 h-3" />
Expand Down Expand Up @@ -109,8 +109,7 @@ export default function Composer() {
ref={fileInputRef}
onChange={(e) => {
if (e.target.files) {
//@ts-ignore
setFiles(e.target.files);
setFiles([...e.target.files]);
}
}}
/>
Expand Down
8 changes: 4 additions & 4 deletions examples/nextjs-ai-chatbot/components/markdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import Weather from './tools/weather';
export const NonMemoizedMarkdown = ({ children }: { children: string }) => {
const components = {
p: ({ children }: { children: string }) => {
return <div className="no-prose">{children}</div>;
return <div className='no-prose'>{children}</div>;
},
pre: ({ children, ...props }: any) => {
const codeElement = React.Children.only(children);
Expand All @@ -33,21 +33,21 @@ export const NonMemoizedMarkdown = ({ children }: { children: string }) => {
},
ol: ({ node, children, ...props }: any) => {
return (
<ol className="list-decimal list-inside ml-4" {...props}>
<ol className='list-decimal list-inside ml-4' {...props}>
{children}
</ol>
);
},
li: ({ node, children, ...props }: any) => {
return (
<li className="py-1" {...props}>
<li className='py-1' {...props}>
{children}
</li>
);
},
ul: ({ node, children, ...props }: any) => {
return (
<ul className="list-decimal list-inside ml-4" {...props}>
<ul className='list-decimal list-inside ml-4' {...props}>
{children}
</ul>
);
Expand Down
30 changes: 15 additions & 15 deletions examples/nextjs-ai-chatbot/components/messages.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use client';

import { UIMessage } from '@ai-sdk/react';
import type { UIMessage } from '@ai-sdk/react';
import { Sparkles } from 'lucide-react';
import { Markdown } from '@/components/markdown';
import { useApp } from '@/contexts/app';
Expand All @@ -23,19 +23,19 @@ export default function Messages() {

if (isLoadingMessages) {
return (
<div className="flex justify-center items-center h-full animate__animated animate__fadeIn">
<span className="loading loading-spinner loading-md"></span>
<div className='flex justify-center items-center h-full animate__animated animate__fadeIn'>
<span className='loading loading-spinner loading-md'></span>
</div>
);
}

if (!id) {
return (
<div className="flex justify-center items-center flex-col h-full ">
<h1 className="animate__animated animate__fadeInUp mb-0 ">
<span className="ai-thinking">Welcome to AI Assistant</span>
<div className='flex justify-center items-center flex-col h-full '>
<h1 className='animate__animated animate__fadeInUp mb-0 '>
<span className='ai-thinking'>Welcome to AI Assistant</span>
</h1>
<p className="animate__animated animate__fadeInUp animate__delay-1s text-gray-500">
<p className='animate__animated animate__fadeInUp animate__delay-1s text-gray-500'>
Ready to help you with any questions or tasks. How can I assist you
today?
</p>
Expand All @@ -44,29 +44,29 @@ export default function Messages() {
}

return (
<div className="py-15 pl-3 max-w-3xl mx-auto space-y-5">
<div className='py-15 pl-3 max-w-3xl mx-auto space-y-5'>
{messages.map((m: UIMessage) => (
<div
key={m.id}
className={`chat animate__animated animate__fadeIn ${
m.role === 'user' ? 'chat-end' : 'chat-start'
}`}
>
<div className="flex gap-2 flex-wrap">
<div className='flex gap-2 flex-wrap'>
{m.parts.map(
(part, index) =>
part.type === 'file' &&
part.url && (
<a
key={'file-' + index + m.id}
href={part.url}
target="_blank"
className="not-prose mb-2"
target='_blank'
className='not-prose mb-2'
>
<Image
src={part.url}
alt={part.filename || 'unknown'}
className="w-30 h-30 rounded-lg object-cover"
className='w-30 h-30 rounded-lg object-cover'
width={300}
height={300}
/>
Expand All @@ -91,9 +91,9 @@ export default function Messages() {
</div>
))}
{status === 'submitted' && (
<div className="flex gap-1 items-center text-sm my-4 animate-pulse">
<Sparkles className="w-3 h-3 animate-pulse text-[#00ffe0]" />
<span className="ai-thinking">Thinking</span>
<div className='flex gap-1 items-center text-sm my-4 animate-pulse'>
<Sparkles className='w-3 h-3 animate-pulse text-[#00ffe0]' />
<span className='ai-thinking'>Thinking</span>
</div>
)}
<div ref={messagesEndRef} />
Expand Down
22 changes: 11 additions & 11 deletions examples/nextjs-ai-chatbot/components/sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,18 @@
import { useApp } from '@/contexts/app';
import { Dot, MessageSquarePlus, MessageSquareText } from 'lucide-react';
import Link from 'next/link';
import { Chat as ChatType } from '@/types';
import type { Chat as ChatType } from '@/types';
import { useParams } from 'next/navigation';

export default function Sidebar({ title = 'Chats' }) {
const { chats } = useApp();
const { id } = useParams();
return (
<>
<h3 className="flex items-center gap-2">
<MessageSquareText className="w-5 h-5" /> {title}
<h3 className='flex items-center gap-2'>
<MessageSquareText className='w-5 h-5' /> {title}
</h3>
<div className="animate__animated animate__fadeIn relative">
<div className='animate__animated animate__fadeIn relative'>
{chats?.length > 0 ? (
chats.map((chat: ChatType) => (
<Link
Expand All @@ -25,23 +25,23 @@ export default function Sidebar({ title = 'Chats' }) {
id === chat.id ? 'text-primary' : ''
}`}
>
<div className="flex items-center gap-1 min-w-0">
<Dot className="flex-shrink-0" />
<span className="truncate">{chat.name}</span>
<div className='flex items-center gap-1 min-w-0'>
<Dot className='flex-shrink-0' />
<span className='truncate'>{chat.name}</span>
</div>
</Link>
))
) : (
<div className="flex items-center gap-2 text-gray-600">
<div className='flex items-center gap-2 text-gray-600'>
No chats found
</div>
)}
</div>
<Link
href="/"
className="mb-2 btn btn-default btn-soft left-4 right-4 absolute bottom-2"
href='/'
className='mb-2 btn btn-default btn-soft left-4 right-4 absolute bottom-2'
>
<MessageSquarePlus className="w-4 h-4" />
<MessageSquarePlus className='w-4 h-4' />
New Chat
</Link>
</>
Expand Down
22 changes: 11 additions & 11 deletions examples/nextjs-ai-chatbot/components/tools/weather.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
import { WeatherToolResponse } from '@/types';
import { MapPinIcon, CloudSunIcon } from 'lucide-react';
import type { WeatherToolResponse } from '@/types';
import { CloudSunIcon, MapPinIcon } from 'lucide-react';

export default function Weather({ data }: { data: string }) {
const weather: WeatherToolResponse = JSON.parse(data);
return (
<div className="bg-base-200 p-4 pb-8 rounded-lg relative overflow-hidden min-w-sm">
<div className="text-lg font-bold flex items-center gap-2">
<MapPinIcon className="w-4 h-4" />
<div className='bg-base-200 p-4 pb-8 rounded-lg relative overflow-hidden min-w-sm'>
<div className='text-lg font-bold flex items-center gap-2'>
<MapPinIcon className='w-4 h-4' />
{weather.location?.name || 'Unknown'}
</div>
<div className="grid grid-cols-[1fr_2fr] gap-4 items-center justify-center my-4 font-bold">
<div className='grid grid-cols-[1fr_2fr] gap-4 items-center justify-center my-4 font-bold'>
<div>
<img
src={weather.current?.condition?.icon}
alt={weather.current?.condition?.text}
className="object-cover not-prose bg-base-100 rounded-lg p-2"
className='object-cover not-prose bg-base-100 rounded-lg p-2'
width={64}
height={64}
/>
Expand All @@ -24,15 +24,15 @@ export default function Weather({ data }: { data: string }) {
<br /> Feels like: {weather.current?.feelslike_c}°C
</div>
</div>
<div className="text-sm text-gray-500">
<div className='text-sm text-gray-500'>
<div>Condition: {weather.current?.condition?.text}</div>
<div>Wind: {weather.current?.wind_kph} km/h</div>
<div>Humidity: {weather.current?.humidity}%</div>
<div>Pressure: {weather.current?.pressure_mb} mb</div>
</div>
<div className="flex items-center gap-1 opacity-50 text-xs absolute bottom-2 right-2 text-[#00ffe0]">
<CloudSunIcon className="w-3 h-3" />
<span className="ai-thinking">weather tool</span>
<div className='flex items-center gap-1 opacity-50 text-xs absolute bottom-2 right-2 text-[#00ffe0]'>
<CloudSunIcon className='w-3 h-3' />
<span className='ai-thinking'>weather tool</span>
</div>
</div>
);
Expand Down
Loading