Spaces:
Runtime error
Runtime error
added from github repo, branch ~peter, added chatbot
Browse files- Home.py +169 -0
- README.md +3 -3
- module/__custom__.py +157 -23
- module/__selectpage__.py +5 -10
- Overall.py β pages/01 Overall.py +0 -0
- pages/{01 Category.py β 02 Category.py} +3 -1
- pages/03 DLC_Counts.py +4 -1
- pages/{02 Genre.py β 04 Genre.py} +11 -1
- pages/{04 Price.py β 05 Price.py} +3 -1
- pages/{05 Age_Restriction.py β 06 Age_Restriction.py} +5 -2
- pages/{06 Settings.py β 07 Settings.py} +9 -1
- pages/{07 OS.py β 08 OS.py} +11 -1
- pages/{08 Publisher.py β 09 Publisher.py} +3 -1
- pages/{09 Developer.py β 10 Developer.py} +3 -1
Home.py
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import streamlit as st
|
| 2 |
+
import os
|
| 3 |
+
import random
|
| 4 |
+
import time
|
| 5 |
+
from module.__custom__ import *
|
| 6 |
+
from streamlit_extras.switch_page_button import switch_page
|
| 7 |
+
|
| 8 |
+
# Openai API Key
|
| 9 |
+
import openai
|
| 10 |
+
import json
|
| 11 |
+
def read_api_key_from_secrets(file_path='secrets.json'):
|
| 12 |
+
try:
|
| 13 |
+
with open(file_path, 'r') as secrets_file:
|
| 14 |
+
secrets_data = json.load(secrets_file)
|
| 15 |
+
openai_api_key = secrets_data.get('openai_api_key')
|
| 16 |
+
|
| 17 |
+
if openai_api_key is not None:
|
| 18 |
+
return openai_api_key
|
| 19 |
+
else:
|
| 20 |
+
raise KeyError("'openai_api_key' not found in secrets.json")
|
| 21 |
+
except FileNotFoundError:
|
| 22 |
+
raise FileNotFoundError(f"The file {file_path} was not found.")
|
| 23 |
+
except json.JSONDecodeError:
|
| 24 |
+
raise ValueError(f"Error decoding JSON in {file_path}. Please check the file format.")
|
| 25 |
+
|
| 26 |
+
# Example usage
|
| 27 |
+
try:
|
| 28 |
+
key = read_api_key_from_secrets()
|
| 29 |
+
openai.api_key = key
|
| 30 |
+
os.environ['OPENAI_API_KEY'] = key
|
| 31 |
+
print(f"OpenAI API Key Found")
|
| 32 |
+
except (FileNotFoundError, ValueError, KeyError) as e:
|
| 33 |
+
print(f"Error: {e}")
|
| 34 |
+
|
| 35 |
+
from langchain.vectorstores import Chroma
|
| 36 |
+
from langchain.embeddings.openai import OpenAIEmbeddings
|
| 37 |
+
from langchain.chains.query_constructor.base import AttributeInfo
|
| 38 |
+
from langchain.retrievers.self_query.base import SelfQueryRetriever
|
| 39 |
+
embedding = OpenAIEmbeddings()
|
| 40 |
+
# from langchain.embeddings.sentence_transformer import SentenceTransformerEmbeddings
|
| 41 |
+
# embedding = SentenceTransformerEmbeddings(model_name="all-MiniLM-L6-v2")
|
| 42 |
+
|
| 43 |
+
# LLM
|
| 44 |
+
from langchain.chat_models import ChatOpenAI
|
| 45 |
+
llm_name = "gpt-3.5-turbo"
|
| 46 |
+
llm = ChatOpenAI(model_name=llm_name, temperature=0)
|
| 47 |
+
|
| 48 |
+
# load from disk
|
| 49 |
+
db_cos = Chroma(
|
| 50 |
+
persist_directory="./data/docs/chroma_cos",
|
| 51 |
+
embedding_function=embedding
|
| 52 |
+
)
|
| 53 |
+
db_plot = Chroma(
|
| 54 |
+
persist_directory="./data/docs/chroma_plot",
|
| 55 |
+
embedding_function=embedding
|
| 56 |
+
)
|
| 57 |
+
|
| 58 |
+
metadata_field_info = [
|
| 59 |
+
AttributeInfo(
|
| 60 |
+
name="name",
|
| 61 |
+
description="The name of the video game on steam",
|
| 62 |
+
type="string",
|
| 63 |
+
)
|
| 64 |
+
]
|
| 65 |
+
document_content_description = "Brief summary of a video game on Steam"
|
| 66 |
+
|
| 67 |
+
|
| 68 |
+
with st.sidebar: is_plot = st.toggle('Enable Plot')
|
| 69 |
+
db_selected = db_cos
|
| 70 |
+
if is_plot: db_selected = db_plot
|
| 71 |
+
|
| 72 |
+
|
| 73 |
+
retriever = SelfQueryRetriever.from_llm(
|
| 74 |
+
llm,
|
| 75 |
+
db_selected,
|
| 76 |
+
document_content_description,
|
| 77 |
+
metadata_field_info,
|
| 78 |
+
enable_limit=True,
|
| 79 |
+
)
|
| 80 |
+
|
| 81 |
+
emoji = 'πΉοΈ GameInsightify'
|
| 82 |
+
st.header(emoji)
|
| 83 |
+
|
| 84 |
+
# Initialize chat history
|
| 85 |
+
if "messages" not in st.session_state:
|
| 86 |
+
st.session_state.messages = []
|
| 87 |
+
if 'gamenames' not in st.session_state:
|
| 88 |
+
st.session_state.gamenames = []
|
| 89 |
+
|
| 90 |
+
# Slider on range and button to clear chat history
|
| 91 |
+
col1, col2= st.columns([8,2])
|
| 92 |
+
with col1:
|
| 93 |
+
st.title("Game Recommender")
|
| 94 |
+
with col2:
|
| 95 |
+
if st.button("Clear chat"):
|
| 96 |
+
st.session_state.messages = []
|
| 97 |
+
st.session_state.gamenames = []
|
| 98 |
+
|
| 99 |
+
|
| 100 |
+
# Display chat messages from history on app rerun
|
| 101 |
+
tab1, tab2= st.tabs(['Chatbot', ' '])
|
| 102 |
+
with tab1: # this tab exist becasue i have to limit the height of chatbot
|
| 103 |
+
for message in st.session_state.messages:
|
| 104 |
+
with st.chat_message(message["role"]):
|
| 105 |
+
st.markdown(message["content"])
|
| 106 |
+
with tab2: pass # this tab exist becasue i have to limit the height of chatbot
|
| 107 |
+
|
| 108 |
+
|
| 109 |
+
# Accept user input
|
| 110 |
+
if prompt := st.chat_input("Need a game recommendation?"):
|
| 111 |
+
st.session_state.messages.append({"role": "user", "content": prompt}) # Add user message to chat history
|
| 112 |
+
with st.chat_message("user"): # Display user message in chat message container
|
| 113 |
+
st.markdown(prompt)
|
| 114 |
+
|
| 115 |
+
|
| 116 |
+
with st.chat_message("assistant"): # Display assistant response in chat message container
|
| 117 |
+
message_placeholder = st.empty()
|
| 118 |
+
|
| 119 |
+
# docs = db.max_marginal_relevance_search(prompt,k=query_num, fetch_k=10) # Sending query to db
|
| 120 |
+
docs = retriever.invoke(prompt) # retrieve response from chatgpt
|
| 121 |
+
full_response = random.choice( # 1st sentence of response
|
| 122 |
+
["I recommend the following games:\n",
|
| 123 |
+
f"Hi, human! These are the {len(docs)} best games:\n",
|
| 124 |
+
f"I bet you will love these {len(docs)} games:\n",]
|
| 125 |
+
)
|
| 126 |
+
|
| 127 |
+
# formatting response from db
|
| 128 |
+
top_games = []
|
| 129 |
+
assistant_response = ""
|
| 130 |
+
for idx, doc in enumerate(docs):
|
| 131 |
+
gamename = doc.metadata['name']
|
| 132 |
+
top_games.append(gamename)
|
| 133 |
+
assistant_response += f"{idx+1}. {gamename}\n"
|
| 134 |
+
|
| 135 |
+
# separating response into chunk of words
|
| 136 |
+
chunks = []
|
| 137 |
+
for line in assistant_response.splitlines():
|
| 138 |
+
for word in line.split() : chunks.append(word)
|
| 139 |
+
chunks.append('\n')
|
| 140 |
+
chunks = chunks[0:-1]
|
| 141 |
+
|
| 142 |
+
# Simulate stream of response with milliseconds delay
|
| 143 |
+
for chunk in chunks:
|
| 144 |
+
full_response += chunk + " "
|
| 145 |
+
time.sleep(0.05)
|
| 146 |
+
message_placeholder.markdown(full_response + "β") # Add a blinking cursor to simulate typing
|
| 147 |
+
message_placeholder.markdown(full_response)
|
| 148 |
+
|
| 149 |
+
# Add assistant response to chat history
|
| 150 |
+
st.session_state.messages.append({"role": "assistant", "content": full_response})
|
| 151 |
+
if is_plot: st.session_state.gamenames.append(top_games)
|
| 152 |
+
|
| 153 |
+
col1, col2, col3= st.columns([4,2,4])
|
| 154 |
+
with col2:
|
| 155 |
+
if is_plot and db_selected==db_plot:
|
| 156 |
+
if st.button("Plot Games"): # button in center column
|
| 157 |
+
switch_page('Overall')
|
| 158 |
+
|
| 159 |
+
|
| 160 |
+
# Styling on Tabs
|
| 161 |
+
css=f'''
|
| 162 |
+
div.stTabs {{
|
| 163 |
+
height: 40vh;
|
| 164 |
+
overflow-y: scroll;
|
| 165 |
+
overflow-x: hidden;
|
| 166 |
+
}}
|
| 167 |
+
</style>
|
| 168 |
+
'''
|
| 169 |
+
st.markdown(f'<style>{css}</style>', unsafe_allow_html=True)
|
README.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
| 1 |
---
|
| 2 |
title: Streamlit
|
| 3 |
-
emoji:
|
| 4 |
-
colorFrom:
|
| 5 |
colorTo: green
|
| 6 |
sdk: streamlit
|
| 7 |
sdk_version: 1.27.0
|
| 8 |
-
app_file:
|
| 9 |
pinned: false
|
| 10 |
---
|
|
|
|
| 1 |
---
|
| 2 |
title: Streamlit
|
| 3 |
+
emoji: πΉοΈ
|
| 4 |
+
colorFrom: blue
|
| 5 |
colorTo: green
|
| 6 |
sdk: streamlit
|
| 7 |
sdk_version: 1.27.0
|
| 8 |
+
app_file: Home.py
|
| 9 |
pinned: false
|
| 10 |
---
|
module/__custom__.py
CHANGED
|
@@ -39,13 +39,36 @@ def name(target):
|
|
| 39 |
# Appending favorite game selected by user to filtered list
|
| 40 |
"""use after search box
|
| 41 |
"""
|
| 42 |
-
def add_top_games(top_games,
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
|
|
|
|
|
|
|
|
|
| 47 |
return top_games
|
| 48 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 49 |
# Linear search over all gamenames
|
| 50 |
def search(target):
|
| 51 |
gamenames = df['gamename'].unique() # all unique gamenames
|
|
@@ -65,16 +88,39 @@ def searchbox():
|
|
| 65 |
)
|
| 66 |
return selected_game
|
| 67 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 68 |
|
| 69 |
########## PAGE SECTION ##########
|
| 70 |
# Datafram Section
|
| 71 |
"""Dataframe
|
| 72 |
together with Title
|
| 73 |
"""
|
| 74 |
-
def dfbox(ax_name, y_name, df_ax):
|
| 75 |
-
title = f"1.
|
| 76 |
-
st.
|
| 77 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 78 |
|
| 79 |
# plot 1 Section
|
| 80 |
"""Plot contains the top ranked games
|
|
@@ -89,10 +135,15 @@ def plot1_box(ax, y, order_name, ranges, df_ax, top_games):
|
|
| 89 |
st.subheader(title)
|
| 90 |
|
| 91 |
# Plot 1 - select box
|
| 92 |
-
|
| 93 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 94 |
options = top_games
|
| 95 |
-
|
|
|
|
| 96 |
|
| 97 |
# Plot 1
|
| 98 |
title_names = ','.join(selected_options)
|
|
@@ -178,6 +229,81 @@ def plot2_box(theme, y, genres, df_bx):
|
|
| 178 |
with tab3:
|
| 179 |
st.plotly_chart(fig_sc)
|
| 180 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 181 |
|
| 182 |
##### Execute Page #####
|
| 183 |
def exec_page(emoji, theme, page_genres):
|
|
@@ -217,7 +343,7 @@ def exec_page(emoji, theme, page_genres):
|
|
| 217 |
max = len(max)-1
|
| 218 |
ranges = st.slider(
|
| 219 |
label=f'Select range of the {order_name.lower()} games',
|
| 220 |
-
value = (1,
|
| 221 |
min_value=1, max_value=30,
|
| 222 |
# min_value=1, max_value=max,
|
| 223 |
)
|
|
@@ -225,7 +351,8 @@ def exec_page(emoji, theme, page_genres):
|
|
| 225 |
|
| 226 |
|
| 227 |
# Dataframe preview
|
| 228 |
-
|
|
|
|
| 229 |
|
| 230 |
##### PLOT 1 #####
|
| 231 |
# Plot 1 - markdown
|
|
@@ -242,7 +369,7 @@ def exec_page_home(theme):
|
|
| 242 |
st_page_selectbox(theme)
|
| 243 |
|
| 244 |
# Header
|
| 245 |
-
st.header(
|
| 246 |
st.title("Customized Plot on :blue[General Features]")
|
| 247 |
|
| 248 |
##### FILTER #####
|
|
@@ -266,14 +393,15 @@ def exec_page_home(theme):
|
|
| 266 |
max = len(max)-1
|
| 267 |
ranges = st.slider(
|
| 268 |
label=f'Select range of the {order_name.lower()} games',
|
| 269 |
-
value = (1,
|
| 270 |
min_value=1, max_value=30,
|
| 271 |
# min_value=1, max_value=max,
|
| 272 |
)
|
| 273 |
top_games = df_ax.gamename.unique()[ranges[0]-1:ranges[1]]
|
| 274 |
|
| 275 |
# Dataframe preview
|
| 276 |
-
|
|
|
|
| 277 |
|
| 278 |
|
| 279 |
##### PLOT 1 #####
|
|
@@ -284,10 +412,15 @@ def exec_page_home(theme):
|
|
| 284 |
|
| 285 |
|
| 286 |
# Plot 1 - select box
|
| 287 |
-
|
| 288 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 289 |
options = top_games
|
| 290 |
-
|
|
|
|
| 291 |
|
| 292 |
# Plot 1
|
| 293 |
title_names = ','.join(selected_options)
|
|
@@ -359,11 +492,12 @@ def exec_page_pub(emoji, theme, main_genre):
|
|
| 359 |
top_games = df_ax.gamename.unique()[ranges[0]-1:ranges[1]]
|
| 360 |
|
| 361 |
# Dataframe preview
|
| 362 |
-
|
|
|
|
| 363 |
|
| 364 |
-
title = f"1.2
|
| 365 |
st.subheader(title)
|
| 366 |
-
st.
|
| 367 |
|
| 368 |
|
| 369 |
|
|
|
|
| 39 |
# Appending favorite game selected by user to filtered list
|
| 40 |
"""use after search box
|
| 41 |
"""
|
| 42 |
+
def add_top_games(top_games, fav_games, ranges, df_ax):
|
| 43 |
+
ranges_last = ranges[1]
|
| 44 |
+
for fav in fav_games:
|
| 45 |
+
if fav in top_games:
|
| 46 |
+
range_last+=1
|
| 47 |
+
top_games = df_ax.gamename.unique()[ranges[0]-1:range_last]
|
| 48 |
+
elif fav!=None:
|
| 49 |
+
top_games = np.append(top_games, fav)
|
| 50 |
return top_games
|
| 51 |
|
| 52 |
+
def add_list(favorite_game, rec_games):
|
| 53 |
+
fav_games = []
|
| 54 |
+
if favorite_game[0]: fav_games = favorite_game
|
| 55 |
+
if rec_games:
|
| 56 |
+
fav_games = list(set(fav_games + rec_games))
|
| 57 |
+
return fav_games
|
| 58 |
+
|
| 59 |
+
# fav_games = []
|
| 60 |
+
# if favorite_game: fav_games = [favorite_game]
|
| 61 |
+
# if st.session_state.gamenames[-1]:
|
| 62 |
+
# rec_games = st.session_state.gamenames[-1]
|
| 63 |
+
# fav_games = list(set(fav_games + rec_games))
|
| 64 |
+
|
| 65 |
+
# def add_top_games(top_games, favorite_game, ranges, df_ax):
|
| 66 |
+
# if favorite_game in top_games:
|
| 67 |
+
# top_games = df_ax.gamename.unique()[ranges[0]-1:ranges[1]+1]
|
| 68 |
+
# elif favorite_game!=None:
|
| 69 |
+
# top_games = np.append(top_games, favorite_game)
|
| 70 |
+
# return top_games
|
| 71 |
+
|
| 72 |
# Linear search over all gamenames
|
| 73 |
def search(target):
|
| 74 |
gamenames = df['gamename'].unique() # all unique gamenames
|
|
|
|
| 88 |
)
|
| 89 |
return selected_game
|
| 90 |
|
| 91 |
+
# Overloaded with target name
|
| 92 |
+
def searchbox(target):
|
| 93 |
+
col1, col2= st.columns([1,1])
|
| 94 |
+
with col1:
|
| 95 |
+
selected_game = st_searchbox(
|
| 96 |
+
search_function=search,
|
| 97 |
+
key="gamename_searchbox",
|
| 98 |
+
default_options=target,
|
| 99 |
+
placeholder="Compare with your Favorite Game...",
|
| 100 |
+
)
|
| 101 |
+
return selected_game
|
| 102 |
|
| 103 |
########## PAGE SECTION ##########
|
| 104 |
# Datafram Section
|
| 105 |
"""Dataframe
|
| 106 |
together with Title
|
| 107 |
"""
|
| 108 |
+
def dfbox(ax_name, y_name, df_ax, ranges, order_name):
|
| 109 |
+
title = f"1.2 :blue[{ax_name}] Games with the {order_name} :blue[{y_name}]:"
|
| 110 |
+
with st.sidebar:
|
| 111 |
+
gamenames = df_ax.gamename.unique()
|
| 112 |
+
df_names = pd.DataFrame(gamenames, columns=['gamename'])
|
| 113 |
+
st.write(title)
|
| 114 |
+
st.dataframe(df_names[ranges[0]:ranges[1]+1])
|
| 115 |
+
|
| 116 |
+
def rec_dfbox():
|
| 117 |
+
title = f"1.1 :blue[Recommended] by :green[GameInsightify]"
|
| 118 |
+
if len(st.session_state.gamenames) > 0:
|
| 119 |
+
with st.sidebar:
|
| 120 |
+
rec_games = st.session_state.gamenames[-1]
|
| 121 |
+
df_names = pd.DataFrame(rec_games, columns=['gamename'])
|
| 122 |
+
st.write(title)
|
| 123 |
+
st.dataframe(df_names[0:len(rec_games)])
|
| 124 |
|
| 125 |
# plot 1 Section
|
| 126 |
"""Plot contains the top ranked games
|
|
|
|
| 135 |
st.subheader(title)
|
| 136 |
|
| 137 |
# Plot 1 - select box
|
| 138 |
+
rec_games = []
|
| 139 |
+
if len(st.session_state.gamenames) > 0 : rec_games = st.session_state.gamenames[-1]
|
| 140 |
+
favorite_game = searchbox(None) # search box to add a user favorite game on Plot 1
|
| 141 |
+
fav_games = add_list([favorite_game], rec_games)
|
| 142 |
+
fav_options = st.multiselect('Select Recommended Games', fav_games)
|
| 143 |
+
|
| 144 |
options = top_games
|
| 145 |
+
selected_tops = st.multiselect('Select Video Games', options)
|
| 146 |
+
selected_options = add_top_games(selected_tops, fav_options, ranges, df_ax)
|
| 147 |
|
| 148 |
# Plot 1
|
| 149 |
title_names = ','.join(selected_options)
|
|
|
|
| 229 |
with tab3:
|
| 230 |
st.plotly_chart(fig_sc)
|
| 231 |
|
| 232 |
+
# Plot 3 - Pie chart
|
| 233 |
+
import plotly.express as px
|
| 234 |
+
def plot3_box(theme, labels):
|
| 235 |
+
title = f"2.1 Ratio of Games Among :blue[{theme}]"
|
| 236 |
+
st.subheader(title)
|
| 237 |
+
|
| 238 |
+
if (type(labels)==str):
|
| 239 |
+
values = []
|
| 240 |
+
index = df[labels].unique().tolist()
|
| 241 |
+
for idx, value in enumerate(index):
|
| 242 |
+
count = len(df[df[labels] == value])
|
| 243 |
+
values.append(count)
|
| 244 |
+
if(count/len(df) < 0.02): index[idx] = 'Other'
|
| 245 |
+
|
| 246 |
+
df_p = pd.DataFrame(data = values,
|
| 247 |
+
index = index,
|
| 248 |
+
columns = ['counts'])
|
| 249 |
+
df_p = df_p.reset_index().rename(columns={'index':labels})
|
| 250 |
+
fig_ratio = px.pie(df_p, values='counts', names=labels)
|
| 251 |
+
st.plotly_chart(fig_ratio)
|
| 252 |
+
|
| 253 |
+
else:
|
| 254 |
+
values = []
|
| 255 |
+
for label in labels:
|
| 256 |
+
value = len(df[df[label]==1])
|
| 257 |
+
values.append(value)
|
| 258 |
+
|
| 259 |
+
fig_ratio = go.Figure(data=[go.Pie(labels=labels, values=values)])
|
| 260 |
+
st.plotly_chart(fig_ratio)
|
| 261 |
+
|
| 262 |
+
# Could not overload function, so renamed it
|
| 263 |
+
def plot3_box_limit(theme, labels, limit_perc):
|
| 264 |
+
title = f"2.1 Ratio of Games Among :blue[{theme}] over :blue[{limit_perc*100}%]"
|
| 265 |
+
st.subheader(title)
|
| 266 |
+
|
| 267 |
+
values = []
|
| 268 |
+
index = df[labels].unique().tolist()
|
| 269 |
+
for idx, value in enumerate(index):
|
| 270 |
+
count = len(df[df[labels] == value])
|
| 271 |
+
values.append(count)
|
| 272 |
+
if(count/len(df) < limit_perc): index[idx] = 'Other'
|
| 273 |
+
|
| 274 |
+
df_p = pd.DataFrame(data = values,
|
| 275 |
+
index = index,
|
| 276 |
+
columns = ['counts'])
|
| 277 |
+
df_p = df_p.reset_index().rename(columns={'index':labels})
|
| 278 |
+
fig_ratio = px.pie(df_p, values='counts', names=labels)
|
| 279 |
+
st.plotly_chart(fig_ratio)
|
| 280 |
+
|
| 281 |
+
def plot_chat_box(y, query_num, top_games):
|
| 282 |
+
y_name = name(y) # formeting strings
|
| 283 |
+
|
| 284 |
+
title = f"1.2 Comparison on The {query_num} Best Recommended Games on :blue[{y_name}]"
|
| 285 |
+
st.subheader(title)
|
| 286 |
+
|
| 287 |
+
# Plot 1 - select box # search box to add a user favorite game on Plot 1
|
| 288 |
+
options = top_games
|
| 289 |
+
selected_options = st.multiselect('Select Video Games', options)
|
| 290 |
+
|
| 291 |
+
# Plot 1
|
| 292 |
+
title_names = ','.join(selected_options)
|
| 293 |
+
plot_title = f"Monthly {y_name} of {title_names} Over Time"
|
| 294 |
+
gb = df.sort_values(by='date')
|
| 295 |
+
gb_list = {game: gb[gb["gamename"] == game] for game in selected_options}
|
| 296 |
+
|
| 297 |
+
fig_1 = go.Figure()
|
| 298 |
+
fig_1.update_layout(
|
| 299 |
+
title = plot_title,
|
| 300 |
+
xaxis_title = 'Date',
|
| 301 |
+
yaxis_title = y_name,
|
| 302 |
+
)
|
| 303 |
+
for game, gb in gb_list.items():
|
| 304 |
+
fig_1 = fig_1.add_trace(go.Scatter(x=gb["date"], y=gb[y], name=game, mode='lines'))
|
| 305 |
+
st.plotly_chart(fig_1)
|
| 306 |
+
|
| 307 |
|
| 308 |
##### Execute Page #####
|
| 309 |
def exec_page(emoji, theme, page_genres):
|
|
|
|
| 343 |
max = len(max)-1
|
| 344 |
ranges = st.slider(
|
| 345 |
label=f'Select range of the {order_name.lower()} games',
|
| 346 |
+
value = (1, 3),
|
| 347 |
min_value=1, max_value=30,
|
| 348 |
# min_value=1, max_value=max,
|
| 349 |
)
|
|
|
|
| 351 |
|
| 352 |
|
| 353 |
# Dataframe preview
|
| 354 |
+
rec_dfbox()
|
| 355 |
+
dfbox(ax_name, y_name, df_ax, ranges, order_name)
|
| 356 |
|
| 357 |
##### PLOT 1 #####
|
| 358 |
# Plot 1 - markdown
|
|
|
|
| 369 |
st_page_selectbox(theme)
|
| 370 |
|
| 371 |
# Header
|
| 372 |
+
st.header("π")
|
| 373 |
st.title("Customized Plot on :blue[General Features]")
|
| 374 |
|
| 375 |
##### FILTER #####
|
|
|
|
| 393 |
max = len(max)-1
|
| 394 |
ranges = st.slider(
|
| 395 |
label=f'Select range of the {order_name.lower()} games',
|
| 396 |
+
value = (1, 3),
|
| 397 |
min_value=1, max_value=30,
|
| 398 |
# min_value=1, max_value=max,
|
| 399 |
)
|
| 400 |
top_games = df_ax.gamename.unique()[ranges[0]-1:ranges[1]]
|
| 401 |
|
| 402 |
# Dataframe preview
|
| 403 |
+
rec_dfbox()
|
| 404 |
+
dfbox("", y_name, df_ax, ranges, order_name)
|
| 405 |
|
| 406 |
|
| 407 |
##### PLOT 1 #####
|
|
|
|
| 412 |
|
| 413 |
|
| 414 |
# Plot 1 - select box
|
| 415 |
+
rec_games = []
|
| 416 |
+
if len(st.session_state.gamenames)>0: rec_games = st.session_state.gamenames[-1]
|
| 417 |
+
favorite_game = searchbox(None) # search box to add a user favorite game on Plot 1
|
| 418 |
+
fav_games = add_list([favorite_game], rec_games)
|
| 419 |
+
fav_options = st.multiselect('Select Recommended Games', fav_games)
|
| 420 |
+
|
| 421 |
options = top_games
|
| 422 |
+
selected_tops = st.multiselect('Select Video Games', options)
|
| 423 |
+
selected_options = add_top_games(selected_tops, fav_options, ranges, df_ax)
|
| 424 |
|
| 425 |
# Plot 1
|
| 426 |
title_names = ','.join(selected_options)
|
|
|
|
| 492 |
top_games = df_ax.gamename.unique()[ranges[0]-1:ranges[1]]
|
| 493 |
|
| 494 |
# Dataframe preview
|
| 495 |
+
rec_dfbox()
|
| 496 |
+
dfbox(ax_name, y_name, df_ax, ranges, order_name)
|
| 497 |
|
| 498 |
+
title = f"1.2 5 :blue[{theme}s] with the :red[{order_name}] Monthly :blue[{y_name}]:"
|
| 499 |
st.subheader(title)
|
| 500 |
+
st.dataframe(genres[0:5])
|
| 501 |
|
| 502 |
|
| 503 |
|
module/__selectpage__.py
CHANGED
|
@@ -2,18 +2,13 @@ import streamlit as st
|
|
| 2 |
from streamlit_extras.switch_page_button import switch_page
|
| 3 |
import os
|
| 4 |
|
| 5 |
-
|
| 6 |
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
|
| 12 |
-
pages = [
|
| 13 |
-
"Overall",
|
| 14 |
-
"Category", "Genre", "DLC Counts", "Price", "Age Restriction",
|
| 15 |
-
"Settings", "OS", "Publisher", "Developer",
|
| 16 |
-
]
|
| 17 |
|
| 18 |
def st_page_selectbox(current_page):
|
| 19 |
current_index = pages.index(current_page)
|
|
|
|
| 2 |
from streamlit_extras.switch_page_button import switch_page
|
| 3 |
import os
|
| 4 |
|
| 5 |
+
pages = ["Overall"]
|
| 6 |
|
| 7 |
+
files = os.listdir('.\pages')
|
| 8 |
+
for name in files:
|
| 9 |
+
name = name.split()[1].replace('.py', '').replace('_', ' ')
|
| 10 |
+
pages.append(name)
|
| 11 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 12 |
|
| 13 |
def st_page_selectbox(current_page):
|
| 14 |
current_index = pages.index(current_page)
|
Overall.py β pages/01 Overall.py
RENAMED
|
File without changes
|
pages/{01 Category.py β 02 Category.py}
RENAMED
|
@@ -5,6 +5,8 @@ from module.__custom__ import *
|
|
| 5 |
theme = "Category"
|
| 6 |
page_genres = ['multi_player', 'pvp', 'co-op', 'single_player']
|
| 7 |
add_genre = ['single_player', 'multi_player']
|
|
|
|
| 8 |
|
| 9 |
add_opp_features(add_genre)
|
| 10 |
-
exec_page('π€Ό', theme, page_genres)
|
|
|
|
|
|
| 5 |
theme = "Category"
|
| 6 |
page_genres = ['multi_player', 'pvp', 'co-op', 'single_player']
|
| 7 |
add_genre = ['single_player', 'multi_player']
|
| 8 |
+
labels = ['pvp', 'co-op', 'single_player']
|
| 9 |
|
| 10 |
add_opp_features(add_genre)
|
| 11 |
+
exec_page('π€Ό', theme, page_genres)
|
| 12 |
+
plot3_box(theme, labels)
|
pages/03 DLC_Counts.py
CHANGED
|
@@ -11,8 +11,11 @@ add_genres = [[0, 1, 'dlc_0', 'dlc_count'],
|
|
| 11 |
[41, 101, 'dlc_100', 'dlc_count'],
|
| 12 |
[101, 301, 'dlc_300', 'dlc_count'],
|
| 13 |
[301, 9999, 'dlc_most', 'dlc_count']]
|
|
|
|
|
|
|
| 14 |
|
| 15 |
# ### adding single-player feature ###
|
| 16 |
for add in add_genres:
|
| 17 |
add_range_features(add)
|
| 18 |
-
exec_page('πͺ', theme, page_genres)
|
|
|
|
|
|
| 11 |
[41, 101, 'dlc_100', 'dlc_count'],
|
| 12 |
[101, 301, 'dlc_300', 'dlc_count'],
|
| 13 |
[301, 9999, 'dlc_most', 'dlc_count']]
|
| 14 |
+
labels = 'dlc_count'
|
| 15 |
+
|
| 16 |
|
| 17 |
# ### adding single-player feature ###
|
| 18 |
for add in add_genres:
|
| 19 |
add_range_features(add)
|
| 20 |
+
exec_page('πͺ', theme, page_genres)
|
| 21 |
+
plot3_box(theme, labels)
|
pages/{02 Genre.py β 04 Genre.py}
RENAMED
|
@@ -7,6 +7,16 @@ page_genres = ['genre_action', 'genre_adventure', 'genre_casual',
|
|
| 7 |
'genre_sexual_content', 'genre_strategy', 'genre_sports',
|
| 8 |
'genre_racing', 'genre_rpg', 'genre_simulation', 'indie', 'mainstream']
|
| 9 |
add_genre = ['mainstream', 'indie']
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10 |
|
| 11 |
add_opp_features(add_genre)
|
| 12 |
-
exec_page('π¦ΉββοΈ', theme, page_genres)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7 |
'genre_sexual_content', 'genre_strategy', 'genre_sports',
|
| 8 |
'genre_racing', 'genre_rpg', 'genre_simulation', 'indie', 'mainstream']
|
| 9 |
add_genre = ['mainstream', 'indie']
|
| 10 |
+
labels = ['genre_action', 'genre_adventure', 'genre_casual',
|
| 11 |
+
'genre_sexual_content', 'genre_strategy', 'genre_sports',
|
| 12 |
+
'genre_racing', 'genre_rpg', 'genre_simulation']
|
| 13 |
+
labels_2 = add_genre
|
| 14 |
|
| 15 |
add_opp_features(add_genre)
|
| 16 |
+
exec_page('π¦ΉββοΈ', theme, page_genres)
|
| 17 |
+
|
| 18 |
+
tab1, tab2= st.tabs(['Genre ratio', 'Indie versus mainstream ratio'])
|
| 19 |
+
with tab1:
|
| 20 |
+
plot3_box(theme, labels)
|
| 21 |
+
with tab2:
|
| 22 |
+
plot3_box(theme, labels_2)
|
pages/{04 Price.py β 05 Price.py}
RENAMED
|
@@ -12,8 +12,10 @@ add_genres = [[0, 0.001, 'price_free', 'price'],
|
|
| 12 |
[20.001, 40.001, 'price_40', 'price'],
|
| 13 |
[40.001, 60.001, 'price_60', 'price'],
|
| 14 |
[60.001, 9999, 'price_most', 'price']]
|
|
|
|
| 15 |
|
| 16 |
# ### adding single-player feature ###
|
| 17 |
for add in add_genres:
|
| 18 |
add_range_features(add)
|
| 19 |
-
exec_page('πΈ', theme, page_genres)
|
|
|
|
|
|
| 12 |
[20.001, 40.001, 'price_40', 'price'],
|
| 13 |
[40.001, 60.001, 'price_60', 'price'],
|
| 14 |
[60.001, 9999, 'price_most', 'price']]
|
| 15 |
+
labels = 'price'
|
| 16 |
|
| 17 |
# ### adding single-player feature ###
|
| 18 |
for add in add_genres:
|
| 19 |
add_range_features(add)
|
| 20 |
+
exec_page('πΈ', theme, page_genres)
|
| 21 |
+
plot3_box(theme, labels)
|
pages/{05 Age_Restriction.py β 06 Age_Restriction.py}
RENAMED
|
@@ -1,7 +1,10 @@
|
|
| 1 |
import streamlit as st
|
| 2 |
|
| 3 |
-
from module.__custom__ import
|
| 4 |
|
| 5 |
theme = "Age Restriction"
|
| 6 |
page_genres = ['age_0_plus', 'age_13_plus', 'age_18_plus']
|
| 7 |
-
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
import streamlit as st
|
| 2 |
|
| 3 |
+
from module.__custom__ import *
|
| 4 |
|
| 5 |
theme = "Age Restriction"
|
| 6 |
page_genres = ['age_0_plus', 'age_13_plus', 'age_18_plus']
|
| 7 |
+
labels = page_genres
|
| 8 |
+
|
| 9 |
+
exec_page('π΄', theme, page_genres)
|
| 10 |
+
plot3_box(theme, labels)
|
pages/{06 Settings.py β 07 Settings.py}
RENAMED
|
@@ -5,8 +5,16 @@ from module.__custom__ import *
|
|
| 5 |
theme = "Settings"
|
| 6 |
page_genres = ['full_audio', 'full_controller_support', 'not_full_audio', 'not_full_controller']
|
| 7 |
add_genres = [['not_full_audio', 'full_audio'], ['not_full_controller', 'full_controller_support'] ]
|
|
|
|
|
|
|
| 8 |
|
| 9 |
# ### adding single-player feature ###
|
| 10 |
for add in add_genres:
|
| 11 |
add_opp_features(add)
|
| 12 |
-
exec_page('π§', theme, page_genres)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5 |
theme = "Settings"
|
| 6 |
page_genres = ['full_audio', 'full_controller_support', 'not_full_audio', 'not_full_controller']
|
| 7 |
add_genres = [['not_full_audio', 'full_audio'], ['not_full_controller', 'full_controller_support'] ]
|
| 8 |
+
labels = ['not_full_controller', 'full_controller_support']
|
| 9 |
+
labels_2 = ['not_full_audio', 'full_audio']
|
| 10 |
|
| 11 |
# ### adding single-player feature ###
|
| 12 |
for add in add_genres:
|
| 13 |
add_opp_features(add)
|
| 14 |
+
exec_page('π§', theme, page_genres)
|
| 15 |
+
tab1, tab2= st.tabs(['Controller support ratio', 'Full audio ratio'])
|
| 16 |
+
with tab1:
|
| 17 |
+
plot3_box(theme, labels)
|
| 18 |
+
with tab2:
|
| 19 |
+
plot3_box(theme, labels_2)
|
| 20 |
+
|
pages/{07 OS.py β 08 OS.py}
RENAMED
|
@@ -5,8 +5,18 @@ from module.__custom__ import *
|
|
| 5 |
theme = "OS"
|
| 6 |
page_genres = ['windows', 'mac', 'linux', 'not_windows', 'not_mac', 'not_linux']
|
| 7 |
add_genres = [['not_windows', 'windows'], ['not_mac', 'mac'], ['not_linux', 'linux'] ]
|
|
|
|
|
|
|
|
|
|
| 8 |
|
| 9 |
# ### adding single-player feature ###
|
| 10 |
for add in add_genres:
|
| 11 |
add_opp_features(add)
|
| 12 |
-
exec_page('π₯', theme, page_genres)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5 |
theme = "OS"
|
| 6 |
page_genres = ['windows', 'mac', 'linux', 'not_windows', 'not_mac', 'not_linux']
|
| 7 |
add_genres = [['not_windows', 'windows'], ['not_mac', 'mac'], ['not_linux', 'linux'] ]
|
| 8 |
+
labels = ['not_windows', 'windows']
|
| 9 |
+
labels_2 = ['not_mac', 'mac']
|
| 10 |
+
labels_3 = ['not_linux', 'linux']
|
| 11 |
|
| 12 |
# ### adding single-player feature ###
|
| 13 |
for add in add_genres:
|
| 14 |
add_opp_features(add)
|
| 15 |
+
exec_page('π₯', theme, page_genres)
|
| 16 |
+
tab1, tab2, tab3 = st.tabs(['Windows game ratio', 'Mac game ratio', 'Linux game ratio'])
|
| 17 |
+
with tab1:
|
| 18 |
+
plot3_box(theme, labels)
|
| 19 |
+
with tab2:
|
| 20 |
+
plot3_box(theme, labels_2)
|
| 21 |
+
with tab3:
|
| 22 |
+
plot3_box(theme, labels_3)
|
pages/{08 Publisher.py β 09 Publisher.py}
RENAMED
|
@@ -4,5 +4,7 @@ from module.__custom__ import *
|
|
| 4 |
|
| 5 |
theme = "Publisher"
|
| 6 |
main_genre = "publishers"
|
|
|
|
| 7 |
|
| 8 |
-
exec_page_pub('π', theme, main_genre)
|
|
|
|
|
|
| 4 |
|
| 5 |
theme = "Publisher"
|
| 6 |
main_genre = "publishers"
|
| 7 |
+
labels = main_genre
|
| 8 |
|
| 9 |
+
exec_page_pub('π', theme, main_genre)
|
| 10 |
+
plot3_box_limit(theme, labels, 0.01)
|
pages/{09 Developer.py β 10 Developer.py}
RENAMED
|
@@ -4,5 +4,7 @@ from module.__custom__ import *
|
|
| 4 |
|
| 5 |
theme = "Developer"
|
| 6 |
main_genre = "developers"
|
|
|
|
| 7 |
|
| 8 |
-
exec_page_pub('π½', theme, main_genre)
|
|
|
|
|
|
| 4 |
|
| 5 |
theme = "Developer"
|
| 6 |
main_genre = "developers"
|
| 7 |
+
labels = main_genre
|
| 8 |
|
| 9 |
+
exec_page_pub('π½', theme, main_genre)
|
| 10 |
+
plot3_box_limit(theme, labels, 0.005)
|