Project Info
Inspiration
Introducing Ghostwriter: Your silent partner in progress. Ever been in a class where resources are so hard to come by, you find yourself practically living at office hours? As teaching assistants on increasingly short-handed course staffs, it can be difficult to keep up with student demands while making long-lasting improvements to your favorite courses. Imagine effortlessly improving your course materials as you interact with students during office hours. Ghostwriter listens intelligently to these conversations, capturing valuable insights and automatically updating your notes and class documentation. No more tedious post-session revisions or forgotten improvement ideas. Instead, you can really focus on helping your students in the moment. Ghostwriter is your silent partner in educational excellence, turning every interaction into an opportunity for long-term improvement. It's the invisible presence that delivers visible results, making continuous refinement effortless and impactful. With Ghostwriter, you're not just tutoring or bug-bashing - you're evolving your content with every conversation.
What it does
Ghostwriter hosts your class resources, and supports searching across them in many ways (by metadata, semantically by content). It allows adding, deleting, and rendering markdown notes. However, Ghostwriter's core feature is in its recording capabilities. The record button starts a writing session. As you speak, Ghostwriter will transcribe and digest your speech, decide whether it's worth adding to your notes, and if so, navigate to the appropriate document and insert them at a line-by-line granularity in your notes, integrating seamlessly with your current formatting.
How we built it
We used Reflex to build the app full-stack in Python, and support the various note-management features including addition, deleting, selecting, and rendering. As notes are added to the application database, they are also summarized and then embedded by Gemini 1.5 Flash-8B before being added to ChromaDB with a shared key. Our semantic search is also powered by Gemini-embedding and ChromaDB. The recording feature is powered by Deepgram's threaded live-audio transcription API. The text is processed live by Gemini, and chunks are sent to ChromaDB for queries. Distance metrics are used as thresholds to not create notes, add to an existing note, or create a new note. In the latter two cases, llama3-70b-8192 is run through Groq to write on our (existing) documents. It does this through a RAG on our docs, as well as some prompt-engineering. To make insertion granular we add unique tokens to identify candidate insertion-points throughout our original text. We then structurally generate the desired markdown, as well as the desired point of insertion, and render the changes live to the user.
Challenges we ran into
Using Deepgram and live-generation required a lot of tasks to run concurrently, without blocking UI interactivity. We had some trouble reconciling the requirements posed by Deepgram and Reflex on how these were handled, and required us redesign the backend a few times. Generation was also rather difficult, as text would come out with irrelevant vestiges and explanations. It took a lot of trial and error through prompting and other tweaks to the generation calls and structure to get our required outputs.
Accomplishments we're proud of
Our whole live note-generation pipeline! From audio transcription process to the granular retrieval-augmented structured generation process. Spinning up a full-stack application using Reflex (especially the frontend, as two backend engineers) We were also able to set up a few tools to push dummy data into various points of our process, which made debugging much, much easier.
What's next
Ghostwriter can work on the student-side as well, allowing a voice-interface to improving your own class notes, perhaps as a companion during lecture. We find Ghostwriter's note identification and improvement process very useful ourselves. On the teaching end, we hope GhostWriter will continue to grow into a well-rounded platform for educators on all ends. We envision that office hour questions and engagement going through our platform can be aggregated to improve course planning to better fit students' needs. Ghostwriter's potential doesn't stop at education. In the software world, where companies like AWS and Databricks struggle with complex documentation and enormous solutions teams, Ghostwriter shines. It transforms customer support calls into documentation gold, organizing and structuring information seamlessly. This means fewer repetitive calls and more self-sufficient users!
Introducing Ghostwriter: Your silent partner in educational excellence. Ever been in a class where resources are so hard to come by, you find yourself living in office hours? As teaching assistants on increasingly short-handed course staffs, it can be difficult to keep up with student demands, while making long-lasting improvements to your favorite courses.
Imagine effortlessly improving your course materials as you interact with students during office hours. Ghostwriter listens intelligently to these conversations, capturing valuable insights and automatically updating your notes and class documentation. No more tedious post-session revisions or forgotten improvement ideas.
Ghostwriter turns every interaction into an opportunity for improvement. It's the invisible presence that delivers visible results, making continuous refinement effortless and impactful. With Ghostwriter, you're not just tutoring or bug-bashing - you're evolving your content with every conversation.
Analysis
View
Metric
- 15
- 9
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
- PythonIn code
- Google GeminiClaimed
- ReactClaimed
1 of 3 appear in the indexed code. 2 claimed on Devpost could not be matched to code, which may simply mean the tool leaves no trace in the repository.
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
62 KB
Source files
25
Counts recognized source files only; vendored directories, binaries and lockfiles are excluded, so this is smaller than the repository on disk.
Repository
rqchao/calhacks24
32 files · 76 KB · @ 8cff272
Structure
Interface
6 files · 19%Screens, components and styles rendered to the user.
Application logic
18 files · 56%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
- Python98%
- Markdown2%
Share of indexed source by file size. Binary and vendored files are excluded.
Dependencies
requirements.txt
pypi · 9- chromadb
- deepgram-sdk
- groq
- janus
- psycopg2-binary
- PyAudio
- python-dotenv
- reflex
- websockets
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
Add markdown notesVerified
Allows adding markdown notes to the app database
Claimed on Devposthigh confidencecustomer_data_app/backend/backend.py:373— add_note_to_db builds a Note, commits it to the DB session, reloads entries, and adds it to ChromaDBcustomer_data_app/views/main.py:159— Add Note dialog form submits to State.add_note_to_db
Automatically updates notes from conversationVerified
Listens to conversations and automatically updates notes/documentation, persisting changes
Claimed on readmehigh confidencecustomer_data_app/backend/backend.py:201— update_notes takes the transcript, generates additions and writes the updated content back to the Note in the DB sessioncustomer_data_app/backend/backend.py:199— stop_recording passes the accumulated transcript into update_notes when a session ends
Delete notesVerified
Allows deleting notes
Claimed on Devposthigh confidencecustomer_data_app/backend/backend.py:415— delete_note removes the note from the DB and deletes its id from the ChromaDB collectioncustomer_data_app/views/main.py:19— Trash icon button in each table row calls State.delete_note
Distance thresholds decide create/append/new noteVerified
Distance metrics used as thresholds to not create a note, add to an existing note, or create a new note
Claimed on Devposthigh confidencecustomer_data_app/backend/vectordb.py:51— get_relevant_files returns None when the nearest distance >= 0.7, otherwise the matching note idcustomer_data_app/backend/backend.py:205— update_notes branches on results: no match creates a new note, a match appends to the existing note
Full-stack app built with Reflex in PythonVerified
Built full-stack in Python using Reflex
Claimed on Devposthigh confidencecustomer_data_app/customer_data_app.py:29— rx.App instantiated with a Reflex theme and index page addedrequirements.txt:1— reflex>=0.5.2 is the core dependency
Line-by-line granular insertion of generated notesVerified
Insert new content at line-by-line granularity, integrating with current formatting
Claimed on Devposthigh confidencecustomer_data_app/backend/backend.py:293— location_and_new_content returns a numeric location which is used to split lines into before/after and insert the new markdown at that pointcustomer_data_app/backend/backend.py:327— location_and_new_content parses model output on '===' into (location, rewritten_summary) and validates the location is a digit
Live audio transcription via DeepgramVerified
Recording powered by Deepgram's threaded live-audio transcription API
Claimed on Devposthigh confidencecustomer_data_app/backend/backend.py:146— start_recording opens a Deepgram websocket, registers a Transcript handler, and streams the microphone in a background taskcustomer_data_app/backend/backend.py:179— Microphone(dg_connection.send) started to feed live audio to Deepgram
Live streamed rendering of note changesVerified
Render the changes live to the user (typing/streaming effect)
Claimed on Devposthigh confidencecustomer_data_app/backend/backend.py:305— generated content is appended in small chunks with asyncio.sleep between updates so the document renders progressively
Notes summarized and embedded by Gemini before ChromaDBVerified
Notes are summarized and then embedded by Gemini before being added to ChromaDB
Claimed on Devpostmedium confidencecustomer_data_app/backend/vectordb.py:36— create_text_summary summarizes note text via a Gemini 1.5 Flash model (claim says Flash-8B; code uses gemini-1.5-flash)customer_data_app/backend/vectordb.py:23— GeminiEmbeddingFunction embeds documents via genai.embed_content (text-embedding-004) before db.add
Persistent database with migrationsVerified
Notes are stored in the application database
Claimed on Devposthigh confidencecustomer_data_app/backend/backend.py:36— Note is a persisted rx.Model table with rx.session() commits throughoutalembic.ini:1— Alembic migration config present; alembic/versions contains schema migrations backing the DB
Record button starts a writing sessionVerified
The record button starts a writing session (start/stop recording)
Claimed on Devposthigh confidencecustomer_data_app/views/navbar.py:54— record_button toggles State.recording and shows a recording indicatorcustomer_data_app/backend/backend.py:130— toggle_recording dispatches start_recording or stop_recording
Render markdown notesVerified
Renders markdown notes
Claimed on Devposthigh confidencecustomer_data_app/views/main.py:192— document_display_box renders State.display_content via rx.markdowncustomer_data_app/backend/backend.py:67— display_content computed var returns the selected note's document_content
Search notes by metadataVerified
Supports searching across resources by metadata
Claimed on Devposthigh confidencecustomer_data_app/backend/backend.py:93— load_entries builds an ilike filter across Note fields from search_valuecustomer_data_app/views/navbar.py:32— 'Search metadata...' box calls State.filter_values which sets search_value and reloads
Select/navigate to a note documentVerified
Selecting and navigating to the appropriate document
Claimed on Devposthigh confidencecustomer_data_app/backend/backend.py:79— select_note looks up a note by uuid and loads its content into document_contentcustomer_data_app/views/main.py:30— Table rows call State.select_note on click
Semantic search by contentVerified
Semantic search across resources by content, powered by Gemini-embedding and ChromaDB
Claimed on Devposthigh confidencecustomer_data_app/backend/vectordb.py:49— get_relevant_files queries the Chroma collection (built with a Gemini embedding function) for the closest notecustomer_data_app/backend/backend.py:71— perform_search runs get_relevant_files against the vector_db and shows resultscustomer_data_app/views/main.py:244— test_chroma_query provides the 'Semantic search...' UI input and results dialog
Structured RAG generation via Groq/LlamaVerified
llama3-70b-8192 run through Groq to write on existing docs via RAG plus prompt-engineering
Claimed on Devpostmedium confidencecustomer_data_app/backend/backend.py:344— location_and_new_content calls Groq chat completions with SYSTEM_PROMPT and EXAMPLE_PROMPT to generate insertion output (model is llama-3.1-70b-versatile, not llama3-70b-8192 as claimed)customer_data_app/backend/backend.py:26— Groq client initialized with GROQ_API_KEY
Tools to push dummy data into the pipelineVerified
Set up tools to push dummy data into various points of the process for debugging
Claimed on Devposthigh confidencecustomer_data_app/backend/backend.py:435— create_sample_notes inserts three predefined sample notes into the DB and vector storecustomer_data_app/views/main.py:37— 'Push Data' button wired to State.create_sample_notes
Unique tokens mark candidate insertion pointsVerified
Unique tokens added to identify candidate insertion-points throughout original text for granular insertion
Claimed on Devposthigh confidencecustomer_data_app/backend/backend.py:286— note content is split into non-empty lines and each line annotated with an incrementing index used as an insertion-point markercustomer_data_app/backend/const.py:1— SYSTEM_PROMPT instructs the model to pick a numbered location and return it before a '===' delimiter
Live text processed by Gemini during recordingCode-supported
Text is processed live by Gemini and chunks are sent to ChromaDB for queries
Claimed on Devpostmedium confidencecustomer_data_app/backend/backend.py:205— transcript is sent to ChromaDB via get_relevant_files (Gemini embedding), but note-writing generation uses Groq/Llama rather than Gemini, and processing happens after stop_recording rather than continuously live
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.