diff --git a/dennis/.gitignore b/dennis/.gitignore new file mode 100644 index 0000000..83fa1a9 --- /dev/null +++ b/dennis/.gitignore @@ -0,0 +1,4 @@ +bin/ +lib/ +__pycache__/ +pyvenv.cfg diff --git a/dennis/main.py b/dennis/main.py new file mode 100644 index 0000000..16b24f2 --- /dev/null +++ b/dennis/main.py @@ -0,0 +1,6 @@ +import uvicorn +import multiprocessing + +if __name__ == "__main__": + multiprocessing.freeze_support() + uvicorn.run('src.dennis:api', host="127.0.0.1", port=9696, reload=True) diff --git a/dennis/requirements.txt b/dennis/requirements.txt new file mode 100644 index 0000000..97dc7cd --- /dev/null +++ b/dennis/requirements.txt @@ -0,0 +1,2 @@ +fastapi +uvicorn diff --git a/dennis/src/dennis.py b/dennis/src/dennis.py new file mode 100644 index 0000000..d6a443e --- /dev/null +++ b/dennis/src/dennis.py @@ -0,0 +1,83 @@ +from fastapi import FastAPI +from fastapi.middleware.cors import CORSMiddleware + +from pydantic import BaseModel + + +class Article(BaseModel): + content_type: str + title: str + date: str # use datetime + url: str + + +api = FastAPI() + + +api.add_middleware( + CORSMiddleware, + allow_origins=['*'], + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], +) + + +@api.get('/dennis/blog') +async def return_blog_posts(): + return [ + Article( + content_type='article', + title='''It's a post about nothing!''', + date='Jul 01, 2022', + url='blog/20220701-progress.html', + ), + Article( + content_type='article', + title='''Back to School''', + date='Jun 02, 2022', + url='blog/20220602-back.html', + ), + Article( + content_type='article', + title='''It's about time, NVIDIA''', + date='May 20, 2022', + url='blog/20220520-nvidia.html', + ), + Article( + content_type='article', + title='''Change''', + date='May 06, 2022', + url='blog/20220506-change.html', + ), + Article( + content_type='article', + title='''''', + date='', + url='blog/00000000-swim.html', + ), + ] + + +@api.get('/dennis/projects') +async def return_projects(): + return [ + Article( + content_type='chatbot', + title='''Cartman''', # this stuff will change + date='Feb 17, 2023', + url='projects/20230217-cartman.html', + ), + Article( + content_type='article', + title='''What Goes Into a Successful Reddit Post?''', + date='Jun 14, 2022', + url='projects/20220614-reddit.html', + ), + Article( + content_type='article', + title='''Predicting Housing Prices''', + date='May 29, 2022', + url='projects/20220529-housing.html', + ), + ] diff --git a/doordesk/package-lock.json b/doordesk/package-lock.json index d128ad3..e7a2794 100644 --- a/doordesk/package-lock.json +++ b/doordesk/package-lock.json @@ -11,6 +11,8 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "react-markdown": "^8.0.5", + "react-router-dom": "^6.8.1", + "react-window": "^1.8.8", "rehype-raw": "^6.1.1" }, "devDependencies": { @@ -21,6 +23,17 @@ "vite": "^4.1.0" } }, + "node_modules/@babel/runtime": { + "version": "7.20.13", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.13.tgz", + "integrity": "sha512-gt3PKXs0DBoL9xCvOIIZ2NEqAGZqHjAnmVbfQtB620V0uReIQutpel14KcneZuer7UioY8ALKZ7iocavvzTNFA==", + "dependencies": { + "regenerator-runtime": "^0.13.11" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@esbuild/android-arm": { "version": "0.16.17", "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.16.17.tgz", @@ -373,6 +386,14 @@ "node": ">=12" } }, + "node_modules/@remix-run/router": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.3.2.tgz", + "integrity": "sha512-t54ONhl/h75X94SWsHGQ4G/ZrCEguKSRQr7DrjTciJXW0YU1QhlwYeycvK5JgkzlxmvrK7wq1NB/PLtHxoiDcA==", + "engines": { + "node": ">=14" + } + }, "node_modules/@swc/core": { "version": "1.3.32", "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.32.tgz", @@ -1034,6 +1055,11 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/memoize-one": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz", + "integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==" + }, "node_modules/micromark": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/micromark/-/micromark-3.1.0.tgz", @@ -1612,6 +1638,57 @@ "react": ">=16" } }, + "node_modules/react-router": { + "version": "6.8.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.8.1.tgz", + "integrity": "sha512-Jgi8BzAJQ8MkPt8ipXnR73rnD7EmZ0HFFb7jdQU24TynGW1Ooqin2KVDN9voSC+7xhqbbCd2cjGUepb6RObnyg==", + "dependencies": { + "@remix-run/router": "1.3.2" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/react-router-dom": { + "version": "6.8.1", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.8.1.tgz", + "integrity": "sha512-67EXNfkQgf34P7+PSb6VlBuaacGhkKn3kpE51+P6zYSG2kiRoumXEL6e27zTa9+PGF2MNXbgIUHTVlleLbIcHQ==", + "dependencies": { + "@remix-run/router": "1.3.2", + "react-router": "6.8.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, + "node_modules/react-window": { + "version": "1.8.8", + "resolved": "https://registry.npmjs.org/react-window/-/react-window-1.8.8.tgz", + "integrity": "sha512-D4IiBeRtGXziZ1n0XklnFGu7h9gU684zepqyKzgPNzrsrk7xOCxni+TCckjg2Nr/DiaEEGVVmnhYSlT2rB47dQ==", + "dependencies": { + "@babel/runtime": "^7.0.0", + "memoize-one": ">=3.1.1 <6" + }, + "engines": { + "node": ">8.0.0" + }, + "peerDependencies": { + "react": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" + }, "node_modules/rehype-raw": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/rehype-raw/-/rehype-raw-6.1.1.tgz", @@ -1990,6 +2067,14 @@ } }, "dependencies": { + "@babel/runtime": { + "version": "7.20.13", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.13.tgz", + "integrity": "sha512-gt3PKXs0DBoL9xCvOIIZ2NEqAGZqHjAnmVbfQtB620V0uReIQutpel14KcneZuer7UioY8ALKZ7iocavvzTNFA==", + "requires": { + "regenerator-runtime": "^0.13.11" + } + }, "@esbuild/android-arm": { "version": "0.16.17", "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.16.17.tgz", @@ -2144,6 +2229,11 @@ "dev": true, "optional": true }, + "@remix-run/router": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.3.2.tgz", + "integrity": "sha512-t54ONhl/h75X94SWsHGQ4G/ZrCEguKSRQr7DrjTciJXW0YU1QhlwYeycvK5JgkzlxmvrK7wq1NB/PLtHxoiDcA==" + }, "@swc/core": { "version": "1.3.32", "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.32.tgz", @@ -2581,6 +2671,11 @@ "@types/mdast": "^3.0.0" } }, + "memoize-one": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz", + "integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==" + }, "micromark": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/micromark/-/micromark-3.1.0.tgz", @@ -2908,6 +3003,37 @@ "vfile": "^5.0.0" } }, + "react-router": { + "version": "6.8.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.8.1.tgz", + "integrity": "sha512-Jgi8BzAJQ8MkPt8ipXnR73rnD7EmZ0HFFb7jdQU24TynGW1Ooqin2KVDN9voSC+7xhqbbCd2cjGUepb6RObnyg==", + "requires": { + "@remix-run/router": "1.3.2" + } + }, + "react-router-dom": { + "version": "6.8.1", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.8.1.tgz", + "integrity": "sha512-67EXNfkQgf34P7+PSb6VlBuaacGhkKn3kpE51+P6zYSG2kiRoumXEL6e27zTa9+PGF2MNXbgIUHTVlleLbIcHQ==", + "requires": { + "@remix-run/router": "1.3.2", + "react-router": "6.8.1" + } + }, + "react-window": { + "version": "1.8.8", + "resolved": "https://registry.npmjs.org/react-window/-/react-window-1.8.8.tgz", + "integrity": "sha512-D4IiBeRtGXziZ1n0XklnFGu7h9gU684zepqyKzgPNzrsrk7xOCxni+TCckjg2Nr/DiaEEGVVmnhYSlT2rB47dQ==", + "requires": { + "@babel/runtime": "^7.0.0", + "memoize-one": ">=3.1.1 <6" + } + }, + "regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" + }, "rehype-raw": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/rehype-raw/-/rehype-raw-6.1.1.tgz", diff --git a/doordesk/package.json b/doordesk/package.json index 6c77a61..0cc4b90 100644 --- a/doordesk/package.json +++ b/doordesk/package.json @@ -4,7 +4,7 @@ "version": "0.0.0", "type": "module", "scripts": { - "dev": "vite", + "dev": "vite --host", "build": "tsc && vite build", "preview": "vite preview" }, @@ -12,6 +12,8 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "react-markdown": "^8.0.5", + "react-router-dom": "^6.8.1", + "react-window": "^1.8.8", "rehype-raw": "^6.1.1" }, "devDependencies": { diff --git a/doordesk/public/bg.png b/doordesk/public/bg.png new file mode 100644 index 0000000..7c36f0c Binary files /dev/null and b/doordesk/public/bg.png differ diff --git a/doordesk/public/blog/000000000-swim.html b/doordesk/public/blog/000000000-swim.html new file mode 100644 index 0000000..01cc813 --- /dev/null +++ b/doordesk/public/blog/000000000-swim.html @@ -0,0 +1,158 @@ +
+

+ April 22, 1958
+ 57 Perry Street
+ New York City
+

+

Dear Hume,

+

+ You ask advice: ah, what a very human and very dangerous thing to do! For to give advice + to a man who asks what to do with his life implies something very close to egomania. To + presume to point a man to the right and ultimate goal—to point with a trembling + finger in the RIGHT direction is something only a fool would take upon himself. +

+

+     I am not a fool, but I respect your sincerity in asking my + advice. I ask you though, in listening to what I say, to remember that all advice can + only be a product of the man who gives it. What is truth to one may be a disaster to + another. I do not see life through your eyes, nor you through mine. If I were to attempt + to give you + specific advice, it would be too much like the blind leading the blind. +

+

+ + "To be, or not to be: that is the question: Whether 'tis nobler in the mind to + suffer the slings and arrows of outrageous fortune, or to take arms against a sea of + troubles..." + +
+ (Shakespeare) +

+

+ And indeed, that IS the question: whether to float with the tide, or to swim for a goal. + It is a choice we must all make consciously or unconsciously at one time in our lives. + So few people understand this! Think of any decision you've ever made which had a + bearing on your future: I may be wrong, but I don't see how it could have been anything + but a choice however indirect—between the two things I've mentioned: the floating + or the swimming. +

+

+     But why not float if you have no goal? That is another question. + It is unquestionably better to enjoy the floating than to swim in uncertainty. So how + does a man find a goal? Not a castle in the stars, but a real and tangible thing. How + can a man be sure he's not after the "big rock candy mountain," the enticing sugar-candy + goal that has little taste and no substance? +

+

+     The answer—and, in a sense, the tragedy of life—is + that we seek to understand the goal and not the man. We set up a goal which demands of + us certain things: and we do these things. We adjust to the demands of a concept which + CANNOT be valid. When you were young, let us say that you wanted to be a fireman. I feel + reasonably safe in saying that you no longer want to be a fireman. Why? Because your + perspective has changed. It's not the fireman who has changed, but you. Every man is the + sum total of his reactions to experience. As your experiences differ and multiply, you + become a different man, and hence your perspective changes. This goes on and on. Every + reaction is a learning process; every significant experience alters your perspective. +

+

+     So it would seem foolish, would it not, to adjust our lives to + the demands of a goal we see from a different angle every day? How could we ever hope to + accomplish anything other than galloping neurosis? +

+

+     The answer, then, must not deal with goals at all, or not with + tangible goals, anyway. It would take reams of paper to develop this subject to + fulfillment. God only knows how many books have been written on "the meaning of man" and + that sort of thing, and god only knows how many people have pondered the subject. (I use + the term "god only knows" purely as an expression.) There's very little sense in my + trying to give it up to you in the proverbial nutshell, because I'm the first to admit + my absolute lack of qualifications for reducing the meaning of life to one or two + paragraphs. +

+

+     I'm going to steer clear of the word "existentialism," but you + might keep it in mind as a key of sorts. You might also try something called + Being and Nothingness by Jean-Paul Sartre, and another little thing called + Existentialism: From Dostoyevsky to Sartre. These are merely suggestions. If + you're genuinely statisfied with what you are and what you're doing, then give those + books a wide berth. (Let sleeping dogs lie.) But back to the answer. As I said, to put + our faith in tangible goals would seem to be, at best, unwise. So we do not strive to be + firemen, we do not strive to be bankers, nor policemen, nor doctors. WE STRIVE TO BE + OURSELVES. +

+

+     But don't misunderstand me. I don't mean that we can't BE + firemen, bankers, or doctors—but that we must make the goal conform to the + individual, rather than make the individual conform to the goal. In every man, heredity + and environment have combined to produce a creature of certain abilities and + desires—including a deeply ingrained need to function in such a way that his life + will be MEANINGFUL. A man has to BE something; he has to matter. +

+

+     As I see it then, the formula runs something like this: a man + must choose a path which will let his ABILITIES function at maximum efficiency toward + the gratification of his DESIRES. In doing this, he is fulfilling a need (giving himself + identity by functioning in a set pattern toward a set goal) he avoids frustrating his + potential (choosing a path which puts no limit on his self-development), and he avoids + the terror of seeing his goal wilt or lose its charm as he draws closer to it (rather + than bending himself to meet the demands of that which he seeks, he has bent his goal to + conform to his own abilities and desires). +

+

+     In short, he has not dedicated his life to reaching a + pre-defined goal, but he has rather chosen a way of like he KNOWS he will enjoy. The + goal is absolutely secondary: it is the + functioning toward the goal which is important. And it seems almost ridiculous to + say that a man MUST function in a pattern of his own choosing; for to let another man + define your own goals is to give up one of the most meaningful aspects of life—the + definitive act of will which makes a man an individual. +

+

+     Let's assume that you think you have a choice of eight paths to + follow (all pre-defined paths, of course). And let's assume that you can't see any real + purpose in any of the eight. Then—and here is the essence of all I've + said—you MUST FIND A NINTH PATH. +

+

+     Naturally, it isn't as easy as it sounds. you've lived a + relatively narrow life, a vertical rather than a horizontal existence. So it isn't any + too difficult to understand why you seem to feel the way you do. But a man who + procrastinates in his CHOOSING will inevitably have his choice made for him by + circumstance. +

+

+     So if you now number yourself among the disenchanted, then you + have no choice but to accept things as they are, or to seriously seek something else. + But beware of looking for + goals: look for a way of life. Decide how you want to live and then see what you + can do to make a living WITHIN that way of life. But you say, "I don't know where to + look; I don't know what to look for." +

+

+     And there's the crux. Is it worth giving up what I have to look + for something better? I don't know—is it? Who can make that decision but you? But + even by DECIDING TO LOOK, you go a long way toward making the choice. +

+

+     If I don't call this to a halt, I'm going to find myself writing + a book. I hope it's not as confusing as it looks at first glance. Keep in mind, of + course, that this is MY WAY of looking at things. I happen to think that it's pretty + generally applicable, but you may not. Each of us has to create our own credo—this + merely happens to be mine. +

+

+     If any part of it doesn't seem to make sense, by all means call + it to my attention. I'm not trying to send you out "on the road" in search of Valhalla, + but merely pointing out that it is not necessary to accept the choices handed down to + you by life as you know it. There is more to it than that—no one HAS to do + something he doesn't want to do for the rest of his life. But then again, if that's what + you wind up doing, by all means convince yourself that you HAD to do it. You'll have + lots of company. +

+
+

    And that's it for now. Until I hear from you again, I remain,

+

+ your friend...
+ Hunter +

+
diff --git a/doordesk/public/blog/20220506-change.html b/doordesk/public/blog/20220506-change.html new file mode 100644 index 0000000..1f9158f --- /dev/null +++ b/doordesk/public/blog/20220506-change.html @@ -0,0 +1,54 @@ +
+

May 06, 2022

+

Change

+

+ "Life should not be a journey to the grave with the intention of arriving safely in + a pretty and well preserved body, but rather to skid in broadside in a cloud of + smoke, thoroughly used up, totally worn out, and loudly proclaiming "Wow! What a + Ride!" +
+ (Hunter S.Thompson) +

+

+     There comes a time in one's life, perhaps multiple, when there + is an unquestionable need for change. Maybe you're not sure how, why, or where it came + from, or where even it is you're headed, or how to get there, but here you are taking + your first steps toward a new life. A journey into the unknown. I've just set out on one + of these journeys, and even as I sit here typing this now I can't help but feel a little + bit nervous, but even more excited. I have absolutely no idea where I'm headed to be + quite honest. But I know where I've been. +

+

+     Growing up I would always be taking things apart, I HAD to see + what was inside. What makes this thing, a thing. What makes it tick? Can it tick faster? + For no particular reason I just had to know every little detail about what made the + thing the thing that it was and why it did what it did. It's a gift and a curse of + sorts. Quickly this led to taking apart things of increasing complexity, our home + computer for instance. Luckily I was able to get it put back together before my parents + got home because it was made clear that this was not allowed, and the CPU didn't seem to + mind the sudden absence of thermal compound either. I must have been around 7 or 8 years + old at that time, and it still puzzles me just what is going on inside there. +

+

+     I have a better idea now, naturally I had to figure out just + what all those pieces were, what they did, and how they did it. What if I replaced some + of these parts with other parts? As I honed my web searching skills to try to answer the + seemingly endless hows and whys I ended up building myself a little hotrod computer and + then raced it against other peoples' computers because why not, right? And I actually + won! It was an overclocking contest called the winter suicides, a kind of computer drag + race. Highest CPU clock speed wins, you have to boot into Windows XP, open CPU-Z, and + take a screenshot. If it crashes immediately after that (and it did) it still counts. I + got some pretty weird looks from my father as I stuck my computer outside in the snow + but that was a small price to pay for the grand prize which was a RAM kit (2GB of DDR400 + I believe) and RAM cooler. +

+

+     After getting comfortable with hardware I started to study the + software side of things, I tried teaching myself C++ (and didn't get very far), I did + teach myself HTML and CSS, some JavaScript, and started playing around with Linux. It + took until only a year or two ago to finally be completely on Linux full time (gaming + holding me back), I even have a Linux phone now (Pinephone Pro). At this point I reached + high school and my attention moved from computers to cars. +

+

To be continued...

+
diff --git a/doordesk/public/blog/20220520-nvidia.html b/doordesk/public/blog/20220520-nvidia.html new file mode 100644 index 0000000..29824b8 --- /dev/null +++ b/doordesk/public/blog/20220520-nvidia.html @@ -0,0 +1,13 @@ +
+

May 20, 2022

+

It's about time, NVIDIA

+

   It's about time... NVIDIA has finally released and is starting to + support Open-source software with their new modules released recently for the Linux + kernel. NVIDIA historically has been seemingly against Linux/OSS for whatever reason. + This is a huge step forward both for end users and NVIDIA. +

+

+ + NVIDIA open-gpu-kernel-modules on github. +

+
diff --git a/doordesk/public/blog/20220602-back.html b/doordesk/public/blog/20220602-back.html new file mode 100644 index 0000000..dbb0ae7 --- /dev/null +++ b/doordesk/public/blog/20220602-back.html @@ -0,0 +1,45 @@ +
+

Jun 02, 2022

+

Back to School

+

Where the hell have I been!?

+

+ Looking back at the past 5 weeks, it's impressive the amount of new things that have + been shoved in my face. A list I'll try to make contains: +

+ +

+ It doesn't seem like much at the time except chaos, but then about a week later it + finally sets in. After tomorrow we'll be halfway through the course and while I guess + you could say that it's half over, or that it signifies progress, I feel it's more like + being halfway up Mount Everest and looking—trying to squint through the clouds and + make out what looks like the peak. I don't see a peak and maybe it's because I'm + nearsighted but I can also tell you that if were to look down then I can't see where + I've started either! +

+

+ It's been quite a ride and I hope to see it to the end. I don't have time to even think + about it further. It's where I perform my best though, on my heels. Probably by + design... +

+

After?

+

+ I would like to use these skills to expand on some of the class projects I've worked on + and I have some other ideas using language processing I think would be fun to play with. + I think it would be fun to create an internet chat bot, we'll start with text but if + speech recognition is practical then I may add and play with that too. I would also like + to make some sort of "Propaganda Detector" +

+
diff --git a/doordesk/public/blog/20220701-progress.html b/doordesk/public/blog/20220701-progress.html new file mode 100644 index 0000000..bbe02ef --- /dev/null +++ b/doordesk/public/blog/20220701-progress.html @@ -0,0 +1,96 @@ +
+

Jul 01, 2022

+

It's a post about nothing!

+

The progress update

+

+ +

+

Bots

+

+ After finding a number of ways not to begin the project formerly known as my capstone, + I've finally settled on a + dataset. + The project is about detecting bots, starting with twitter. I've + studied a + few + different + methods of bot detection and particularly like the + DeBot and + BotWalk methods and think I will try to mimic them, + in that order. +

+

+ Long story short, DeBot uses a fancy method of time correlation to group accounts + together based on their posting habits. By identifying accounts that all have identical + posting habits that are beyond what a human could do by coincidence, this is a great + first step to identifying an inital group of seed bots. This can then be expanded by + using BotWalk's method of checking all the followers of the bot accounts and comparing + anomalous behavior to separate humans from non-humans. Rinse and repeat. I'll begin this + on twitter but hope to make it platform independent. +

+

The Real Capstone

+

+ The bot project is too much to complete in this short amount of time, so instead I'm + working with a + small dataset + containing info about cars with some specs and I'll predict MPG. The problem itself for + me is trivial from past study/experience as an auto mechanic so I should have a nice + playground to focus completely on modeling. It's a very small data set too at < 400 + lines, I should be able to test multiple models in depth very quickly. It may or may not + be interesting, expect a write-up anyway. +

+

Cartman

+

+ Well I guess I've adopted an 8 year old. Based on + this project + I've trained a chat bot with the personality of Eric Cartman. He's a feature of my + Discord bot living on a Raspberry Pi 4B, which I would say is probably the slowest + computer you would ever want to run something like this on. It takes a somewhat + reasonable amount of time to respond, almost feeling human if you make it think a bit. + The project uses PyTorch to train the model. I'd like + to re-create it using TensorFlow as an + exercise to understand each one better, but that's a project for another night. It also + only responds to one line at a time so it can't carry a conversation with context, + yet... +

+

Website

+

+ I never thought I'd end up having a blog. I had no plans at all actually when I set up + this server, just to host a silly page that I would change from time to time whenever I + was bored. I've been looking at + Hugo as a way to organize what is now just a list of + divs in a single html file slowly growing out of control. Basically you just dump each + post into its own file, create a template of how to render them, and let it do its + thing. I should be able to create a template that recreates exactly what you see right + now, which is beginning to grow on me. +

+

+ If you haven't noticed yet, (and I don't blame you if you haven't because only a handful + of people even visit this page) each time there is an update there is a completely new + background image, color scheme, a whole new theme. This is because this page is a near + identical representation of terminal windows open my computer and each time I update the + page I also update it with my current wallpaper, which generates the color scheme + dynamically using + Pywal. +

+ TODO: + +

That's all for now

+
diff --git a/doordesk/public/games/index.html b/doordesk/public/games/index.html new file mode 100644 index 0000000..cee4ada --- /dev/null +++ b/doordesk/public/games/index.html @@ -0,0 +1,22 @@ +

Some games using wasm/webgl

+

Browser performance as of January 2023

+

Tested better:

+
    +
  1. Opera
  2. +
  3. Firefox Developer Edition
  4. +
  5. Brave
  6. +
+

Tested poor or broken:

+
    +
  1. Safari
  2. +
  3. Chrome stable release or older
  4. +
  5. Edge, see above^
  6. +
+

Consider anything else average or let me know otherwise

+ diff --git a/doordesk/public/projects/20220529-housing.html b/doordesk/public/projects/20220529-housing.html new file mode 100644 index 0000000..515d299 --- /dev/null +++ b/doordesk/public/projects/20220529-housing.html @@ -0,0 +1,138 @@ +
+

May 29, 2022

+

Predicting Housing Prices

+

+ A recent project I had for class was to use + scikit-learn + to create a regression model that will predict the price of a house based on some + features of that house. +

+

How?

+
    +
  1. + Pick out and analyze certain features from the dataset. Used here is the + Ames Iowa Housing Data + set. +
  2. +
  3. + Do some signal processing to provide a clearer input down the line, improving + accuracy +
  4. +
  5. Make predictions on sale price
  6. +
  7. + Compare the predicted prices to recorded actual sale prices and score the results +
  8. +
+

What's important?

+

+ Well, I don't know much about appraising houses. But I have heard the term "price per + square foot" so we'll start with that: +

+

+

+ There is a feature for 'Above Grade Living Area' meaning floor area that's not basement. + It looks linear, there were a couple outliers to take care of but this should be a good + signal. +

+

Next I calculated the age of every house at time of sale and plotted it:

+

+

+ Exactly what I'd expect to see. Price drops as age goes up, a few outliers. We'll + include that in the model. +

+

Next I chose the area of the lot:

+

+

+ Lot area positively affects sale price because land has value. Most of the houses here + have similarly sized lots. +

+

Pre-Processing

+
+

+ Here is an example where using + StandardScaler() + just doesn't cut it. The values are all scaled in a way where they can be compared + to one-another, but outliers have a huge effect on the clarity of the signal as a + whole. +

+ +
+ + +
+
+
+

+ You should clearly see in the second figure that an old shed represented in the top left + corner will sell for far less than a brand new mansion represented in the bottom right + corner. This is the result of using the + QuantileTransformer() + for scaling. +

+

The Model

+

+ A simple + LinearRegression() + should do just fine, with + QuantileTransformer() + scaling of course. +

+
+ +
+

+ Predictions were within about $35-$40k on average.
+ It's a little fuzzy in the higher end of prices, I believe due to the small sample size. + There are a few outliers that can probably be reduced with some deeper cleaning however + I was worried about going too far and creating a different story. An "ideal" model in + this case would look like a straight line. +

+

Conclusion

+

+ This model was designed with a focus on quality and consistency. With some refinement, + the margin of error should be able to be reduced to a reasonable number and then + reliable, accurate predictions can be made for any application where there is a need to + assess the value of a property. +

+

+ I think a large limiting factor here is the size of the dataset compared to the quality + of the features provided. There are + more features + from this dataset that can be included but I think the largest gains will be had from + simply feeding in more data. As you stray from the "low hanging fruit" features, the + quality of your model overall starts to go down. +

+

Here's an interesting case, Overall Condition of Property:

+
+ +
+

+ You would expect sale price to increase with quality, no? Yet it goes down.. Why?
+ I believe it's because a lot of sellers want to say that their house is of highest + quality, no matter the condition. It seems that most normal people (who aren't liars) + dont't care to rate their property and just say it's average. Both of these combined + actually create a negative trend for quality which definitely won't help predictions! +

+

+ I would like to expand this in the future, maybe scraping websites like Zillow to gather + more data.
+ We'll see. +

+
diff --git a/doordesk/public/projects/20220529-housing/pics/age.png b/doordesk/public/projects/20220529-housing/pics/age.png new file mode 100644 index 0000000..318184d Binary files /dev/null and b/doordesk/public/projects/20220529-housing/pics/age.png differ diff --git a/doordesk/public/projects/20220529-housing/pics/age_liv_area_ss.png b/doordesk/public/projects/20220529-housing/pics/age_liv_area_ss.png new file mode 100644 index 0000000..ffb5739 Binary files /dev/null and b/doordesk/public/projects/20220529-housing/pics/age_liv_area_ss.png differ diff --git a/doordesk/public/projects/20220529-housing/pics/age_liv_qt.png b/doordesk/public/projects/20220529-housing/pics/age_liv_qt.png new file mode 100644 index 0000000..1f9782a Binary files /dev/null and b/doordesk/public/projects/20220529-housing/pics/age_liv_qt.png differ diff --git a/doordesk/public/projects/20220529-housing/pics/livarea_no_outliers.png b/doordesk/public/projects/20220529-housing/pics/livarea_no_outliers.png new file mode 100644 index 0000000..520a4a3 Binary files /dev/null and b/doordesk/public/projects/20220529-housing/pics/livarea_no_outliers.png differ diff --git a/doordesk/public/projects/20220529-housing/pics/lot_area.png b/doordesk/public/projects/20220529-housing/pics/lot_area.png new file mode 100644 index 0000000..f5eb2bc Binary files /dev/null and b/doordesk/public/projects/20220529-housing/pics/lot_area.png differ diff --git a/doordesk/public/projects/20220529-housing/pics/mod_out.png b/doordesk/public/projects/20220529-housing/pics/mod_out.png new file mode 100644 index 0000000..7bad6cc Binary files /dev/null and b/doordesk/public/projects/20220529-housing/pics/mod_out.png differ diff --git a/doordesk/public/projects/20220529-housing/pics/overall_cond.png b/doordesk/public/projects/20220529-housing/pics/overall_cond.png new file mode 100644 index 0000000..8141f20 Binary files /dev/null and b/doordesk/public/projects/20220529-housing/pics/overall_cond.png differ diff --git a/doordesk/public/projects/20220614-reddit.html b/doordesk/public/projects/20220614-reddit.html new file mode 100644 index 0000000..449b97f --- /dev/null +++ b/doordesk/public/projects/20220614-reddit.html @@ -0,0 +1,128 @@ +
+

Jun 14, 2022

+

What Goes Into a Successful Reddit Post?

+

+ In an attempt to find out what about a Reddit post makes it successful I will use some + classification models to try to determine which features have the highest influence on + making a correct prediction. In particular I use + Random Forest + and + KNNeighbors + classifiers. Then I'll score the results and see what the highest predictors are. +

+

+ To find what goes into making a successful Reddit post we'll have to do a few things, + first of which is collecting data: +

+

Introducing Scrapey!

+

+ Scrapey is my scraper script that takes a snapshot + of Reddit/r/all hot and saves the data to a .csv file including a calculated age for + each post about every 12 minutes. Run time is about 2 minutes per iteration and each + time adds about 100 unique posts to the list while updating any post it's already seen. +

+

+ I run this in the background in a terminal and it updates my data set every ~12 minutes. + I have records of all posts within about 12 minutes of them disappearing from /r/all. +

+

EDA

+

+ Next I take a quick look to see what looks useful, what + doesn't, and check for outliers that will throw off the model. There were a few outliers + to drop from the num_comments column. +

+ Chosen Features: + +

+ Then I split the data I'm going to use into two dataframes (numeric and non) to prepare + for further processing. +

+

Clean

+

Cleaning the data further consists of:

+ +

Model

+

+ If the number of comments of a post is greater than the median total number of comments + then it's assigned a 1, otherwise a 0. This is the target column. I then try some + lemmatizing, it doesn't seem to add much. After that I create and join some dummies, + then split and feed the new dataframe into + Random Forest + and + KNNeighbors + classifiers. Both actually scored the same with + cross validation + so I mainly used the forest. +

+

Notebook Here

+

Conclusion

+

Some Predictors from Top 25:

+ +

+ Popular words: 'like', 'just', 'time', 'new', 'oc', 'good', 'got', 'day', 'today', 'im', + 'dont', and 'love'. +

+

+ People on Reddit (at least in the past few days) like their memes, porn, and talking + about their day. And it's preferred if the content is original and self posted. So yes, + post your memes to memes and shitposting, tag them NSFW, use some words from the list, + and rake in all that sweet karma! +

+

+ But it's not that simple, this is a fairly simple model, with simple data. To go beyond + this I think the comments would have to be analyzed. + Lemmatisation I thought would + be the most influential piece, and I still think that thinking is correct. But in this + case it doesn't apply because there is no real meaning to be had from reddit post + titles, at least to a computer. (or I did something wrong) +

+

+ There's a lot more seen by a human than just the text in the title, there's often an + image attached, most posts reference a recent/current event, they could be an inside + joke of sorts. For some posts there could be emojis in the title, and depending on their + combination they can take on a meaning completely different from their individual + meanings. The next step from here I believe is to analyze the comments section of these + posts because in this moment I think that's the easiest way to truly describe the + meaning of a post to a computer. With what was gathered here I'm only to get 10% above + baseline and I think that's all there is to be had here, I mean we can tweak for a few + percent probably but I don't think there's much left on the table. +

+
diff --git a/doordesk/public/projects/20230217-cartman.html b/doordesk/public/projects/20230217-cartman.html new file mode 100644 index 0000000..02ecf43 --- /dev/null +++ b/doordesk/public/projects/20230217-cartman.html @@ -0,0 +1,36 @@ +

Feb 17, 2023

+

Cartman

+ +

+ You can download a Docker image if you'd like to run it on your own hardware for either + x86_64 + or + aarch64. +

+

+ More info here as well as + example scripts + to talk to the docker container. +

diff --git a/doordesk/src/App.tsx b/doordesk/src/App.tsx deleted file mode 100644 index 2cf626b..0000000 --- a/doordesk/src/App.tsx +++ /dev/null @@ -1,87 +0,0 @@ -import { Component } from 'react' -import './App.css' -import Header from './components/Header.js' -import Home from './components/Home.js' -import Blog from './components/Blog.js' -import Projects from './components/Projects.js' -import Games from './components/Games.js' -import Cartman from './components/Cartman.js' - -const FAKE_IT_TIL_YOU_MAKE_IT: string[] = [ - // component carousel - 'Home', // table of top 5 from(when enough content) *; then interleave latest from * - 'Blog', // blog posts - 'Projects', // project writeups - 'Games', // cards with thumbnail and summary - 'Cartman', // with knobs! -] - -type IAppProps = { -} - -type IAppState = { - currentPage: string; - currentPageIndex: number; -} - -class App extends Component { - constructor(props: IAppProps) { - super(props) - this.state = { - currentPage: 'Home', - currentPageIndex: 0 - } - } - handleClick(message: string) { - this.setState({currentPage: message}) - } - ratchet() { - console.log(this.state.currentPageIndex) - - if (this.state.currentPageIndex >= FAKE_IT_TIL_YOU_MAKE_IT.length - 1) { - this.setState({ - currentPageIndex: 0, - currentPage: FAKE_IT_TIL_YOU_MAKE_IT[0] - }) - } - else { - this.setState({ - currentPageIndex: this.state.currentPageIndex + 1, - currentPage: FAKE_IT_TIL_YOU_MAKE_IT[this.state.currentPageIndex+1] - }) - - } - } - render() { - // could probably be dynamic - let page: JSX.Element; - switch (this.state.currentPage) { - case 'Blog': - page = - break; - case 'Projects': - page = - break; - case 'Games': - page = - break; - case 'Cartman': - page = - break; - default: - page = - break; - } - return ( -
this.ratchet()}> -
- {page} -
- ) - } -} - -export default App diff --git a/doordesk/src/components/BlogPost.tsx b/doordesk/src/components/Article.tsx similarity index 61% rename from doordesk/src/components/BlogPost.tsx rename to doordesk/src/components/Article.tsx index 3716215..06df64c 100644 --- a/doordesk/src/components/BlogPost.tsx +++ b/doordesk/src/components/Article.tsx @@ -2,14 +2,14 @@ import { Component } from 'react' import ReactMarkdown from 'react-markdown' import rehypeRaw from 'rehype-raw' -type IBlogPostProps = { +type ArticleProps = { postURL: string; } -type IBlogPostState = { +type ArticleState = { postHTML: string; } -class BlogPost extends Component { - constructor(props: IBlogPostProps) { +class Article extends Component { + constructor(props: ArticleProps) { super(props) this.state = { 'postHTML': '' @@ -26,14 +26,12 @@ class BlogPost extends Component { render() { return (
-
- -
+
) } } -export default BlogPost +export default Article diff --git a/doordesk/src/components/Blog.tsx b/doordesk/src/components/Blog.tsx index c1fb811..2f901eb 100644 --- a/doordesk/src/components/Blog.tsx +++ b/doordesk/src/components/Blog.tsx @@ -1,38 +1,27 @@ import { Component } from 'react' -import BlogPost from './BlogPost.js' +import { VariableSizeList as List } from 'react-window' +import Slingshot from './Slingshot.js' -// should render one by one -// make api that has post id, title, date, etc with url to article; then -// distribute to blog posts - -const FAKE_IT_TIL_YOU_MAKE_IT: string[] = [ - 'blog/20220701-progress.html', - 'blog/20220602-back.html', - 'blog/20220520-nvidia.html', - 'blog/20220506-change.html', - 'blog/000000000-swim.html', -] - -type IBlogProps = { -} - -type IBlogState = { -} - -class Blog extends Component { - constructor(props: IBlogProps) { +class Blog extends Component { + constructor(props) { super(props) + this.state = { + articles: [], + } } - renderPosts(urls: string[]): JSX.Element[] { - return ( - urls.map((postURL) => ) - ) + async fetchBlogPosts() { + return fetch('http://127.0.0.1:9696/dennis/blog') + .then((res) => res.json()); + } + componentDidMount() { + this.fetchBlogPosts() + .then((articles) => this.setState({ articles })) } render() { return ( <> - {this.renderPosts(FAKE_IT_TIL_YOU_MAKE_IT)} + {console.log(this.state.articles.map(asd => asd.url))} ) } diff --git a/doordesk/src/components/Cartman.tsx b/doordesk/src/components/Cartman.tsx index b684121..a6f13d7 100644 --- a/doordesk/src/components/Cartman.tsx +++ b/doordesk/src/components/Cartman.tsx @@ -1,21 +1,174 @@ import { Component } from 'react' -type ICartmanProps = { +type CartmanProps = { } -type ICartmanState = { +type CartmanState = { + bot_name: string + message: string + max_new_tokens: number + num_beams: number + num_beam_groups: number + no_repeat_ngram_size: number + length_penalty: number + diversity_penalty: number + repetition_penalty: number + early_stopping: boolean + chat_history: string } -class Cartman extends Component { - constructor(props: ICartmanProps) { +class Cartman extends Component { + constructor(props: CartmanProps) { super(props) + this.state = { + bot_name: 'cartman', + message: 'Enter text here', + max_new_tokens: 200, + num_beams: 8, // must be divisible by num_beam_groups + num_beam_groups: 4, + no_repeat_ngram_size: 3, + length_penalty: 1.4, + diversity_penalty: 0, + repetition_penalty: 2.1, + early_stopping: true, + chat_history: 'responses', + } } + + onSubmit(message, history) { + let options = { + method: 'POST', + headers: { + 'Content-Type': + 'application/json;charset=utf-8' + }, + body: JSON.stringify(this.state) + } + + history.value = history.value + 'You: ' + message.value + '\n'; + message.value = ""; + history.scrollTop = history.scrollHeight + + let fetchRes = fetch('http://localhost:6969/chat', options); + fetchRes.then(res => + res.json()).then(d => { + history.value = `${history.value}${d.name}: ${d.message}\n`; + history.scrollTop = history.scrollHeight + }) + } + render() { return (
-
-

cartman

-
+

Cartman

+
+