from sqlalchemy import or_, and_
from sqlalchemy.orm import Session

import configuration
from model.company import Company
from model.credit_type import CreditType
from model.genre import Genre
from model.movie import Movie
from model.movies_to_genres import movies_to_genres_association_table
from model.movies_to_named_entities import MoviesToNamedEntities
from model.named_entity import NamedEntity
from model.person import Person
from model.credit import Credit
from model.keyword import Keyword
from model.reviews import Review
from model.base import Base
import sqlalchemy
from sqlalchemy.sql import select

def select_movies_by_title(session, title, date_from=None, date_to=None, match_title=False):
    query = session.query(Movie)
    title = f'%{title.lower()}%'
    if match_title is True:
        query = query.filter(Movie.title.match(title))
    else:
        query = query.filter(sqlalchemy.func.lower(Movie.title).like(title))
    if date_from is not None:
        query = query.filter(Movie.release_date >= date_from)
    if (date_to is not None):
        query = query.filter(Movie.release_date <= date_to)
    result = query.order_by(Movie.vote_count.desc()).all()
    return result

def select_movie_by_id(session, tmdb_id):
    query = session.query(Movie)
    query = query.filter(Movie.tmdb_id == tmdb_id)
    print(query)
    result = query.all()
    return result

def select_movies_by_people_id(session, tmdb_id):
    query = session.query(Movie).join(Movie.credits).filter(Credit.people_id == tmdb_id)
    result = query.all()
    return result

def select_movies_by_actor_name(session, actor, date_from=None, date_to=None, match_actor=False):
    query = session.query(Movie, Person).join(Movie.credits).join(Credit.type).join(Credit.people)
    actor = f'%{actor.lower()}%'
    if match_actor is True:
        query = query.filter(Person.name.match(actor))
    else:
        query = query.filter(sqlalchemy.func.lower(Person.name).like(actor))
    query = query.filter(CreditType.name.match('cast'))
    if date_from is not None:
        query = query.filter(Movie.release_date >= date_from)
    if (date_to is not None):
        query = query.filter(Movie.release_date <= date_to)
    # print(query)
    result = query.order_by(Movie.vote_count.desc()).all()
    return result

def select_movies_by_actors_or(session, actors, date_from=None, date_to=None, limit=100):
    filters = []
    for e in actors:
        filters.append(sqlalchemy.func.lower(Person.name) == sqlalchemy.func.lower(e))

    sub_actors = session.query(Movie.tmdb_id).join(Movie.credits).join(Credit.people).filter(
        Credit.credit_type_id == 'cast')
    sub_actors = sub_actors.filter(or_(*filters))
    if date_from is not None:
        sub_actors = sub_actors.filter(Movie.release_date >= date_from)
    if (date_to is not None):
        sub_actors = sub_actors.filter(Movie.release_date <= date_to)
    query = session.query(Movie).where(Movie.tmdb_id.in_(sub_actors.subquery()))
    # print(query)
    return query.order_by(Movie.vote_count.desc()).limit(limit).all()

def select_movies_directed_by(session, directors, date_from=None, date_to=None, limit=100):
    filters = []
    for e in directors:
        filters.append(sqlalchemy.func.lower(Person.name) == sqlalchemy.func.lower(e))

    sub_actors = session.query(Movie.tmdb_id).join(Movie.credits).join(Credit.people).filter(
        Credit.credit_type_id == 'crew').filter(Credit.credit_job_id == 'Director')
    sub_actors = sub_actors.filter(or_(*filters))
    if date_from is not None:
        sub_actors = sub_actors.filter(Movie.release_date >= date_from)
    if (date_to is not None):
        sub_actors = sub_actors.filter(Movie.release_date <= date_to)
    query = session.query(Movie).where(Movie.tmdb_id.in_(sub_actors.subquery()))
    # print(query)
    return query.order_by(Movie.vote_count.desc()).limit(limit).all()

def select_movies_by_named_entities_description(session, entities):
    query = session.query(Movie).join(Movie.named_entities)
    filters = []
    for e in entities:
        filters.append(NamedEntity.value == e)
    query = query.order_by(Movie.vote_count.desc()).filter(or_(*filters))

    result = query.all()
    return result

def select_movies_by_named_entity_reviews(session, entities):
    query = session.query(Movie).join(Movie.reviews).join(Review.named_entities)
    filters = []
    for e in entities:
        filters.append(sqlalchemy.func.lower(NamedEntity.value) == sqlalchemy.func.lower(e))
    query = query.filter(or_(*filters))
    # print(query)
    result = query.order_by(Movie.vote_count.desc()).all()
    return result

def select_movies_by_named_entities(session, entities, limit=100):
    """

    :param session:
    :param entities:
    :return: zwraca liste filmow na podstawie znalezionych named entities w opisie filmu i review
    """
    filters = []
    for e in entities:
        filters.append(sqlalchemy.func.lower(NamedEntity.value) == sqlalchemy.func.lower(e))

    sub_description = session.query(Movie.tmdb_id).join(Movie.named_entities)
    sub_description = sub_description.filter(or_(*filters))
    sub_reviews = session.query(Movie.tmdb_id).join(Movie.reviews).join(Review.named_entities)
    sub_reviews = sub_reviews.filter(or_(*filters))

    union = sub_description.union(sub_reviews)
    query = session.query(Movie).where(Movie.tmdb_id.in_(union))
    return query.order_by(Movie.vote_count.desc()).limit(limit).all()

def select_movies_by_named_entities_or(session, entities, limit=100):
    filters = []
    for e in entities:
        filters.append(sqlalchemy.func.lower(NamedEntity.value) == sqlalchemy.func.lower(e))

    sub_description = session.query(Movie.tmdb_id).join(Movie.named_entities)
    sub_description = sub_description.filter(or_(*filters))

    query = session.query(Movie).where(Movie.tmdb_id.in_(sub_description.subquery()))
    return query.order_by(Movie.vote_count.desc()).limit(limit).all()

def select_movies_by_named_entities_and(session, entities):
    query = session.query(Movie)
    for e in entities:
        sub = session.query(MoviesToNamedEntities.movie_id).join(NamedEntity).filter(NamedEntity.value == e)
        subquery = sub.subquery()
        query = query.filter(Movie.tmdb_id.in_(subquery))
    result = query.order_by(Movie.vote_count.desc()).all()
    return result

def select_movies_by_two_actors(session, actors, date_from=None, date_to=None):
    query = session.query(Movie)
    for e in actors:
        e = f'%{e.lower()}%'
        sub = session.query(Credit.movie_id).join(Person).filter(sqlalchemy.func.lower(Person.name).like(e)).filter(
            Credit.credit_type_id == 'cast')
        subquery = sub.subquery()
        query = query.filter(Movie.tmdb_id.in_(subquery))
    if date_from is not None:
        query = query.filter(Movie.release_date >= date_from)
    if (date_to is not None):
        query = query.filter(Movie.release_date <= date_to)
    result = query.order_by(Movie.vote_count.desc()).all()
    return result

def not_used_select_movies_by_named_entities_and(session, entities):
    filters = []
    for e in entities:
        filters.append(sqlalchemy.func.lower(NamedEntity.value) == sqlalchemy.func.lower(e))

    sub_description = session.query(Movie.tmdb_id).join(Movie.named_entities)
    sub_description = sub_description.filter(and_(*filters))
    sub_reviews = session.query(Movie.tmdb_id).join(Movie.reviews).join(Review.named_entities)
    sub_reviews = sub_reviews.filter(and_(*filters))

    union = sub_description.union(sub_reviews)
    query = session.query(Movie).where(Movie.tmdb_id.in_(union))
    return query.order_by(Movie.vote_count.desc()).all()

def select_movies_by_genres_or(session, genres, limit=20):
    for g in genres:
        g = g.lower()
    query = session.query(Movie).join(Movie.genres)
    query = query.where(sqlalchemy.func.lower(Genre.name).in_(genres))
    query = query.order_by(Movie.vote_count.desc()).limit(limit)
    result = query.all()
    return result

def select_movies_by_genres_and(session, genres, limit=20):
    query = session.query(Movie)
    for g in genres:
        g = g.lower()
        sub = session.query(Movie.tmdb_id).join(Movie.genres).filter(sqlalchemy.func.lower(Genre.name) == g)
        subquery = sub.subquery()
        query = query.filter(Movie.tmdb_id.in_(subquery))
    query = query.order_by(Movie.vote_count.desc()).limit(limit)
    result = query.all()
    return result

def get_movie_details(session, id):
    movie = session.query(Movie).filter(Movie.tmdb_id == id).scalar()
    query = session.query(Credit, Person).join(Person.credits).filter(Credit.movie_id == id)
    query = query.filter(Credit.credit_department_id == None).order_by(Person.popularity.desc())
    cast = query.all()
    query = session.query(Credit, Person).join(Person.credits).filter(Credit.movie_id == id)
    query = query.filter(Credit.credit_department_id.isnot(None)).order_by(Person.popularity.desc())
    crew = query.all()
    return movie, cast, crew

if __name__ == "__main__":
    # get_movie_details(182)
    engine = sqlalchemy.create_engine(configuration.conn_string)
    with Session(engine) as session:
        #     # result=select_movies_by_title(session, 'Ram', date_from='1980-01-12', date_to='2012-11-11')
        #     # result=select_movies_by_actor_name(session, "Polanski")
        #     # result=select_movies_by_named_entities(session, ["nakatomi plaza", "jaws"])
        #     # result=select_movies_by_genres_and(session, ['horror', 'comedy'])
        #     result = select_movie_by_id(session, 8891)
        result = select_movies_directed_by(session, ['Sylvester Stallone', 'Roman Polanski'])
        for i, k in enumerate(result):
            print(i, k)
            # for j in k:
            #     print(j,k[j])


from globals import LAYERS, BERT_CONFIG, VOCAB_FILE, NUM_TPU_CORES, MAX_SEQ_LENGTH, INIT_CHECKPOINT, BATCH_SIZE
from bert import modeling, tokenization
import tensorflow as tf
from read_sequence import  read_sequence
from ex_to_features import convert_examples_to_features
from model_func_builder import model_fn_builder, input_fn_builder
import collections
import numpy as np

def get_features(input_text, dim=768):
    layer_indexes = LAYERS

    bert_config = modeling.BertConfig.from_json_file(BERT_CONFIG)

    tokenizer = tokenization.FullTokenizer(
        vocab_file=VOCAB_FILE, do_lower_case=True
    )

    is_per_host = tf.compat.v1.estimator.tpu.InputPipelineConfig.PER_HOST_V2
    tpu_cluster_resolver = tf.distribute.cluster_resolver.TPUClusterResolver(TPU_ADDRESS)
    run_config = tf.contrib.tpu.RunConfig(
        cluster=tpu_cluster_resolver,
        tpu_config=tf.contrib.tpu.TPUConfig(
            num_shards=NUM_TPU_CORES,
            per_host_input_for_training=is_per_host))

    examples = read_sequence(input_text)

    features =  convert_examples_to_features(
        examples=examples, seq_length=MAX_SEQ_LENGTH, tokenizer=tokenizer
    )

    unique_id_to_feature = {}
    for feature in features:
        unique_id_to_feature[feature.unique_id] = feature

    model_fn = model_fn_builder(
        bert_config=bert_config,
        init_checkpoint=INIT_CHECKPOINT,
        layer_indexes=layer_indexes,
        use_tpus=True,
        use_one_hot_embeddings=True
    )

    # If TPU is not available, this will fall back to normal Estimator on CPU or CPU
    estimator = tf.compat.v1.estimator.tpu.TPUEstimator(
        use_tpu=True,
        model_fn=model_fn,
        config=run_config,
        predict_batch_size=BATCH_SIZE,
        train_batch_size=BATCH_SIZE
    )

    input_fn = input_fn_builder(
        features=features, seq_length=MAX_SEQ_LENGTH
    )

    # GET Features
    for result in estimator.predict(input_fn, yield_single_examples=True):
        unique_id = int(result["unique_id"])
        feature = unique_id_to_feature[unique_id]
        output = collections.OrderedDict()
        for (i, token) in enumerate(feature.tokens):
            layers = []
            for (j, layer_index) in enumerate(layer_indexes):
                layer_output = result["layer_output_%d" % j]
                layer_output_flat = np.array([x for x in layer_output[i:(i + 1)].flat])
                layers.append(layer_output_flat)
            output[token] = sum(layers)[:dim]

        return output

if __name__ == "__main__":
    get_embedding = get_features(input_text="I wish to fight a war")
    print(get_embedding)


import logging
import pyvideo
from pyvideo.exceptions import MediaException

logger = logging.getLogger(__name__)

class VideoException(Exception):
    pass

class VideoLoadException(VideoException, IOError):
    pass

class VideoInfo(object):
    width = None
    height = None
    audio_channels = None
    audio_samplerate = None
    fps = None
    duration = None

    def __init__(self, width, height, fps, channels, samplerate, duration):
        self.width = width
        self.height = height
        self.audio_channels = channels
        self.audio_samplerate = samplerate
        self.fps = fps
        self.duration = duration

    def __unicode__(self):
        return self.__str__()

    def __str__(self):
        return "[V:%sx%s %s fps][A:%sch %sHz] %s s" % (self.width, self.height, self.fps, self.audio_channels, self.audio_samplerate, self.duration)

class VideoFile(object):
    info = None
    _current_frame = None
    _current_frame_timestamp = None
    _fps = None

    def __init__(self, filepath, keyframes_only = False):
        self.filepath = unicode(filepath)
        self.load(keyframes_only)

    def load(self, keyframes_only=False):
        try:
            self.source = pyvideo.load(self.filepath, keyframes_only=keyframes_only)
        except MediaException as e:
            raise VideoLoadException("Unknown video format.\n%s" % (e,))
        except IOError as e:
            raise VideoLoadException("Could not load video file.\n%s" % (e,))

        self._determine_fps()
        self.info = VideoInfo(self.source.video_format.width,
                              self.source.video_format.height,
                              self._fps,
                              self.source.audio_format.channels,
                              self.source.audio_format.sample_rate,
                              self.source.duration)

    def seek_to(self, timestamp):
        self.source.seek(timestamp)

    def get_frame(self):
        # Try to get next un-broken frame
        while self._current_frame is None:
            if self._current_frame_timestamp is None:
                break
            self.get_next_frame()

        return self._current_frame_timestamp, self._current_frame

    def get_next_frame(self):
        self._current_frame_timestamp = self.source.get_next_video_timestamp()
        self._current_frame = self.source.get_next_video_frame()
        return self._current_frame_timestamp, self._current_frame

    def get_audio_data(self):
        return self.source.get_audio_data()

    def _determine_fps(self):
        """
        This consumes one frame to determine FPS
        """
        while self._current_frame_timestamp is None and self._current_frame is None:
            self.get_next_frame()

        current_timestamp = self._current_frame_timestamp
        diff = self.source.get_next_video_timestamp() - current_timestamp
        self._fps = 1.0 / diff
        return self._fps

    def get_info(self):
        return self.info


from __future__ import annotations

from typing import TYPE_CHECKING, TypeAlias

import discord
from discord.ext import commands

from constants import GUILD_ID, Roles

if TYPE_CHECKING:
    from .bot import Bot

__all__ = (
    "Context",
    "GuildContext",
    "Interaction",
)

Interaction: TypeAlias = discord.Interaction["Bot"]

class Context(commands.Context["Bot"]):
    @discord.utils.cached_property
    def replied_reference(self) -> discord.MessageReference | discord.Message:
        ref = self.message.reference
        if ref and isinstance(ref.resolved, discord.Message):
            return ref.resolved.to_reference(fail_if_not_exists=False)
        return self.message

    @discord.utils.cached_property
    def replied_message(self) -> discord.Message | discord.Message:
        ref = self.message.reference
        if ref and isinstance(ref.resolved, discord.Message):
            return ref.resolved
        return self.message

    def author_is_mod(self) -> bool:
        member: discord.Member

        if self.guild is None:  # dms
            guild = self.bot.get_guild(GUILD_ID)

            if not guild:
                return False

            _member = guild.get_member(self.author.id)
            if _member is not None:
                member = _member

            else:
                return False

        else:
            member = self.author  # type: ignore

        roles = member._roles  # type: ignore # we know this won't change for a while
        return roles.has(Roles.ADMIN) or roles.has(Roles.MODERATOR)

class GuildContext(Context):
    guild: discord.Guild  # type: ignore # type lie due to narrowing
    author: discord.Member  # type: ignore # type lie due to narrowing


import yaml
import hvac
import os

client = hvac.Client(url="https://%s" % os.getenv("EAST_VAULT_ADDR"), token=os.getenv("EAST_VAULT_TOKEN"), verify=False)
list = client.list_secret_backends()
for item in list:
    if "sys" not in item and "cubbyhole" not in item and "request_id" not in item and "lease_id" not in item \
            and "renewable" not in item and "lease_duration" not in item and "data" not in item and "wrap_info" not in item \
            and "warnings" not in item and "auth" not in item and "identity" not in item:
        clean_key = str(item).replace("/", "")
        os.system("rvault read %s -a https://%s -t %s -f yaml | tail -n +2 > %s.yml" % (clean_key, os.getenv("WEST_VAULT_ADDR"), os.getenv("WEST_VAULT_TOKEN"), clean_key))
        with open("%s.yml" % clean_key, 'r') as stream:
            data_loaded = yaml.safe_load(stream)
        if data_loaded is not "":
            for secret in data_loaded:
                string=""
                if "1" in str(list[item]["options"]):
                    string = "client.write(path="
                    string += '"/%s%s"' % (clean_key, secret)
                elif "2" in str(list[item]["options"]):
                    string = "client.secrets.kv.v2.create_or_update_secret(mount_point='%s', path=" % clean_key
                    string += '"%s"' % secret
                ca = ""
                private_key = ""
                private = ""
                public = ""
                certificate = ""
                type_cert = ""
                if "1" in str(list[item]["options"]):
                    print("Version 1")
                elif "2" in str(list[item]["options"]):
                    string += ", "
                    string += "secret=dict("
                for key in data_loaded[secret]:
                    if "ca" in str(key) or "certificate" in str(key) or "private_key" in str(key) or "private" in str(key)or "public" in str(key):
                        type_cert = True
                        if "ca" == str(key):
                            ca = data_loaded[secret][key]
                        elif "certificate" == str(key):
                            certificate = data_loaded[secret][key]
                        elif "private_key" == str(key):
                            private_key = data_loaded[secret][key]
                        elif "private" == str(key):
                            private = data_loaded[secret][key]
                        elif "public" == str(key):
                            public = data_loaded[secret][key]
                    else:
                        if "1" in str(list[item]["options"]):
                            string += ", "
                            string += key
                            string += "="
                            string += '"%s"' % data_loaded[secret][key]
                        elif "2" in str(list[item]["options"]):
                            string += ", "
                            string += key
                            string += " = "
                            string += '"%s"' % data_loaded[secret][key]
                if type_cert is True:
                    if certificate is not "":
                        string += ", "
                        string += "certificate"
                        string += "="
                        string+='"%s" % certificate'
                    if ca is not "":
                        string += ", "
                        string += "ca"
                        string += "="
                        string+='"%s" % ca'
                    if private_key is not "":
                        string += ", "
                        string += "private_key"
                        string += "="
                        string+='"%s" % private_key'
                    if private is not "":
                        string += ", "
                        string += "private"
                        string += "="
                        string+='"%s" % private'
                    if public is not "":
                        string += ", "
                        string += "public"
                        string += "="
                        string+='"%s" % public'
                string+=")"
                if "1" in str(list[item]["options"]):
                    print("Version 1")
                elif "2" in str(list[item]["options"]):
                    string+=")"
                run_string = string.replace("dict(, ", "dict(")
                eval(run_string)


# trading_bot.py - Python program to trade stocks using Alpaca API
# 4/4/2022
# Meshal Albaiz

import alpaca_trade_api as tradeapi # trading API
import time # time functions
from symbols import symbol_list # python file with list of stock market tickers
from dictionary_symbols import * # python dictionary of symbols and order information
import math # math functions
from datetime import datetime # time and date functions
import pytz # python timezone library

SEC_KEY = 'XXXX' # secret and public keys for the Alpaca API
PUB_KEY = 'XXXX'
BASE_URL = 'https://paper-api.alpaca.markets' # URL to access API
api = tradeapi.REST(key_id= PUB_KEY, secret_key=SEC_KEY, base_url=BASE_URL) # API object

now = pytz.utc.localize(datetime.utcnow()) # current time UTC
tz = pytz.timezone("America/New_York") # New York timezone
ny_time = now.astimezone(tz) # convert time to NY timezone
hour = ny_time.hour # hour in NY
minute = ny_time.minute # minute in NY
day = ny_time.weekday() # day in NY

# time and day checks to only trade Mon-Fri 9:35AM to 3:55PM
time_check = (hour == 9 and minute >= 35) or (hour == 15 and minute < 56) or (15 > hour > 9)
day_check = 0 <= day < 5

def selling(): # function to sell held position
    for symbol in symbol_list: # for every ticker in list
        position = get_pos(symbol) # get position of company
        if position != False: # if position exists
            if(get_position_csv(symbol)['held'] == "True"): # if sell order was not placed then order sell
                cost = float(position.avg_entry_price) # get cost of position
                price = str(truncate(cost*1.01, 2)) # set selling price at 1% more
                sell(symbol, "1", price) # sell 1 stock

def buying(): # function to buy unheld position
    for symbol in symbol_list: # for every ticker in list
        position = get_pos(symbol) # get position of company
        if position == False: # if position doesn't exist
            if(get_position_csv(symbol)['held'] == "False"): # if buy  order was not placed then order buy
                buy(symbol, "1") # buy 1 stock at market price

def get_pos(symbol): # function to get held positions through API
    try:
        pos = api.get_position(symbol) # get position of symbol
        return pos # retrun position
    except:
        return False # return False if position does not exist

def sell(symbol, qty, price): # function to place sell order
    try: # try to submit sell order
        api.submit_order(
            symbol=symbol,
            qty=qty,
            limit_price=price,
            side='sell',
            type='limit',
            time_in_force='gtc'
        )
        update_position(symbol, "False") # update position in CSV file to indicate sell order was placed
    except:
        return False

def buy(symbol, qty): # function to place buy order
    try: # try to submit buy order
        api.submit_order(
            symbol=symbol,
            qty=qty,
            side='buy',
            type='market',
            time_in_force='day'
        )
        update_position(symbol, "True") # update position in CSV file to indicate buy order was placed
    except:
        return False

def get_price(symbol): # function to get price of specific stock
    price_data = api.get_bars(symbol, tradeapi.TimeFrame.Minute, limit=1)
    return price_data

def truncate(number, digits) -> float: # function to truncate float decimal value
    stepper = 10.0 ** digits
    return math.trunc(stepper * number) / stepper

if(time_check and day_check): # if market is open
    selling() # place sell orders for all held positions
    buying() # place buy orders for all unheld positions


# %%
import random
import numpy as np
import gym
import matplotlib.pyplot as plt

# %%
class QStatistics:

    def __init__(self):
        self.rewards = []
        self.explorationRate = []
        self.stepsPerEpoch = []
        self.exploredAtEpoch = 0
        self.stepsAtEpoch = 0
        self.rewardsAtEpoch = 0

    def NextEpoch(self):
        self.rewards.append(self.rewardsAtEpoch)
        self.explorationRate.append(self.exploredAtEpoch)
        self.stepsPerEpoch.append(self.stepsAtEpoch)

        self.exploredAtEpoch = 0
        self.stepsAtEpoch = 0
        self.rewardsAtEpoch = 0

    def StepTaken(self, reward):
        self.rewardsAtEpoch+=reward
        self.stepsAtEpoch+=1

    def Explored(self):
        self.exploredAtEpoch+=1

# %%
class ExpTradeOff:
    def __init__(self, startEpsilon, endEpsilon, decayRate):
        self.epsilon = startEpsilon
        self.startEpsilon = startEpsilon
        self.endEpsilon = endEpsilon
        self.decayRate = decayRate

    def NextEpoch(self, epoch):
        self.epsilon = self.endEpsilon + (self.startEpsilon - self.endEpsilon) * np.exp(-self.decayRate * epoch)
    def ShouldExplore(self):
        threshold = random.uniform(0,1)
        return threshold < self.epsilon

# %%
frozenLake = gym.make("FrozenLake-v0")

# %%
epochs = 50*1000
maxSteps = 99

learningRate = 0.8
gamma = 0.95

# %%
actionSize = frozenLake.action_space.n
stateSize = frozenLake.observation_space.n
qtable = np.zeros((stateSize, actionSize))
expTradeOff = ExpTradeOff(1.0, 0.01, 0.005)

# statistics
stat = QStatistics()

for epoch in range(epochs):
    state = frozenLake.reset()
    step = 0
    done = False
    for step in range(maxSteps):
        if expTradeOff.ShouldExplore():
            action = frozenLake.action_space.sample()
            stat.Explored()
        else:
            action = np.argmax(qtable[state,:])

        newState, reward, done, info = frozenLake.step(action)
        qtable[state,action] = qtable[state,action] + learningRate * (reward + gamma * np.max(qtable[newState,:])-qtable[state,action])
        stat.StepTaken(reward)
        state = newState

        if done:
            break

    expTradeOff.NextEpoch(epoch)
    stat.NextEpoch()
# %%
print(qtable[:2,:])
print ("Score over time: " +  str(sum(stat.rewards)/epochs))
plt.plot(stat.rewards)
#%%
print ("Exploration/exploitation trade-off")
plt.plot(stat.explorationRate)

# %%
print ("Steps per epoch")
plt.plot(stat.stepsPerEpoch)
# %%
totalReward = 0
for episode in range(1000):
    state = frozenLake.reset()
    step = 0
    done = False
    frozenLake.render()

    for step in range(maxSteps):
        action = np.argmax(qtable[state,:])
        new_state, reward, done, info = frozenLake.step(action)
        if done:
            frozenLake.render()
            totalReward += reward # reward is 1 for the target cell, otherwise 0
            print("Steps taken: ",step)
            break
        # frozenLake.render()
        state = new_state
print("\nTotalReward:", totalReward)
print("\nover")

# %%
frozenLake.close()
# %%


from django.urls import path
from django.contrib.auth import views as auth_views
from . import views
from .views import  ReservationDetailView, ReservationCreateQuickView, ReservationUpdateView, ReservationDeleteView
from .views import extendCreateView
#from .views import ReservationListView
#from .views import ReservationListView

# just for the test run on server
urlpatterns = [
    path('home/', views.home, name="home"),
    path('register/', views.register, name="register"),
    path('profile/', views.profile, name="profile"),
    path('login/', auth_views.LoginView.as_view(template_name = 'reservations/login.html'), name="login"),
    path('logout/', auth_views.LogoutView.as_view(template_name='reservations/logout.html'), name="logout"),
    path('restaurants/', views.restaurants, name="restaurants"),
    path('restaurant_details/<int:id>/', views.restaurant_details, name="restaurant_detail"),
    path('reservation/<int:pk>/', ReservationDetailView.as_view(), name='reservation_details'),
    path('reservation/<int:pk>/update/', ReservationUpdateView.as_view(), name='reservation_update'),
    path('reservation/<int:pk>/delete/', ReservationDeleteView.as_view(), name='reservation_delete'),
    path('reservation/new/', extendCreateView.as_view(), name='reservation_create'),
    path('reservation/quickSearch/', ReservationCreateQuickView.as_view(), name='reservation_quickSearch'),
    path('newrestaurant/', views.new_restaurant, name="new_restaurant"),
    # path('profile/<int:pk>', ReservationDetailView.as_view(), name="reservation_detail")
]


import plotly.plotly as py
import plotly.graph_objs as go
from collections import defaultdict

def histo(string):
 """takes string, returns dict of wordlength vs percent frequency"""
 string=stripper(string)
 liststring=string.split()
 lens=list(map(len,liststring))
 #at this point we have a list of the lengths of each word
 counts=counter(lens)
 return counts

def counter(a):
 """takes list of word lengths, gives frequency of each length"""
 counts=defaultdict(int)
 for length in a:
  counts[length]+=1
 return counts

def stripper(a):
 """the pattented grammer stripper 3000. Takes out the grammar from the string"""
 chars=['"','(',')','.','?','!',';','-','--',',',':']
 for i in chars:
  a=a.replace(i,'')
 return a

def makehisto(*args):
 """take variable numbers of strings, use histo to make a list of dicts of wordlength vs frequency, then converts that to a bar graph with plotly"""
 titles=(input('what are the titles, in order: '))
 titles=titles.split()
 wordlendicts=[]
 for i in args:
  wordlendicts.append(histo(i))
 data=[]
 kys=[]
 vls=[]
 for i in wordlendicts:
  kys.append(list(i.keys()))
  vls.append(list(i.values()))
 for n,(k,v) in enumerate(zip(kys,vls)):
  data.append(go.Bar(x=k,y=v,name=titles[n]))
 layout=go.Layout(barmode='group',
 yaxis=dict(title='percent frequency of occurence'),
 xaxis=dict(title='length of word'))
 fig=go.Figure(data=data,layout=layout)
 py.plot(fig,filename=str(titles))


from copy import copy
from dataclasses import dataclass
from xml.etree.ElementTree import tostring
import PIL
import cv2
from pandas import array, wide_to_long
import phe
from phe import paillier
from PIL import Image,ImageOps
import numpy as np
import matplotlib.pyplot as plt

public_key, private_key = paillier.generate_paillier_keypair()

img=Image.open("lenna128_noised.png")
img=ImageOps.grayscale(img)
height,width=img.size
print(height,width)

imgcv=cv2.imread("lenna128_noised.png",0)

def encryptImage(img_n):
    my_array = [[0]*height]*width
    img_data=np.asarray(img_n)
    for i in range(0, height):
        my_array[i]=[public_key.encrypt(int(x),None,None) for x in img_data[i]]
    return my_array

def decryptImage(my_array):
    my_array_dec = [[0]*height]*width
    for i in range(0, height):
        my_array_dec[i]=[private_key.decrypt(x) for x in my_array[i]]
    my_array_nolist=np.array(my_array_dec)
    im=Image.fromarray((255-my_array_nolist * 255).astype('uint8'), mode='L')
 #nu salveaza bine, face poza neagra, incerc rezolv
    return im

#trebe testatae cu imaginea citita cu Image.open, nu cu cv2.open
def control_brightness_image(myimg,brightness=0):
    myimg=myimg+brightness
    return myimg

def control_brightness_crypted(myimg_Array, brightness=0):
    for i in range(0, height):
        for j in range(0,width):
            myimg_Array[i][j]=myimg_Array[i][j]+ brightness
    return myimg_Array

def image_negation_image(myimg):
    myimg=255-myimg
    return myimg
def image_negation_crypted(myimg_Array):
    for i in range(0, height):
        for j in range(0,width):
            myimg_Array[i][j]=255-myimg_Array[i][j]
    return myimg_Array

def encrypt_image_second(img, public_key):
    shape = img.shape
    img = img.flatten()
    img_enc = []
    for i in range(len(img)):
        tmp = public_key.encrypt(int(img[i]))
        img_enc.append(tmp)
        x = private_key.decrypt(tmp)
    return np.reshape(img_enc, shape)

def decrypt_image_second(img, private_key):
  shape = img.shape
  img = img.flatten()
  img_dec = []
  for i in range(len(img)):
    tmp = private_key.decrypt(img[i])
    img_dec.append(tmp)
  return np.reshape(np.array(img_dec).astype(np.uint8), shape)

def secure_noise_reduction_image(myimg):
    imgnou=myimg.copy()
    cv2.fastNlMeansDenoising(myimg,imgnou,h=10)
    return imgnou

def secure_noise_reduction_crypted(myimg,kernel_size):
    myimg = np.array(myimg)
    img_filtered = myimg.copy()
    (n, m) = myimg.shape
    offset = kernel_size // 2
    for i in range(offset, n-offset, 1):
        for j in range(offset, m-offset, 1):
            window = myimg[i-offset:i+offset+1, j-offset:j+offset+1]
            img_filtered[i][j] = np.mean(window)
    return img_filtered

def edge_detection_image(myimg):
    edges = cv2.Canny(myimg,50,150)
    return edges

def edge_detection_encrypted(myimage):
    nonoiseimg=secure_noise_reduction_crypted(myimage,3)
    edges=myimage-nonoiseimg
    return edges

img2=imgcv.copy()
#img_encrypted=encryptImage(img)

# img_encrypted_plus_brig=control_brightness_crypted(img_encrypted,100)
#img_plus_brig=control_brightness_image(img2,100)

#img_encrypted_negate=image_negation_crypted(img_encrypted)
#img_negate=image_negation_image(img2)

# img_enc=encrypt_image_second(imgcv,public_key)
# img_noise_reduction=secure_noise_reduction_image(img2)
# img_noise_encrypted=secure_noise_reduction_crypted(img_enc,3)
# img_dec=decrypt_image_second(img_noise_encrypted,private_key)

img_enc=encrypt_image_second(imgcv,public_key)
img_edge=edge_detection_image(img2)
img_edge_encrypted=edge_detection_encrypted(img_enc)
img_dec=decrypt_image_second(img_edge_encrypted,private_key)

#img_decrypted=decryptImage(img_noise_encrypted)

fig=plt.figure()
fig.add_subplot(1,3,1)
plt.imshow(imgcv, cmap='gray')
fig.add_subplot(1,3,2)
plt.imshow(img_edge,cmap='gray')
fig.add_subplot(1,3,3)
plt.imshow(img_dec,cmap='gray')

plt.show()


"""Definition for module Crumb"""
from __future__ import annotations
from typing import Optional, Dict, Callable, Any
import inspect
import json
from importlib.util import spec_from_file_location, module_from_spec
import os

from crumb.bakery_items.generic import BakeryItem
from crumb.logger import LoggerQueue, log, logging

class Crumb(BakeryItem):
    """
    Crumb is a class that contains information about how to run a function.
    @param name: name given to the crumb
    @param file: the file where this crumb was identified
    @param func: the underlying function
    @param input: the input of the function: {'param1': int, 'param2': class, ...}
    @param output: the output of the function, int, float, class, ..., obtained from type()
    """
    def __init__(self, name: str, file: str, func: Callable, input: Optional[Dict[str, type]] = None, output: Optional[type] = None):
        log(LoggerQueue.get_logger(), f'Starting crumb {name} from {file}', logging.DEBUG)
        self._crumb_check_input(func, input)
        super().__init__(name, input, output)
        self.file = file.replace('\\', '/')
        self.func = func

    def __repr__(self):
        return f'{self.__class__.__name__} at {hex(id(self))} with ({self.input})=>({str(self.output)})'

    def __str__(self):
        return self.__repr__()

    @classmethod
    def create_from_json(cls, json_str: str) -> Crumb:
        """
        Starts a Crumb based on a json string
        @param json_str
        """
        def dummy_function():
            return None
        crumb = Crumb('dummy_function', '.', dummy_function, input=None, output=None)
        crumb.from_json(json_str)
        return crumb

    def load_from_file(self, filepath: str, this_name: str) -> None:
        from crumb.repository import CrumbRepository  # in here to avoid recursive imports
        crumb_repository = CrumbRepository()
        # redirect crumbs creation to ensure we have the right function
        crumbs_repo: dict = {}
        redirect_status = crumb_repository.get_redirected()
        crumb_repository.redirect({'target': crumbs_repo})
        # load file to recover crumbs
        _, pkg = os.path.split(filepath)
        spec = spec_from_file_location(os.path.splitext(pkg)[0], filepath)
        if spec is None:
            raise RuntimeError('Cannot load file "{filepath}" with function.')
        mod = module_from_spec(spec)
        _ = spec.loader.exec_module(mod)  # type: ignore  # already handled above
        # get crumb
        restored_crumb = crumb_repository.get_crumb(this_name)
        self.name = this_name
        self.input = restored_crumb.input
        self.output = restored_crumb.output
        self.file = filepath
        self.func = restored_crumb.func
        # restore redirection
        crumb_repository.redirect({'target': redirect_status})

    def from_json(self, json_str: str) -> None:
        json_obj = json.loads(json_str)
        filepath = json_obj['executable_file']
        crumb_name = json_obj['name']
        self.load_from_file(filepath, crumb_name)

    def to_json(self) -> str:
        return json.dumps(self.to_dict())

    def to_dict(self) -> dict:
        this_structure = {
            'name': self.name,
            'executable_file': self.file
        }
        return this_structure

    def reload(self) -> None:
        self.load_from_file(self.file, self.name)

    def run(self, input) -> Any:
        if self.func is None:
            self.reload()
        return self.func(**input)

    def _get_args(self, func: Callable) -> Dict[str, type]:
        sign = inspect.signature(func)
        return {k: v.default for k, v in sign.parameters.items()}

    def _crumb_check_input(self, func: Callable, input: Optional[Dict[str, type]]) -> None:
        # check if input parameter is a dictionary
        if input is not None and not isinstance(input, dict):
            raise ValueError('input parameter must be dict, obtained' + str(type(input)))
        # if there are inputs to be evaluated
        func_args = self._get_args(func)
        # check if all elements defined in input are in the function call:
        _not_valid = []
        if 'kwargs' in func_args.keys():
            # for the functions that have more parameters we can not check if the list we have really exist
            pass
        elif input is not None:
            # first check for the ones that are not in the function
            for i in input.keys():
                if i not in func_args:
                    _not_valid.append(i)
        # then check for the ones that do not have a default parameter, and they must be in there
        _not_valid_missing = []
        for i, in_type in func_args.items():
            if in_type is inspect.Parameter.empty:
                if input is None or i not in input:
                    _not_valid_missing.append(i)
        # compile the relation of errors
        err = ''
        if len(_not_valid) > 0:
            invalid_list = '", "'.join(_not_valid)
            err += f'input definition for a parameter that is not in the function: "{invalid_list}"'
        if len(_not_valid_missing) > 0:
            if len(err) > 0:
                err += '\n\tAND\n'
            invalid_missing = '", "'.join(_not_valid_missing)
            err += f'input definition missing for a parameter without default value: "{invalid_missing}"'
        if len(err) > 0:
            raise ValueError(err)


import random
import torch
def synthetic_data(w, b, num_examples): #@save
  """⽣成y=Xw+b+噪声"""
  X = torch.normal(0, 1, (num_examples, len(w)))
  y = torch.matmul(X, w) + b
  y += torch.normal(0, 0.01, y.shape)
  return X, y.reshape((-1, 1))
true_w = torch.tensor([2, -3.4])
true_b = 4.2
features, labels = synthetic_data(true_w, true_b, 1000)
def data_iter(batch_size, features, labels):
  num_examples = len(features)
  indices = list(range(num_examples))
# 这些样本是随机读取的，没有特定的顺序
  random.shuffle(indices)
  for i in range(0, num_examples, batch_size):
    batch_indices = torch.tensor(indices[i: min(i + batch_size, num_examples)])
    yield features[batch_indices], labels[batch_indices]
batch_size = 10
w = torch.normal(0, 0.01, size=(2,1), requires_grad=True)
b = torch.zeros(1, requires_grad=True)
def linreg(X, w, b): #@save
  """线性回归模型"""
  return torch.matmul(X, w) + b
def squared_loss(y_hat, y): #@save
  """均⽅损失"""
  return (y_hat - y.reshape(y_hat.shape)) ** 2 / 2
def sgd(params, lr, batch_size): #@save
  """⼩批量随机梯度下降"""
  with torch.no_grad():
    for param in params:
      param -= lr * param.grad / batch_size
      param.grad.zero_()
lr = 0.03
num_epochs = 3
net = linreg
loss = squared_loss
for epoch in range(num_epochs):
  for X, y in data_iter(batch_size, features, labels):
    l = loss(net(X, w, b), y) # X和y的⼩批量损失
    # 因为l形状是(batch_size,1)，⽽不是⼀个标量。l中的所有元素被加到⼀起，
   # 并以此计算关于[w,b]的梯度
    l.sum().backward()
    sgd([w, b], lr, batch_size) # 使⽤参数的梯度更新参数
  with torch.no_grad():
    train_l = loss(net(features, w, b), labels)
    print(f'epoch {epoch + 1}, loss {float(train_l.mean()):f}')

1.线性神经网络/1.1线性回归/1.1.2从零代码实现.py


import glob
import cv2
from skimage.util import view_as_windows

from ..patch_extraction.extraction_utils import get_ref_df

def get_patches(image_mat, stride):
    """
    Extract patches rom an image
    :param image_mat: The image as a matrix
    :param stride: The stride of the patch extraction process
    :returns: The patches
    """
    window_shape = (128, 128, 3)
    windows = view_as_windows(image_mat, window_shape, step=stride)
    patches = []
    for m in range(windows.shape[0]):
        for n in range(windows.shape[1]):
            patches += [windows[m][n][0]]
    return patches

def get_images_and_labels(tampered_path, authentic_path):
    """
    Get the images and their corresponding labels
    :param tampered_path: The path containing the tampered images
    :param authentic_path: The path containing the authentic images
    :returns: Dictionary with images and labels
    """
    tampered_dir = tampered_path
    authentic_dir = authentic_path
    images = {}
    for im in glob.glob(authentic_dir):
        images[im] = {}
        images[im]['mat'] = cv2.imread(im)
        images[im]['label'] = 0
    for im in glob.glob(tampered_dir):
        images[im] = {}
        images[im]['mat'] = cv2.imread(im)
        images[im]['label'] = 1
    return images

def get_images_and_labels_nc():
    """
    Get the images and their corresponding labels for the NC 2016 dataset
    :returns: Dictionary with images and labels
    """
    refs = get_ref_df()
    images = {}
    for _, data in refs.iterrows():
        if data['ProbeFileName'] in images:
            continue
        im = data['ProbeFileName']
        images[im] = 1 if data['IsTarget'] == 'Y' else 0
    return images


from PIL import Image, ImageDraw, ImageFont
from enum import Enum, unique
from fontTools.ttLib import TTFont
import numpy as np
import io
import os
import base64
import hashlib
import time
import random
import logging

class BackgroundType(Enum):
    RANDOM = 'random'
    IMAGE = 'image'
    RGB = 'rgb'

class RandomCaptcha(object):
    """随机英数样本生成器"""
    def __init__(self):
        self.__width = [130, 160]
        self.__height = [50, 60]
        self.__background_mode = BackgroundType.RGB
        self.__background_img_assests_path = None
        self.__rgb = {
            'r': [0, 255],
            'g': [0, 255],
            'b': [0, 255]
        }
        self.__fonts_list = []
        self.__samples = []
        self.__fonts_num = [4, 4]
        self.__font_size = [26, 36]
        self.__font_mode = 0
        self.__max_line_count = 2
        self.__max_point_count = 20

    @property
    def max_point_count(self):
        return self.__max_point_count

    @max_point_count.setter
    def max_point_count(self, value: int):
        self.__max_point_count = value

    @property
    def max_line_count(self):
        return self.__max_line_count

    @max_line_count.setter
    def max_line_count(self, value: int):
        self.__max_line_count = value

    @property
    def font_mode(self):
        return self.__font_mode

    @font_mode.setter
    def font_mode(self, value: int):
        self.__font_mode = value

    @property
    def font_size(self) -> list:
        return self.__font_size

    @font_size.setter
    def font_size(self, value: list):
        if type(value) == list and type(value[0]) == int and type(value[1]) == int and value[0] >= 0 and value[1] > 0 and value[0] < value[1]:
            self.__font_size = value
        else:
            raise ValueError("input value should be like [0, 255]")

    @property
    def fonts_num(self) -> list:
        return self.__fonts_num

    @fonts_num.setter
    def fonts_num(self, value: list):
        self.__fonts_num = value

    @property
    def sample(self) -> list:
        return self.__samples

    @sample.setter
    def sample(self, value: list):
        self.__samples = value

    @property
    def fonts_list(self) -> list:
        return self.__fonts_list

    @fonts_list.setter
    def fonts_list(self, value: list):
        self.__fonts_list = value

    @property
    def rgb(self) -> dict:
        return self.__rgb

    @property
    def rgb_r(self) -> list:
        return self.__rgb['r']

    @rgb_r.setter
    def rgb_r(self, value: list):
        if type(value) == list and type(value[0]) == int and type(value[1]) == int and value[0] >= 0 and value[1] > 0 and value[0] < value[1] and value[0] <= 255:
            self.__rgb['r'] = value
        else:
            raise ValueError("input value should be like [0, 255]")

    @property
    def rgb_g(self) -> list:
        return self.__rgb['g']

    @rgb_g.setter
    def rgb_g(self, value: list):
        if type(value) == list and type(value[0]) == int and type(value[1]) == int and value[0] >= 0 and value[1] > 0 and value[0] < value[1] and value[0] <= 255:
            self.__rgb['g'] = value
        else:
            raise ValueError("input value should be like [0, 255]")

    @property
    def rgb_b(self) -> list:
        return self.__rgb['b']

    @rgb_b.setter
    def rgb_b(self, value: list):
        if type(value) == list and type(value[0]) == int and type(value[1]) == int and value[0] >= 0 and value[1] > 0 and value[0] < value[1]:
            self.__rgb['b'] = value
        else:
            raise ValueError("input value should be like [0, 255]")

    @property
    def background_mode(self) -> BackgroundType:
        return self.__background_mode

    @background_mode.setter
    def background_mode(self, value: BackgroundType):
        self.__background_mode = value

    @property
    def background_img_path(self) -> str:
        return self.__background_img_assests_path

    @background_img_path.setter
    def background_img_path(self, value: str):
        self.__background_img_assests_path = value

    @property
    def height(self):
        return self.__height

    @height.setter
    def height(self, value):
        self.__height = value

    @property
    def width(self):
        return self.__width

    @width.setter
    def width(self, value):
        self.__width = value

    def check_font(self):
        for font_type in self.fonts_list:
            try:
                font = TTFont(font_type)
                uni_map = font['cmap'].tables[0].ttFont.getBestCmap()
                for item in self.sample:
                    codepoint = ord(str(item))
                    if codepoint in uni_map.keys():
                        continue
                    else:
                        font.close()
                        raise Exception("{} not found!".format(item))
            except Exception as e:
                try:
                    os.remove(font_type)
                except:
                    pass
                del self.fonts_list[self.fonts_list.index(font_type)]

        pass

    def set_text(self, __image: ImageDraw, img_width, img_height):

        if img_width >= 150:
            font_size = random.choice(range(self.font_size[0], self.font_size[1]))
        else:
            font_size = random.choice(range(self.font_size[0], int((self.font_size[0] + self.font_size[1])/2)))

        font_num = random.choice(range(self.fonts_num[0], self.fonts_num[1]))
        max_width = int(img_width / font_num)
        max_height = int(img_height)
        font_type = random.choice(self.fonts_list)
        try:
            font = ImageFont.truetype(font_type, font_size)
        except OSError:
            del self.fonts_list[self.fonts_list.index(font_type)]
            raise Exception("{} opened fail")
        labels = []
        for idx in range(font_num):
            fw = range(int(max_width - font_size))
            if len(fw) > 0:
                x = max_width * idx + random.choice(fw)
            else:
                x = max_width * idx
            y = random.choice(range(int(max_height - font_size)))
            f = random.choice(self.sample)
            labels.append(f)
            __image.text((x, y), f, font=font,
                         fill=(random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)))
        return labels, font_type

    def set_noise(self, __image: ImageDraw, img_width, img_height):
        for i in range(self.max_line_count):
            # 噪线的起点横坐标和纵坐标
            x1 = random.randint(0, img_width)
            y1 = random.randint(0, img_height)
            # 噪线的终点横坐标和纵坐标
            x2 = random.randint(0, img_width)
            y2 = random.randint(0, img_height)
            # 通过画笔对象draw.line((起点的xy, 终点的xy), fill='颜色')来划线
            __image.line((x1, y1, x2, y2),
                         fill=(random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)))
        for i in range(self.max_point_count):
            __image.point([random.randint(0, img_width), random.randint(0, img_height)], fill=(random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)))
            x = random.randint(0, img_width)
            y = random.randint(0, img_height)
            __image.arc((x, y, x + 4, y + 4), 0, 40, fill=(random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)))

    def set_content(self, __image: ImageDraw, img_width, img_height):
        labels, font_type = self.set_text(__image, img_width, img_height)
        self.set_noise(__image, img_width, img_height)
        return labels, font_type

    def create(self, mode: str = "bytes", img_format: str = "png"):
        if type(self.width) == list:
            img_width = random.choice(range(self.width[0], self.width[1]))
        else:
            img_width = self.width
        if type(self.height) == list:
            img_height = random.choice(range(self.height[0], self.height[1]))
        else:
            img_height = self.height

        background_mode = self.background_mode
        if type(background_mode) is BackgroundType:
            if background_mode.value == BackgroundType.RGB.value:
                rgb_range = self.rgb
                r_range = rgb_range['r']
                g_range = rgb_range['g']
                b_range = rgb_range['b']
                rgb = (random.randint(r_range[0], r_range[1]), random.randint(g_range[0], g_range[1]),
                       random.randint(b_range[0], b_range[1]))
                __image = Image.new('RGB', (img_width, img_height), rgb)
                img = ImageDraw.Draw(__image)
                labels, font_type = self.set_content(img, img_width, img_height)
                if mode == "bytes":
                    img_byte_arr = io.BytesIO()
                    __image.save(img_byte_arr, format=img_format)
                    return img_byte_arr.getvalue(), labels, font_type
                elif mode == "numpy":
                    return np.array(__image), labels, font_type
                elif mode == "base64":
                    img_byte_arr = io.BytesIO()
                    __image.save(img_byte_arr, format=img_format)
                    _bytes = img_byte_arr.getvalue()
                    return base64.b64encode(_bytes).decode(), labels, font_type
                else:
                    raise FutureWarning("暂不支持的输出类型")
            else:
                raise FutureWarning("暂不支持的背景类型")
        else:
            raise TypeError("background mode must be BGMODEL.")


from astropy.io import fits
import os
import csv
import datetime
import json
dates = {}

class Sort:
    def __init__(self):
        with open('./data.json', 'r') as f:
            self.weather = json.load(f)
    def organize(self):
        print('Organizing All FITS Files Now')
        for file in os.listdir('./fits'):
            if 'out' in file:
                continue
            try:
                filename = file
                if 'tmp' not in file and '.fits' in file:
                    if file == '.DS_Store':
                        continue
                    file = fits.open(f"./fits/{file}")
                    file.close()
                    date = file[0].header['DATE-OBS'].split('T')[0]
                    if 'TIME-OBS' in file[0].header:
                        time = 'T' + file[0].header['TIME-OBS'].replace(':', '-')
                    else:
                        time = ''
                    if date not in os.listdir('./fits'):
                        try:
                            os.mkdir(f"./fits/{date}")
                        except Exception as e:
                            print(e)
                            pass
                        os.rename(f"./fits/{filename}", f"./fits/{date}/{file[0].header['DATE-OBS']}{time}".replace(':', '-') + ".fits")
                    else:
                        os.rename(f"./fits/{filename}", f"./fits/{date}/{file[0].header['DATE-OBS']}{time}".replace(':', '-') + ".fits")
            except Exception as e:
                print("Error handling " + str(file) + ": " + str(e))
        return 'Files have been organized.'

    def getData(self):
        a = ''
        for directory in os.listdir('./fits'):
            if directory == 'out':
                continue
            try:
                if os.path.isdir(f"./fits/{directory}"):
                    for file in os.listdir(f"./fits/{directory}"):
                        filename = file
                        if 'tmp' not in file and '.fits' in file:
                            if file == '.DS_Store':
                                continue
                            file = fits.open(f"./fits/{directory}/{file}")
                            date = file[0].header['DATE-OBS'].split('T')[0]
                            a += file[0].header['DATE-OBS'] + '\n'
                            bugs = 0
                            if file[0].header['bugs']:
                                bugs = 1
                            if date not in dates:
                                dates[date] = {
                                    "pictures": 1,
                                    "telescopeUsed": file[0].header['TELESCOP'],
                                    "location": file[0].header['OBSERVER'],
                                    "instrument": file[0].header['INSTRUME'],
                                    "dates": [file[0].header['DATE-OBS']],
                                    "bugs": bugs
                                }
                            else:
                                dates[date]['pictures'] += 1
                                dates[date]['dates'].append(file[0].header['DATE-OBS'])
                                if 'bugs' in dates[date]:
                                    dates[date]['bugs'] += bugs
                                else:
                                    dates[date]['bugs'] = bugs
                                if(dates[date]['telescopeUsed'] != file[0].header['TELESCOP']):
                                    print('telescope mismatch')
                                if(dates[date]['instrument'] != file[0].header['INSTRUME']):
                                    print('Instrument mismatch')
                            if 'TIME-OBS' in file[0].header:
                                dates[date]['time'] = file[0].header['TIME-OBS'].replace(':', '-')
                            else:
                                dates[date]['time'] = None
            except Exception as e:
                print("Error handling directory" + str(directory) + ": " + str(e))

        for date, value in dates.items():
            lowestTime = {"value": 24, "string": None}
            highestTime = {"value": 0, "string": None}
            for iso in value['dates']:
                if not value['time']:
                    if ':' in iso:
                        time = iso.split('T')[1].split(':')
                    else:
                        time = iso.split('T')[1].split('-')
                else:
                    if ':' in value['time']:
                        time = value['item'].split(':')
                    else:
                        time = value['time'].split('-')
                hour = time[0]
                minute = time[1]
                second = time[2]
                time = int(hour) + int(minute)/60 + float(second)/3600
                if time > highestTime['value']:
                    highestTime['string'] = f"{hour}:{minute}:{second}"
                    highestTime['value'] = time
                elif time < lowestTime['value']:
                    lowestTime['string'] = f"{hour}:{minute}:{second}"
                    lowestTime['value'] = time
            dates[date]['lowestTime'] = lowestTime
            dates[date]['highestTime'] = highestTime
            del dates[date]['dates']

        for date, value in dates.items():
            with open(f"./fits/{date}/metadata.json", 'w') as f:
                json.dump(value, f)

        return dates

    def csvGen(self):
        try:
            with open('data' + '.csv', 'w') as file:
                writer = csv.writer(file, delimiter =',', quotechar='"',  quoting=csv.QUOTE_ALL)
                writer.writerow(['FILE NAME', 'DATE', 'TIME', 'DAY/NIGHT', 'EXPTIME', 'LOCATION', 'INSTRUMENT', 'BUGS', 'UNIX', 'TEMP', 'CLOUD %', 'VISIBILITY', 'INFO'])
                for directory in os.listdir('./fits'):
                    if directory == 'out':
                        continue
                    if os.path.isdir(f"./fits/{directory}"):
                        for file in os.listdir(f"./fits/{directory}"):
                            if file == 'metadata.json':
                                continue
                            filename = file
                            if 'tmp' not in file and '.fits' in file:
                                if file == '.DS_Store':
                                    continue
                                file = fits.open(f"./fits/{directory}/{file}")
                                hdr = file[0].header
                                if('TIME-OBS' in file[0].header):
                                    time = file[0].header['TIME-OBS'].replace('-', ':')
                                    date = file[0].header['DATE-OBS'].replace(':', '-')
                                    dayNight = 0
                                    timeSplit = time.split(':')
                                    if 7 <= int(timeSplit[0]) <= 19:
                                        dayNight = 'Day'
                                    else:
                                        dayNight = 'Night'

                                    isots = datetime.datetime.strptime(f"{date}T{time}", '%Y-%m-%dT%H:%M:%S')
                                    unix = (isots - datetime.datetime(1970, 1, 1)).total_seconds()
                                    unix = int(unix//3600 * 3600)
                                else:
                                    time = file[0].header['DATE-OBS'].split('T')[1].replace(':', '-')
                                    dayNight = 0
                                    timeSplit = time.split('-')
                                    if 7 <= int(timeSplit[0]) <= 19:
                                        dayNight = 'Day'
                                    else:
                                        dayNight = 'Night'
                                    date = file[0].header['DATE-OBS'].split('T')[0].replace(':', '-')
                                    isots = datetime.datetime.strptime(f"{date}T{time}", '%Y-%m-%dT%H-%M-%S.%f')
                                    unix = (isots - datetime.datetime(1970, 1, 1)).total_seconds()
                                    unix = int(unix//3600 * 3600)
                                for item in self.weather:
                                    if item['dt'] == unix:
                                        temp = item
                                        break
                                if 'BUGS' in hdr:
                                    bugs = hdr['BUGS']
                                else:
                                    bugs = 0
                                writer.writerow([filename, date, time.replace('-', ':'), dayNight, hdr['EXPTIME'], hdr['OBSERVER'], hdr['INSTRUME'], bugs, unix, temp['main']['temp'], temp['clouds']['all'], temp['visibility'], temp['weather'][0]['description']])
        except Exception as e:
            print("Error writing CSV: " + str(e))


## Hand Tracker Controller for robotic manipulator control
# resolve the function issue: https://github.com/google/mediapipe/issues/2818
# code mainly comes from the tutorial: https://www.analyticsvidhya.com/blog/2021/07/building-a-hand-tracking-system-using-opencv/
# mediapipe documentation: https://google.github.io/mediapipe/solutions/hands#python-solution-api
# color thresholding from: https://pyimagesearch.com/2014/08/04/opencv-python-color-detection/

import cv2
from matplotlib.colors import hsv_to_rgb
import mediapipe as mp
import numpy as np
import time

# detect colors
# place marker on robot manipulator based on average of x and y values
# maybe something to ignore outliers
class manipulatorDetector():
    def __init__(self):
        self.img = 0

    def findBlueJoint(self, img):
        blue = np.uint8([[[255,250,240 ]]])
        hsv_blue = cv2.cvtColor(blue,cv2.COLOR_BGR2HSV)
        print( hsv_blue )

        # Reading the image
        img = cv2.imread('hand_tracker_controller/gloved_hand2.jpg')

        # convert to hsv colorspace
        hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

        # lower bound and upper bound for Green color
        # these values were determined using the color picker at the beginning of the code
        # with some tolerance
        lower_bound = np.array([95,  5, 210])
        upper_bound = np.array([105, 255, 255])

        # find the colors within the boundaries
        mask = cv2.inRange(hsv, lower_bound, upper_bound)

        #define kernel size
        kernel = np.ones((7,7),np.uint8)

        # Remove unnecessary noise from mask
        mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel)
        mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel)

        # Segment only the detected region
        segmented_img = cv2.bitwise_and(img, img, mask=mask)

                # Find contours from the mask
        contours, hierarchy = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        output = cv2.drawContours(segmented_img, contours, -1, (0, 0, 255), 3)

        # Draw contour on original image
        output = cv2.drawContours(img, contours, -1, (0, 0, 255), 3)

        return segmented_img

class handDetector():
    def __init__(self, mode = False, maxHands = 2, modelCom = 1, detectionCon = 0.5, trackCon = 0.5):
        self.mode = mode
        self.maxHands = maxHands
        self.modelCom = modelCom
        self.detectionCon = detectionCon
        self.trackCon = trackCon

        self.mpHands = mp.solutions.hands
        self.hands = self.mpHands.Hands(self.mode, self.maxHands, self.modelCom, self.detectionCon, self.trackCon)
        self.mpDraw = mp.solutions.drawing_utils

    def findHands(self, img, draw = True):
        imgRGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
        self.results = self.hands.process(imgRGB)
        # print(results.multi_hand_landmarks)

        if self.results.multi_hand_landmarks:
            for handLms in self.results.multi_hand_landmarks:
                if draw:
                    self.mpDraw.draw_landmarks(img, handLms, self.mpHands.HAND_CONNECTIONS)
        return img

    def findPosition(self, img, handNo = 0, draw = True):

        lmlist = []
        if self.results.multi_hand_landmarks:
            myHand = self.results.multi_hand_landmarks[handNo]
            for id, lm in enumerate(myHand.landmark):
                h, w, c = img.shape
                cx, cy = int(lm.x * w), int(lm.y * h)
                lmlist.append([id, cx, cy])
                if draw:
                    cv2.circle(img, (cx, cy), 3, (255, 0, 255), cv2.FILLED)
        return lmlist

class actuationSensor():
    def __init__(self):
        self.isAvgObtained = 0
        self.i = 0
        self.avgMaxActuationDist = 0

    ## get the maximum actuation distance
    # checks if first iteration and gets the starting time of the recording
    # eventually take an argument for what finger to detect
    def getMaxActuationDistance(self, lmlist):
        if (self.i == 0):
            self.startTime = time.time()
            self.maxActuationDistArray = np.array([])

        # checks if 5 seconds have passed
        if ((time.time() - self.startTime) < 5):
            self.maxActuationDistArray = np.append(self.maxActuationDistArray, abs(lmlist[8][2] - lmlist[5][2]))
            print(str(self.maxActuationDistArray[self.i]))

        else:
            self.avgMaxActuationDist = np.average(self.maxActuationDistArray)
            print(str(self.avgMaxActuationDist))
            self.isAvgObtained = 1
        self.i += 1

def main():
    manipulator = manipulatorDetector()
    detector = handDetector()
    hand = actuationSensor()
    render_im_path = "hand_tracker_controller/gloved_hand2.jpg"

    img = cv2.imread(render_im_path)
    #print(img)
    cv2.imshow("Image", img)

    segmented_img = manipulator.findBlueJoint(img)

    cv2.imshow("segmented", segmented_img)
    cv2.waitKey(0)

    # img = detector.findHands(img)
    # lmlist = detector.findPosition(img)
    # # prints the coordinates of the Landmark with the ID passed to lmlist
    # if len(lmlist) != 0:
    #     print(lmlist[0])

    # cv2.imshow("Image", img)
    # cv2.waitKey(0)

if __name__ == "__main__":
    main()


import os
import subprocess
import argparse
import sys
import signal
import shutil

from PyQt6.QtGui import QIcon, QFont, QPainter, QPen
from PyQt6.QtCore import QDir, Qt, QUrl, QSize
from PyQt6.QtMultimedia import QMediaPlayer
from PyQt6.QtMultimediaWidgets import QVideoWidget
from PyQt6.QtWidgets import (QApplication, QFileDialog, QHBoxLayout, QLabel, QStyleFactory,
        QPushButton, QSizePolicy, QSlider, QStyle, QVBoxLayout, QWidget, QStatusBar, QMessageBox, QProgressDialog)
from PIL import Image, UnidentifiedImageError
import imagehash
import glob
import cv2
import tensorflow as tf

def quit_app(*args):
    QApplication.instance().quit()

def resize_image(image_path, output_path, scale_factor):
    #image = Image.open(image_path)
    #new_size = (int(image.width * scale_factor), int(image.height * scale_factor))
    #image_resized = image.resize(new_size)
    #image_resized.save(output_path)
    image = cv2.imread(image_path)
    height, width = image.shape[:2]
    new_height = int(width * scale_factor)
    new_width = int(height * scale_factor)
    image_resized = tf.image.resize(image, [new_width, new_height])
    # image_resized.save(output_path)
    tf.keras.utils.save_img(output_path, image_resized)

def filter_similar_images(directory, hash_threshold=10):
    # image hash value
    image_files = sorted(glob.glob(os.path.join(directory, '*.jpg')))
    total_images = len(image_files)

    hashes = []
    for idx, img_file in enumerate(image_files):
        with Image.open(img_file) as img:
            h = imagehash.phash(img)
            hashes.append((img_file, h))
        # Print progress for every 10 images
        if idx % 10 == 0:
            print(f"Processed {idx}/{total_images} images", end='\r')

    # grouping
    checked = set()
    to_keep = set()
    for i, (img_file1, hash1) in enumerate(hashes):
        if img_file1 in checked:
            continue
        similar_group = [img_file1]
        for j, (img_file2, hash2) in enumerate(hashes[i+1:], start=i+1):
            if hash1 - hash2 <= hash_threshold:  # setting for hashing
                similar_group.append(img_file2)
        checked.update(similar_group)
        to_keep.update(similar_group[:40])

    # delete other images
    for img_file in image_files:
        if img_file not in to_keep:
            os.remove(img_file)

def create_directory(path, name):
    directory_path = os.path.join(path, name)
    if os.path.exists(directory_path):
        shutil.rmtree(directory_path)  # delete folder (reset)
    os.makedirs(directory_path)

def encode_to_120fps(input_file, output_file):
    abs_input_path = os.path.abspath(input_file)
    abs_output_path = os.path.abspath(output_file)
    command = f"ffmpeg -i {abs_input_path} -r 120 {abs_output_path}"
    subprocess.call(command, shell=True)

def extract_frames(input_file, output_folder, last_frame_number):
    abs_input_path = os.path.abspath(input_file)
    abs_output_folder = os.path.abspath(output_folder)

    if os.path.exists(abs_output_folder):
        shutil.rmtree(abs_output_folder)

    os.makedirs(abs_output_folder)

    output_path = os.path.join(abs_output_folder, '%d.jpg')
    command = f'ffmpeg -i "{abs_input_path}" -vf fps=120 -vframes {last_frame_number} "{output_path}"'

    result = subprocess.run(command, shell=True, capture_output=True, text=True)

    if result.returncode != 0:
        print(f"Error occurred during ffmpeg execution:\n{result.stderr}")
    else:
        print(f"ffmpeg output:\n{result.stdout}")

def save_extracted_images(output_folder, marks, group_name, hash_threshold):
    start = 1
    for idx, sublist in marks:
        if len(sublist) == 0:
            print(f"task is completed.")
            return
        end = min(sublist)

        # true image save
        for true_frame in sublist:
            true_image = os.path.join(output_folder, f"{true_frame}.jpg")
            destination = os.path.join(os.path.abspath(group_name), str(idx), 'true')
            shutil.copy(true_image, destination)

        # false image save
        for false_frame in range(start, end):
            false_image = os.path.join(output_folder, f"{false_frame}.jpg")
            destination = os.path.join(os.path.abspath(group_name), str(idx), 'false')
            shutil.copy(false_image, destination)

        start = min(sublist)

        false_dirs = os.path.join(group_name, str(idx), 'false')
        filter_similar_images(false_dirs, hash_threshold)

class CustomSlider(QSlider):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.marked_positions = []

# main class
class VideoPlayer(QWidget):
    def __init__(self, parent=None, group_name=None, directory_path=None):
        super(VideoPlayer, self).__init__(parent)
        self.group_name = group_name
        self.directory_path = directory_path
        self.setFocusPolicy(Qt.FocusPolicy.StrongFocus)
        self.frame_duration = float(1000 / 120)  # time of 1 frame (milisec)
        self.mediaPlayer = QMediaPlayer()
        self.frame_range = {}
        self.true_frames = {key: [] for key in range(16)}

        btnSize = QSize(16, 16)
        videoWidget = QVideoWidget()
        videoWidget.setStyleSheet("background-color: black;")

        openButton = QPushButton("Open Video")
        openButton.setToolTip("Open Video File")
        openButton.setStatusTip("Open Video File")
        openButton.setFixedHeight(24)
        openButton.setIconSize(btnSize)
        openButton.setFont(QFont("Noto Sans", 8))
        openButton.setIcon(QIcon.fromTheme("document-open", QIcon("D:/_Qt/img/open.png")))
        openButton.clicked.connect(self.abrir)

        self.playButton = QPushButton()
        self.playButton.setEnabled(False)
        self.playButton.setFixedHeight(24)
        self.playButton.setIconSize(btnSize)
        self.playButton.setIcon(self.style().standardIcon(QStyle.StandardPixmap.SP_MediaPlay))
        self.playButton.clicked.connect(self.play)

        self.positionSlider = CustomSlider(Qt.Orientation.Horizontal)
        self.positionSlider.setRange(0, 0)
        self.positionSlider.sliderMoved.connect(self.setPosition)

        self.statusBar = QStatusBar()
        self.statusBar.setFont(QFont("Noto Sans", 7))
        self.statusBar.setFixedHeight(14)

        self.markFrameButton = QPushButton("No Marked")
        self.markFrameButton.setEnabled(False)

        self.extractButton = QPushButton("Extract Images")
        self.extractButton.setEnabled(False)
        self.extractButton.clicked.connect(self.extract_images)

        controlLayout = QHBoxLayout()
        controlLayout.setContentsMargins(0, 0, 0, 0)
        controlLayout.addWidget(openButton)
        controlLayout.addWidget(self.playButton)
        controlLayout.addWidget(self.positionSlider)
        controlLayout.addWidget(self.markFrameButton)
        controlLayout.addWidget(self.extractButton)

        self.markedInfoLabel = QLabel()  # Used to display marked frames
        self.markedInfoLabel.setFont(QFont("Noto Sans", 10))

        markedInfoLayout = QHBoxLayout()
        markedInfoLayout.addWidget(self.markedInfoLabel)

        self.frameInfoLabel = QLabel()  # Used to display current frame number
        self.frameInfoLabel.setFont(QFont("Noto Sans", 12))

        self.timeLabel = QLabel()  # label for timer
        self.timeLabel.setFont(QFont("Noto Sans", 12))
        self.timeLabel.setAlignment(Qt.AlignmentFlag.AlignRight)

        labelLayout = QHBoxLayout()
        labelLayout.addWidget(self.frameInfoLabel)
        labelLayout.addWidget(self.timeLabel)

        mainLayout = QVBoxLayout()
        mainLayout.addWidget(videoWidget)
        mainLayout.addLayout(controlLayout)
        mainLayout.addLayout(markedInfoLayout)
        mainLayout.addLayout(labelLayout)

        self.setLayout(mainLayout)

        self.mediaPlayer.setVideoOutput(videoWidget)
        self.mediaPlayer.playbackStateChanged.connect(self.mediaStateChanged)
        self.mediaPlayer.positionChanged.connect(self.positionChanged)
        self.mediaPlayer.durationChanged.connect(self.durationChanged)
        self.mediaPlayer.errorChanged.connect(self.handleError)
        self.statusBar.showMessage("Ready")

        self.markedInfoLabel.setText("Marked Info")
        self.frameInfoLabel.setText("frame Info")
        self.timeLabel.setText("Time Info")

        self.markedInfoLabel.setFixedHeight(12)
        self.frameInfoLabel.setFixedHeight(20)
        self.timeLabel.setFixedHeight(20)

    # open video
    def abrir(self):
        fileName, _ = QFileDialog.getOpenFileName(self, "Select Media",
                ".", "Video Files (*.mp4 *.flv *.ts *.mts *.avi *.m4a)")

        self.markFrameButton.setEnabled(True)
        self.extractButton.setEnabled(True)

        if fileName != '':
            # end with 'encoded'
            if not os.path.splitext(fileName)[0].endswith("_encoded"):
                # do encoding
                basename = os.path.basename(fileName)
                name, ext = os.path.splitext(basename)
                encoded_file = os.path.join(os.path.dirname(fileName), f"{name}_encoded{ext}")
                encode_to_120fps(fileName, encoded_file)
            else:
                # skip encoding
                encoded_file = fileName

            self.mediaPlayer.setSource(QUrl.fromLocalFile(encoded_file))
            self.playButton.setEnabled(True)
            self.statusBar.showMessage(encoded_file)
            self.play()

    def extract_images(self):
        url = self.mediaPlayer.source()
        video_file = url.toLocalFile()

        output_folder = os.path.join(self.directory_path, "image")

        marks = [frame for sublist in self.true_frames.values() for frame in sublist]
        last_frame = max(marks) if marks else 0
        print(f"{last_frame}")
        extract_frames(video_file, output_folder, last_frame)
        print(f"Images extracted to {output_folder}")

        for filename in os.listdir(output_folder):
            if filename.endswith(".jpg"):
                img_path = os.path.join(output_folder, filename)
                resize_image(img_path, img_path, 1/2)

        # Create folders
        for idx, frames in self.true_frames.items():
            if len(frames) == 0:
                continue

            new_folder_name = str(idx)
            new_folder_path = os.path.join(self.group_name, new_folder_name)
            create_directory(self.group_name, new_folder_name)

            # true and false subfolder
            create_directory(new_folder_path, "true")
            create_directory(new_folder_path, "false")

        save_extracted_images(os.path.abspath(output_folder), self.true_frames.items(), self.group_name, hash_threshold=args.s)

    def update_marked_info(self):
        marked_info_texts = []
        for index, ranges in self.frame_range.items():
            ranges_count = len(ranges)
            if ranges_count == 0:
                continue
            elif ranges_count == 1:
                marked_info_texts.append(f"Mark {index-48}: {ranges[0]}~{ranges[0]}")
            else:
                marked_info_texts.append(f"Mark {index-48}: {ranges[0]}~{ranges[1]}")
        self.markedInfoLabel.setText(" | ".join(marked_info_texts))

    def play(self):
        if self.mediaPlayer.playbackState() == QMediaPlayer.PlaybackState.PlayingState:
            self.mediaPlayer.pause()
        else:
            self.mediaPlayer.play()

    def mediaStateChanged(self, state):
        if self.mediaPlayer.playbackState() == QMediaPlayer.PlaybackState.PlayingState:
            self.playButton.setIcon(
                    self.style().standardIcon(QStyle.StandardPixmap.SP_MediaPause))
        else:
            self.playButton.setIcon(
                    self.style().standardIcon(QStyle.StandardPixmap.SP_MediaPlay))

    def setPosition(self, position):
        self.mediaPlayer.setPosition(position)

    def positionChanged(self, position):
        self.positionSlider.setValue(position)
        self.update_frame_number()

        # minutes, seconds = divmod(position // 1000, 60)
        minutes, remainder = divmod(position, 60000)
        seconds, millisec = divmod(remainder, 1000)
        self.timeLabel.setText(f"{minutes:02}:{seconds:02}.{millisec:03}")
        # current location = mark frame location
        self.update_button_text()

    def durationChanged(self, duration):
        self.positionSlider.setRange(0, duration)
        self.update_frame_number()

    def update_frame_number(self):
        current_frame = int(self.mediaPlayer.position() // self.frame_duration)
        if current_frame != 0:
            current_frame += 1
        total_frames = int(self.mediaPlayer.duration() // self.frame_duration)
        self.frameInfoLabel.setText(f"{current_frame}/{total_frames}")

    def update_button_text(self):
        current_position = int(self.mediaPlayer.position() // self.frame_duration)
        if current_position != 0:
            current_position += 1
        # current location = mark frame location
        group_name = None
        for group, frames in self.true_frames.items():
            if current_position in frames:
                group_name = str(group) if group < 10 else chr(ord('A') + group - 10)
                break

        if group_name:
            self.markFrameButton.setText(group_name)
        else:
            self.markFrameButton.setText("No Marked")

    def keyPressEvent(self, event):
        if event.key() == Qt.Key.Key_Space:
            self.play()
            return

        if event.key() == Qt.Key.Key_Right:
            self.mediaPlayer.pause()
            position = self.mediaPlayer.position()
            new_position = int(round(position + self.frame_duration))
            self.mediaPlayer.setPosition(new_position)
        elif event.key() == Qt.Key.Key_Left:
            self.mediaPlayer.pause()
            position = self.mediaPlayer.position()
            new_position = int(round(max(0, position - self.frame_duration)))
            self.mediaPlayer.setPosition(new_position)
        frame_keys = [Qt.Key.Key_0, Qt.Key.Key_1, Qt.Key.Key_2, Qt.Key.Key_3,
                      Qt.Key.Key_4, Qt.Key.Key_5, Qt.Key.Key_6, Qt.Key.Key_7,
                      Qt.Key.Key_8, Qt.Key.Key_9, Qt.Key.Key_A, Qt.Key.Key_B,
                      Qt.Key.Key_C, Qt.Key.Key_D, Qt.Key.Key_E, Qt.Key.Key_F]

        for i, key in enumerate(frame_keys):
            if event.key() == key:
                current_frame = int(self.mediaPlayer.position() // self.frame_duration)
                if current_frame != 0:
                    current_frame += 1
                if key not in self.frame_range:
                    self.frame_range[key] = []
                    self.frame_range[key].append(current_frame)  # Set start frame
                    self.true_frames[i].append(current_frame)
                else:
                    if len(self.frame_range[key]) >= 2:
                        if current_frame < self.frame_range[key][0]:
                            del self.frame_range[key][0]
                            self.frame_range[key].insert(0, current_frame)
                        elif current_frame == self.frame_range[key][0]:
                            self.frame_range[key][0] = self.frame_range[key][1]
                        else:
                            del self.frame_range[key][1]
                            self.frame_range[key].append(current_frame)
                    else:
                        if current_frame < self.frame_range[key][0]:
                            self.frame_range[key].insert(0, current_frame)
                        else:
                            self.frame_range[key].append(current_frame)
                    start_frame = self.frame_range[key][0]
                    end_frame = self.frame_range[key][1]

                    # Update
                    self.true_frames[i] = list(range(start_frame, end_frame + 1))

                self.update_marked_info()
                self.update_button_text()

    def handleError(self):
        self.playButton.setEnabled(False)
        self.statusBar.showMessage("Error: " + self.mediaPlayer.errorString())

if __name__ == '__main__':
    signal.signal(signal.SIGINT, quit_app)

    parser = argparse.ArgumentParser(description='Process arguments.', usage='video.py -g [name] <-s [int]>')
    parser.add_argument('-g', required=True, help='Name for new directory')
    parser.add_argument('-s', type=int, default=10, help='Hash setting, Default = 10')
    parser.add_argument('-p', default="", help='path setting, Default = Video path')
    args = parser.parse_args()

    directory_path = args.p if args.p else os.getcwd()
    create_directory(directory_path, args.g)

    app = QApplication(sys.argv)
    app.setStyleSheet("""
        QStatusBar {
            font-size: 12px;
        }
    """)
    player = VideoPlayer(group_name=args.g, directory_path=directory_path)
    player.setWindowTitle("Player")
    player.resize(900, 600)
    player.show()
    sys.exit(app.exec())


import requests
from googletrans import Translator
import re,string
import contractions

def normalize_text(text):
    """
    Remove punctuation except in real value or date(e.g. 2.5, 25/10/2015),line break and lowercase all words
    :param text: sentence to normalize
    :return return a preprocessed sentence e.g. "This is a ? 12\3  ?? 5.5 covid-19 ! ! *  & $ % ^" => "this is a 12\3 5.5 covid-19"
    """
    regex = "(?<!\w)[!\"#$%&'()*-+/:;<=>?@[\]^_`{|}~](?!\w)"

    #remove punctuation
    result = re.sub(regex, "", text, 0)

    #trim to remove excessive whitespace
    result = re.sub(' +', ' ',(result.replace('\n',' '))).strip().lower()

    return result

def expand_contractions(text):
    """ expand shortened words, e.g. don't to do not """

    return contractions.fix(text)

def translate_wrapper(sentence,target):
    """
    Translate sentence to target language using googletrans library which is a Google Translate API wrapper,
    call this function when you don't have Google Translate API credentials
    :param sentence: sentence to translate
    :param target: target language value can be: ar,fr,en,de,ru,zh,ja,it,... visit for more language https://cloud.com/translate/docs/languages
    :return translated sentence
    """
    translator = Translator()

    try:
        # translate the 'text' column
        response = translator.translate(sentence, dest=target)

    except Exception as e: # mean Google restrict IP address
        response = "Probably Google has banned your client IP addres"+str(e)
        return response
    tmp = expand_contractions(response.text)
    return normalize_text(tmp)
    # return response.text

def translate(utterance,target,api_key):
    """
    Translate a sentence
    :param utterance: sentence to translate
    :param target: target language
    :param api_key: Authentication Key for DeepL API https://www.deepl.com/pro-account.html
    :return Translated utterance
    """

    data = {
    'auth_key': api_key,
    'text': utterance,
    'target_lang': target
    }

    response = requests.post('https://api.deepl.com/v2/translate', data=data)
    data = response.json()
    return data['translations'][0]['text']

def multi_translate(utterance,api_key,pivot_level):
  """
  Translate sentence
  :param utterance: sentence to translate
  :param api_key: Authentication Key for DeepL API https://www.deepl.com/pro-account.html
  :param pivot_level: integer that indicate the pivot language level, single-pivot or multi-pivot range,1 =single-pivot, 2=double-pivot, 0=apply single and double
  :return list of utterance translations
  """

  response = set()
  text = utterance
  if pivot_level == 0 or pivot_level == 1:
    tmp = translate(text,'IT',api_key)
    response.add(translate_wrapper(tmp,'en')) # translate back to english with google translator wrapper
    # tmp = translate(tmp,'EN',api_key) # translate back to english with deepl
    tmp = translate(tmp,'EN',api_key)
    tmp = expand_contractions(tmp)
    response.add(normalize_text(tmp))

    tmp = translate(text,'RU',api_key)
    response.add(translate_wrapper(tmp,'en'))
    tmp = translate(tmp,'EN',api_key)
    tmp = expand_contractions(tmp)
    response.add(normalize_text(tmp))

    tmp = translate(text,'FR',api_key)
    response.add(translate_wrapper(tmp,'en'))
    tmp = translate(tmp,'EN',api_key)
    tmp = expand_contractions(tmp)
    response.add(normalize_text(tmp))

    tmp = translate(text,'JA',api_key)
    response.add(translate_wrapper(tmp,'en'))
    tmp = translate(tmp,'EN',api_key)
    tmp = expand_contractions(tmp)
    response.add(normalize_text(tmp))

    tmp = translate(text,'DE',api_key)
    response.add(translate_wrapper(tmp,'en'))
    tmp = translate(tmp,'EN',api_key)
    tmp = expand_contractions(tmp)
    response.add(normalize_text(tmp))

  if pivot_level == 0 or pivot_level == 2:
    tmp = translate(text,'IT',api_key)
    tmp = translate(tmp,'RU',api_key)
    response.add(translate_wrapper(tmp,'en'))
    tmp = translate(tmp,'EN',api_key)
    tmp = expand_contractions(tmp)
    response.add(normalize_text(tmp))

    tmp = translate(text,'IT',api_key)
    tmp = translate(tmp,'DE',api_key)
    response.add(translate_wrapper(tmp,'en'))
    tmp = translate(tmp,'EN',api_key)
    tmp = expand_contractions(tmp)
    response.add(normalize_text(tmp))

    tmp = translate(text,'RU',api_key)
    tmp = translate(tmp,'FR',api_key)
    response.add(translate_wrapper(tmp,'en'))
    tmp = translate(tmp,'EN',api_key)
    tmp = expand_contractions(tmp)
    response.add(normalize_text(tmp))

    tmp = translate(text,'RU',api_key)
    tmp = translate(tmp,'JA',api_key)
    response.add(translate_wrapper(tmp,'en'))
    tmp = translate(tmp,'EN',api_key)
    tmp = expand_contractions(tmp)
    response.add(normalize_text(tmp))

    tmp = translate(text,'JA',api_key)
    tmp = translate(tmp,'FR',api_key)
    response.add(translate_wrapper(tmp,'en'))
    tmp = translate(tmp,'EN',api_key)
    tmp = expand_contractions(tmp)
    response.add(normalize_text(tmp))

    tmp = translate(text,'JA',api_key)
    tmp = translate(tmp,'DE',api_key)
    response.add(translate_wrapper(tmp,'en'))
    tmp = translate(tmp,'EN',api_key)
    tmp = expand_contractions(tmp)
    response.add(normalize_text(tmp))
  return response

def translate_file(file_path,api_key,pivot_level):
  """
  Translate a file
  :param file_path: file path
  :param api_key: Authentication Key for DeepL API https://www.deepl.com/pro-account.html
  :param pivot_level: integer that indicate the pivot language level, single-pivot or multi-pivot range,1 =single-pivot, 2=double-pivot, 0=apply single and double
  :return Python dictionary containing translsation, Key are initial sentence and vaule are a set of translations
  """

  paraphrases = dict()
  #import data from file_path
  f=open(file_path, "r")
  while True:
      # Get next line from file
      line = f.readline()
      if not line:
          break
      line = line.replace('\n', '').replace('\r', '') #remove linebreak
      tmp = multi_translate(line,api_key,pivot_level)
      paraphrases[line]=tmp

  return paraphrases

def translate_dict(data,api_key,pivot_level):
  """
  Translate a dictionary
  :param data: data in python dictionary, Key initial expression and value is a set of translations
  :param api_key: Authentication Key for DeepL API https://www.deepl.com/pro-account.html
  :param pivot_level: integer that indicate the pivot language level, single-pivot or multi-pivot range,1 =single-pivot, 2=double-pivot, 0=apply single and double
  :return Python dictionary containing translsation, Key are initial sentence and vaule are a set of translations
  """
  paraphrases = dict()

  for key,value in data.items():
    tmp = multi_translate(value,api_key,pivot_level)
    paraphrases[key]=tmp
  return paraphrases

def translate_list(data,api_key,pivot_level):
  """
  Translate a List of sentences
  :param data: data in python List, list of sentences
  :param api_key: Authentication Key for DeepL API https://www.deepl.com/pro-account.html
  :param pivot_level: integer that indicate the pivot language level, single-pivot or multi-pivot range,1 =single-pivot, 2=double-pivot, 0=apply single and double
  :return Python dictionary containing translsation, Key are initial sentence and vaule are a set of translations
  """
  paraphrases = dict()

  for sentence in data:
    tmp = multi_translate(sentence,api_key,pivot_level)
    paraphrases[sentence]=tmp
  return paraphrases

if __name__ == "__main__":
    print(multi_translate('How does COVID-19 spread?','f55c628f-a052-4431-90a7-86d0b8ca861b',1))


from PIL import Image, ImageEnhance, ImageFont, ImageDraw, ImageStat
from collections import defaultdict
from bisect import bisect
import random as r

Image.MAX_IMAGE_PIXELS = 100000000

def _calc_gradient(font_object) -> defaultdict:
    gradient = defaultdict(list)
    table = defaultdict(list)
    table[0].append(chr(32))
    min = 0
    max = 0

    for i in range(33,127):
        # finds the characters height and width and creates an image where it pastes the
        # character and processes it
        h, w = font_object.getsize(chr(i))
        image = Image.new('L', (h, w))
        draw = ImageDraw.Draw(image)
        draw.text((0,0), chr(i), font=font_object, fill=255)

        # finds the brightness value of the character and adds it to the table
        brightness_sum = ImageStat.Stat(image).sum[0]
        brightness_value = brightness_sum//(h*w)
        table[brightness_value].append(chr(i))

        if (brightness_value > max):
            max = brightness_value

    for key in table:
        tmp = (255 * (key - min)) // (max - min)
        gradient[tmp] = table[key]

    return gradient

def _select_symbol(gradient, val) -> str:
    keys = sorted(gradient.keys())
    idx = bisect(keys, val) - 1
    key = keys[idx]
    symbols = gradient[key]
    if (len(symbols) > 1):
        idx = r.randint(0, len(symbols) - 1)
        return symbols[idx]
    else:
        return symbols[0]

def print_dict(dictionary):
    for key in sorted(dictionary.keys()):
        print(key, dictionary[key])

def _block_brightness(image, box) -> int:
    image = image.crop(box)
    area = (box[2]-box[0])*(box[3]-box[1])
    return ImageStat.Stat(image).sum[0] // area

def _gradient_selector(font, size = None) -> [defaultdict, int]:
    try:
        ImageFont.truetype(font, 12)
    except OSError:
        try:
            ImageFont.load(font)
        except OSError:
            print('Cannot open font file')

    gradient = defaultdict(list)
    length = -1

    if size == None:
        for i in range(8, 131):
            tmp = _calc_gradient(ImageFont.truetype(font, i))
            tmp_length = len(tmp)
            if (tmp_length > length):
                gradient = tmp
                length = tmp_length
                size = i
    else:
        gradient = _calc_gradient(font, size)

    return gradient, size

def generate(image, font):
    gradient, size = _gradient_selector(font)
    font = ImageFont.truetype(font, size)
    ascii_art = ''
    with Image.open(image) as image:
        image_w, image_h = image.size
        font_w, font_h = font.getsize(_select_symbol(gradient, 255))

        for y in range(0, image_h, font_h):
            for x in range(0, image_w, font_w):
                brightness = _block_brightness(image, (x, y, x+font_w, y+font_h))
                char = _select_symbol(gradient, brightness)
                ascii_art += char
            ascii_art += '\n'
    return ascii_art

# def generate(image, font, fontsize, gradient):
#     font = ImageFont.truetype(font, fontsize)
#     sorted_table_keys = sorted(gradient.keys())

#     image_string = []
#     scale_ratio = 0
#     with Image.open(image) as image:
#         image_w = image.size[0]
#         image_h = image.size[1]
#         font_w, font_h = font.getsize(_select_symbol(gradient, 255))
#         font_aspect_ratio = font_w/font_h
#         font_scaler = image_h/100
#         font_w = int(font_aspect_ratio * font_scaler * 1.1)
#         font_h = int(font_scaler)

#         brightness = 0
#         scale_ratio = image_w

#         for y in range(0, image_h, font_h):
#             for x in range(0, image_w, font_w):
#                 brightness = _block_brightness(image, (x, y, x+font_w, y+font_h))
#                 char = _select_symbol(gradient, brightness)
#                 image_string.append(char)
#             image_string.append('\n')
#         image_string = ''.join(image_string)

#     im = Image.new("RGB", (10000,10000))
#     img = ImageDraw.Draw(im)

#     img.text((0,0), image_string, font=font)

#     im = im.crop(im.getbbox())
#     im = im.convert('L')
#     scale_ratio /= im.size[0]
#     im = im.resize((int(im.size[0]*scale_ratio),
#                     int(im.size[1]*scale_ratio)),
#                     resample=Image.BICUBIC)
#     im.show()
#     return im

_gradient_selector("UbuntuMono-R.ttf")