Project Info
Inspiration
TreeHacks fell on Valentine's Day. One of our teammates spent the entire week fighting with his girlfriend about it. The same argument kept resurfacing in different forms. Over text, at dinner, in the car. By Friday he couldn't even remember what they were actually fighting about. Just a heavy foreboding feeling and the sense that it was going to happen again. That's the problem. People fight and can't even pinpoint why they're fighting. You can't fix a pattern you can't see. And you can't see it because you're always inside the conversation, never above it. There's a gap between what you felt and what actually happened. We built Third Party to fill that gap.
What it does
ThirdParty runs in the background on your phone or Meta glasses, capturing conversations and turning your day into a private relationship timeline. It transcribes and breaks interactions into moments, tags tone shifts and flags important points by aligning them with wearable stress proxy spikes. It also saves who you were with using facial recognition that links moments to contacts, so you can see patterns per relationship, not just per day. Why always-on recording? We know always-on recording sounds uncomfortable. But every generation resists the next layer of self-awareness, then can't live without it. Your phone already tracks every step you take and every place you go, but the most important part of your life, your relationships, has zero data. The next generation won't think twice about having a conversation archive the same way nobody thinks twice about a photo library today. We're just building it first.
How we built it
Always-on relationship capture is sensitive, so the biggest challenge was designing for trust: clear consent, minimizing what gets shared, and keeping the “shared session” partner-safe. We also had to handle noisy signals, because wearable stress proxies spike for lots of reasons. On the technical side, segmenting messy real conversations into moments that feel accurate, then keeping the journaling prompts calm and nonjudgmental, took a lot of iteration.
Challenges we ran into
Always-on capture is sensitive, so we focused on trust: consent, minimizing what gets shared, and keeping shared sessions partner-safe. Signals are also noisy, so we decided that stress spikes have to treated as places to pay attention to and not “this caused that.” Our biggest technical blocker was the people tab. It took a while to get facial recognition and speaker diarization working together reliably so moments attach to the right person, especially with imperfect audio, interruptions, and overlapping speech.
Accomplishments we're proud of
Continuous audio capture + image recognition + live conversation parsing that structures your day automatically, no manual journaling required. A visual, scrollable map of your day where each interaction becomes a “relational bubble.” Bubble size & temperature reflect conversation duration, discourse intensity (mock cortisol / heart rate signals), AI-scored meaningfulness, and emotional energy inferred from tone Every person has a living profile with a full archive of past conversations, typical topics & emotional patterns, interaction frequency & tone trends, editable labels, and custom photos/notes. Simulated physiological overlays (cortisol/heart-rate proxies) demonstrate how real biometric hardware could quantify escalation and calm over time. A UI that feels quiet and human, not clinical
What we learned
Most people do not need a verdict after a conflict. They need structure. When you can slow down, separate facts from stories, and name the underlying need, repair gets easier. We also learned that patterns matter more than single arguments: one tense moment feels random, but repeated triggers become actionable. Finally, for something this personal, trust is not a feature, it is the product.
What's next
The system automatically identifies pivotal moments: laughter spikes, escalation shifts, reconciliations, deep exchanges, and surfaces them as highlights. Two users can merge perspectives into a partner-safe shared summary that removes adversarial framing and highlights mutual ground. Image recognition adds environmental metadata (location, setting, group context) to conversation logs, giving relational context, not just transcripts.
ThirdParty
ThirdParty is a relationship mirror and guided journaling app for TreeHacks 2026.
Stack
- Next.js 14 App Router
- TypeScript
- Anthropic SDK + strict JSON validation with zod
- Local JSON storage in
data/
Quick start
-
Install dependencies
npm install -
Environment
cp .env.example .env.localEdit
.env.localand set at least:OPENAI_API_KEY=sk-...(required for Voice tab transcription + diarization)ANTHROPIC_API_KEY=...(for mediator/reflections; optional)
Never commit
.env.localor paste keys into the repo. -
Run the app
npm run devOpen http://localhost:3003. Use the Voice tab to upload or record and transcribe with speaker labels.
-
Optional: real speaker IDs (ECAPA-TDNN)
For persistent “who is this voice?” across sessions (not just placeholder labels):
-
Install Python 3 and pip, then run the embedder in a second terminal:
npm run embedderOr manually:
cd services/speaker_embedder pip install -r requirements.txt uvicorn app:app --host 0.0.0.0 --port 5000 -
In
.env.localadd (or uncomment):SPEAKER_EMBEDDER_URL=http://localhost:5000/embed -
Restart
npm run dev. The Voice page will show “ECAPA-TDNN” when the embedder is reachable.
-
-
Optional: audio conversion (webm/mp3 → WAV)
The app uses ffmpeg-static (installed with
npm install) to convert uploads to 16 kHz mono WAV for best embedder results. No separate ffmpeg install needed. If conversion fails (e.g. unsupported format), transcription still runs; speaker IDs may be less accurate without the embedder.
Run locally (summary)
Same as Quick start above: npm install → copy .env.example to .env.local and set keys → npm run dev → optional npm run embedder + SPEAKER_EMBEDDER_URL.
Conversation awareness and Meta glasses
The app now includes a conversation-awareness detector and recording pipeline:
POST /api/conversationAwareness/listen:- body:
{ "listeningEnabled": true | false }
- body:
GET /api/conversationAwareness/state:- returns detector state, recent sessions, and recent events
POST /api/conversationAwareness/ingestSignal:- body:
{ "source": "microphone" | "meta_glasses" | "phone_camera", "audioLevel": 0..1, "presenceScore": 0..1, "speakerHints": [{ personTag, speakingScore }] }
- body:
POST /api/conversationAwareness/uploadClip:- body:
{ "sessionId": "...", "audioBase64": "...", "mimeType": "audio/webm" }
- body:
POST /api/metaGlasses/ingest:- body:
{ "deviceId": "...", "audioLevel": 0..1, "speakerHints": [{ personTag, speakingScore }] }
- body:
Safety behavior
- Facial recognition is not implemented.
- Identity is based on consented person tags and speaker hints only.
- Raw captured audio is stored locally in
data/awareness/clipsand is not shared by the shared-session flow. - Phone camera mode computes co-presence and motion scores only. It does not identify people and does not persist video frames.
UI flow
- Go to
/timeline - Tap the gear icon to open
/settings - Start listening to activate microphone monitoring, optional phone camera co-presence monitoring, and detector-triggered recording
- Use the Meta glasses signal panel to ingest device-side speaker hints
Voice: Transcribe + Speaker Identification
Two pipelines:
-
OpenAI + speaker memory (recommended)
OpenAIgpt-4o-transcribe-diarizefor transcription + diarization (speaker turns). Then speaker embeddings + clustering (cosine similarity, centroid updates) to build persistent “who is this voice?” across sessions. No Azure Speaker Recognition; open-world discovery. See docs/voice-pipeline.md. -
Pyannote diarization + speaker memory (optional)
Run local pyannote diarization service and set:VOICE_DIARIZATION_BACKEND=pyannotePYANNOTE_DIARIZER_URL=http://localhost:5010/diarizeThis uses pyannote for speaker-turn detection and keeps the same speaker clustering/persistent profiles pipeline.
-
Google + Azure (optional)
Google Speech-to-Text for diarization; Azure Speaker Recognition to identify enrolled speakers only.
Setup (OpenAI pipeline)
See Quick start above. In short:
- Set OPENAI_API_KEY in
.env.local(never commit it). - Real speaker IDs (optional): Run
npm run embedderin a second terminal (or run the Python service manually; see Quick start). Set SPEAKER_EMBEDDER_URL=http://localhost:5000/embed in.env.local.
Details: docs/speaker-embedding-analysis.md. - Audio conversion: The app uses ffmpeg-static (installed with npm) to convert uploads to WAV 16 kHz mono; no separate ffmpeg install needed.
Setup (Pyannote diarization backend)
- In a second terminal run:
npm run diarizer- or follow
services/pyannote/README.md
- In
.env.localset:VOICE_DIARIZATION_BACKEND=pyannotePYANNOTE_DIARIZER_URL=http://localhost:5010/diarize
- Keep
OPENAI_API_KEYoptional for fallback behavior if the local pyannote service is unavailable.
Setup (Google + Azure)
-
Google Cloud
- Create a project and enable the Speech-to-Text API.
- Create a service account, download a JSON key, and set in
.env.local:GOOGLE_APPLICATION_CREDENTIALS=/absolute/path/to/your-key.json
- Or use
gcloud auth application-default loginand setGOOGLE_CLOUD_PROJECT=your-project-id.
-
Azure
- Create a Speech resource and in
.env.localset:AZURE_SPEECH_KEY=your-keyAZURE_SPEECH_REGION=westus(or your region).
- Create a Speech resource and in
-
Copy .env.example to
.env.localand fill in the keys.
Flow
- Voice tab: Choose “OpenAI + speaker memory” (default) or “Google + Azure”. Upload or record → “Transcribe & identify”. With OpenAI: segments get stable speaker IDs over time; you can name speakers via
PATCH /api/voice/speakers. With Google+Azure: enroll people in People → person → “Enroll voice”, then transcribe to match to those enrolled.
About
TreeHacks 2026 project
Analysis
View
Metric
- 25
- 25
- 20
- 12
- 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
- AnthropicIn code
- CSSIn code
- FastAPIIn code
- HTMLIn code
- Next.jsIn code
- OpenAIIn code
- PythonIn code
- PyTorchIn code
- ReactIn code
- TypeScriptIn code
10 of 10 appear in the indexed code.
AI coding agents
- Claude CodeCommits
- CursorCommits
Detected from committed agent config files and commit authorship. Absence of a signal is not proof an agent was unused.
Codebase size
Source size
572 KB
Source files
103
Counts recognized source files only; vendored directories, binaries and lockfiles are excluded, so this is smaller than the repository on disk.
Repository
kevenpi/Third-Party
150 files · 1.6 MB · @ f411312
Structure
Interface
31 files · 21%Screens, components and styles rendered to the user.
+7 moreAPI & routing
31 files · 21%Request entry points: routes, handlers and controllers.
Application logic
68 files · 45%Domain rules, services and shared utilities.
+7 more
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
- TypeScript94%
- Markdown3%
- Python2%
- CSS1%
- HTML0%
Share of indexed source by file size. Binary and vendored files are excluded.
Dependencies
package.json
npm · 18- @anthropic-ai/sdk
- @google-cloud/speech
- @google/genai
- ffmpeg-static
- framer-motion
- lucide-react
- next
- openai
- react
- react-dom
- recharts
- zod
- +6 more
services/speaker_embedder/requirements.txt
pypi · 8- fastapi
- numpy
- python-multipart
- soundfile
- speechbrain
- torch
- torchaudio
- uvicorn[standard]
services/pyannote/requirements.txt
pypi · 7- fastapi
- numpy
- pyannote.audio
- soundfile
- torch
- torchaudio
- uvicorn
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.
This project’s features have not been analysed yet.
Export this project's context (description, README, evidence, key source files) to chat with an AI agent elsewhere.