Skip to content

Commit

Permalink
Merge pull request #19 from emmanueposu/jbranch4
Browse files Browse the repository at this point in the history
updated trivia gen page using classes and components
  • Loading branch information
demuthsa authored May 6, 2024
2 parents ec2f7d6 + e70b29d commit abf2038
Show file tree
Hide file tree
Showing 11 changed files with 160 additions and 44 deletions.
13 changes: 12 additions & 1 deletion trivia-forge/frontend/src/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -104,9 +104,20 @@
background-color: white;
}

h2 {
text-align: center;
}

.CardPadding {
margin: 20px;
background-color: bisque;
}

footer {
position: absolute;
position: fixed;
bottom: 0;
background-color: #282c34;
color: white;
text-align: center;
width: 100%;
}
Expand Down
17 changes: 17 additions & 0 deletions trivia-forge/frontend/src/Components/Choices.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import React from "react";
import { Choice } from "../Model/Choice";

function Choices({ choices }) {
return (
<div>
{choices.map((choice, index) => {
return (
<div className="card-body" key={index}>
<textarea className="form-control" defaultValue={choice.choice}></textarea>
</div>
);
})}
</div>
);
}
export default Choices;
30 changes: 30 additions & 0 deletions trivia-forge/frontend/src/Components/Questions.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React from "react";
import Choices from "../Components/Choices";
import { Card } from "react-bootstrap";

import { Question } from "../Model/Question";

function Questions({ data }) {
let choices = data.choices;
return (
<div>
<Card className="CardPadding">
<h2 className="centered">Question</h2>
<div className="card-body">
<textarea className="form-control" defaultValue={data.question}></textarea>
</div>
<h2>Choices</h2>
<Choices choices={choices} />
<h2>Answer</h2>
<div className="card-body">
<textarea className="form-control" defaultValue={data.answer}></textarea>
</div>
<h2>Hint</h2>
<div className="card-body">
<textarea className="form-control" defaultValue={data.hint}></textarea>
</div>
</Card>
</div>
)
}
export default Questions;
8 changes: 6 additions & 2 deletions trivia-forge/frontend/src/Model/Category.jsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
export class Category {
constructor(id, name, gameID) {
this.id = id;
constructor(name, gameID = null) {
this.id = null;
this.name = name;
this.gameID = gameID
this.questions = [];
}

addQuestion(question) {
this.questions.push(question);
}

toJsonObject() {
return {
id: this.id,
Expand Down
4 changes: 2 additions & 2 deletions trivia-forge/frontend/src/Model/Choice.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export class Choice {
constructor(id, choice, questionID) {
this.id = id;
constructor(choice, questionID = null) {
this.id = null;
this.choice = choice;
this.questionID = questionID;
}
Expand Down
12 changes: 5 additions & 7 deletions trivia-forge/frontend/src/Model/Game.jsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
export class Game {
constructor(id, userID, date, name, questions) {
this.id = id;
this.date = date;
constructor(name, date, userID = null) {
this.id = null;
this.name = name;
this.questions = [];
this.categories = [];
this.userID = userID;
}

addGame(question) {
this.questions.push(question);
addCategory(category) {
this.categories.push(category);
}

toJsonObject() {
return {
id: this.id,
date: this.date,
name: this.name,
userID: this.userID
}
Expand Down
5 changes: 3 additions & 2 deletions trivia-forge/frontend/src/Model/Question.jsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
export class Question {
constructor(id, question, answer, categoryID) {
this.id = id;
constructor(question, answer, hint, categoryID = null) {
this.id = null;
this.question = question;
this.answer = answer;
this.hint = hint;
this.categoryID = categoryID;
this.choices = [];
}
Expand Down
7 changes: 3 additions & 4 deletions trivia-forge/frontend/src/Model/User.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import datetime from 'node-datetime';
export class User {
constructor(id, date, email, password, profilePic) {
this.id = id;
this.date = date;
constructor(date, email, password, profilePic = null) {
this.id = null;
this.email = email;
this.password = password;
this.profilePic = profilePic;
Expand All @@ -14,7 +14,6 @@ export class User {
toJsonObject() {
return {
id: this.id,
date: this.date,
email: this.email,
password: this.password,
profilePic: this.profilePic
Expand Down
71 changes: 53 additions & 18 deletions trivia-forge/frontend/src/Pages/TriviaGenPage.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import React, { useState } from "react"; // variables that cause the component to re-render when they change
import OpenAI from "openai";
import { Game } from "../Model/Game";
import { useNavigate } from "react-router-dom";
import { Question } from "../Model/Question";
import { Choice } from "../Model/Choice";
import { Category } from "../Model/Category";


// initialize openai client using configuration specified in vite environment variables
Expand All @@ -16,17 +20,17 @@ function TriviaGenPage() {
const [category, setCategory] = useState('');
const [isMultipleChoice, setIsMultipleChoice] = useState(false);
const navigate = useNavigate();



const handleSubmit = async (event) => {
event.preventDefault(); // prevent default form submission behavior(browser reload)

//for each category
let prompt = `Generate ${numberOfQuestions} trivia questions about ${category}.`;
if (isMultipleChoice) {
prompt += "Each question should include four multiple-choice options, the correct answer, and a fun fact. Separate each component with a newline.";
prompt += "Each question should be in the format Question:...\nChoice:...\nChoice:...\nChoice:...\nChoice:...\nAnswer:...\nHint:...\n---\nQuestion:... ect. include four multiple-choice options";
} else {
prompt += "Each question should come with its answer and a fun fact. Separate each component with a newline.";
prompt += "Each question should be in the format \nQuestion:...\nAnswer:...\n---\nQuestion:... ect.";
}

// api call
Expand All @@ -35,17 +39,48 @@ function TriviaGenPage() {
// API call to OpenAI
const completion = await openai.chat.completions.create({
model: "gpt-3.5-turbo",
messages: [{role: "user", content: prompt }],
messages: [{ role: "user", content: prompt }],
// adjust and use token limit if necessary
// max_tokens: 200
// implment and adjust temperature if needed
// temperature scale is 0-1 and used to tune randomness of output
// temperature: .5
});

const questions = completion.choices[0].message.content.split('\n'); // store trivia questions
//create a new game and category object and add category to game
let game = new Game();
let newCategory = new Category(category);
game.addCategory(newCategory);

//parse response from API
let sections = completion.choices[0].message.content.split('\n'); // store trivia questions
for (let i = 0; i < sections.length; i++) {
if (sections[i] === '') { sections.splice(i, 1); }
}
//loop through sections and create question and choice objects
for (let i = 0; i < sections.length; i += 7) {
let question = sections[i];
let choices = [];
for (let k = 0; k < 4; k++) {
let choice = sections[i + k + 1];
let newChoice = new Choice(choice);
choices.push(newChoice);
}
let answer = sections[i + 5];
let hint = sections[i + 6];

//create question object and add it to category
let newQuestion = new Question(question, answer, hint);
newCategory.addQuestion(newQuestion);

//add choices to question object
for (let i = 0; i < choices.length; i++) {
newQuestion.addChoice(choices[i]);
}


}
// state property to pass data as object to new route
navigate('/review', { state: { questions } });
navigate('/review', { state: { game } });
//console.log(completion.choices[0].message);
} catch (error) {
console.error('Error calling OpenAI API:', error);
Expand All @@ -61,34 +96,34 @@ function TriviaGenPage() {
<form onSubmit={handleSubmit}>
<div className="form-group">
<label htmlFor="triviaTitle">Number of Questions:</label>
<input
<input
type="number"
value={numberOfQuestions}
onChange={e => setNumberOfQuestions(Math.min(10, Math.max(1, parseInt(e.target.value, 10))))}
className="form-control"
id="triviaTitle"
placeholder="Number of Questions"
className="form-control"
id="triviaTitle"
placeholder="Number of Questions"
/>
</div>
<div className="form-group">
<label htmlFor="triviaCategory">Category:</label>
<input
<input
type="text"
value={category}
onChange={e => setCategory(e.target.value)}
className="form-control"
id="triviaCategory"
placeholder="Category"
className="form-control"
id="triviaCategory"
placeholder="Category"
/>
</div>
<div className="form-group">
<label htmlFor="multipleChoice">Include Multiple Choice Answers:</label>
<input
<input
type="checkbox"
checked={isMultipleChoice}
onChange={e => setIsMultipleChoice(e.target.value)}
//className="form-control"
id="multipleChoice"
id="multipleChoice"
/>
</div>
<button type="submit" className="btn btn-primary">Generate</button>
Expand Down
19 changes: 11 additions & 8 deletions trivia-forge/frontend/src/Pages/TriviaReviewPage.jsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,25 @@
import React from 'react';
import { useLocation } from 'react-router-dom'; // used to access passed state
import Questions from '../Components/Questions';
import { Button } from 'react-bootstrap';

function TriviaReviewPage() {
// Reference: https://reactrouter.com/en/main/hooks/use-location
// pulls object from state property in TriviaGenPage
const location = useLocation();
const { questions } = location.state;

const { game } = location.state;
let category = game.categories[0];
let questions = category.questions;
return (
<div>
<h1>Review and Edit Trivia Questions</h1>
{questions.map((question, index) => (
<div key={index} className="card">
<div className="card-body">
<textarea className="form-control" defaultValue={question}></textarea>
</div>
</div>

{questions.map((q, index) => (
<Questions key={index} data={q} />

))}
<Button variant="primary" size="lg" block>
Save Changes</Button>
</div>
);
}
Expand Down
18 changes: 18 additions & 0 deletions trivia-forge/frontend/src/Services/Services.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import * as db from './TF-db_services';

export const addAllForGame = async (game) => {
const newGame = await db.addGame(game);
game.categories.forEach(async (category) => {
category.gameID = newGame.id;
const newCategory = await db.addCategory(category);
category.questions.forEach(async (question) => {
question.categoryID = newCategory.id;
const newQuestion = await db.addQuestion(question);
question.choices.forEach(async (choice) => {
choice.questionID = newQuestion.id;
await db.addChoice(choice);
});
});
});
return newGame;
}

0 comments on commit abf2038

Please sign in to comment.