Skip to content

Commit

Permalink
Adding cake table
Browse files Browse the repository at this point in the history
  • Loading branch information
carlyrichmond committed Apr 22, 2024
1 parent 2e20b70 commit 371fff2
Show file tree
Hide file tree
Showing 14 changed files with 289 additions and 8 deletions.
1 change: 1 addition & 0 deletions cake-game/.eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ module.exports = {
plugins: ['react-refresh'],
rules: {
'react/jsx-no-target-blank': 'off',
'react/prop-types': 'off',
'react-refresh/only-export-components': [
'warn',
{ allowConstantExport: true },
Expand Down
20 changes: 19 additions & 1 deletion cake-game/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion cake-game/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
"axios": "^1.6.8",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.22.3"
"react-router-dom": "^6.22.3",
"uuid": "^9.0.1"
},
"devDependencies": {
"@jest/globals": "^29.7.0",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
.image {
width: 50px;
height: auto;
}

.classification {
font-weight: normal;
}

tr {
padding: 0.5rem 3rem;
}

.row {
background-color: var(--qwik-dark-background);
}

.alternative-row {
background-color: var(--qwik-alt-background);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import "./ClassifierTableRow.css";

function ClassifierTableRow(props) {

function formatClassificationCollections(predictions, attributeName) {
if (!predictions || predictions.length === 0) {
return 'N/A';
}

return predictions[0][attributeName];
}

function formatClassificationString(classifier) {
if (!classifier) {
return 'N/A';
}

return classifier;
}

return (
<>
<tr className={`${ props.rowNumber % 2 === 0 ? 'alternative-row' : 'row'}`}>
<th>
<img className="image" alt="Random image" src={props.result.image_url} />
</th>
<th className="classification">{ props.result.user_category }</th>
<th className="classification">{ formatClassificationCollections(props.result.models.mobilenet_classifier, 'className') }</th>
<th className="classification">{ formatClassificationCollections(props.result.models?.coco_ssd_predictions, 'class') }</th>
<th className="classification">{ formatClassificationString(props.result.models?.my_transfer_model_classifier?.category) }</th>
<th className="classification">{ formatClassificationString(props.result.models?.my_model_classifier.category) }</th>
</tr>
</>
);
}

export default ClassifierTableRow;
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { test, expect } from '@playwright/experimental-ct-react';
import ClassifierTableRow from './ClassifierTableRow';

test.use({ viewport: { width: 500, height: 500 } });

test('should render', async ({ mount }) => {
const component = await mount(<ClassifierTableRow />);
expect(component).toBeDefined();
});
26 changes: 26 additions & 0 deletions cake-game/src/functions/game_results.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { getGameResults } from "../util/elasticsearch";
import { convertRequest, generateResponse } from "../util/helper";

/**
* Get a random image
* Note: Netlify deploys this function at the endpoint /.netlify/functions/image
* @param {*} event
* @param {*} context
* @returns
*/
export async function handler(event, context) {
const gameMetadata = convertRequest(event.body);

try {
const response = await getGameResults(gameMetadata);
const results = response.hits.hits.flatMap((document) => {
return document._source;
});

return generateResponse(200, results);
} catch (e) {
console.log(e);

return generateResponse(500, e);
}
}
1 change: 1 addition & 0 deletions cake-game/src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
--qwik-dark-purple: #713fc2;
--qwik-dirty-black: #1d2033;
--qwik-dark-background: #151934;
--qwik-alt-background: #332b6a;
--qwik-dark-text: #ffffff;
}

Expand Down
7 changes: 6 additions & 1 deletion cake-game/src/main.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import Error from './Error.jsx';
import Start from './routes/start/Start.jsx';
import Play from './routes/play/Play.jsx';
import Home from './routes/home/Home.jsx';
import End from './routes/end/End.jsx';

const router = createBrowserRouter([
{
Expand All @@ -29,7 +30,11 @@ const router = createBrowserRouter([
},
{
path: '/play',
element: <Play />
element: <Play />,
},
{
path: '/end',
element: <End />
}
]
},
Expand Down
29 changes: 29 additions & 0 deletions cake-game/src/routes/end/End.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
section {
display: flex;
flex-direction: column;
align-items: center;
gap: 2rem;

margin: auto;
}

table {
width: 95%;

/*padding: 0.5rem 2rem;*/

border: 1px solid;
border-color: var(--qwik-dark-purple);
}

.header-row {
background-color: var(--qwik-dark-background);
color: var(--qwik-dark-text);
font-size: large;

height: 5rem;
}

th {
text-wrap: wrap;
}
92 changes: 92 additions & 0 deletions cake-game/src/routes/end/End.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import { useEffect, useState } from "react"; //TO DO should I use useMemo to get results and classifications
import { useNavigate, useSearchParams } from "react-router-dom";

import axios from "axios";

import "./End.css";
import ClassifierTableRow from "../../components/classifier-table-row/ClassifierTableRow";
import StartButton from "../../components/start-button/StartButton";

function End() {
const navigate = useNavigate();
const [searchParams, setSearchParams] = useSearchParams();

const [username, setUsername] = useState();
const [gameId, setGameId] = useState();

const [results, setResults] = useState();

useEffect(() => {
if (searchParams && !gameId) {
const user = searchParams.get("username");
const game = searchParams.get("game_id");

setUsername(user);
setGameId(game);

getGameResults(user, game);
}
}, [username, gameId]);

async function getGameResults(user, game) {
const gameMetadata = { username: user, game_id: game };

try {
const response = await axios.post(
".netlify/functions/game_results",
gameMetadata
);

if (response.status !== 200) {
throw new Error("Unable to get game results");
}

const gameResults = response.data;
setResults(gameResults);
} catch (error) {
console.log("Unable to get game results");
setResults([]);
}
}

return (
<>
<section className="section bright">
<h1>
Were they <span className="highlight">(F)ake</span>?!
</h1>

<p>
Did you find the cake? Check out how you fared against our models
below.
</p>

{results && results.length > 0 ? (
<table>
<thead className="table-header">
<tr className="header-row">
<th>Image</th>
<th>You</th>
<th>MobileNet</th>
<th>COCO-SSD</th>
<th>MobileNet Transfer Classifier</th>
<th>Carly Model</th>
</tr>
</thead>
<tbody>
{results.map((result, index) => {
return <ClassifierTableRow key={index} rowNumber={index} result={result} />;
})}
</tbody>
</table>
) : (
<p>No results available!</p>
)}
<p>Want to try again?</p>
<StartButton />
</section>
</>
);
}

export default End;
10 changes: 10 additions & 0 deletions cake-game/src/routes/end/End.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { test, expect } from '@playwright/experimental-ct-react';
import End from './End';

test.use({ viewport: { width: 500, height: 500 } });

test('should work', async ({ mount }) => {
const component = await mount(<End />);
expect(component).toBeDefined();
//await expect(component).toContainText('Is it (F)ake?!');
});
16 changes: 14 additions & 2 deletions cake-game/src/routes/play/Play.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,19 @@ import { useEffect, useState } from "react";
import { useNavigate, useSearchParams } from 'react-router-dom';

import axios from "axios";
import { v4 as uuidv4 } from 'uuid';

import "./Play.css";

function Play() {
const navigate = useNavigate();
const [searchParams, setSearchParams] = useSearchParams();

// UUID is
const gameId = useState(uuidv4());

const [username, setUsername] = useState();
const [imageCount, setImageCount] = useState(0);
const [imageUrl, setImageUrl] = useState();
const [expectedCategory, setExpectedCategory] = useState('cake');

Expand Down Expand Up @@ -45,20 +50,27 @@ function Play() {

async function castVote(event) {
const classification = {
game_id: gameId[0],
username: username,
timestamp: new Date().toISOString(),
image_url: imageUrl,
expected_category: expectedCategory,
user_category: event.target.value
}
};

try {
const response = await axios.post('.netlify/functions/result', classification);

if (response.status !== 200) {
throw new Error('Unable to get next image');
}

await getNextRandomImage();
setImageCount(imageCount + 1);
if (imageCount < 9) {
await getNextRandomImage();
} else {
navigate(`/end?username=${username}&game_id=${classification.game_id}`);
}
}
catch(error) {
console.log('Unable to get next image');
Expand Down
Loading

0 comments on commit 371fff2

Please sign in to comment.