WIP: Website Initial Implementation #1
					 11 changed files with 302 additions and 0 deletions
				
			
		
							
								
								
									
										8
									
								
								Dockerfile
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								Dockerfile
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,8 @@ | ||||||
|  | FROM python:3.12-bookworm | ||||||
|  | 
 | ||||||
|  | EXPOSE 8080 | ||||||
|  | 
 | ||||||
|  | COPY . /site | ||||||
|  | RUN pip install /site | ||||||
|  | 
 | ||||||
|  | ENTRYPOINT [ "launch-site" ] | ||||||
							
								
								
									
										1
									
								
								requirements.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								requirements.txt
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1 @@ | ||||||
|  | nicegui~=2.10 | ||||||
							
								
								
									
										27
									
								
								setup.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								setup.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -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'] | ||||||
|  |     } | ||||||
|  | ) | ||||||
							
								
								
									
										0
									
								
								site_mcknight_tech/__init__.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								site_mcknight_tech/__init__.py
									
										
									
									
									
										Normal file
									
								
							
							
								
								
									
										94
									
								
								site_mcknight_tech/__main__.py
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										94
									
								
								site_mcknight_tech/__main__.py
									
										
									
									
									
										Executable file
									
								
							|  | @ -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() | ||||||
							
								
								
									
										1
									
								
								site_mcknight_tech/page_content/404.md
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								site_mcknight_tech/page_content/404.md
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1 @@ | ||||||
|  | Oops. This content hasn't been written yet... | ||||||
							
								
								
									
										15
									
								
								site_mcknight_tech/page_content/bio.md
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								site_mcknight_tech/page_content/bio.md
									
										
									
									
									
										Normal file
									
								
							|  | @ -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 😉. | ||||||
							
								
								
									
										47
									
								
								site_mcknight_tech/page_content/footer.html
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								site_mcknight_tech/page_content/footer.html
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,47 @@ | ||||||
|  | <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"> | ||||||
|  | 
 | ||||||
|  | <div> | ||||||
|  |   <span class="text-3xl"> | ||||||
|  |     <a href="https://forge.mcknight.tech/d_mcknight" class="fa"> | ||||||
|  |       <svg height="30" width="20" fill="currentcolor" viewBox="50 0 120 212" xmlns="http://www.w3.org/2000/svg"> | ||||||
|  |         <metadata | ||||||
|  |           xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | ||||||
|  |           xmlns:cc="http://creativecommons.org/ns#" | ||||||
|  |           xmlns:dc="http://purl.org/dc/elements/1.1/" | ||||||
|  |         > | ||||||
|  |           <rdf:RDF> | ||||||
|  |             <cc:Work rdf:about="https://codeberg.org/forgejo/meta/src/branch/readme/branding#logo"> | ||||||
|  |               <dc:title>Forgejo logo</dc:title> | ||||||
|  |               <cc:creator rdf:resource="https://caesarschinas.com/"><cc:attributionName>Caesar Schinas</cc:attributionName></cc:creator> | ||||||
|  |               <cc:license rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/" /> | ||||||
|  |             </cc:Work> | ||||||
|  |           </rdf:RDF> | ||||||
|  |         </metadata> | ||||||
|  |         <g transform="translate(6,6)"> | ||||||
|  |           <path d="M58 168 v-98 a50 50 0 0 1 50-50 h20" stroke-width="25" fill="none" stroke="currentcolor" /> | ||||||
|  |           <path d="M58 168 v-30 a50 50 0 0 1 50-50 h20" stroke-width="25" fill="none" stroke="currentcolor" /> | ||||||
|  |           <circle cx="142" cy="20" r="18" stroke-width="15" fill="none" stroke="currentcolor" /> | ||||||
|  |           <circle cx="142" cy="88" r="18" stroke-width="15" fill="none" stroke="currentcolor" /> | ||||||
|  |           <circle cx="58" cy="180" r="18" stroke-width="15" fill="none" stroke="currentcolor" /> | ||||||
|  |         </g> | ||||||
|  |       </svg> | ||||||
|  |     </a> | ||||||
|  |     <a href="https://github.com/neondaniel" class="fa fa-github"></a> | ||||||
|  |     <a href="https://www.linkedin.com/in/daniel-mcknight-55a5a15a/" class="fa fa-linkedin-square"></a> | ||||||
|  |     <a href="https://matrix.to/#/@d_mcknight:matrix.mcknight.tech" class="fa"> | ||||||
|  |       <svg version="1.1" height="30" fill="currentcolor" viewBox="0 0 27.9 32" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> | ||||||
|  |        <g transform="translate(-.4 0)"> | ||||||
|  |         <path d="m27.1 31.2v-30.5h-2.19v-0.732h3.04v32h-3.04v-0.732z"/> | ||||||
|  |         <path d="m8.23 10.4v1.54h0.044c0.385-0.564 0.893-1.03 1.49-1.37 0.58-0.323 1.25-0.485 1.99-0.485 0.72 0 1.38 0.14 1.97 0.42 0.595 0.279 1.05 0.771 1.36 1.48 0.338-0.5 0.796-0.941 1.38-1.32 0.58-0.383 1.27-0.574 2.06-0.574 0.602 0 1.16 0.074 1.67 0.22 0.514 0.148 0.954 0.383 1.32 0.707 0.366 0.323 0.653 0.746 0.859 1.27 0.205 0.522 0.308 1.15 0.308 1.89v7.63h-3.13v-6.46c0-0.383-0.015-0.743-0.044-1.08-0.0209-0.307-0.103-0.607-0.242-0.882-0.133-0.251-0.336-0.458-0.584-0.596-0.257-0.146-0.606-0.22-1.05-0.22-0.44 0-0.796 0.085-1.07 0.253-0.272 0.17-0.485 0.39-0.639 0.662-0.159 0.287-0.264 0.602-0.308 0.927-0.052 0.347-0.078 0.697-0.078 1.05v6.35h-3.13v-6.4c0-0.338-7e-3 -0.673-0.021-1-0.0114-0.314-0.0749-0.623-0.188-0.916-0.108-0.277-0.3-0.512-0.55-0.673-0.258-0.168-0.636-0.253-1.14-0.253-0.198 0.0083-0.394 0.042-0.584 0.1-0.258 0.0745-0.498 0.202-0.705 0.374-0.228 0.184-0.422 0.449-0.584 0.794-0.161 0.346-0.242 0.798-0.242 1.36v6.62h-3.13v-11.4z"/> | ||||||
|  |         <path d="m0.936 0.732v30.5h2.19v0.732h-3.04v-32h3.03v0.732z"/> | ||||||
|  |        </g> | ||||||
|  |       </svg> | ||||||
|  |     </a> | ||||||
|  |   </span> | ||||||
|  | </div> | ||||||
|  | <div> | ||||||
|  |   <span class="text-sm text-gray-500 sm:text-center dark:text-gray-400"> | ||||||
|  |       © 2025 Daniel McKnight. All Rights Reserved. | ||||||
|  |   </span> | ||||||
|  | </div> | ||||||
|  | 
 | ||||||
							
								
								
									
										8
									
								
								site_mcknight_tech/page_content/home.md
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								site_mcknight_tech/page_content/home.md
									
										
									
									
									
										Normal file
									
								
							|  | @ -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). | ||||||
							
								
								
									
										50
									
								
								site_mcknight_tech/page_content/portfolio.md
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								site_mcknight_tech/page_content/portfolio.md
									
										
									
									
									
										Normal file
									
								
							|  | @ -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/)! | ||||||
							
								
								
									
										51
									
								
								site_mcknight_tech/page_content/resume.md
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								site_mcknight_tech/page_content/resume.md
									
										
									
									
									
										Normal file
									
								
							|  | @ -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 | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue