Skip to content

Commit

Permalink
made changes to trivia gen form. added an overall theme and ability t…
Browse files Browse the repository at this point in the history
…o have multiple categories for a game
  • Loading branch information
justinstoner2 committed May 6, 2024
1 parent e70b29d commit 546fdf4
Show file tree
Hide file tree
Showing 7 changed files with 169 additions and 76 deletions.
1 change: 1 addition & 0 deletions trivia-forge/frontend/src/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ h2 {

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

Expand Down
17 changes: 17 additions & 0 deletions trivia-forge/frontend/src/Components/Categories.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import React from "react";
import Questions from "../Components/Questions";

function Categories({ category }) {
let questions = category.questions;
return (
<div>
<h2>{category.name}</h2>
{questions.map((question, index) => {
return (
<Questions key={index} data={question} />
);
})}
</div>
);
}
export default Categories;
2 changes: 1 addition & 1 deletion trivia-forge/frontend/src/Components/Choices.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from "react";
import { Choice } from "../Model/Choice";


function Choices({ choices }) {
return (
Expand Down
3 changes: 2 additions & 1 deletion trivia-forge/frontend/src/Components/Questions.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ function Questions({ data }) {
<textarea className="form-control" defaultValue={data.hint}></textarea>
</div>
</Card>
</div>

</div >
)
}
export default Questions;
5 changes: 3 additions & 2 deletions trivia-forge/frontend/src/Model/Game.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
export class Game {
constructor(name, date, userID = null) {
constructor(name, theme, userID = null) {
this.id = null;
this.name = name;
this.theme = theme;
this.categories = [];
this.userID = userID;
}
Expand All @@ -12,8 +13,8 @@ export class Game {

toJsonObject() {
return {
id: this.id,
name: this.name,
theme: this.theme,
userID: this.userID
}
}
Expand Down
208 changes: 141 additions & 67 deletions trivia-forge/frontend/src/Pages/TriviaGenPage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { useNavigate } from "react-router-dom";
import { Question } from "../Model/Question";
import { Choice } from "../Model/Choice";
import { Category } from "../Model/Category";
import { Card } from "react-bootstrap";


// initialize openai client using configuration specified in vite environment variables
Expand All @@ -18,41 +19,71 @@ function TriviaGenPage() {
// state hooks for managaing number of questions and catergory input by user
const [numberOfQuestions, setNumberOfQuestions] = useState('');
const [category, setCategory] = useState('');
const [isMultipleChoice, setIsMultipleChoice] = useState(false);
const [Title, setTitle] = useState('');
const [Theme, setTheme] = useState('');
const [categories, setCategories] = useState([]);
const [isMultipleChoice, setIsMultipleChoice] = useState(true);
const navigate = useNavigate();

const handleAddCategory = () => {
const newCategory = { name: '' };
setCategories([...categories, newCategory]);
};

const handleChangeCategoryDetail = (index, field, value) => {
const newCategories = categories.map((category, idx) => {
if (idx === index) {
return { ...category, [field]: value };
}
return category;
});
setCategories(newCategories);
};

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 be in the format Question:...\nChoice:...\nChoice:...\nChoice:...\nChoice:...\nAnswer:...\nHint:...\n---\nQuestion:... ect. include four multiple-choice options";
} else {
prompt += "Each question should be in the format \nQuestion:...\nAnswer:...\n---\nQuestion:... ect.";

let responses = []

for (let i = 0; i < categories.length; i++) {
let prompt = `Generate ${numberOfQuestions} trivia questions that have an overall theme of ${Theme} about ${categories[i].name}.`;
if (isMultipleChoice) {
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 be in the format \nQuestion:...\nAnswer:...\n---\nQuestion:... ect.";
}

// api call
try {

// API call to OpenAI
const completion = await openai.chat.completions.create({
model: "gpt-3.5-turbo",
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
});
let response = completion.choices[0].message.content.split('\n');

responses.push(response);
}
catch (error) {
console.error('Error calling OpenAI API:', error);
}
}
//create a new game and category object and add category to game
let game = new Game(Title, Theme);

// api call
try {

// API call to OpenAI
const completion = await openai.chat.completions.create({
model: "gpt-3.5-turbo",
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
});
//create a new game and category object and add category to game
let game = new Game();
let newCategory = new Category(category);
for (let i = 0; i < categories.length; i++) {
let newCategory = new Category(categories[i].name);
console.log(newCategory.name);
game.addCategory(newCategory);

//parse response from API
let sections = completion.choices[0].message.content.split('\n'); // store trivia questions
let sections = responses[i]; // store trivia questions
for (let i = 0; i < sections.length; i++) {
if (sections[i] === '') { sections.splice(i, 1); }
}
Expand All @@ -76,15 +107,15 @@ function TriviaGenPage() {
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: { game } });
//console.log(completion.choices[0].message);
} catch (error) {
console.error('Error calling OpenAI API:', error);
}
// state property to pass data as object to new route
navigate('/review', { state: { game } });
//console.log(completion.choices[0].message);


};

// render component as a form
Expand All @@ -93,43 +124,86 @@ function TriviaGenPage() {
<h1>
Trivia Generator
</h1>
<form onSubmit={handleSubmit}>
<div className="form-group">
<label htmlFor="triviaTitle">Number of Questions:</label>
<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"
/>
</div>
<div className="form-group">
<label htmlFor="triviaCategory">Category:</label>
<input
type="text"
value={category}
onChange={e => setCategory(e.target.value)}
className="form-control"
id="triviaCategory"
placeholder="Category"
/>
</div>
<div className="form-group">
<label htmlFor="multipleChoice">Include Multiple Choice Answers:</label>
<input
type="checkbox"
checked={isMultipleChoice}
onChange={e => setIsMultipleChoice(e.target.value)}
//className="form-control"
id="multipleChoice"
/>
</div>
<button type="submit" className="btn btn-primary">Generate</button>
</form>

</div>
<Card>
<form onSubmit={handleSubmit}>
<div className="form-group">
<label htmlFor="triviaTitle">Title:</label>
<input
type="text"
value={Title}
onChange={e => setTitle(e.target.value)}
className="form-control"
id="triviaTitle"
placeholder="Title"
/>
</div>

<div className="form-group">
<label htmlFor="triviaTitle">Theme:</label>
<input
type="text"
value={Theme}
onChange={e => setTheme(e.target.value)}
className="form-control"
id="triviaTheme"
placeholder="Theme"
/>
</div>

<div className="form-group">
<label htmlFor="triviaTitle">Number of Questions per Category:</label>
<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"
/>
</div>

<div className="form-group">

{categories.map((category, index) => (
<Card key={index} className="CardPadding">
<div >
<label>Category Name:</label>
<input
type="text"
value={category.name}
onChange={e => handleChangeCategoryDetail(index, 'name', e.target.value)}
className="form-control"
id="categoryName"
placeholder="Category"
/>

<br />
</div>
</Card>

))}

</div>
<button type="button" className="btn btn-secondary" onClick={handleAddCategory}>Add Category</button>



<div className="form-group">
<label htmlFor="multipleChoice">Include Multiple Choice Answers:</label>
<input
type="checkbox"
checked={isMultipleChoice}
onChange={e => setIsMultipleChoice(e.target.value)}
//className="form-control"
id="multipleChoice"
/>
</div>

<button type="submit" className="btn btn-primary">Generate</button>
</form >
</Card >

</div >
);

}
Expand Down
9 changes: 4 additions & 5 deletions trivia-forge/frontend/src/Pages/TriviaReviewPage.jsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
import React from 'react';
import { useLocation } from 'react-router-dom'; // used to access passed state
import Questions from '../Components/Questions';
import Categories from '../Components/Categories';
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 { game } = location.state;
let category = game.categories[0];
let questions = category.questions;
let categories = game.categories;
return (
<div>
<h1>Review and Edit Trivia Questions</h1>

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

))}
<Button variant="primary" size="lg" block>
Expand Down

0 comments on commit 546fdf4

Please sign in to comment.