Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

updated trivia gen page using classes and components #19

Merged
merged 2 commits into from
May 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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;
}