diff --git a/.gitignore b/.gitignore
index e534153..9812bf1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -24,4 +24,5 @@ dist-ssr
*.sw?
output.sh
.next
-ui
\ No newline at end of file
+ui
+.env
diff --git a/app/api/bot/create-conversation/route.ts b/app/api/bot/create-conversation/route.ts
new file mode 100644
index 0000000..fa8dfab
--- /dev/null
+++ b/app/api/bot/create-conversation/route.ts
@@ -0,0 +1,20 @@
+import { NextResponse } from 'next/server'
+
+export async function POST() {
+ try {
+ const response = await fetch('https://generalbots.online/directline/PROD-GeneralBots006/conversations', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ })
+
+ const data = await response.json()
+ return NextResponse.json(data)
+ } catch (error) {
+ return NextResponse.json(
+ { error: 'Failed to create conversation' },
+ { status: 500 }
+ )
+ }
+}
\ No newline at end of file
diff --git a/app/api/get-token/route.ts b/app/api/get-token/route.ts
new file mode 100644
index 0000000..888faf1
--- /dev/null
+++ b/app/api/get-token/route.ts
@@ -0,0 +1,14 @@
+import { NextResponse } from 'next/server'
+
+export async function GET(request: Request) {
+ const { searchParams } = new URL(request.url)
+ const room = searchParams.get('room')
+ const identity = searchParams.get('identity')
+
+ const response = await fetch(
+ `https://generalbots.online/PROD-GeneralBots006/meeting-token?room=${room}&identity=${identity}`
+ )
+ const data = await response.json()
+
+ return NextResponse.json(data)
+}
\ No newline at end of file
diff --git a/app/chat/components/chat/chat-header.tsx b/app/chat/components/chat/chat-header.tsx
index cfaf4d0..a73c463 100644
--- a/app/chat/components/chat/chat-header.tsx
+++ b/app/chat/components/chat/chat-header.tsx
@@ -4,19 +4,15 @@ import '../../styles/chat.css';
export function ChatHeader() {
const { instance } = useChat();
-
return (
-
- {instance?.name || 'Chat'}
-
+ {instance?.name || 'Qwen Chat'}
Online
-
diff --git a/app/chat/components/chat/chat-input.tsx b/app/chat/components/chat/chat-input.tsx
index 5fc7ed2..fb82853 100644
--- a/app/chat/components/chat/chat-input.tsx
+++ b/app/chat/components/chat/chat-input.tsx
@@ -1,5 +1,5 @@
import React from 'react';
-import { EmojiPicker } from '../ui/emoji-picker';
+
import { useChat } from '../../providers/chat-provider';
import { useSound } from '../../providers/sound-provider';
import '../../styles/chat.css';
@@ -20,9 +20,9 @@ export function ChatInput() {
setMessage('');
};
- const handleEmojiSelect = (emoji: string) => {
+ const handleEmojiSelect = (emoji) => {
playSound('click');
- setMessage(prev => prev + emoji);
+ setMessage((prev) => prev + emoji);
};
return (
@@ -30,46 +30,43 @@ export function ChatInput() {
-
-
-
- {
playSound('click');
setShowEmoji(false);
}}
onEmojiSelect={handleEmojiSelect}
- />
+ /> */}
>
);
}
diff --git a/app/chat/components/chat/chat-window.tsx b/app/chat/components/chat/chat-window.tsx
index 710ea17..eec339b 100644
--- a/app/chat/components/chat/chat-window.tsx
+++ b/app/chat/components/chat/chat-window.tsx
@@ -13,13 +13,11 @@ export function ChatWindow() {
React.useEffect(() => {
if (!line) return;
-
- const subscription = line.activity$.subscribe((activity: any) => {
+ const subscription = line.activity$.subscribe((activity) => {
if (activity.type === 'message') {
- setMessages(prev => [...prev, activity as Message]);
+ setMessages((prev) => [...prev, activity]);
}
});
-
return () => subscription.unsubscribe();
}, [line]);
diff --git a/app/chat/components/chat/message-list.tsx b/app/chat/components/chat/message-list.tsx
index e406944..44a9d54 100644
--- a/app/chat/components/chat/message-list.tsx
+++ b/app/chat/components/chat/message-list.tsx
@@ -9,7 +9,7 @@ interface MessageListProps {
}
export function MessageList({ messages }: MessageListProps) {
- const scrollRef = React.useRef(null);
+ const scrollRef = React.useRef(null);
const { user } = useChat();
const { playSound } = useSound();
const prevMessagesLength = React.useRef(messages.length);
@@ -30,14 +30,10 @@ export function MessageList({ messages }: MessageListProps) {
{messages.map((message, index) => (
{message.text}
-
- {new Date(message.timestamp).toLocaleTimeString()}
-
+
{new Date(message.timestamp).toLocaleTimeString()}
))}
diff --git a/app/chat/components/projector/projector-view.tsx b/app/chat/components/projector/projector-view.tsx
index e6ba946..0aa60d3 100644
--- a/app/chat/components/projector/projector-view.tsx
+++ b/app/chat/components/projector/projector-view.tsx
@@ -1,5 +1,4 @@
"use client";
-
import React from 'react';
import { VideoPlayer } from './video-player';
import { ImageViewer } from './image-viewer';
@@ -9,24 +8,20 @@ import '../../styles/projector.css';
export function ProjectorView() {
const { line } = useChat();
- const [content, setContent] = React.useState(null);
+ const [content, setContent] = React.useState(null);
React.useEffect(() => {
if (!line) return;
-
- const subscription = line.activity$
- .subscribe((activity: any) => {
- if (activity.type === 'event' && activity.name === 'project') {
- setContent(activity.value);
- }
- });
-
+ const subscription = line.activity$.subscribe((activity) => {
+ if (activity.type === 'event' && activity.name === 'project') {
+ setContent(activity.value);
+ }
+ });
return () => subscription.unsubscribe();
}, [line]);
const renderContent = () => {
if (!content) return null;
-
switch (content.type) {
case 'video':
return ;
@@ -39,9 +34,5 @@ export function ProjectorView() {
}
};
- return (
-
- {renderContent()}
-
- );
+ return {renderContent()}
;
}
diff --git a/app/chat/components/selector/person-selector.tsx b/app/chat/components/selector/person-selector.tsx
index 0341ac3..37e8399 100644
--- a/app/chat/components/selector/person-selector.tsx
+++ b/app/chat/components/selector/person-selector.tsx
@@ -10,14 +10,11 @@ export function PersonSelector() {
return (
- {instance?.logo && (
-

- )}
+ {instance?.logo &&

}
-
-
{['FAQ', 'Support', 'Sales'].map((item) => (
diff --git a/app/chat/components/sound-initializer.tsx b/app/chat/components/sound-initializer.tsx
index 767aad2..59fe760 100644
--- a/app/chat/components/sound-initializer.tsx
+++ b/app/chat/components/sound-initializer.tsx
@@ -1,39 +1,28 @@
"use client";
import React, { useEffect, useState } from 'react';
-import { soundAssets } from '../../../../public/sounds/manifest';
-//import { cacheAssets } from '../lib/asset-loader';
-export function SoundInitializer({ children }: { children: React.ReactNode }) {
+export function SoundInitializer({ children }) {
const [isReady, setIsReady] = useState(false);
- const [error, setError] = useState
(null);
+ const [error, setError] = useState(null);
useEffect(() => {
const initializeSounds = async () => {
try {
- // await cacheAssets(Object.values(soundAssets));
+ // Simulate sound initialization
setIsReady(true);
} catch (err) {
- setError(err instanceof Error ? err.message : 'Failed to initialize sounds');
+ setError(err.message || 'Failed to initialize sounds');
}
};
-
initializeSounds();
}, []);
if (error) {
- return (
-
- );
+ return ;
}
if (!isReady) {
- return (
-
- );
+ return ;
}
return <>{children}>;
diff --git a/app/chat/lib/utils.ts b/app/chat/lib/utils.ts
index fb5c47d..637eb6e 100644
--- a/app/chat/lib/utils.ts
+++ b/app/chat/lib/utils.ts
@@ -1,14 +1,14 @@
-export function formatTimestamp(date: Date): string {
+export function formatTimestamp(date) {
return new Intl.DateTimeFormat('en-US', {
hour: '2-digit',
minute: '2-digit',
}).format(date);
}
-export function cn(...classes: string[]): string {
+export function cn(...classes) {
return classes.filter(Boolean).join(' ');
}
-export function generateId(): string {
+export function generateId() {
return Math.random().toString(36).slice(2);
}
diff --git a/app/chat/page.tsx b/app/chat/page.tsx
index f671f60..79716cd 100644
--- a/app/chat/page.tsx
+++ b/app/chat/page.tsx
@@ -4,7 +4,7 @@ import { ChatLayout } from './components/chat-layout';
import { SoundInitializer } from './components/sound-initializer';
import { SoundProvider } from './providers/sound-provider';
- export default function Chat() {
+export default function Chat() {
return (
diff --git a/app/chat/providers/chat-provider.tsx b/app/chat/providers/chat-provider.tsx
index cd40089..d1c8aa4 100644
--- a/app/chat/providers/chat-provider.tsx
+++ b/app/chat/providers/chat-provider.tsx
@@ -2,102 +2,66 @@
import React, { createContext, useContext, useState, useEffect } from 'react';
import { User, ChatInstance } from '../types';
-interface ChatContextType {
- line: any;
- user: User;
- instance: ChatInstance | null;
- sendActivity: (activity: any) => Promise;
- selectedVoice: any;
- setVoice: (voice: any) => void;
+const ChatContext = createContext(undefined);
+
+async function apiFetch(endpoint, options = {}) {
+ const baseUrl = 'http://localhost:4242/';
+ const response = await fetch(`${baseUrl}${endpoint}`, options);
+ if (!response.ok) throw new Error('API request failed');
+ return response.json();
}
-const ChatContext = createContext(undefined);
-
-// Unified API caller that works in both environments
-async function apiFetch(endpoint: string, options?: RequestInit) {
- const baseUrl = 'http://localhost:4242/'; //typeof window !== 'undefined' ? window.location.origin : '';
-
- if (typeof window !== 'undefined' && '__TAURI__' in window) {
- // Tauri environment - use HTTP module for better security
- const { http } = await import('@tauri-apps/api');
- return http.fetch(`${baseUrl}${endpoint}`, options);
- }
-
- // Web environment - standard fetch
- return fetch(`${baseUrl}${endpoint}`, options);
-}
-
-export function ChatProvider({ children }: { children: React.ReactNode }) {
- const [line, setLine] = useState(null);
- const [instance, setInstance] = useState(null);
- const [selectedVoice, setSelectedVoice] = useState(null);
+export function ChatProvider({ children }) {
+ const [line, setLine] = useState(null);
+ const [instance, setInstance] = useState(null);
const [user] = useState({
id: `user_${Math.random().toString(36).slice(2)}`,
- name: 'You'
+ name: 'You',
});
useEffect(() => {
const initializeChat = async () => {
try {
- const botId = 'doula'; // window.location.pathname.split('/')[1] || 'default';
-
- // Get instance from REST API
- const response = await apiFetch(`/instances/${botId}`);
- if (!response.ok) throw new Error('Failed to get chat instance');
- const instanceData = await response.json();
+ const botId = 'doula'; // Default bot ID
+ const instanceData = await apiFetch(`/instances/${botId}`);
setInstance(instanceData);
- // Initialize chat service
const chatService = {
activity$: { subscribe: () => {} },
- postActivity: (activity: any) => ({
- subscribe: (observer: any) => {
- // Handle real-time updates if needed
+ postActivity: (activity) => ({
+ subscribe: (observer) => {
return { unsubscribe: () => {} };
- }
- })
+ },
+ }),
};
setLine(chatService);
} catch (error) {
console.error('Failed to initialize chat:', error);
}
};
-
initializeChat();
}, []);
- const sendActivity = async (activity: any) => {
+ const sendActivity = async (activity) => {
try {
const fullActivity = {
...activity,
from: user,
- timestamp: new Date().toISOString()
+ timestamp: new Date().toISOString(),
};
-
- // Send activity via REST API
- const response = await apiFetch('/activities', {
+ await apiFetch('/activities', {
method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- },
- body: JSON.stringify(fullActivity)
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify(fullActivity),
});
-
- if (!response.ok) throw new Error('Failed to send activity');
-
- // Notify local chat service
line?.postActivity(fullActivity).subscribe();
} catch (error) {
console.error('Failed to send activity:', error);
}
};
- const setVoice = (voice: any) => {
- setSelectedVoice(voice);
- };
-
return (
-
+
{children}
);
@@ -109,4 +73,4 @@ export function useChat() {
throw new Error('useChat must be used within ChatProvider');
}
return context;
-}
\ No newline at end of file
+}
diff --git a/app/chat/providers/sound-provider.tsx b/app/chat/providers/sound-provider.tsx
index ada8369..51a5e27 100644
--- a/app/chat/providers/sound-provider.tsx
+++ b/app/chat/providers/sound-provider.tsx
@@ -1,24 +1,15 @@
"use client";
import React, { createContext, useContext, useCallback } from 'react';
-import { core } from '@tauri-apps/api';
-interface SoundContextType {
- playSound: (sound: string) => void;
- setEnabled: (enabled: boolean) => void;
-}
+const SoundContext = createContext(undefined);
-const SoundContext = createContext(undefined);
-
-export function SoundProvider({ children }: { children: React.ReactNode }) {
+export function SoundProvider({ children }) {
const [enabled, setEnabled] = React.useState(true);
- const playSound = useCallback(async (sound: string) => {
+ const playSound = useCallback((sound) => {
if (!enabled) return;
- try {
- await core.invoke('play_sound', { sound });
- } catch (error) {
- console.error('Failed to play sound:', error);
- }
+ const audio = new Audio();
+ audio.play().catch((err) => console.error('Failed to play sound:', err));
}, [enabled]);
return (
diff --git a/app/chat/styles/chat.css b/app/chat/styles/chat.css
index fcce2ba..a7d0824 100644
--- a/app/chat/styles/chat.css
+++ b/app/chat/styles/chat.css
@@ -2,7 +2,7 @@
display: flex;
flex-direction: column;
height: 100%;
- background-color: #111;
+ background-color: #f5f5f5;
}
.chat-header {
@@ -10,8 +10,8 @@
justify-content: space-between;
align-items: center;
padding: 1rem;
- background-color: #111;
- border-bottom: 1px solid #333;
+ background-color: #fff;
+ border-bottom: 1px solid #ccc;
}
.header-content {
@@ -20,15 +20,14 @@
}
.header-title {
- color: white;
font-size: 1.25rem;
font-weight: bold;
margin: 0;
}
.header-subtitle {
- color: #00f3ff;
font-size: 0.875rem;
+ color: #007dff;
margin-top: 0.25rem;
}
@@ -47,24 +46,23 @@
.user-message {
align-self: flex-end;
- background-color: rgba(0, 243, 255, 0.1);
- border: 1px solid #00f3ff;
+ background-color: rgba(0, 180, 255, 0.15);
+ border: 1px solid #00cfff;
}
.bot-message {
align-self: flex-start;
- background-color: rgba(191, 0, 255, 0.1);
- border: 1px solid #bf00ff;
+ background-color: rgba(180, 0, 255, 0.1);
+ border: 1px solid #c400ff;
}
.message-text {
- color: white;
margin: 0;
}
.message-time {
- color: #666;
font-size: 0.75rem;
+ color: #666;
margin-top: 0.25rem;
}
@@ -72,8 +70,8 @@
display: flex;
align-items: center;
padding: 1rem;
- border-top: 1px solid #333;
- background-color: #111;
+ border-top: 1px solid #ccc;
+ background-color: #fff;
}
.chat-input {
@@ -82,9 +80,9 @@
max-height: 6rem;
padding: 0.5rem 1rem;
margin: 0 0.5rem;
- background-color: #1a1a1a;
- color: white;
- border: 1px solid #333;
+ background-color: #f0f0f0;
+ color: #000;
+ border: 1px solid #ccc;
border-radius: 1.25rem;
resize: none;
}
@@ -92,14 +90,14 @@
.icon-button {
background: none;
border: none;
- color: #00f3ff;
+ color: #007dff;
cursor: pointer;
padding: 0.5rem;
}
.send-button {
- background-color: rgba(0, 243, 255, 0.1);
- border: 1px solid #00f3ff;
+ background-color: rgba(0, 180, 255, 0.15);
+ border: 1px solid #00cfff;
border-radius: 50%;
padding: 0.5rem;
cursor: pointer;
diff --git a/app/chat/styles/layout.css b/app/chat/styles/layout.css
index cd32b60..6acd3b6 100644
--- a/app/chat/styles/layout.css
+++ b/app/chat/styles/layout.css
@@ -12,11 +12,12 @@
.main-content {
flex: 1;
display: flex;
+ flex-direction: column;
}
.projector {
- width: 40%;
- border-right: 1px solid #333;
+ height: 30%;
+ border-bottom: 1px solid #333;
}
.chat-area {
diff --git a/app/chat/styles/projector.css b/app/chat/styles/projector.css
index d6ae6be..dcc06a3 100644
--- a/app/chat/styles/projector.css
+++ b/app/chat/styles/projector.css
@@ -27,8 +27,8 @@
overflow-y: auto;
}
-.markdown-container h1,
-.markdown-container h2,
+.markdown-container h1,
+.markdown-container h2,
.markdown-container h3 {
color: #00f3ff;
}
diff --git a/app/chat/styles/ui.css b/app/chat/styles/ui.css
index f2e1ae9..1922f58 100644
--- a/app/chat/styles/ui.css
+++ b/app/chat/styles/ui.css
@@ -4,7 +4,7 @@
right: 2rem;
width: 20rem;
max-height: 25rem;
- background-color: rgba(0, 0, 0, 0.95);
+ background-color: whitesmoke;
border: 1px solid #00f3ff;
border-radius: 0.75rem;
box-shadow: 0 0 1rem rgba(0, 243, 255, 0.5);
@@ -111,7 +111,7 @@
right: 0;
bottom: 0;
background-color: #333;
- transition: .4s;
+ transition: 0.4s;
border-radius: 1.5rem;
}
@@ -123,7 +123,7 @@
left: 0.2rem;
bottom: 0.2rem;
background-color: #666;
- transition: .4s;
+ transition: 0.4s;
border-radius: 50%;
}
diff --git a/app/client-nav.tsx b/app/client-nav.tsx
index 7e1c5f3..d3e3135 100644
--- a/app/client-nav.tsx
+++ b/app/client-nav.tsx
@@ -4,17 +4,17 @@ import { usePathname, useRouter } from 'next/navigation';
import { Button } from '../src/components/ui/button';
const examples = [
- { name: "Home", href: "/auth" },
- { name: "Dashboard", href: "/dashboard" },
{ name: "Chat", href: "/chat" },
+ { name: "Meet", href: "/meet" },
+ { name: "Dashboard", href: "/dashboard" },
{ name: "Mail", href: "/mail" },
{ name: "Tree", href: "/tree" },
{ name: "Editor", href: "/editor" },
{ name: "Tables", href: "/table" },
- { name: "Video", href: "/video" },
+ { name: "Videos", href: "/videos" },
{ name: "Music", href: "/music" },
{ name: "Templates", href: "/templates" },
- { name: "Settings", href: "/sync" },
+ { name: "Settings", href: "/settings" },
];
export function Nav() {
diff --git a/app/layout.tsx b/app/layout.tsx
index e17286d..798831f 100644
--- a/app/layout.tsx
+++ b/app/layout.tsx
@@ -1,3 +1,5 @@
+import { ThemeProvider } from "@/components/ui/theme-provider";
+import { Metadata } from 'next';
import { Nav } from './client-nav';
import './globals.css';
@@ -8,9 +10,11 @@ export default function RootLayout({ children }: { children: ReactNode }) {
return (
-
-
- {children}
+
+
+ {/* */}
+ {children}
+
)
diff --git a/app/meet/page.tsx b/app/meet/page.tsx
new file mode 100644
index 0000000..25967ef
--- /dev/null
+++ b/app/meet/page.tsx
@@ -0,0 +1,255 @@
+// app/meeting/[room]/page.tsx
+'use client'
+
+import { useState, useEffect, useRef } from 'react'
+import { LiveKitRoom, VideoConference } from '@livekit/components-react'
+import { RoomEvent, Track } from 'livekit-client'
+import { useRouter } from 'next/navigation'
+import { Button } from '@/components/ui/button'
+import { Input } from '@/components/ui/input'
+import { Card } from '@/components/ui/card'
+import { ScrollArea } from '@/components/ui/scroll-area'
+import { Avatar, AvatarFallback } from '@/components/ui/avatar'
+import { Mic, MicOff, Video, VideoOff, Send, Bot } from 'lucide-react'
+
+export default function MeetingPage({ params }: { params: { room: string } }) {
+ const router = useRouter()
+ const [name, setName] = useState('')
+ const [roomName, setRoomName] = useState(params.room || '')
+ const [token, setToken] = useState('')
+ const [isConnected, setIsConnected] = useState(false)
+ const [messages, setMessages] = useState>([])
+ const [inputMessage, setInputMessage] = useState('')
+ const [micEnabled, setMicEnabled] = useState(true)
+ const [cameraEnabled, setCameraEnabled] = useState(true)
+ const [botTyping, setBotTyping] = useState(false)
+ const botConnectionRef = useRef(null)
+ const audioContextRef = useRef()
+ const processorRef = useRef()
+ const participantsRef = useRef