diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..9bc1645 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,8 @@ +FROM python:3.12-bookworm + +EXPOSE 8080 + +COPY . /site +RUN pip install /site + +ENTRYPOINT [ "launch-site" ] diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..0d3d37e --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +nicegui~=2.10 \ No newline at end of file diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..fa54a3f --- /dev/null +++ b/setup.py @@ -0,0 +1,27 @@ +# Copyright (C) 2025 Daniel McKnight - All Rights Reserved +from os.path import join, dirname + +from setuptools import setup, find_packages + + +def get_requirements(requirements_filename: str): + requirements_file = join(dirname(__file__), requirements_filename) + with open(requirements_file, 'r', encoding='utf-8') as r: + requirements = r.readlines() + requirements = [r.strip() for r in requirements if r.strip() + and not r.strip().startswith("#")] + return requirements + +setup( + name="site-mcknight-tech", + author="Daniel McKnight", + author_email="daniel@mcknight.tech", + description="McKnight Tech Website", + packages=find_packages(), + include_package_data=True, + package_data={"site_mcknight_tech": ["page_content/*"]}, + install_requires=get_requirements("requirements.txt"), + entry_points={ + "console_scripts": ['launch-site=site_mcknight_tech.__main__:main'] + } +) \ No newline at end of file diff --git a/site_mcknight_tech/__init__.py b/site_mcknight_tech/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/site_mcknight_tech/__main__.py b/site_mcknight_tech/__main__.py new file mode 100755 index 0000000..098aaa0 --- /dev/null +++ b/site_mcknight_tech/__main__.py @@ -0,0 +1,94 @@ +# Copyright (C) 2025 Daniel McKnight - All Rights Reserved + +from os.path import isfile, join, dirname +from typing import Optional + +from fastapi.openapi.models import RequestBody +from nicegui import ui +from fastapi.requests import Request + +# TODO: Read from configuration +_tab_to_content = { + "home": "page_content/home.md", + "portfolio": "page_content/portfolio.md", + "resume": "page_content/resume.md", + "bio": "page_content/bio.md" +} + +_error_page = "page_content/404.md" +_footer_block = "page_content/footer.html" + + +@ui.page("/{name}") +def _render_path(name: str): + """ + Parse a path element to render a page + :param name: path element of the request + """ + render_site(name) + +def _get_content_from_file(file_name: str) -> str: + """ + Take a file name/path and return its contents + :param file_name: Relative or absolute path to a file + """ + file_name = join(dirname(__file__), file_name) + if not isfile(file_name): + file_name = _error_page + with open(file_name, 'r') as f: + return f.read() + + +def render_tab(tab_name: str): + """ + Render a simple webpage tab from a single file + :param tab_name: Tab name to render + """ + file_name = _tab_to_content.get(tab_name, _error_page) + with ui.scroll_area().classes('w-full h-screen no-wrap'): + ui.markdown(_get_content_from_file(file_name), + extras=['cuddled-lists', 'fenced-code-blocks', 'tables']) + + +def render_header() -> ui.tab_panels: + """ + Render sticky page header with navigation + """ + tab_names = _tab_to_content.keys() + with ui.tabs().classes('w-full') as tabs: + tab_list = {name: ui.tab(name) for name in tab_names} + with ui.tab_panels(tabs).classes('w-full mx-auto h-screen').style('max-width: 1200px') as header: + for name, t in tab_list.items(): + with ui.tab_panel(t): + render_tab(name) + return header + + +def render_site(page_name: Optional[str] = None): + """ + Renders the site with the requested page active + :param page_name: Page to render. If `None` or invalid, `Home` will be rendered + """ + header = render_header() + if page_name and page_name in _tab_to_content.keys(): + header.set_value(page_name) + else: + header.set_value(list(_tab_to_content.keys())[0]) + ui.query('.nicegui-content').classes('h-screen no-wrap') + ui.html(_get_content_from_file(_footer_block), tag="footer").classes("rounded-lg shadow-sm m-4 w-full text-center") + ui.add_css(""" + .fa { + font-size: 30px; + text-decoration: none; + margin: 10px 5px; + vertical-align: bottom; + } + """) + +def main(): + render_site() + ui.run(dark=None, reload=False, title="Daniel McKnight") + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/site_mcknight_tech/page_content/404.md b/site_mcknight_tech/page_content/404.md new file mode 100644 index 0000000..debde83 --- /dev/null +++ b/site_mcknight_tech/page_content/404.md @@ -0,0 +1 @@ +Oops. This content hasn't been written yet... \ No newline at end of file diff --git a/site_mcknight_tech/page_content/bio.md b/site_mcknight_tech/page_content/bio.md new file mode 100644 index 0000000..dfd72d1 --- /dev/null +++ b/site_mcknight_tech/page_content/bio.md @@ -0,0 +1,15 @@ +## About Me +I'm a software engineer with a passion for conversational AI, and open source development. With a background in physics +and a range of interests that extend from software development to 3D printing, woodworking, and circuit design, +I am constantly finding new projects to apply my skills to. + +At Neon AI, I have found the perfect environment to pursue my interests in tech. With a range of projects, my work at +Neon AI aligns with my commitment to responsible software development. All the projects I've worked on respect user +privacy, and many are run on user-owned hardware, ensuring that users maintain control over their data and their systems. + +I have also had the pleasure of working with a large software stack, including voice technologies, +model training and customization (LLMs, Speech Synthesis, and Intent Determination), data organization, system +architecture and design, code and workflow optimization, documentation, and infrastructure management. I've called out a +few projects that highlight my work in these areas in my Portfolio. + +Yes, an LLM helped me write this 😉. diff --git a/site_mcknight_tech/page_content/footer.html b/site_mcknight_tech/page_content/footer.html new file mode 100644 index 0000000..26bd77f --- /dev/null +++ b/site_mcknight_tech/page_content/footer.html @@ -0,0 +1,47 @@ + + +
+ + + + + + + Forgejo logo + Caesar Schinas + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + © 2025 Daniel McKnight. All Rights Reserved. + +
+ diff --git a/site_mcknight_tech/page_content/home.md b/site_mcknight_tech/page_content/home.md new file mode 100644 index 0000000..b5fa04c --- /dev/null +++ b/site_mcknight_tech/page_content/home.md @@ -0,0 +1,8 @@ +# Daniel McKnight +## Coder, Sysadmin, Manager + +I work in the design and implementation of voice assistants, LLMs, infrastructure, and plenty more. Check out a selection +of my work [in my portfolio](https://www.mcknight.tech/portfolio) or learn some more about me and my experience +[in my bio](https://www.mcknight.tech/bio) and [resume](https://www.mcknight.tech/resume), respectively. +I built this site using [NiceGUI](https://nicegui.io/), with the source code available +[on Forgejo](https://forge.mcknight.tech/d_mcknight/website-mcknight-tech). diff --git a/site_mcknight_tech/page_content/portfolio.md b/site_mcknight_tech/page_content/portfolio.md new file mode 100644 index 0000000..9c5c828 --- /dev/null +++ b/site_mcknight_tech/page_content/portfolio.md @@ -0,0 +1,50 @@ +# Project Portfolio +I have developed and contributed to hundreds of open source repositories on GitHub (as well as some Private ones that +I cannot share here). This is just a selection of some of my favorite projects and what I like about them. + +## [Neon Core](https://github.com/neongeckocom/NeonCore) +This is the primary project I contribute to as part of my work at NeonGecko. It started as work with the (now defunct) +open source Mycroft AI project, turned into a proprietary fork, and then we ended up open sourcing that fork. Working on +this project, I learned a lot about contributing to open source and managing open source projects. At the start, I learned +how to be a helpful individual contributor, and later I was on the other side, learning how to interface with the community +to balance internal goals with community feedback. + +## [`neon-data-models`](https://github.com/neongeckocom/neon-data-models) +This repository contains barely any functional code, but it was an exercise in careful planning. +It is structured into a logical hierarchy with documentation and unit tests. +This project was not fully integrated to the extent I planned, but it proved invaluable in defining/validating +messages sent between modules. The use of Pydantic also means that validator methods can be used to adapt an old-style +input into a new one when an API changes. + +## [`neon-users-service`](https://github.com/neongeckocom/neon-users-service) +This project defines a service for managing a user database with a flexible backend; initially, it supports SQLite for +a standalone system (and easy development/testing) and MongoDb, which is what we used for production at NeonGecko. +I implemented a very simple CRUD (Create/Read/Update/Delete) design, with RBAC (Role-Based Access Controls) to enable +easy integration with applications. The design enables the service to be easily adapted to any user database and to +allow other services to easily operate on user entries (with the proper permissions, of course). + +## [`neon-hana`](https://github.com/neongeckocom/neon-hana) +This is primarily a RESTful API used to access other services. This is one of the more complex FastAPI applications +I have written; it implements JWT authentication and Pydantic models to validate requests/responses. + +## [`neon-diana`](https://github.com/neongeckocom/neon-diana-utils) +This isn't the prettiest project, but it is my first foray into writing Helm charts. The module provides some +developer-oriented CLI tools for generating Helm charts to deploy the same services NeonGecko uses in production +systems. + +## [`neon-debos`](https://github.com/neongeckocom/neon_debos) +This project was my first exposure to Go templates. It started as a fork of another similar project which I adapted to +our needs. As part of this project, I used squashfs/overlayfs to enable safe OS updates with methods to roll back or +reset an installation in case of any errors. To support this, I compiled custom kernels and implemented a customized +initramfs. + +## [`.github`](https://github.com/neongeckocom/.github) +This repository contains a number of shared GitHub Actions, in addition to the standard issue templates and other special +files GitHub supports here. Creating this repository was part of an effort to consolidate code and make sprawling +repositories more manageable. + +## [`neon-docs`](https://neongeckocom.github.io/neon-docs/) +Just what it says, this is all documentation. + +## [This Site](https://forge.mcknight.tech/d_mcknight/website-mcknight-tech) +I built this site using [nicegui](https://nicegui.io/)! diff --git a/site_mcknight_tech/page_content/resume.md b/site_mcknight_tech/page_content/resume.md new file mode 100644 index 0000000..bf1f847 --- /dev/null +++ b/site_mcknight_tech/page_content/resume.md @@ -0,0 +1,51 @@ +## Work Experience +### Neon Gecko Inc. +Software Developer, Developer Relations Manager, Lead Hardware Developer + +December 2017 – Present. Responsibilities Include: + +- Managing multiple projects and work from individual contributors, one-off contractors, and long-term contract workers +- Working with management and developers to develop roadmaps, set timelines, and spec projects +- Extensive Python programming +- Extensive GitOps and workflow design, automation, and management +- Being fluent in voice assistant concepts and technologies +- Having a strong understanding of LLM technologies and model fine-tuning +- Deploying and maintaining infrastructure with Kubernetes, XCP-ng, and various cloud providers +- Kotlin for Android app development and Google Play Store publication + +### Best Buy/Geek Squad +Consultation Agent, Sales Associate + +November 2015 - December 2017 + +- Experience with Windows and Mac system administration, troubleshooting, and repair + +## Technologies +### Languages +- Python +- SQL +- MongoDb +- Kotlin + +### Frameworks +- Git and GitHub +- FastAPI +- SocketIO +- Sentry +- Kubernetes + +## Education +### University of Washington +Bachelor of Science in Physics, June 2018 + +Secretary, Physics Club at UW Bothell + +### Bellevue College +Associate of Science in Engineering, June 2016 + +Member, Phi Theta Kappa Honors Society + +### Mercer Island High School +High School Diploma, June 2012 + +Recipient, Washington State Honors Award