Merge pull request #105 from ThomasRubini/reactions
@ -1,8 +1,10 @@
|
||||
|
||||
import argparse
|
||||
import yaml
|
||||
from dotenv import load_dotenv
|
||||
load_dotenv()
|
||||
|
||||
import sys
|
||||
import yaml
|
||||
import os
|
||||
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
from truthinquiry.ext.database.models import *
|
||||
from truthinquiry.ext.database.sa import engine
|
||||
@ -29,21 +31,20 @@ class LocaleManager():
|
||||
return self.used_lids[1:]
|
||||
|
||||
|
||||
def bulk_import(data):
|
||||
def bulk_import(data, dir):
|
||||
|
||||
# Data list that will be commited to the db
|
||||
TEXT_LIST = []
|
||||
TRAIT_LIST = []
|
||||
TRAIT_DICT = {}
|
||||
REACTION_LIST = []
|
||||
QUESTIONS_LIST = []
|
||||
ANSWER_LIST = []
|
||||
NPC_LIST = []
|
||||
NPC_DICT = {}
|
||||
ROOMS_LIST = []
|
||||
|
||||
# helper list to simplify
|
||||
trait_names = {}
|
||||
lm = LocaleManager()
|
||||
getid = lm.get_unused_lid
|
||||
reactions_img_dir = os.path.join(dir, data["reactions_img_dir"])
|
||||
|
||||
# Questions
|
||||
|
||||
@ -70,38 +71,30 @@ def bulk_import(data):
|
||||
|
||||
# Traits
|
||||
traits = data["traits"]
|
||||
for trait in traits.values():
|
||||
for trait_key, trait in traits.items():
|
||||
# create the new trait
|
||||
new_trait = Trait(0,getid(), getid())
|
||||
new_trait = Trait(None, getid(), getid())
|
||||
|
||||
for lang in trait["name"]:
|
||||
TEXT_LIST.append(Text(0,new_trait.NAME_LID,
|
||||
lang, trait["name"][lang]))
|
||||
trait_names[trait["name"][lang]] = new_trait.TRAIT_ID
|
||||
|
||||
for lang in trait["description"]:
|
||||
TEXT_LIST.append(Text(0,new_trait.DESC_LID, lang,
|
||||
trait["description"][lang]))
|
||||
|
||||
TRAIT_LIST.append(new_trait)
|
||||
TRAIT_DICT[trait_key] = new_trait
|
||||
|
||||
# Npcs
|
||||
npcs = data["npcs"]
|
||||
npcid = 1
|
||||
for npc in npcs.values():
|
||||
for npc_key, npc in npcs.items():
|
||||
new_npc = Npc(npcid, getid())
|
||||
|
||||
# handle the names
|
||||
for lang in npc["name"]:
|
||||
TEXT_LIST.append(Text(0,new_npc.NAME_LID, lang, npc["name"][lang]))
|
||||
|
||||
# TODO handle reactions
|
||||
"""
|
||||
for reaction in npc["reactions"]:
|
||||
if reaction in list(trait_names.keys()):
|
||||
new_reaction = Reaction(0,new_npc.NPC_ID, trait_names[reaction])
|
||||
REACTION_LIST.append(new_reaction) """
|
||||
|
||||
for question_type in npc["answers"]:
|
||||
question_type_id = question_type_zero.QUESTION_TYPE_ID if question_type == "where" else question_type_one.QUESTION_TYPE_ID
|
||||
|
||||
@ -113,9 +106,30 @@ def bulk_import(data):
|
||||
text = list(answer.values())[0]
|
||||
TEXT_LIST.append(Text(0,new_answer.TEXT_LID, lang, text))
|
||||
|
||||
NPC_LIST.append(new_npc)
|
||||
NPC_DICT[npc_key] = new_npc
|
||||
npcid += 1
|
||||
|
||||
# Reactions
|
||||
for npc_key in os.listdir(reactions_img_dir):
|
||||
for reaction_file in os.listdir(os.path.join(reactions_img_dir, npc_key)):
|
||||
|
||||
img_path = os.path.join(reactions_img_dir, npc_key, reaction_file)
|
||||
with open(img_path, "rb") as f:
|
||||
img_data = f.read()
|
||||
|
||||
npc = NPC_DICT[npc_key]
|
||||
trait_key = os.path.splitext(reaction_file)[0]
|
||||
if trait_key == 'default':
|
||||
npc.DEFAULT_IMG = img_data
|
||||
else:
|
||||
trait = TRAIT_DICT[trait_key]
|
||||
|
||||
new_reaction = Reaction(None, npc.NPC_ID, None)
|
||||
new_reaction.TRAIT = trait
|
||||
new_reaction.IMG = img_data
|
||||
|
||||
REACTION_LIST.append(new_reaction)
|
||||
|
||||
# rooms
|
||||
rooms = data["rooms"]
|
||||
for room in rooms.values():
|
||||
@ -126,7 +140,7 @@ def bulk_import(data):
|
||||
|
||||
for lid in lm.get_used_lids():
|
||||
print("lid :"+ str(lid))
|
||||
session.add(Locale(lid));
|
||||
session.add(Locale(lid))
|
||||
|
||||
for text in TEXT_LIST:
|
||||
print("Text : "+str(text))
|
||||
@ -138,12 +152,12 @@ def bulk_import(data):
|
||||
session.add(question)
|
||||
session.commit()
|
||||
|
||||
for trait in TRAIT_LIST:
|
||||
for trait in TRAIT_DICT.values():
|
||||
print("Trait : "+ str(trait))
|
||||
session.add(trait)
|
||||
session.commit()
|
||||
|
||||
for npc in NPC_LIST:
|
||||
for npc in NPC_DICT.values():
|
||||
print("Npc : "+ str(npc))
|
||||
session.add(npc)
|
||||
session.commit()
|
||||
@ -163,6 +177,8 @@ def bulk_import(data):
|
||||
session.add(room)
|
||||
session.commit()
|
||||
|
||||
file = open("bulk_data.yml", "r")
|
||||
|
||||
bulk_import(yaml.load(file, yaml.Loader))
|
||||
if len(sys.argv) <= 1:
|
||||
print("Please enter input file")
|
||||
else:
|
||||
path = sys.argv[1]
|
||||
bulk_import(yaml.load(open(path, "r"), yaml.Loader), os.path.dirname(path))
|
||||
|
@ -1,5 +1,7 @@
|
||||
reactions_img_dir: imgs
|
||||
|
||||
npcs:
|
||||
1:
|
||||
medecin:
|
||||
answers:
|
||||
where:
|
||||
- FR: "Il y avait {SALLE} \xE7a m'a intrigu\xE9."
|
||||
@ -9,7 +11,7 @@ npcs:
|
||||
- FR: "Je suis pratiquement s\xFBr que j'\xE9tais avec {NPC}."
|
||||
name:
|
||||
FR: "Le M\xE9decin"
|
||||
2:
|
||||
diplomate:
|
||||
answers:
|
||||
where:
|
||||
- FR: Je profitais d'une collation dans {SALLE}.
|
||||
@ -20,7 +22,7 @@ npcs:
|
||||
- FR: "Avec {NPC} pour exposer nos diff\xE9rents points de vus sur divers sujets."
|
||||
name:
|
||||
FR: Le Diplomate
|
||||
3:
|
||||
combattant:
|
||||
answers:
|
||||
where:
|
||||
- FR: '{SALLE} nous a servi de salle de duel.'
|
||||
@ -30,7 +32,7 @@ npcs:
|
||||
- FR: "{NPC} et moi nous sommes engag\xE9s dans une joute verbale des plus palpitante."
|
||||
name:
|
||||
FR: Le Combattant
|
||||
4:
|
||||
duchesse:
|
||||
answers:
|
||||
where:
|
||||
- FR: Pour votre gouverne je me trouvais dans {SALLE}.
|
||||
@ -40,7 +42,7 @@ npcs:
|
||||
- FR: "J'\xE9tais avec {NPC}."
|
||||
name:
|
||||
FR: La Duchesse
|
||||
5:
|
||||
diva:
|
||||
answers:
|
||||
where:
|
||||
- FR: "{SALLE} me semblait \xEAtre la plus belle pi\xE8ce de la maison."
|
||||
@ -51,7 +53,7 @@ npcs:
|
||||
\ qu'une coupe de champagne."
|
||||
name:
|
||||
FR: La Diva
|
||||
6:
|
||||
parieuse:
|
||||
answers:
|
||||
where:
|
||||
- FR: "J'avais mont\xE9 une table de jeu dans {SALLE}."
|
||||
@ -63,7 +65,7 @@ npcs:
|
||||
- FR: "Si vous tenez \xE0 votre argent ne jouez jamais au poker avec {NPC}."
|
||||
name:
|
||||
FR: La Parieuse
|
||||
7:
|
||||
agent:
|
||||
answers:
|
||||
where:
|
||||
- FR: On pouvait me retrouver dans {SALLE}.
|
||||
@ -73,7 +75,7 @@ npcs:
|
||||
- FR: '{NPC}'
|
||||
name:
|
||||
FR: L'Agent
|
||||
8:
|
||||
voyageuse:
|
||||
answers:
|
||||
where:
|
||||
- FR: '{SALLE} me semblait un bon endroit pour me poser'
|
||||
@ -110,7 +112,7 @@ rooms:
|
||||
6:
|
||||
FR: Le jardin
|
||||
traits:
|
||||
1:
|
||||
mefiant:
|
||||
description:
|
||||
FR: "Un maintien rigide des traits du visage, un regard de travers. Une crispation\
|
||||
\ des sourcils et parfois des rides autour de la bouche. Ces caract\xE9ristiques\
|
||||
@ -118,7 +120,7 @@ traits:
|
||||
\ la personne en face."
|
||||
name:
|
||||
FR: "m\xE9fiant(e),"
|
||||
2:
|
||||
heureux:
|
||||
description:
|
||||
FR: "Un visage d\xE9contract\xE9 et ouvert, les muscles des joues contract\xE9\
|
||||
s qui laissent appara\xEEtre un sourire. On le d\xE9termine aussi par des\
|
||||
@ -128,7 +130,7 @@ traits:
|
||||
\ para\xEEtre ses r\xE9elles \xE9motions."
|
||||
name:
|
||||
FR: heureux(se),
|
||||
3:
|
||||
triste:
|
||||
description:
|
||||
FR: "Des sourcils contract\xE9s et resserr\xE9s vers le centre du visage auxquels\
|
||||
\ s'ajoute un regard vide ou fuyant de l'interlocuteur, soit en fermant les\
|
||||
@ -137,7 +139,7 @@ traits:
|
||||
\ ou accusations de son interlocuteur."
|
||||
name:
|
||||
FR: triste
|
||||
4:
|
||||
stresse:
|
||||
description:
|
||||
FR: "Un visage crisp\xE9 qui s'accompagne habituellement de sourcils fronc\xE9\
|
||||
s, un regard perdu qui se d\xE9tourne de celui de son interlocuteur. Cela\
|
||||
@ -146,7 +148,7 @@ traits:
|
||||
\ ou une peur de ce qu'annonce ou peut nous annoncer l'interlocuteur en face."
|
||||
name:
|
||||
FR: "stress\xE9(e),"
|
||||
5:
|
||||
surpris:
|
||||
description:
|
||||
FR: "G\xE9n\xE9ralement par des yeux \xE9carquill\xE9s et un haussement des\
|
||||
\ sourcils. Cela peut \xE9galement se distinguer par une bouche ouverte ou,\
|
||||
|
Before Width: | Height: | Size: 174 KiB After Width: | Height: | Size: 174 KiB |
Before Width: | Height: | Size: 174 KiB After Width: | Height: | Size: 174 KiB |
Before Width: | Height: | Size: 176 KiB After Width: | Height: | Size: 176 KiB |
Before Width: | Height: | Size: 176 KiB After Width: | Height: | Size: 176 KiB |
Before Width: | Height: | Size: 177 KiB After Width: | Height: | Size: 177 KiB |
Before Width: | Height: | Size: 179 KiB After Width: | Height: | Size: 179 KiB |
Before Width: | Height: | Size: 147 KiB After Width: | Height: | Size: 147 KiB |
Before Width: | Height: | Size: 141 KiB After Width: | Height: | Size: 141 KiB |
Before Width: | Height: | Size: 143 KiB After Width: | Height: | Size: 143 KiB |
Before Width: | Height: | Size: 147 KiB After Width: | Height: | Size: 147 KiB |
Before Width: | Height: | Size: 149 KiB After Width: | Height: | Size: 149 KiB |
Before Width: | Height: | Size: 150 KiB After Width: | Height: | Size: 150 KiB |
Before Width: | Height: | Size: 148 KiB After Width: | Height: | Size: 148 KiB |
Before Width: | Height: | Size: 144 KiB After Width: | Height: | Size: 144 KiB |
Before Width: | Height: | Size: 145 KiB After Width: | Height: | Size: 145 KiB |
Before Width: | Height: | Size: 146 KiB After Width: | Height: | Size: 146 KiB |
Before Width: | Height: | Size: 146 KiB After Width: | Height: | Size: 146 KiB |
Before Width: | Height: | Size: 145 KiB After Width: | Height: | Size: 145 KiB |
Before Width: | Height: | Size: 228 KiB After Width: | Height: | Size: 228 KiB |
Before Width: | Height: | Size: 226 KiB After Width: | Height: | Size: 226 KiB |
Before Width: | Height: | Size: 229 KiB After Width: | Height: | Size: 229 KiB |
Before Width: | Height: | Size: 230 KiB After Width: | Height: | Size: 230 KiB |
Before Width: | Height: | Size: 231 KiB After Width: | Height: | Size: 231 KiB |
Before Width: | Height: | Size: 232 KiB After Width: | Height: | Size: 232 KiB |
Before Width: | Height: | Size: 199 KiB After Width: | Height: | Size: 199 KiB |
Before Width: | Height: | Size: 199 KiB After Width: | Height: | Size: 199 KiB |
Before Width: | Height: | Size: 201 KiB After Width: | Height: | Size: 201 KiB |
Before Width: | Height: | Size: 202 KiB After Width: | Height: | Size: 202 KiB |
Before Width: | Height: | Size: 201 KiB After Width: | Height: | Size: 201 KiB |
Before Width: | Height: | Size: 199 KiB After Width: | Height: | Size: 199 KiB |
Before Width: | Height: | Size: 185 KiB After Width: | Height: | Size: 185 KiB |
Before Width: | Height: | Size: 177 KiB After Width: | Height: | Size: 177 KiB |
Before Width: | Height: | Size: 178 KiB After Width: | Height: | Size: 178 KiB |
Before Width: | Height: | Size: 180 KiB After Width: | Height: | Size: 180 KiB |
Before Width: | Height: | Size: 185 KiB After Width: | Height: | Size: 185 KiB |
Before Width: | Height: | Size: 179 KiB After Width: | Height: | Size: 179 KiB |
Before Width: | Height: | Size: 193 KiB After Width: | Height: | Size: 193 KiB |
Before Width: | Height: | Size: 192 KiB After Width: | Height: | Size: 192 KiB |
Before Width: | Height: | Size: 194 KiB After Width: | Height: | Size: 194 KiB |
Before Width: | Height: | Size: 194 KiB After Width: | Height: | Size: 194 KiB |
Before Width: | Height: | Size: 198 KiB After Width: | Height: | Size: 198 KiB |
Before Width: | Height: | Size: 200 KiB After Width: | Height: | Size: 200 KiB |
Before Width: | Height: | Size: 127 KiB After Width: | Height: | Size: 127 KiB |
Before Width: | Height: | Size: 126 KiB After Width: | Height: | Size: 126 KiB |
Before Width: | Height: | Size: 132 KiB After Width: | Height: | Size: 132 KiB |
Before Width: | Height: | Size: 129 KiB After Width: | Height: | Size: 129 KiB |
Before Width: | Height: | Size: 130 KiB After Width: | Height: | Size: 130 KiB |
Before Width: | Height: | Size: 132 KiB After Width: | Height: | Size: 132 KiB |
@ -1,4 +1,4 @@
|
||||
from sqlalchemy import Column, Integer, VARCHAR, Text, ForeignKey
|
||||
from sqlalchemy import Column, Integer, VARCHAR, Text, LargeBinary, ForeignKey
|
||||
from sqlalchemy.orm import relationship, declarative_base
|
||||
|
||||
Base = declarative_base()
|
||||
@ -11,7 +11,7 @@ class Text(Base):
|
||||
|
||||
__tablename__ = 'T_TEXT'
|
||||
|
||||
TEXT_ID = Column(Integer, primary_key=True, comment="ID of this specific text. These IDs may be recycled in the future and may only be used for a short time period.")
|
||||
TEXT_ID = Column(Integer, autoincrement=True, primary_key=True, comment="ID of this specific text. These IDs may be recycled in the future and may only be used for a short time period.")
|
||||
LID = Column(Integer, ForeignKey("T_LOCALE.LID"), comment="Reference to the locale that this text provides")
|
||||
LANG = Column(VARCHAR(2), comment="lang ID of the text value in this row, e.g FR, EN, ES")
|
||||
TEXT = Column(Text, comment="Actual text stored")
|
||||
@ -39,7 +39,7 @@ class Locale(Base):
|
||||
"""
|
||||
|
||||
__tablename__ = 'T_LOCALE'
|
||||
LID = Column(Integer, primary_key=True, comment="ID of this locale (the other tables references to this with *_LID columns)")
|
||||
LID = Column(Integer, primary_key=True, autoincrement=True, comment="ID of this locale (the other tables references to this with *_LID columns)")
|
||||
|
||||
def __init__(self, LID):
|
||||
self.LID = LID
|
||||
@ -57,7 +57,7 @@ class Place(Base):
|
||||
"""
|
||||
|
||||
__tablename__ = 'T_PLACE'
|
||||
PLACE_ID = Column(Integer, primary_key=True, comment="ID of this place")
|
||||
PLACE_ID = Column(Integer, primary_key=True, autoincrement=True, comment="ID of this place")
|
||||
NAME_LID = Column(Integer, ForeignKey("T_LOCALE.LID"), comment="Place name")
|
||||
LOCALE = relationship("Locale")
|
||||
|
||||
@ -100,7 +100,7 @@ class Answer(Base):
|
||||
"""
|
||||
|
||||
__tablename__ = "T_ANSWER"
|
||||
QUESTION_TYPE_ID = Column(Integer,ForeignKey("T_QUESTION_TYPE.QUESTION_TYPE_ID"),primary_key=True, comment="Question type ID")
|
||||
QUESTION_TYPE_ID = Column(Integer, ForeignKey("T_QUESTION_TYPE.QUESTION_TYPE_ID"), primary_key=True, comment="Question type ID")
|
||||
NPC_ID = Column(Integer, ForeignKey("T_NPC.NPC_ID"), primary_key=True, comment="ID of the NPC that will say this answer")
|
||||
TEXT_LID = Column(Integer, ForeignKey("T_LOCALE.LID"), comment="Text of the answer")
|
||||
LOCALE = relationship("Locale")
|
||||
@ -127,6 +127,7 @@ class Npc(Base):
|
||||
__tablename__ = "T_NPC"
|
||||
NPC_ID = Column(Integer, autoincrement=True, primary_key=True, comment="ID of this Npc")
|
||||
NAME_LID = Column(Integer, ForeignKey("T_LOCALE.LID"), comment="Name of this Npc")
|
||||
DEFAULT_IMG = Column(LargeBinary(length=2**24), comment="Binary data of the default image of this Npc")
|
||||
LOCALE = relationship("Locale")
|
||||
|
||||
def __init__(self, NPC_ID, NAME_LID):
|
||||
@ -145,7 +146,7 @@ class Trait(Base):
|
||||
Store reaction types, e.g 'happy', 'sad', without relation with NPCs
|
||||
"""
|
||||
__tablename__ = "T_TRAIT"
|
||||
TRAIT_ID = Column(Integer, primary_key=True, comment="ID of this trait")
|
||||
TRAIT_ID = Column(Integer, primary_key=True, autoincrement=True, comment="ID of this trait")
|
||||
NAME_LID = Column(Integer, ForeignKey("T_LOCALE.LID"), comment="Name of this trait")
|
||||
DESC_LID = Column(Integer, ForeignKey("T_LOCALE.LID"), comment="Description of this trait")
|
||||
|
||||
@ -170,9 +171,10 @@ class Reaction(Base):
|
||||
Relation between a NPC and a Trait
|
||||
"""
|
||||
__tablename__ = "T_REACTION"
|
||||
REACTION_ID = Column(Integer, primary_key=True, comment="ID of this reaction")
|
||||
REACTION_ID = Column(Integer, primary_key=True, autoincrement=True, comment="ID of this reaction")
|
||||
NPC_ID = Column(Integer, ForeignKey("T_NPC.NPC_ID"), primary_key=True, comment="Name of the NPC that will have this reaction")
|
||||
TRAIT_ID = Column(Integer, ForeignKey("T_TRAIT.TRAIT_ID"), primary_key=True, comment="ID of the trait of this reaction")
|
||||
IMG = Column(LargeBinary(length=2**24), comment="Binary data of the image associated to this npc and trait")
|
||||
NPC = relationship("Npc")
|
||||
TRAIT = relationship("Trait")
|
||||
|
||||
|
@ -2,7 +2,10 @@ import string
|
||||
import random
|
||||
from typing import Union
|
||||
|
||||
from sqlalchemy import select, and_
|
||||
|
||||
from truthinquiry.ext.database.models import *
|
||||
from truthinquiry.ext.database.fsa import db
|
||||
from truthinquiry.ext.database import dbutils
|
||||
|
||||
games_list = {}
|
||||
@ -129,10 +132,16 @@ class Game:
|
||||
:param npc_id: the id of the npc, to get the reactions from, must be in the current game
|
||||
:return: the reaction image as bytes
|
||||
"""
|
||||
print(self.reaction_table)
|
||||
if npc_id not in self.reaction_table:
|
||||
return 0
|
||||
reaction_id = self.reaction_table[npc_id]
|
||||
return read_image(f"./truthinquiry/static/images/npc/{npc_id}/{reaction_id}.png")
|
||||
trait_id = self.reaction_table[npc_id]
|
||||
|
||||
reaction = db.session.execute(
|
||||
select(Reaction)
|
||||
.where(and_(Reaction.NPC_ID == int(npc_id), Reaction.TRAIT_ID == int(trait_id)))
|
||||
).one()[0]
|
||||
return reaction.IMG
|
||||
|
||||
def get_player_results(self, responses: dict) -> Union[dict, None]:
|
||||
"""
|
||||
@ -322,4 +331,5 @@ def get_npc_image(npc_id: int):
|
||||
:param npc_id: npc to get the neutral image from
|
||||
:return: the byte representation of the image, none if its not found or not readable
|
||||
"""
|
||||
return read_image(f"./truthinquiry/static/images/npc/{npc_id}/0.png")
|
||||
npc = db.session.execute(select(Npc).where(Npc.NPC_ID==npc_id)).one()[0]
|
||||
return npc.DEFAULT_IMG
|
||||
|
@ -124,7 +124,7 @@ def get_data():
|
||||
|
||||
@routes_api.route("/getNpcImage", methods=["GET", "POST"])
|
||||
def get_npc_image():
|
||||
npc_id = flask.request.values.get("npcid")
|
||||
npc_id = int(flask.request.values.get("npcid"))
|
||||
if npc_id is None:
|
||||
return {"error": 1, "msg": "no npc was given"}
|
||||
image = game_logic.get_npc_image(npc_id)
|
||||
@ -149,7 +149,7 @@ def get_npc_reaction():
|
||||
image = game.get_npc_reaction(npc_id)
|
||||
errors = ["npc not in game","error reading file"]
|
||||
if image in [0,1]:
|
||||
return {"error" :1, "msg": errors[image]} , 500
|
||||
return {"error": 1, "msg": errors[image]}
|
||||
|
||||
response = flask.make_response(image)
|
||||
response.headers.set('Content-Type', 'image/png')
|
||||
|