diff --git a/frontend/src/index.sass b/frontend/src/index.sass index 447f76e..982985d 100644 --- a/frontend/src/index.sass +++ b/frontend/src/index.sass @@ -189,12 +189,13 @@ h2 color: #a0aec0 font-size: 1.5rem -.record-btn +.record-container + background-color: white !important position: fixed - bottom: 20px + bottom: 0px left: 50% transform: translateX(-50%) - width: calc(100% - 40px) + width: 100% padding: 10px 16px .record-btn.red @@ -209,7 +210,7 @@ h2 margin: 20px auto .message - margin: 10px + margin: 3px padding: 10px border-radius: 5px color: white @@ -223,8 +224,6 @@ h2 align-self: flex-start background-color: $c-green border-radius: 0 20px 20px 20px -<<<<<<< HEAD -======= .tags display: flex @@ -257,5 +256,4 @@ h2 color: white display: flex align-items: center - justify-content: center ->>>>>>> 199c0b0 (Added Creating Random Users) + justify-content: center \ No newline at end of file diff --git a/frontend/src/index.tsx b/frontend/src/index.tsx index 2b3709e..9e2fadb 100644 --- a/frontend/src/index.tsx +++ b/frontend/src/index.tsx @@ -13,6 +13,8 @@ import Review from './pages/Review'; import CharacterSelection from './pages/CharacterSelection'; import Character from './pages/Character'; import Lesson from './pages/Lesson'; +import FakeUserSelection from './pages/FakeUserSelection'; +import UserChat from './pages/UserChat'; const router = createBrowserRouter([ { @@ -54,7 +56,15 @@ const router = createBrowserRouter([ { path: '/lesson', element: - } + }, + { + path: '/fake-user-selection', + element: + }, + { + path: '/user-chat', + element: + }, ]) const root = ReactDOM.createRoot( diff --git a/frontend/src/logic/sdk.ts b/frontend/src/logic/sdk.ts index 26cbfdb..b962fd1 100644 --- a/frontend/src/logic/sdk.ts +++ b/frontend/src/logic/sdk.ts @@ -85,12 +85,12 @@ export interface CharacterChatCreationRequest language: string; } -export interface CharacterChatCreationResponse +export interface ChatCreationResponse { chat_id: string; } -export async function startFictionalChat(character: string): Promise { +export async function startFictionalChat(character: string): Promise { const currUser = getUsername(); const language = getLanguage(); @@ -117,6 +117,42 @@ export async function startFictionalChat(character: string): Promise { + + const request: HumanChatCreationRequest = { + user_name: getUsername(), + user_hobbies: user_hobbies, + target_name: target_name, + target_hobbies: target_hobbies, + language: getLanguage().name + }; + + const response = await fetch(`${backendUrl}/human-chat`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(request), + }); + + if (!response.ok) { + const errorData = await response.json(); + throw new Error(`HTTP error! status: ${response.status}, message: ${errorData.message}`); + } + + const json = await response.json(); + return json.session_id; +} + export async function speechToText(audioBlob: Blob): Promise { const formData = new FormData(); formData.append('audio_file', audioBlob, 'audio.wav'); @@ -156,6 +192,27 @@ export async function characterChatMessage(sessionId: string, message: string): return json; } +export async function humanChatMessage(sessionId: string, message: string): Promise<{ msg: string, audio_id: string }> { + + const request = {msg : message}; + + const response = await fetch(`${backendUrl}/human-chat/${sessionId}`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(request), + }); + + if (!response.ok) { + const errorData = await response.json(); + throw new Error(`HTTP error! status: ${response.status}, message: ${errorData.message}`); + } + + const json = await response.json(); + return json; +} + export async function getAudio(audioId: string): Promise { const response = await fetch(`${backendUrl}/audio/${audioId}`); diff --git a/frontend/src/pages/Character.tsx b/frontend/src/pages/Character.tsx index bef6ccd..24769ff 100644 --- a/frontend/src/pages/Character.tsx +++ b/frontend/src/pages/Character.tsx @@ -16,6 +16,16 @@ export default function Character() { let chunks = [] as any; const mediaRecorder = useRef(null); + const messageEndRef = useRef(null); + + const scrollToBottom = () => { + messageEndRef.current?.scrollIntoView({ behavior: "smooth" }) + } + + useEffect(() => { + scrollToBottom() + }, [messages]); + useEffect(() => { navigator.mediaDevices.getUserMedia({ audio: true }).then((stream) => { mediaRecorder.current = new MediaRecorder(stream); @@ -57,25 +67,30 @@ export default function Character() { }, [isRecording]); return ( -
-
- navigate(-1)} /> -

Talk With...

- {}}/> -
- {messages.length === 0 ? ( -

Please record a message to start the conversation.

- ) : ( - messages.map((message, index) => ( -
-

{message.text}

-
- )) - )} +
+
+
+ navigate(-1)} /> +

Talk With...

+ {}}/> +
+ {messages.length === 0 ? ( +

Please record a message to start the conversation.

+ ) : ( + messages.map((message, index) => ( +
+

{message.text}

+
+ )) + )} +
+
+
+
+
-
) diff --git a/frontend/src/pages/CharacterSelection.tsx b/frontend/src/pages/CharacterSelection.tsx index 3d8800e..d8f4111 100644 --- a/frontend/src/pages/CharacterSelection.tsx +++ b/frontend/src/pages/CharacterSelection.tsx @@ -23,7 +23,7 @@ export default function CharacterSelection() { return (
-
+

Talk With...

{characters.map(character => ( diff --git a/frontend/src/pages/CollabLearning.tsx b/frontend/src/pages/CollabLearning.tsx index c61d3aa..96f0167 100644 --- a/frontend/src/pages/CollabLearning.tsx +++ b/frontend/src/pages/CollabLearning.tsx @@ -1,97 +1,67 @@ import NavBar from "../components/NavBar" import { useState } from 'react'; +import { generateFakeUsers } from '../logic/fakeUsers'; +import { useNavigate } from 'react-router-dom'; export default function CollabLearning() { - const target_interests = [ - "gaming", "cooking", "sci-fi", "sports", "music", "programming", "first-person shooters", "painting", "baking", "astronomy", "archery" - ] + const navigate = useNavigate(); - const target_names = [ - "John", "Mary", "Bob", "Alice", "Jane", "Frank", "Sally", "Jack", "Jill", "Joe", "Sue" - ] - - interface User { - name: string; - interests: string[]; - } - - const [tags, setTags] = useState([]); - const [otherUsers, setOtherUsers] = useState([]); - const [newTag, setNewTag] = useState("") + const [interests, setInterests] = useState([]); + const [newInterest, setNewInterest] = useState("") const [errorMessage, setErrorMessage] = useState("") const handleDelete = (tagToDelete: any) => { - setTags(tags.filter(tag => tag !== tagToDelete)); + setInterests(interests.filter(tag => tag !== tagToDelete)); } const handleAddTag = (event: React.KeyboardEvent) => { if (event.key === 'Enter') { event.preventDefault(); - if (newTag && !tags.includes(newTag)) { - setTags([...tags, newTag]); - setNewTag(''); + if (newInterest && !interests.includes(newInterest)) { + setInterests([...interests, newInterest]); + setNewInterest(''); setErrorMessage(''); - } else if (tags.includes(newTag)) { + } else if (interests.includes(newInterest)) { setErrorMessage('You already entered this interest'); } } } const handleMatchClick = () => { - if (tags.length === 0) { + if (interests.length === 0) { setErrorMessage('Please enter at least one interest'); return; } - const randomNumber = Math.floor(Math.random() * target_names.length) + 1; - - console.log(randomNumber); - - let tempUsers = Array.from(otherUsers); - - for (let i = 0; i < randomNumber; i++) { - const randomName = target_names[Math.floor(Math.random() * target_names.length)]; - const randomNumberOfInterests = Math.floor(Math.random() * target_interests.length) + 1; - const randomInterests: string[] = []; - for (let j = 0; j < randomNumberOfInterests; j++) { - const randomInterest = target_interests[Math.floor(Math.random() * target_interests.length)]; - if (!randomInterests.includes(randomInterest)) { - randomInterests.push(randomInterest); - } - } - const newUser = { name: randomName, interests: randomInterests }; - tempUsers.push(newUser); - } + const fakeUsers = generateFakeUsers(interests) - setOtherUsers(tempUsers); - - console.log(tempUsers); + navigate('/fake-user-selection', { state: { fakeUsers: fakeUsers, interests: interests } }); } return ( -
+

Collaborative Learning

Find people fluent in your taget language to Chat!

Help them learn a language you know!

Interests

- {tags.length === 0 ? ( + {interests.length === 0 ? (

Enter a new interest below and press "Enter"!

) : ( - tags.map((tag) => ( -
- {tag} - { e.stopPropagation(); handleDelete(tag); }}> X + interests.map((interest) => ( +
+ {interest} + { e.stopPropagation(); handleDelete(interest); }}> X
)) )}
{errorMessage &&

{errorMessage}

} - setNewTag(e.target.value)} onKeyDown={handleAddTag} placeholder="Enter your interest here!" /> + setNewInterest(e.target.value)} onKeyDown={handleAddTag} placeholder="Enter your interest here!" />
diff --git a/frontend/src/pages/Lesson.tsx b/frontend/src/pages/Lesson.tsx index d830698..1465f65 100644 --- a/frontend/src/pages/Lesson.tsx +++ b/frontend/src/pages/Lesson.tsx @@ -36,7 +36,7 @@ export default function Course() { }; return ( -
+
navigate(-1)} />

Course Page