Inspiration
Job hunting tools felt fragmented: one place to browse, another to track, another to prep. We wanted one workflow that connects match → apply → practice so every step leads to the next.
What it does
- Ranks jobs by fit and shows a clear “why”
- Tracks applications with a one-click “Applied”
- Generates targeted practice from your skill gaps for jobs you actually applied to
How we built it
- Flask backend + templates UI
- AI matching v2 (app/ai_matching_v2.py): a. Build structured embedding text for the user + chunked text for each job (context/requirements/summary) b. Output matched skills, missing skills, constraint flags + deterministic explanation c. Speed via SQLite embedding cache (hash of model+text) + concurrent embedding calls
Challenges we ran into
- Making rankings feel stable and “not random” (fixed with structured inputs + chunking + hybrid scoring)
- Performance (fixed with SQLite caching + parallel embedding requests)
- Explainability without hallucinations (deterministic explanations, optional LLM rephrase with fallback)
Accomplishments that we're proud of
- A matching engine that is explainable, tunable, and fast
- A clean end-to-end flow where tracking an application automatically powers practice
- A UI that surfaces scores + reasons instead of hiding the logic
What we learned
- “AI features” only matter if they’re reliable and actionable
- Structure + caching + fallbacks are what make AI usable in real apps
- Product value comes from connecting user actions to next steps
What's next for T-53_LinkedOut.AI
- Feedback loop (thumbs up/down) to improve ranking quality over time
- Better skill normalization/synonyms (e.g., Postgres vs PostgreSQL)
- Offline evaluation metrics for ranking (precision@k, nDCG)
- Stronger persistence + analytics as usage grows
Built With
- flask
- html/jinja2-templates
- javascript
- python
- sqlite
- tailwind-css-(cdn)
- the-ollama-http-api-(embeddings-and-optional-generation)
- the-requests-library
Log in or sign up for Devpost to join the conversation.