Merge branch 'test'

This commit is contained in:
Camerin Figueroa 2025-11-17 18:59:31 -05:00
commit ca79036ee6
79 changed files with 7404 additions and 13874 deletions

22
Dockerfile Normal file
View File

@ -0,0 +1,22 @@
# Build Stage
FROM node:22-alpine AS build
# Set the working directory inside the container
WORKDIR /app
# Copy package.json and package-lock.json
COPY package*.json ./
# Install dependencies
RUN npm ci
# Copy the rest of your application files
COPY . .
RUN npm run build
# Production Stage
FROM nginx:stable-alpine AS production
COPY --from=build /app/dist /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

22
dist/api/articles.json vendored Normal file

File diff suppressed because one or more lines are too long

BIN
dist/assets/background-C__p998u.webp vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

1
dist/assets/index-DL13lCrE.css vendored Normal file

File diff suppressed because one or more lines are too long

5016
dist/assets/index-DMCgMsst.js vendored Normal file

File diff suppressed because one or more lines are too long

BIN
dist/bai_model/group1-shard10of27.bin vendored Normal file

Binary file not shown.

BIN
dist/bai_model/group1-shard11of27.bin vendored Normal file

Binary file not shown.

BIN
dist/bai_model/group1-shard12of27.bin vendored Normal file

Binary file not shown.

BIN
dist/bai_model/group1-shard13of27.bin vendored Normal file

Binary file not shown.

BIN
dist/bai_model/group1-shard14of27.bin vendored Normal file

Binary file not shown.

BIN
dist/bai_model/group1-shard15of27.bin vendored Normal file

Binary file not shown.

BIN
dist/bai_model/group1-shard16of27.bin vendored Normal file

Binary file not shown.

BIN
dist/bai_model/group1-shard17of27.bin vendored Normal file

Binary file not shown.

BIN
dist/bai_model/group1-shard18of27.bin vendored Normal file

Binary file not shown.

BIN
dist/bai_model/group1-shard19of27.bin vendored Normal file

Binary file not shown.

BIN
dist/bai_model/group1-shard1of27.bin vendored Normal file

Binary file not shown.

BIN
dist/bai_model/group1-shard20of27.bin vendored Normal file

Binary file not shown.

BIN
dist/bai_model/group1-shard21of27.bin vendored Normal file

Binary file not shown.

BIN
dist/bai_model/group1-shard22of27.bin vendored Normal file

Binary file not shown.

BIN
dist/bai_model/group1-shard23of27.bin vendored Normal file

Binary file not shown.

BIN
dist/bai_model/group1-shard24of27.bin vendored Normal file

Binary file not shown.

BIN
dist/bai_model/group1-shard25of27.bin vendored Normal file

Binary file not shown.

BIN
dist/bai_model/group1-shard26of27.bin vendored Normal file

Binary file not shown.

BIN
dist/bai_model/group1-shard27of27.bin vendored Normal file

Binary file not shown.

BIN
dist/bai_model/group1-shard2of27.bin vendored Normal file

Binary file not shown.

BIN
dist/bai_model/group1-shard3of27.bin vendored Normal file

Binary file not shown.

BIN
dist/bai_model/group1-shard4of27.bin vendored Normal file

Binary file not shown.

BIN
dist/bai_model/group1-shard5of27.bin vendored Normal file

Binary file not shown.

BIN
dist/bai_model/group1-shard6of27.bin vendored Normal file

Binary file not shown.

BIN
dist/bai_model/group1-shard7of27.bin vendored Normal file

Binary file not shown.

BIN
dist/bai_model/group1-shard8of27.bin vendored Normal file

Binary file not shown.

BIN
dist/bai_model/group1-shard9of27.bin vendored Normal file

Binary file not shown.

1
dist/bai_model/model.json vendored Normal file

File diff suppressed because one or more lines are too long

BIN
dist/favicon.ico vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
dist/img/background.webp vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 224 KiB

BIN
dist/img/github.webp vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
dist/img/hackerrank.webp vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

BIN
dist/img/hackthebox.webp vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

BIN
dist/img/hvcu.webp vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

BIN
dist/img/leetcode_logo.webp vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

BIN
dist/img/linkedin.webp vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

BIN
dist/img/marist.webp vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

BIN
dist/img/profile.webp vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 319 KiB

BIN
dist/img/react.webp vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
dist/img/social.webp vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 435 KiB

BIN
dist/img/space.webp vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

BIN
dist/img/sunset.webp vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

BIN
dist/img/udemy.webp vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

23
dist/index.html vendored Normal file
View File

@ -0,0 +1,23 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<title>Cam's Portfolio</title>
<script type="module" crossorigin src="/assets/index-DMCgMsst.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-DL13lCrE.css">
</head>
<body style="background-color: #3F3F4A;">
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<div id="modal"></div>
</body>
</html>

BIN
dist/logo-192.webp vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
dist/logo-512.webp vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

25
dist/manifest.json vendored Normal file
View File

@ -0,0 +1,25 @@
{
"short_name": "Cams Projects",
"name": "Camerin's Projects",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
},
{
"src": "logo-192.webp",
"type": "image/webp",
"sizes": "192x192"
},
{
"src": "logo-512.webp",
"type": "image/webp",
"sizes": "512x512"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#3F3F4A",
"background_color": "#3F3F4A"
}

Binary file not shown.

3
dist/robots.txt vendored Normal file
View File

@ -0,0 +1,3 @@
# https://www.robotstxt.org/robotstxt.html
User-agent: *
Disallow:

View File

@ -17,5 +17,6 @@
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<div id="modal"></div>
<script type="module" src="/src/index.jsx"></script>
</body>
</html>

15692
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -6,6 +6,7 @@
"@reduxjs/toolkit": "^1.9.3",
"@tensorflow/tfjs": "^4.2.0",
"@tensorflow/tfjs-converter": "^4.0.0",
"@vitejs/plugin-react-swc": "^4.2.2",
"axios": "^1.3.4",
"history": "^5.3.0",
"memoize": "^0.1.1",
@ -15,18 +16,17 @@
"react-redux": "^8.0.5",
"react-router": "^6.4.3",
"react-router-dom": "^6.8.2",
"react-scripts": "^5.0.1",
"redux": "^4.2.1",
"redux-thunk": "^2.4.2",
"tfjs": "^0.6.0",
"vite": "^7.2.2",
"vite-plugin-svgr": "^4.5.0",
"web-vitals": "^3.1.1"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"postbuild": "rimraf build/**/*.map",
"test": "react-scripts test",
"eject": "react-scripts eject"
"start": "vite",
"build": "vite build",
"serve": "vite preview"
},
"eslintConfig": {
"extends": [

View File

@ -0,0 +1,34 @@
import React, { useState } from 'react';
import Article from './Article';
import "./css/ArticleEditor.css";
const ArticleEditor = (props) => {
const [content, setContent] = useState("Hello World");
let article = {
"id":"0",
"title": "Article Editor",
"desc":"This is a place to edit articles",
"contents": content
};
let copyToClipboard = () => {
navigator.clipboard.writeText(content).then(function() {
console.log('Async: Copying to clipboard was successful!');
}, function(err) {
console.error('Async: Could not copy text: ', err);
});
};
return (
<div className="ArticleEditor">
<div id="toolbar" className="toolbar">
<div className="btn" onClick={copyToClipboard()}>Copy to Clipboard</div>
</div>
<Article article={article}/>
<textarea onInput={e=>{setContent(e.target.value)}}></textarea>
</div>
);
};
export default ArticleEditor;

109
src/components/Bai.jsx Normal file
View File

@ -0,0 +1,109 @@
import React from 'react';
import { connect } from 'react-redux';
import {downloadModel, loadingModel, predict, error_msg} from '../actions'
import ProgressBar from "./subcomponents/ProgressBar";
//import { Link } from 'react-router-dom';
import './css/Bai.css';
class Bai extends React.Component {
/**
* Blank AI - Artificial Intelligence designed to distinguish photos of blank vs. non-blank paper scans
*/
classes = {0: "Blank", 1: "Not Blank"}
componentDidMount () {
document.title = "Blank AI";
}
extExtractor (filename) {
let name = filename.split('.');
let ext = name[name.length-1];
return ext
}
async fileUpload (target, predict) {
const [file] = target.files;
let image = document.getElementById("preview")
let image_ext = ['jpg', 'png'];
let file_ext = await this.extExtractor(file.name);
if (file && image_ext.includes(file_ext)) {
let imageBM = await createImageBitmap(file);
let prediction = await predict(imageBM);
console.log(this.declassify(prediction[0]));
image.src = await URL.createObjectURL(file);
image.classList.add('show');
} else {
this.props.error_msg('Please pass JPG or PNG file Only');
}
}
declassify(prediction) {
if (prediction > 0.5) {
return this.classes[1];
} else {
return this.classes[0];
}
}
render() {
let content = (this.props.model === null)?
(
<div className="content">
<h1>Would you like to download the model?</h1>
<p>By clicking Accept below, you will download the model which may be between 100 mb in size to 1 gb.</p>
<button className={`btn ${this.props.loading?"hide":""}`} onClick={()=>{this.props.loadingModel();this.props.downloadModel()}}>Accept Download</button>
<h2>{this.props.loading}</h2>
<ProgressBar progress={this.props.downloadProgress}/>
<h2>{this.props.loading?this.props.downloadProgress+"%":""}</h2>
</div>
)
:(
<div className="content">
<h1>BAI Model Prediction</h1>
<p className="prediction">{this.props.last_prediction ? this.declassify(this.props.last_prediction[0]):"Waiting for Prediction"}</p>
<div className={"error " + (this.props.error?'enable':'')}>
{this.props.error}
</div>
<img id="preview" alt="preview of predicted file"/>
<input type='file' id="fileSubmit" onChange={({target}) => this.fileUpload(target, this.props.predict)} />
<button className='btn' onClick={()=>{document.getElementById('fileSubmit').click();}}>Upload Image</button>
</div>
);
return (
<div className="Bai">
{content}
<div className="about">
<h1>About</h1>
<p>
You can find the source, dataset and model created for BAI on github at
</p>
<a href="https://www.github.com/RaspberryProgramming/BAI"> https://www.github.com/RaspberryProgramming/BAI</a>
</div>
</div>
);
}
}
const mapStateToProps = (state) => {
return {model: state.model.model, loading: state.model.loading, last_prediction: state.model.last_prediction, downloadProgress: state.model.progress, error: state.model.error};
}
export default connect(mapStateToProps, {downloadModel, loadingModel, predict, error_msg})(Bai);

View File

@ -0,0 +1,48 @@
import React, { useState } from 'react';
import '../css/Buttons.css';
import { ArrowUpShort, ArrowDownShort } from 'react-bootstrap-icons';
/**
* Buttons - set of button components that are reusable throughout the app.
*/
export const ToggleButton = ({
defVal=true,
icons=[<ArrowUpShort/>, <ArrowDownShort/>],
text="",
clickAction=()=>{}
}) => {
/**
* ToggleButton - A button component for making a toggle button
* defVal: default value, true/false
* icons: array of two jsx values that are displayed depending on value
* text: text next to toggle button
* clickAction: function that will run when clicked. value is passed to this function.
*/
const [value, setValue] = useState(defVal);
return (
<div className="btn toggle" onClick={()=>{setValue(!value); clickAction(value);}} >
<div className={value?'on':'off'}> {icons[0]} </div>
<div className={value?'off':'on'}> {icons[1]} </div>
{text}
</div>
);
};
export const Button = ({children, onClick=()=>{}, href=null, className=""}) => {
if (href === null) {
return (
<button onClick={onClick} className={'btn '+ className}>
{children}
</button>
);
} else {
return (
<a onClick={onClick} href={href} className={'btn '+className}>
{children}
</a>
);
}
}

View File

@ -0,0 +1,210 @@
import React from 'react';
import { connect } from 'react-redux';
import { getRepos, getUser, getRepoLanguages, nextPage, setSortValue } from '../../actions';
import { ToggleButton, Button } from './Buttons';
class GithubRepos extends React.Component {
perPage = 5;
sortOptions = [
// text: displayed text, value: value used for sorting
{text: "Created Date", value: "created_at"},
{text: "Last Pushed", value: "pushed_at"},
{text: "Name", value: "name"},
{text: "Number of Forks", value: "forks"},
{text: "Size", value: "size"},
{text: "Last Updated", value: "updated_at"},
];
componentDidMount() {
document.title = "Github Repos";
if (!this.props.repos) {
this.props.getUser(this.props.username); // Receive the repos at start
this.props.getRepos(this.props.username); // Receive the repos at start
}
}
renderLanguages(name) {
this.props.getRepoLanguages(this.props.username, name);
// Given that we've already received the repo's languages
if (this.props.repoLanguages && this.props.repoLanguages[name]) {
// Create a bubble for each language
return Object.keys(this.props.repoLanguages[name]).map(language=>{
return <div className="language" key={language}>{language}</div>; // Language bubble JSX
});
}
}
roundUp(num) {
return num%1 === 0? num : num-(num%1)+1
}
objArrayBubbleSort(arr, value) {
/**
* arrayBubbleSort
*/
let unsorted;
let tmp;
do {
unsorted = false;
for (let i = 0; i < arr.length-1; i++) {
if (
(value.asc && arr[i][value.value] > arr[i+1][value.value]) // Ascending
|| (!value.asc && arr[i][value.value] < arr[i+1][value.value]) // Descending
) {
tmp = arr[i+1];
arr[i+1] = arr[i];
arr[i] = tmp;
unsorted = true;
}
}
} while (unsorted);
return arr;
}
renderRepos() {
if (this.props.repos) { // If the repos have been received
if (this.props.repos.length > 0) {
// Render each repo
let repos = this.props.single ? [this.props.repos[0]] : this.props.repos
let pages = this.roundUp(repos.length/this.perPage);
let sortedRepos = this.objArrayBubbleSort([...repos], this.props.sortedValue);
const render = sortedRepos.slice(0, this.props.page*this.perPage).map((repo) =>{
let updated = (new Date (repo.updated_at)).toLocaleString();
let created = (new Date (repo.created_at)).toLocaleString();
return (
<div className="repo" key={repo.id}>
<a href={repo.html_url} target="_blank" rel="noreferrer" className="title">{repo.name}</a>
<div className="content">
<p className="description">{repo.description ? repo.description : "No Description"}</p>
{
repo.homepage ? // If the repo has a homepage, render a button
<a href={repo.homepage} target="_blank" rel="noreferrer" className="website"> Project Website </a>:
""
}
</div>
<div className="languages">
Languages:
{
this.renderLanguages(repo.name) // Render each language for the repo
}
</div>
<div className="time">
Last Updated: {updated}
</div>
<div className="time">
Created: {created}
</div>
</div>
);
});
return (
<div className="repo-list">
<div className="sort-menu">
<div className="select-menu">
<p>Sort By:&ensp;</p>
<select className="dropdown-list" onChange={v=>{
this.props.setSortValue({
...this.props.sortedValue,
value: v.target.value
});
}}>
{
this.sortOptions.map(option=>{
return (
<option
value={option.value}
key={option.value}
selected={option.value === this.props.sortedValue.value}
>
{option.text}
</option>);
})
}
</select>
</div>
&ensp;
<ToggleButton defVal={false} clickAction={(val)=>{
console.warn(val);
this.props.setSortValue({
...this.props.sortedValue,
asc: val
});
}} />
</div>
{render}
{this.props.page < pages ?
<Button className="mar-la mar-ra" onClick={()=>this.props.nextPage()}>Load More ({this.props.page}/{pages})</Button>
: ""
}
</div>
); // display the repo list with the rendered repos
} else {
return <div className="loading">User doesn't have any repositories</div>
}
}
// Return nothing if repos haven't been received
return <div className="loading"> Loading Repositories... </div>; // Return nothing if repos haven't been collected
}
render = () => {
return (<div>{this.renderRepos()}</div>);
}
}
const mapStateToProps = (state) => {
return {
repos: state.github.repos,
repoLanguages: state.github.repoLanguages,
page: state.github.page,
sortedValue: state.github.sortedValue
};
}
export default connect(mapStateToProps, {
getRepos,
getRepoLanguages,
getUser,
nextPage,
setSortValue
})(GithubRepos);

View File

@ -0,0 +1,25 @@
import React from 'react';
import { Link } from 'react-router-dom';
import '../css/Listing.css';
const Listing = (props) => {
/**
* Listing - A subcomponent for making lists of content, mostly to make a list of links.
*
*
* title - The title of the listing
* children - JSX that is necessary in the content of the component
*/
return (
<div className="listing">
<Link to={props.link}>
<div className="title">{props.title}</div>
<div className="content">
{props.children}
</div>
</Link>
</div>
);
};
export default Listing;

View File

@ -0,0 +1,25 @@
import React from 'react';
import '../css/ProgressBar.css';
class ProgressBar extends React.Component {
render () {
let pg = document.getElementById("ProgressBar");
let width = 0;
if (pg !== null) {
width = pg.offsetWidth*(this.props.progress/100);
}
return (
<div className="ProgressBar" id="ProgressBar">
<div style={{width:width+"px"}} className="Bar"></div>
</div>
);
}
};
export default ProgressBar;

1
src/vite-env.d.js Normal file
View File

@ -0,0 +1 @@
/// <reference types="vite/client" />

8
vite.config.js Normal file
View File

@ -0,0 +1,8 @@
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react-swc'
// https://vitejs.dev/config/
export default defineConfig({
base: '/',
plugins: [react()]
})