Project Info
This project did not submit a demo video on Devpost.
Overview SpeakEasy: AI Language Companion Visiting another country but don't want to sound like a robot? Want to learn a new language but can't get your intonation to sound like other people's? SpeakEasy can make you sound like, well, you! Features SpeakEasy is an AI language companion which centers around localizing your own voice into other languages. If, for example, you wanted to visit another country but didn't want to sound like a robot or Google Translate, you could still talk in your native language. SpeakEasy can then automatically repeat each statement in the target language in exactly the intonation you would have if you spoke that language. Say you wanted to learn a new language but couldn't quite get your intonation to sound like the source material you were learning from. SpeakEasy is able to provide you phrases in your own voice so you know exactly how your intonation should sound. Background SpeakEasy is the product of a group of four UC Berkeley students. For all of us, this is our first submission to a hackathon and the result of several years of wanting to get together to create something cool together. We are excited to present every part of SpeakEasy; from the remarkably accurate AI speech to just how much we've all learned about rapidly developed software projects.
Inspiration
Our group started by thinking of ways we could make an impact. We then expanded our search to include using and demonstrating technologies developed by CalHacks' generous sponsors, as we felt this would be a good way to demonstrate how modern technology can be used to help everyday people. In the end, we decided on SpeakEasy and used Cartesia to realize many of the AI-powered functions of the application. This enabled us to make something which addresses a specific real-world problem (robotic-sounding translations) many of us have either encountered or are attempting to avoid. Challenges Our group has varying levels of software development experience, and especially given our limited hackathon experience (read: none), there were many challenging steps. For example: deciding on project scope, designing high-level architecture, implementing major features, and especially debugging. What was never a challenge, however, was collaboration. We worked quite well as a team and had a good time doing it. Accomplishments / Learning We are proud to say that despite the many challenges we accomplished a great deal with this project. We have a fully functional Flask backend with React frontend (see "Technical Details") which uses multiple different APIs. This project successfully ties together audio processing, asynchonrous communication, artificial intelligence, UI/UX design, database management, and so much more. What's more is that many of our group members learned this from base fundamentals. Technical Details As mentioned in an earlier section, SpeakEasy is designed with a Flask (Python) backend and React (JavaScript) frontent. This is a very standard setup that is used often at hackathons due to its easy implementation and relatively limited required setup. Flask only requires two lines of code to make an entirely new endpoint, while React can make a full audio-playing page with callbacks that looks absolutely beautiful in less than an hour. For storing data, we use SQLAlchemy (backed by SQLite). When a user opens SpeakEasy, they are first sent to a landing page. After pressing any key, they are taken to a training screen. Here they will record a 15-20 second message (ideally the one shown on screen) which will be used to create an embedding. This is accomplished with the Cartesia "Clone Voice from Clip" endpoint. A Cartesia Voice (abbreviated as "Voice") is created from the returned embedding (using the "Create Voice" endpoint) which contains a Voice ID. This Voice ID is used to uniquely identify each voice, which itself is in a specific language. The database then stores this voice and creates a new user which this voice is associated with. When the recording is complete and the user clicks "Next", they will be taken to a split screen where they can choose between the two main program functions of SpeakEasy. If the user clicks on the vocal translation route, they will be brought to another recording screen. Here, they record a sound in English which is then sent to the backend. The backend encodes this MP3 data into PCM, sends it to a speech-to-text API, and then transfers it into a text translation API. Separately, the backend trains a new Voice (using the Cartesia Localize Voice endpoint, wrapped by get/create Voice since Localize requires an embedding instead of a Voice ID) with the intended target language and uses the Voice ID it returns. The backend then sends the translated text to the Cartesia "Text to Speech (Bytes)" endpoint using this new Voice ID. This is then played back to the user as a response to the original backend request. All created Voices are stored in the database and associated with the current user. This is done so returning users do not have to retrain their voices in any language. If the user clicks on the language learning route, they will be brought to a page which displays a randomly selected phrase in a certain language. It will then query the Cartesia API to pronounce that phrase in that language, using the preexisting Voice ID if available (or prompting to record a new phrase if not). A request is made to the backend to input some microphone input, which is then compared to Cartesia's estimation of your speech in a target language. The backend then returns a set of feedback using the difference between the two pronounciations, and displays that to the user on the frontend. After each route is selected, the user may choose to go back and select either route (the same route again or the other route). Cartesia Issues We were very impressed with Cartesia and its abilities, but noted a few issues which would improve the development experience. Clone Voice From Clip endpoint documentation The documentation for the endpoint in question details a Response which includes a variety of fields: id, name, language, and more. However, the endpoint only returns the embedding in a dictonary. It is then required to send the embedding into the "Create Voice" endpoint to create an id (and other fields), which are required for some further endpoints. The documentation for the endpoint in question details a Response which includes a variety of fields: id, name, language, and more. However, the endpoint only returns the embedding in a dictonary. It is then required to send the embedding into the "Create Voice" endpoint to create an id (and other fields), which are required for some further endpoints. Clone Voice From Clip endpoint length requirements The clip supplied to the endpoint in question appears to require a duration of greater than a second or two. Se "Error reporting" for further details. The clip supplied to the endpoint in question appears to require a duration of greater than a second or two. Se "Error reporting" for further details. Text to Speech (Bytes) endpoint output format The TTS endpoint requires an output format be specified. This JSON object notably lacks an encoding field in the MP3 configuration which is present for the other formats (raw and WAV). The solution to this is to send an encoding field with the value for one of the other two formats, despite this functionally doing nothing. The TTS endpoint requires an output format be specified. This JSON object notably lacks an encoding field in the MP3 configuration which is present for the other formats (raw and WAV). The solution to this is to send an encoding field with the value for one of the other two formats, despite this functionally doing nothing. Embedding format The embedding is specified as a list of 192 numbers, some of which may be negative. Python's JSON parser does not like the dash symbol and frequently encounters issues with this. If possible, it would be good to either allow this encoding to be base64 encoded, hashed, or something else to prevent negatives. Optimally embeddings do not have negatives, though this seems difficult to realize. The embedding is specified as a list of 192 numbers, some of which may be negative. Python's JSON parser does not like the dash symbol and frequently encounters issues with this. If possible, it would be good to either allow this encoding to be base64 encoded, hashed, or something else to prevent negatives. Optimally embeddings do not have negatives, though this seems difficult to realize. Response code mismatches Some response codes returned from endpoints do not match their listed function. For example, a response code of 405 should not be returned when there is a formatting error in the request. Similarly, 400 is returned before 404 when using invalid endpoints, making it difficult to debug. There are several other instances of this but we did not collate a list. Some response codes returned from endpoints do not match their listed function. For example, a response code of 405 should not be returned when there is a formatting error in the request. Similarly, 400 is returned before 404 when using invalid endpoints, making it difficult to debug. There are several other instances of this but we did not collate a list. Error reporting If (most) endpoints return in JSON format, errors should also be turned in JSON format. This prevents many parsing issues and would simplify design. In addition, error messages are too vague to glean any useful information. For example, 500 is always "Bad request" regardless of the underlying error cause. This is the same thing as the error name. If (most) endpoints return in JSON format, errors should also be turned in JSON format. This prevents many parsing issues and would simplify design. In addition, error messages are too vague to glean any useful information. For example, 500 is always "Bad request" regardless of the underlying error cause. This is the same thing as the error name. Future Improvements In the future, it would be interesting to investigate the following: Proper authentication Cloud-based database storage (with redundancy) Increased error checking Unit and integration test coverage, with CI/CD Automatic recording quality analysis Audio streaming (instead of buffering) using WebSockets Mobile device compatibility Reducing audio processing overhead
SpeakEasy
Overview
SpeakEasy: AI Language Companion
Visiting another country but don't want to sound like a robot? Want to learn a new language but can't get your intonation to sound like other people's? SpeakEasy can make you sound like, well, you!
Authors
- Sidd Shashi (sshashi@berkeley.edu)
- Zayd Ali (mzali@berkeley.edu)
- Smit Malde (smit334@berkeley.edu)
- boomaa23 (cmo93003@yahoo.com)
Features
SpeakEasy is an AI language companion which centers around localizing your own voice into other languages.
If, for example, you wanted to visit another country but didn't want to sound like a robot or Google Translate, you could still talk in your native language. SpeakEasy can then automatically repeat each statement in the target language in exactly the intonation you would have if you spoke that language.
Say you wanted to learn a new language but couldn't quite get your intonation to sound like the source material you were learning from. SpeakEasy is able to provide you phrases in your own voice so you know exactly how your intonation should sound.
Background
SpeakEasy is the product of a group of four UC Berkeley students. For all of us, this is our first submission to a hackathon and the result of several years of wanting to get together to create something cool together. We are excited to present every part of SpeakEasy; from the remarkably accurate AI speech to just how much we've all learned about rapidly developed software projects.
Inspiration
Our group started by thinking of ways we could make an impact. We then expanded our search to include using and demonstrating technologies developed by CalHacks' generous sponsors, as we felt this would be a good way to demonstrate how modern technology can be used to help everyday people.
In the end, we decided on SpeakEasy and used Cartesia to realize many of the AI-powered functions of the application. This enabled us to make something which addresses a specific real-world problem (robotic-sounding translations) many of us have either encountered or are attempting to avoid.
Challenges
Our group has varying levels of software development experience, and especially given our limited hackathon experience (read: none), there were many challenging steps. For example: deciding on project scope, designing high-level architecture, implementing major features, and especially debugging.
What was never a challenge, however, was collaboration. We worked quite well as a team and had a good time doing it.
Accomplishments / Learning
We are proud to say that despite the many challenges we accomplished a great deal with this project. We have a fully functional Flask backend with React frontend (see "Technical Details") which uses multiple different APIs. This project successfully ties together audio processing, asynchonrous communication, artificial intelligence, UI/UX design, database management, and so much more. What's more is that many of our group members learned this from base fundamentals.
Technical Details
As mentioned in an earlier section, SpeakEasy is designed with a Flask (Python) backend and React (JavaScript) frontent. This is a very standard setup that is used often at hackathons due to its easy implementation and relatively limited required setup. Flask only requires two lines of code to make an entirely new endpoint, while React can make a full audio-playing page with callbacks that looks absolutely beautiful in less than an hour. For storing data, we use SQLAlchemy (backed by SQLite).
- When a user opens SpeakEasy, they are first sent to a landing page.
- After pressing any key, they are taken to a training screen. Here they will record a 15-20 second message (ideally the one shown on screen) which will be used to create an embedding. This is accomplished with the Cartesia "Clone Voice from Clip" endpoint. A Cartesia Voice (abbreviated as "Voice") is created from the returned embedding (using the "Create Voice" endpoint) which contains a Voice ID. This Voice ID is used to uniquely identify each voice, which itself is in a specific language. The database then stores this voice and creates a new user which this voice is associated with.
- When the recording is complete and the user clicks "Next", they will be taken to a split screen where they can choose between the two main program functions of SpeakEasy.
- If the user clicks on the vocal translation route, they will be brought to another recording screen. Here, they record a sound in English which is then sent to the backend. The backend encodes this MP3 data into PCM, sends it to a speech-to-text API, and then transfers it into a text translation API. Separately, the backend trains a new Voice (using the Cartesia Localize Voice endpoint, wrapped by get/create Voice since Localize requires an embedding instead of a Voice ID) with the intended target language and uses the Voice ID it returns. The backend then sends the translated text to the Cartesia "Text to Speech (Bytes)" endpoint using this new Voice ID. This is then played back to the user as a response to the original backend request. All created Voices are stored in the database and associated with the current user. This is done so returning users do not have to retrain their voices in any language.
- If the user clicks on the language learning route, they will be brought to a page which displays a randomly selected phrase in a certain language. It will then query the Cartesia API to pronounce that phrase in that language, using the preexisting Voice ID if available (or prompting to record a new phrase if not). A request is made to the backend to input some microphone input, which is then compared to Cartesia's estimation of your speech in a target language. The backend then returns a set of feedback using the difference between the two pronounciations, and displays that to the user on the frontend.
- After each route is selected, the user may choose to go back and select either route (the same route again or the other route).
Cartesia Issues
We were very impressed with Cartesia and its abilities, but noted a few issues which would improve the development experience.
- Clone Voice From Clip endpoint documentation
- The documentation for the endpoint in question details a
Responsewhich includes a variety of fields:id,name,language, and more. However, the endpoint only returns the embedding in a dictonary. It is then required to send the embedding into the "Create Voice" endpoint to create anid(and other fields), which are required for some further endpoints.
- The documentation for the endpoint in question details a
- Clone Voice From Clip endpoint length requirements
- The clip supplied to the endpoint in question appears to require a duration of greater than a second or two. Se "Error reporting" for further details.
- Text to Speech (Bytes) endpoint output format
- The TTS endpoint requires an output format be specified. This JSON object notably lacks an
encodingfield in the MP3 configuration which is present for the other formats (raw and WAV). The solution to this is to send anencodingfield with the value for one of the other two formats, despite this functionally doing nothing.
- The TTS endpoint requires an output format be specified. This JSON object notably lacks an
- Embedding format
- The embedding is specified as a list of 192 numbers, some of which may be negative. Python's JSON parser does not like the dash symbol and frequently encounters issues with this. If possible, it would be good to either allow this encoding to be base64 encoded, hashed, or something else to prevent negatives. Optimally embeddings do not have negatives, though this seems difficult to realize.
- Response code mismatches
- Some response codes returned from endpoints do not match their listed function. For example, a response code of 405 should not be returned when there is a formatting error in the request. Similarly, 400 is returned before 404 when using invalid endpoints, making it difficult to debug. There are several other instances of this but we did not collate a list.
- Error reporting
- If (most) endpoints return in JSON format, errors should also be turned in JSON format. This prevents many parsing issues and would simplify design. In addition, error messages are too vague to glean any useful information. For example, 500 is always "Bad request" regardless of the underlying error cause. This is the same thing as the error name.
Future Improvements
In the future, it would be interesting to investigate the following:
- Proper authentication
- Cloud-based database storage (with redundancy)
- Increased error checking
- Unit and integration test coverage, with CI/CD
- Automatic recording quality analysis
- Audio streaming (instead of buffering) using WebSockets
- Mobile device compatibility
- Reducing audio processing overhead
Analysis
View
Metric
- 33
- 23
- 13
- 10
Figures cover GitHub contributors during the hackathon window. A co-authored commit counts in full for each author, so per-member totals add up to more than the whole-team figures.
Technology
- CSSIn code
- FlaskIn code
- HTMLIn code
- JavaScriptIn code
- PythonIn code
- ReactIn code
6 of 6 appear in the indexed code.
AI coding agents
No AI coding agent signals were found in this repository.
Detected from committed agent config files and commit authorship. Absence of a signal is not proof an agent was unused.
Codebase size
Source size
79 KB
Source files
27
Counts recognized source files only; vendored directories, binaries and lockfiles are excluded, so this is smaller than the repository on disk.
Repository
Boomaa23/speak-easy
48 files · 2.3 MB · @ a6e5cc1
Structure
Interface
8 files · 17%Screens, components and styles rendered to the user.
API & routing
9 files · 19%Request entry points: routes, handlers and controllers.
Application logic
7 files · 15%Domain rules, services and shared utilities.
Supporting
Layers are inferred from where files sit in the tree, not from reading the code. A project that names its directories unconventionally will read oddly here — open the file browser to check anything the diagram implies.
Languages
- Python36%
- JavaScript32%
- Markdown15%
- CSS14%
- HTML2%
Share of indexed source by file size. Binary and vendored files are excluded.
Dependencies
client/package.json
npm · 9- @testing-library/jest-dom
- @testing-library/react
- @testing-library/user-event
- react
- react-dom
- react-icons
- react-router-dom
- react-scripts
- web-vitals
server/requirements.txt
pypi · 9- flask
- flask-cors
- Flask-SQLAlchemy
- googletrans
- pydub
- python-dotenv
- requests
- SpeechRecognition
- werkzeug
Declared in the repository’s manifests at the indexed commit. A declared package is not proof it is used, and runtime dependencies are listed first.
Feature verification
Flask backend with React frontend architectureVerified
SpeakEasy is designed with a Flask (Python) backend and React (JavaScript) frontend
Claimed on readmehigh confidenceserver/app.py:15— Flask app created with flask.Flask, CORS, and blueprint registrationclient/package.json:1— React app scaffolding present under client/, consumed via Routes.js and page components
Landing page then training screen then split-screen tool selection flowVerified
User opens app to a landing page, proceeds to a training/recording screen, then a split screen to choose between translation and learning routes
Claimed on readmehigh confidenceclient/src/Routes.js:9— Routes wire / (WelcomePage) -> /traininginput (TrainingInputPage) -> /choosetool (ChooseToolPage) -> /communicate or /practicelangclient/src/pages/ChooseToolPage.js:8— ChooseToolPage offers 'Talk In Another Language' and 'Practice Pronunciation' buttons navigating to the two main routes
Language learning mode: phrase playback in the user's own voiceVerified
Displays a randomly selected phrase in the target language and plays it via Cartesia using the user's existing voice ID, or prompts to train if unavailable
Claimed on readmehigh confidenceserver/routes.py:161— api_get_next_phrase cycles through a fixed phrase list per language (not truly random, but functionally equivalent selection)server/routes.py:178— api_speak resolves or localizes the user's voice_id and calls cartesia.text_to_speech to synthesize the phraseclient/src/pages/PracticeLangPage.js:33— Frontend fetches the next phrase then example speech audio from /api/nextphrase and /api/speak and plays it back
Speech-to-text transcription of recordingsVerified
Backend encodes MP3 audio into PCM and sends it to a speech-to-text API
Claimed on readmemedium confidenceserver/feedback.py:8— transcribe_audio() converts the saved audio to WAV via pydub/ffmpeg and transcribes it using SpeechRecognition's recognize_google (Google Web Speech API), used by both the translation and learning routes
User/voice persistence via SQLAlchemy backed by SQLiteVerified
For storing data, SpeakEasy uses SQLAlchemy backed by SQLite so returning users don't retrain their voices
Claimed on readmehigh confidenceserver/storage.py:10— User and VoiceModel SQLAlchemy models with create_user/create_voice/get_user_by_id repository functionsserver/app.py:18— SQLALCHEMY_DATABASE_URI set to a local sqlite db.db file and db.create_all() invoked at startup
Vocal translation into target language using localized voice (intonation preserving)Verified
User speaks in their native language; backend transcribes, translates the text, and synthesizes the translated text using a Cartesia-localized voice built from the user's own voice embedding so it retains their intonation
Claimed on Devposthigh confidenceserver/routes.py:92— api_upload_audio_comm transcribes audio, translates via googletrans Translator, resolves/creates a localized voice_id, calls cartesia.text_to_speech, and returns the resulting mp3server/cartesia.py:50— localize_voice() fetches the base voice's embedding and calls Cartesia's /voices/localize endpoint to build a same-voice embedding in the target language, matching the described 'wrapped by get/create Voice' flowclient/src/pages/CommunicatePage.js:100— Frontend records the user's speech and POSTs to /api/upload_get_translate, then plays back the returned translated audio
Voice cloning from user recording (train voice)Verified
User records 15-20 seconds to create an embedding via Cartesia Clone Voice from Clip, then a Voice is created with a Voice ID and stored in the database
Claimed on readmehigh confidenceserver/cartesia.py:40— clone_voice() posts audio bytes to Cartesia /voices/clone/clip endpointserver/routes.py:36— api_train endpoint calls cartesia.clone_voice then cartesia.create_voice and persists user_id/voice_id via storage.create_user/create_voiceclient/src/pages/TrainingInputPage.js:86— Frontend records 15-20s audio and POSTs it to /api/train, then stores returned user_id in a cookie
ffmpeg-based audio processingCode-supported
Built-with tag lists ffmpeg as part of the audio processing pipeline
Claimed on Devpostmedium confidenceserver/feedback.py:5— pydub.AudioSegment is used to load and export audio, which relies on an ffmpeg binary under the hood, though no direct ffmpeg invocation or dependency pin is visible in this codebase
Pronunciation feedback comparing user's attempt to target phraseCode-supported
User's microphone input is compared to Cartesia's pronunciation of a target phrase, and the backend returns feedback on the difference
Claimed on readmemedium confidenceserver/feedback.py:45— compare_transcriptions/generate_suggestions perform a text-level diff (difflib) between the correct and user transcriptions, not an audio/phonetic comparison; README itself has a TODO for 'phonetic feedback from comparison of audio files (pitch, freq, etc.)', so pitch/intonation-level feedback is not implemented, only word-level transcript diffingserver/routes.py:68— api_upload_audio_learn wires the recorded audio to transcription, comparison, and suggestion generation, returned to the frontendclient/src/pages/PracticeLangPage.js:131— Frontend posts recorded audio plus the foreign phrase to /api/upload_get_feedback and displays returned feedback text
An AI agent derived these features from the project’s Devpost page and readme, then searched the code for each one. Verified features are backed by cited code; claimed-only features had no supporting code, which is not by itself proof a feature is missing.
Export this project's context (description, README, evidence, key source files) to chat with an AI agent elsewhere.