import FreeCAD
import Path
import Path.Base.Gui.Util as PathGuiUtil
from PySide import QtCore
import math
import PathScripts.PathUtils as PathUtils
from PySide.QtCore import QT_TRANSLATE_NOOP

# lazily loaded modules
from lazy_loader.lazy_loader import LazyLoader

D = LazyLoader("DraftVecUtils", globals(), "DraftVecUtils")

__doc__ = """Dragknife Dressup object and FreeCAD command"""

if FreeCAD.GuiUp:
    import FreeCADGui

translate = FreeCAD.Qt.translate

movecommands = ["G1", "G01", "G2", "G02", "G3", "G03"]
rapidcommands = ["G0", "G00"]
arccommands = ["G2", "G3", "G02", "G03"]

currLocation = {}

class ObjectDressup:
    def __init__(self, obj):
        obj.addProperty(
            "App::PropertyLink",
            "Base",
            "Path",
            QT_TRANSLATE_NOOP("App::Property", "The base path to modify"),
        )
        obj.addProperty(
            "App::PropertyAngle",
            "filterAngle",
            "Path",
            QT_TRANSLATE_NOOP(
                "App::Property",
                "Angles less than filter angle will not receive corner actions",
            ),
        )
        obj.addProperty(
            "App::PropertyFloat",
            "offset",
            "Path",
            QT_TRANSLATE_NOOP(
                "App::Property", "Distance the point trails behind the spindle"
            ),
        )
        obj.addProperty(
            "App::PropertyFloat",
            "pivotheight",
            "Path",
            QT_TRANSLATE_NOOP("App::Property", "Height to raise during corner action"),
        )

        obj.Proxy = self

    def dumps(self):
        return None

    def loads(self, state):
        return None

    def shortcut(self, queue):
        """Determines whether its shorter to twist CW or CCW to align with
        the next move"""
        # get the vector of the last move

        if queue[1].Name in arccommands:
            arcLoc = FreeCAD.Vector(
                queue[2].x + queue[1].I, queue[2].y + queue[1].J, currLocation["Z"]
            )
            radvector = arcLoc.sub(
                queue[1].Placement.Base
            )  # .sub(arcLoc)  # vector of chord from center to point
            # vector of line perp to chord.
            v1 = radvector.cross(FreeCAD.Vector(0, 0, 1))
        else:
            v1 = queue[1].Placement.Base.sub(queue[2].Placement.Base)

        # get the vector of the current move
        if queue[0].Name in arccommands:
            arcLoc = FreeCAD.Vector(
                (queue[1].x + queue[0].I), (queue[1].y + queue[0].J), currLocation["Z"]
            )
            radvector = queue[1].Placement.Base.sub(arcLoc)  # calculate arcangle
            v2 = radvector.cross(FreeCAD.Vector(0, 0, 1))
        else:
            v2 = queue[0].Placement.Base.sub(queue[1].Placement.Base)

        if (v2.x * v1.y) - (v2.y * v1.x) >= 0:
            return "CW"
        else:
            return "CCW"

    def segmentAngleXY(self, prevCommand, currCommand, endpos=False, currentZ=0):
        """returns in the starting angle in radians for a Path command.
        requires the previous command in order to calculate arcs correctly
        if endpos = True, return the angle at the end of the segment."""

        if currCommand.Name in arccommands:
            arcLoc = FreeCAD.Vector(
                (prevCommand.x + currCommand.I),
                (prevCommand.y + currCommand.J),
                currentZ,
            )
            if endpos is True:
                radvector = arcLoc.sub(
                    currCommand.Placement.Base
                )  # Calculate vector at start of arc
            else:
                radvector = arcLoc.sub(
                    prevCommand.Placement.Base
                )  # Calculate vector at end of arc

            v1 = radvector.cross(FreeCAD.Vector(0, 0, 1))
            if currCommand.Name in ["G2", "G02"]:
                v1 = D.rotate2D(v1, math.radians(180))
        else:
            v1 = currCommand.Placement.Base.sub(
                prevCommand.Placement.Base
            )  # Straight segments are easy

        myAngle = D.angle(
            v1, FreeCAD.Base.Vector(1, 0, 0), FreeCAD.Base.Vector(0, 0, -1)
        )
        return myAngle

    def getIncidentAngle(self, queue):
        # '''returns in the incident angle in radians between the current and previous moves'''

        angleatend = float(math.degrees(self.segmentAngleXY(queue[2], queue[1], True)))
        if angleatend < 0:
            angleatend = 360 + angleatend
        angleatstart = float(math.degrees(self.segmentAngleXY(queue[1], queue[0])))
        if angleatstart < 0:
            angleatstart = 360 + angleatstart

        incident_angle = angleatend - angleatstart

        return incident_angle

    def arcExtension(self, obj, queue):
        """returns gcode for arc extension"""
        global currLocation
        results = []

        offset = obj.offset
        # Find the center of the old arc
        C = FreeCAD.Base.Vector(
            queue[2].x + queue[1].I, queue[2].y + queue[1].J, currLocation["Z"]
        )

        # Find radius of old arc
        R = math.hypot(queue[1].I, queue[1].J)

        # Find angle subtended by the extension arc
        theta = math.atan2(queue[1].y - C.y, queue[1].x - C.x)
        if queue[1].Name in ["G2", "G02"]:
            theta = theta - offset / R
        else:
            theta = theta + offset / R

        # XY coordinates of new arc endpoint.
        Bx = C.x + R * math.cos(theta)
        By = C.y + R * math.sin(theta)

        # endpoint = FreeCAD.Base.Vector(Bx, By, currLocation["Z"])
        startpoint = queue[1].Placement.Base
        offsetvector = C.sub(startpoint)

        I = offsetvector.x
        J = offsetvector.y

        extend = Path.Command(queue[1].Name, {"I": I, "J": J, "X": Bx, "Y": By})
        results.append(extend)
        currLocation.update(extend.Parameters)

        replace = None
        return (results, replace)

    def arcTwist(self, obj, queue, lastXY, twistCW=False):
        """returns gcode to do an arc move toward an arc to perform
        a corner action twist. Includes lifting and plungeing the knife"""

        global currLocation
        pivotheight = obj.pivotheight
        offset = obj.offset
        results = []

        # set the correct twist command
        if twistCW is False:
            arcdir = "G3"
        else:
            arcdir = "G2"

        # move to the pivot height
        zdepth = currLocation["Z"]
        retract = Path.Command("G0", {"Z": pivotheight})
        results.append(retract)
        currLocation.update(retract.Parameters)

        # get the center of the destination arc
        arccenter = FreeCAD.Base.Vector(
            queue[1].x + queue[0].I, queue[1].y + queue[0].J, currLocation["Z"]
        )

        # The center of the twist arc is the old line end point.
        C = queue[1].Placement.Base

        # Find radius of old arc
        R = math.hypot(queue[0].I, queue[0].J)

        # find angle of original center to startpoint
        v1 = queue[1].Placement.Base.sub(arccenter)
        segAngle = D.angle(
            v1, FreeCAD.Base.Vector(1, 0, 0), FreeCAD.Base.Vector(0, 0, -1)
        )

        # Find angle subtended by the offset
        theta = offset / R

        # add or subtract theta depending on direction
        if queue[1].Name in ["G2", "G02"]:
            newangle = segAngle + theta
        else:
            newangle = segAngle - theta

        # calculate endpoints
        Bx = arccenter.x + R * math.cos(newangle)
        By = arccenter.y + R * math.sin(newangle)
        endpointvector = FreeCAD.Base.Vector(Bx, By, currLocation["Z"])

        # calculate IJ offsets of twist arc from current position.
        offsetvector = C.sub(lastXY)

        # add G2/G3 move
        arcmove = Path.Command(
            arcdir,
            {
                "X": endpointvector.x,
                "Y": endpointvector.y,
                "I": offsetvector.x,
                "J": offsetvector.y,
            },
        )
        results.append(arcmove)
        currLocation.update(arcmove.Parameters)

        # plunge back to depth
        plunge = Path.Command("G1", {"Z": zdepth})
        results.append(plunge)
        currLocation.update(plunge.Parameters)

        # The old arc move won't work so calculate a replacement command
        offsetv = arccenter.sub(endpointvector)

        replace = Path.Command(
            queue[0].Name,
            {"X": queue[0].X, "Y": queue[0].Y, "I": offsetv.x, "J": offsetv.y},
        )
        return (results, replace)

    def lineExtension(self, obj, queue):
        """returns gcode for line extension"""
        global currLocation

        offset = float(obj.offset)
        results = []

        v1 = queue[1].Placement.Base.sub(queue[2].Placement.Base)

        # extend the current segment to comp for offset
        segAngle = D.angle(
            v1, FreeCAD.Base.Vector(1, 0, 0), FreeCAD.Base.Vector(0, 0, -1)
        )
        xoffset = math.cos(segAngle) * offset
        yoffset = math.sin(segAngle) * offset

        newX = currLocation["X"] + xoffset
        newY = currLocation["Y"] + yoffset

        extendcommand = Path.Command("G1", {"X": newX, "Y": newY})
        results.append(extendcommand)

        currLocation.update(extendcommand.Parameters)

        replace = None
        return (results, replace)

    def lineTwist(self, obj, queue, lastXY, twistCW=False):
        """returns gcode to do an arc move toward a line to perform
        a corner action twist. Includes lifting and plungeing the knife"""
        global currLocation
        pivotheight = obj.pivotheight
        offset = obj.offset

        results = []

        # set the correct twist command
        if twistCW is False:
            arcdir = "G3"
        else:
            arcdir = "G2"

        # move to pivot height
        zdepth = currLocation["Z"]
        retract = Path.Command("G0", {"Z": pivotheight})
        results.append(retract)
        currLocation.update(retract.Parameters)

        C = queue[1].Placement.Base

        # get the vectors between endpoints to calculate twist
        v2 = queue[0].Placement.Base.sub(queue[1].Placement.Base)

        # calc arc endpoints to twist to
        segAngle = D.angle(
            v2, FreeCAD.Base.Vector(1, 0, 0), FreeCAD.Base.Vector(0, 0, -1)
        )
        xoffset = math.cos(segAngle) * offset
        yoffset = math.sin(segAngle) * offset
        newX = queue[1].x + xoffset
        newY = queue[1].y + yoffset

        offsetvector = C.sub(lastXY)
        I = offsetvector.x
        J = offsetvector.y

        # add the arc move
        arcmove = Path.Command(
            arcdir, {"X": newX, "Y": newY, "I": I, "J": J}
        )  # add G2/G3 move
        results.append(arcmove)

        currLocation.update(arcmove.Parameters)

        # plunge back to depth
        plunge = Path.Command("G1", {"Z": zdepth})
        results.append(plunge)
        currLocation.update(plunge.Parameters)

        replace = None
        return (results, replace)

    def execute(self, obj):
        newpath = []
        global currLocation

        if not obj.Base:
            return

        if not obj.Base.isDerivedFrom("Path::Feature"):
            return

        if obj.Base.Path.Commands:

            firstmove = Path.Command("G0", {"X": 0, "Y": 0, "Z": 0})
            currLocation.update(firstmove.Parameters)

            queue = []

            for curCommand in PathUtils.getPathWithPlacement(obj.Base).Commands:
                replace = None
                # don't worry about non-move commands, just add to output
                if curCommand.Name not in movecommands + rapidcommands:
                    newpath.append(curCommand)
                    continue

                if curCommand.x is None:
                    curCommand.x = currLocation["X"]
                if curCommand.y is None:
                    curCommand.y = currLocation["Y"]
                if curCommand.z is None:
                    curCommand.z = currLocation["Z"]

                # rapid retract triggers exit move, else just add to output
                if curCommand.Name in rapidcommands:
                    if (curCommand.z > obj.pivotheight) and (len(queue) == 3):
                        # Process the exit move
                        tempqueue = queue
                        tempqueue.insert(0, curCommand)

                        if queue[1].Name in ["G01", "G1"]:
                            temp = self.lineExtension(obj, tempqueue)
                            newpath.extend(temp[0])
                            lastxy = temp[0][-1].Placement.Base
                        elif queue[1].Name in arccommands:
                            temp = self.arcExtension(obj, tempqueue)
                            newpath.extend(temp[0])
                            lastxy = temp[0][-1].Placement.Base

                    newpath.append(curCommand)
                    currLocation.update(curCommand.Parameters)
                    queue = []
                    continue

                # keep a queue of feed moves and check for needed corners
                if curCommand.Name in movecommands:
                    changedXYFlag = False
                    if queue:
                        if (curCommand.x != queue[0].x) or (curCommand.y != queue[0].y):
                            queue.insert(0, curCommand)
                            if len(queue) > 3:
                                queue.pop()
                            changedXYFlag = True
                    else:
                        queue = [curCommand]

                    # vertical feeding to depth
                    if curCommand.z != currLocation["Z"]:
                        newpath.append(curCommand)
                        currLocation.update(curCommand.Parameters)
                        continue

                    # Corner possibly needed
                    if changedXYFlag and (len(queue) == 3):

                        # check if the inciden angle incident exceeds the filter
                        incident_angle = self.getIncidentAngle(queue)

                        if abs(incident_angle) >= obj.filterAngle:
                            if self.shortcut(queue) == "CW":
                                # if incident_angle >= 0:
                                twistCW = True
                            else:
                                twistCW = False
                            #
                            #  DO THE EXTENSION
                            #
                            if queue[1].Name in ["G01", "G1"]:
                                temp = self.lineExtension(obj, queue)
                                newpath.extend(temp[0])
                                replace = temp[1]
                                lastxy = temp[0][-1].Placement.Base
                            elif queue[1].Name in arccommands:
                                temp = self.arcExtension(obj, queue)
                                newpath.extend(temp[0])
                                replace = temp[1]
                                lastxy = temp[0][-1].Placement.Base
                            else:
                                FreeCAD.Console.PrintWarning("I don't know what's up")
                            #
                            #  DO THE TWIST
                            #
                            if queue[0].Name in ["G01", "G1"]:
                                temp = self.lineTwist(obj, queue, lastxy, twistCW)
                                replace = temp[1]
                                newpath.extend(temp[0])
                            elif queue[0].Name in arccommands:
                                temp = self.arcTwist(obj, queue, lastxy, twistCW)
                                replace = temp[1]
                                newpath.extend(temp[0])
                            else:
                                FreeCAD.Console.PrintWarning("I don't know what's up")
                    if replace is None:
                        newpath.append(curCommand)
                    else:
                        newpath.append(replace)
                    currLocation.update(curCommand.Parameters)
                    continue

            commands = newpath
            path = Path.Path(commands)
            obj.Path = path

class TaskPanel:
    def __init__(self, obj):
        self.obj = obj
        self.form = FreeCADGui.PySideUic.loadUi(":/panels/DragKnifeEdit.ui")
        self.filterAngle = PathGuiUtil.QuantitySpinBox(
            self.form.filterAngle, obj, "filterAngle"
        )
        self.offsetDistance = PathGuiUtil.QuantitySpinBox(
            self.form.offsetDistance, obj, "offset"
        )
        self.pivotHeight = PathGuiUtil.QuantitySpinBox(
            self.form.pivotHeight, obj, "pivotheight"
        )

        FreeCAD.ActiveDocument.openTransaction("Edit Dragknife Dress-up")

    def reject(self):
        FreeCAD.ActiveDocument.abortTransaction()
        FreeCADGui.Control.closeDialog()
        FreeCAD.ActiveDocument.recompute()

    def accept(self):
        self.getFields()
        FreeCAD.ActiveDocument.commitTransaction()
        FreeCADGui.ActiveDocument.resetEdit()
        FreeCADGui.Control.closeDialog()
        FreeCAD.ActiveDocument.recompute()

    def getFields(self):
        self.filterAngle.updateProperty()
        self.offsetDistance.updateProperty()
        self.pivotHeight.updateProperty()
        self.updateUI()

        self.obj.Proxy.execute(self.obj)

    def updateUI(self):
        self.filterAngle.updateSpinBox()
        self.offsetDistance.updateSpinBox()
        self.pivotHeight.updateSpinBox()

    def updateModel(self):
        self.getFields()
        FreeCAD.ActiveDocument.recompute()

    def setFields(self):
        self.updateUI()

    def open(self):
        pass

    def setupUi(self):
        self.setFields()

class ViewProviderDressup:
    def __init__(self, vobj):
        self.Object = vobj.Object

    def attach(self, vobj):
        self.Object = vobj.Object
        if self.Object and self.Object.Base:
            for i in self.Object.Base.InList:
                if hasattr(i, "Group"):
                    group = i.Group
                    for g in group:
                        if g.Name == self.Object.Base.Name:
                            group.remove(g)
                    i.Group = group
                    print(i.Group)
            # FreeCADGui.ActiveDocument.getObject(obj.Base.Name).Visibility = False

    def unsetEdit(self, vobj, mode=0):
        return False

    def setEdit(self, vobj, mode=0):
        FreeCADGui.Control.closeDialog()
        panel = TaskPanel(vobj.Object)
        FreeCADGui.Control.showDialog(panel)
        panel.setupUi()
        return True

    def claimChildren(self):
        return [self.Object.Base]

    def dumps(self):
        return None

    def loads(self, state):
        return None

    def onDelete(self, arg1=None, arg2=None):
        if arg1.Object and arg1.Object.Base:
            FreeCADGui.ActiveDocument.getObject(arg1.Object.Base.Name).Visibility = True
            job = PathUtils.findParentJob(arg1.Object.Base)
            if job:
                job.Proxy.addOperation(arg1.Object.Base, arg1.Object)
            arg1.Object.Base = None
        return True

class CommandDressupDragknife:
    def GetResources(self):
        return {
            "Pixmap": "Path_Dressup",
            "MenuText": QT_TRANSLATE_NOOP("Path_DressupDragKnife", "DragKnife"),
            "ToolTip": QT_TRANSLATE_NOOP(
                "Path_DressupDragKnife",
                "Modifies a path to add dragknife corner actions",
            ),
        }

    def IsActive(self):
        if FreeCAD.ActiveDocument is not None:
            for o in FreeCAD.ActiveDocument.Objects:
                if o.Name[:3] == "Job":
                    return True
        return False

    def Activated(self):

        # check that the selection contains exactly what we want
        selection = FreeCADGui.Selection.getSelection()
        if len(selection) != 1:
            FreeCAD.Console.PrintError(
                translate("Path_DressupDragKnife", "Please select one path object")
                + "\n"
            )
            return
        if not selection[0].isDerivedFrom("Path::Feature"):
            FreeCAD.Console.PrintError(
                translate("Path_DressupDragKnife", "The selected object is not a path")
                + "\n"
            )
            return
        if selection[0].isDerivedFrom("Path::FeatureCompoundPython"):
            FreeCAD.Console.PrintError(
                translate("Path_DressupDragKnife", "Please select a Path object")
            )
            return

        # everything ok!
        FreeCAD.ActiveDocument.openTransaction("Create Dress-up")
        FreeCADGui.addModule("Path.Dressup.Gui.Dragknife")
        FreeCADGui.addModule("PathScripts.PathUtils")
        FreeCADGui.doCommand(
            'obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython","DragknifeDressup")'
        )
        FreeCADGui.doCommand("Path.Dressup.Gui.Dragknife.ObjectDressup(obj)")
        FreeCADGui.doCommand("base = FreeCAD.ActiveDocument." + selection[0].Name)
        FreeCADGui.doCommand("job = PathScripts.PathUtils.findParentJob(base)")
        FreeCADGui.doCommand("obj.Base = base")
        FreeCADGui.doCommand("job.Proxy.addOperation(obj, base)")
        FreeCADGui.doCommand(
            "obj.ViewObject.Proxy = Path.Dressup.Gui.Dragknife.ViewProviderDressup(obj.ViewObject)"
        )
        FreeCADGui.doCommand(
            "Gui.ActiveDocument.getObject(base.Name).Visibility = False"
        )
        FreeCADGui.doCommand("obj.filterAngle = 20")
        FreeCADGui.doCommand("obj.offset = 2")
        FreeCADGui.doCommand("obj.pivotheight = 4")
        FreeCADGui.doCommand("obj.ViewObject.Document.setEdit(obj.ViewObject, 0)")

        # FreeCAD.ActiveDocument.commitTransaction()  # Final `commitTransaction()` called via TaskPanel.accept()
        FreeCAD.ActiveDocument.recompute()

if FreeCAD.GuiUp:
    # register the FreeCAD command
    FreeCADGui.addCommand("Path_DressupDragKnife", CommandDressupDragknife())

FreeCAD.Console.PrintLog("Loading Path_DressupDragKnife... done\n")


import requests
from django import template
from machina.core.db.models import get_model
from machina.core.loading import get_class

from home.models import Advert, Sponsor

Forum = get_model('forum', 'Forum')
Topic = get_model('forum_conversation', 'Topic')
TopicPollVoteForm = get_class('forum_polls.forms', 'TopicPollVoteForm')
register = template.Library()

@register.inclusion_tag('home/tags/adverts.html', takes_context=True)
def adverts(context):
    return {
        'adverts': Advert.objects.all(),
        'request': context['request'],
    }

@register.inclusion_tag('home/tags/sponsors.html', takes_context=True)
def sponsors(context):
    return {
        'sponsors': Sponsor.objects.all(),
    }

@register.simple_tag()
def last_topics(request):
    allowed_forums = request.forum_permission_handler._get_forums_for_user(request.user,[ 'can_read_forum'])
    last_topics = Topic.objects.filter(forum__in=allowed_forums).order_by('-last_post_on')[:4]
    return last_topics

@register.simple_tag()
def discord_users():
    r = requests.get('https://discordapp.com/api/guilds/287487891003932672/widget.json')
    disc_users = r.json()['members']
    return disc_users

@register.simple_tag()
def get_poll_form(poll):
    return TopicPollVoteForm(poll=poll)


"""Miscellaneous utilities"""

# Standard library
import inspect
import contextlib
from functools import wraps
import os
from distutils.version import LooseVersion
from tempfile import NamedTemporaryFile

# Third-party
import astropy.units as u
from astropy.table.meta import get_header_from_yaml
from astropy.io.misc.hdf5 import meta_path
import h5py
import numpy as np
import tables as tb

# Package
from .samples import JokerSamples

# TODO: remove this when we drop support for numpy 1.16
# Numpy version:
NUMPY_LT_1_17 = LooseVersion(np.__version__) < '1.17'

if NUMPY_LT_1_17:
    DEFAULT_RNG = np.random.RandomState
    integers = lambda obj, *args, **kwargs: obj.randint(*args, **kwargs)
else:
    DEFAULT_RNG = np.random.default_rng
    integers = lambda obj, *args, **kwargs: obj.integers(*args, **kwargs)

__all__ = ['batch_tasks', 'table_header_to_units', 'read_batch',
           'tempfile_decorator']

def batch_tasks(n_tasks, n_batches, arr=None, args=None, start_idx=0):
    """Split the tasks into some number of batches to sent out to MPI workers.

    Parameters
    ----------
    n_tasks : int
        The total number of tasks to divide.
    n_batches : int
        The number of batches to split the tasks into. Often, you may want to do
        ``n_batches=pool.size`` for equal sharing amongst MPI workers.
    arr : iterable (optional)
        Instead of returning indices that specify the batches, you can also
        directly split an array into batches.
    args : iterable (optional)
        Other arguments to add to each task.
    start_idx : int (optional)
        What index in the tasks to start from?

    """
    if args is None:
        args = []
    args = list(args)

    tasks = []
    if n_batches > 0 and n_tasks >= n_batches:
        # chunk by the number of batches, often the pool size
        base_batch_size = n_tasks // n_batches
        rmdr = n_tasks % n_batches

        i1 = start_idx
        for i in range(n_batches):
            i2 = i1 + base_batch_size
            if i < rmdr:
                i2 += 1

            if arr is None:  # store indices
                tasks.append([(i1, i2), i1] + args)

            else:  # store sliced array
                tasks.append([arr[i1:i2], i1] + args)

            i1 = i2

    else:
        if arr is None:  # store indices
            tasks.append([(start_idx, n_tasks+start_idx), start_idx] + args)

        else:  # store sliced array
            tasks.append([arr[start_idx:n_tasks+start_idx], start_idx] + args)

    return tasks

def table_header_to_units(header_dataset):
    """
    Convert a YAML-ized astropy.table header into a dictionary that maps from
    column name to unit.
    """

    header = get_header_from_yaml(h.decode('utf-8')
                                  for h in header_dataset)

    units = dict()
    for row in header['datatype']:
        units[row['name']] = u.Unit(row.get('unit', u.one))

    return units

def table_contains_column(root, column):
    from .samples import JokerSamples

    path = meta_path(JokerSamples._hdf5_path)
    header = get_header_from_yaml(h.decode('utf-8') for h in root[path])

    columns = []
    for row in header['datatype']:
        columns.append(row['name'])

    return column in columns

def read_batch(prior_samples_file, columns, slice_or_idx, units=None,
               random_state=None):
    """
    Single-point interface to all read_batch functions below that infers the
    type of read from the ``slice_or_idx`` argument.

    Parameters
    ----------
    prior_samples_file : `str`
        Path to an HDF5 file containing prior samples from The Joker.
    columns : `list`, iterable
        A list of string column names to read in to the batch.
    slice_or_idx : `slice`, `int`, `numpy.ndarray`
        This determines what rows are read in to the batch from the prior
        samples file. If a slice or tuple, this is interpreted as a range of
        contiguous row indices to read. If an integer, this is interpreted as
        the size used to generate random row indices. If a numpy array, this is
        interpreted as the row indices to read.
    units : dict (optional)
        The desired output units to convert the prior samples to.
    random_state : `numpy.random.RandomState`
        Used to generate random row indices if passing an integer (size) in to
        ``slice_or_idx``. This argument is ignored for other read methods.

    Returns
    -------
    batch : `numpy.ndarray`
        The batch of prior samples, loaded into a numpy array and stripped of
        units (converted to the specified ``units``). This array will have
        shape: ``(n_samples, len(columns))``.
    """
    if isinstance(slice_or_idx, tuple):
        # read a contiguous batch of prior samples
        batch = read_batch(prior_samples_file, columns,
                           slice(*slice_or_idx), units=units)

    elif isinstance(slice_or_idx, slice):
        # read a contiguous batch of prior samples
        batch = read_batch_slice(prior_samples_file, columns,
                                 slice_or_idx, units=units)

    elif isinstance(slice_or_idx, int):
        # read a random batch of samples of size "slice_or_idx"
        batch = read_random_batch(prior_samples_file, columns,
                                  slice_or_idx, units=units,
                                  random_state=random_state)

    elif isinstance(slice_or_idx, np.ndarray):
        # read a random batch of samples of size "slice_or_idx"
        batch = read_batch_idx(prior_samples_file, columns,
                               slice_or_idx, units=units)

    else:
        raise ValueError("Invalid input for slice_or_idx: must be a slice, "
                         "int, or numpy array.")

    return batch

def read_batch_slice(prior_samples_file, columns, slice, units=None):
    """
    Read a batch (row block) of prior samples into a plain numpy array,
    converting units where necessary.
    """

    path = JokerSamples._hdf5_path

    # We have to do this with h5py because current (2021-02-05) versions of
    # pytables don't support variable length strings, which h5py is using to
    # serialize units in the astropy table metadata
    with h5py.File(prior_samples_file, mode='r') as f:
        table_units = table_header_to_units(f[meta_path(path)])

    batch = None
    with tb.open_file(prior_samples_file, mode='r') as f:

        for i, name in enumerate(columns):
            arr = f.root[path].read(slice.start, slice.stop, slice.step,
                                    field=name)
            if batch is None:
                batch = np.zeros((len(arr), len(columns)), dtype=arr.dtype)
            batch[:, i] = arr

        if units is not None:
            # See comment above
            # table_units = table_header_to_units(f.root[meta_path(path)])
            for i, name in enumerate(columns):
                if name in units:
                    batch[:, i] *= table_units[name].to(units[name])

    return batch

def read_batch_idx(prior_samples_file, columns, idx, units=None):
    """
    Read a batch (row block) of prior samples specified by the input index
    array, ``idx``, into a plain numpy array, converting units where necessary.
    """
    path = JokerSamples._hdf5_path

    # We have to do this with h5py because current (2021-02-05) versions of
    # pytables don't support variable length strings, which h5py is using to
    # serialize units in the astropy table metadata
    with h5py.File(prior_samples_file, mode='r') as f:
        table_units = table_header_to_units(f[meta_path(path)])

    batch = np.zeros((len(idx), len(columns)))
    with tb.open_file(prior_samples_file, mode='r') as f:
        for i, name in enumerate(columns):
            batch[:, i] = f.root[path].read_coordinates(idx, field=name)

        if units is not None:
            # See comment above
            # table_units = table_header_to_units(f.root[meta_path(path)])
            for i, name in enumerate(columns):
                if name in units:
                    batch[:, i] *= table_units[name].to(units[name])

    return batch

def read_random_batch(prior_samples_file, columns, size, units=None,
                      random_state=None):
    """
    Read a random batch (row block) of prior samples into a plain numpy array,
    converting units where necessary.
    """

    if random_state is None:
        random_state = DEFAULT_RNG()

    path = JokerSamples._hdf5_path
    with tb.open_file(prior_samples_file, mode='r') as f:
        idx = integers(random_state, 0, f.root[path].shape[0], size=size)

    return read_batch_idx(prior_samples_file, columns, idx=idx, units=units)

def tempfile_decorator(func):
    wrapped_signature = inspect.signature(func)
    func_args = list(wrapped_signature.parameters.keys())
    if 'prior_samples_file' not in func_args:
        raise ValueError("Cant decorate function because it doesn't contain an "
                         "argument called 'prior_samples_file'")

    @wraps(func)
    def wrapper(*args, **kwargs):
        args = list(args)
        if 'prior_samples_file' in kwargs:
            prior_samples = kwargs['prior_samples_file']
        else:
            prior_samples = args.pop(func_args.index('prior_samples_file'))

        in_memory = kwargs.get('in_memory', False)

        if not isinstance(prior_samples, str) and not in_memory:
            if not isinstance(prior_samples, JokerSamples):
                raise TypeError("prior_samples_file must either be a string "
                                "filename specifying a cache file contining "
                                "prior samples, or must be a JokerSamples "
                                f"instance, not: {type(prior_samples)}")

            # This is required (instead of a context) because the named file
            # can't be opened a second time on Windows...see, e.g.,
            # https://github.com/Kotaimen/awscfncli/issues/93
            f = NamedTemporaryFile(mode='r+', suffix='.hdf5', delete=False)
            f.close()

            try:
                # write samples to tempfile and recursively call this method
                prior_samples.write(f.name, overwrite=True)
                kwargs['prior_samples_file'] = f.name
                func_return = func(*args, **kwargs)
            except Exception as e:
                raise e
            finally:
                os.unlink(f.name)

        else:
            # FIXME: it's a string, so it's probably a filename, but we should
            # validate the contents of the file!
            kwargs['prior_samples_file'] = prior_samples
            func_return = func(*args, **kwargs)

        return func_return

    return wrapper

@contextlib.contextmanager
def random_state_context(random_state):
    state = np.random.get_state()
    if random_state is not None:
        np.random.seed(integers(random_state, 2**32-1))  # HACK
    try:
        yield
    finally:
        if random_state is not None:
            np.random.set_state(state)


import tornado
from tornado.web import Application, RequestHandler, authenticated
from tornado.websocket import WebSocketHandler
from qavifiserver.qahqchart import QAHqchartDailyHandler, QAHqchartKlineHandler

__version__ = '0.0.2'
__author__ = 'yutiansut'

def run_server():

    app=Application(
        handlers=[
            (r"/test",  QAHqchartDailyHandler),
            (r"/testk", QAHqchartKlineHandler)
        ],
        debug=True
    )
    app.listen(8029)
    tornado.ioloop.IOLoop.current().start()


from lib import config
from lib import functions
from lib import timezones
from lib import feedparser
from lib import seismograph
from models import earthquake
from google.appengine.ext import db
from google.appengine.api import users
from google.appengine.ext import webapp
from google.appengine.api import memcache
from google.appengine.ext.webapp import template
from google.appengine.ext.webapp.util import run_wsgi_app

import os, re, logging, datetime

template.register_template_library('lib.templatefilters')

class ShutdownPage(webapp.RequestHandler):
  def get(self):
    template_values = {
      'host_url': self.request.host_url,
      'deployed': functions.deployed(self.request.host_url)
    }

    template_path = os.path.join(os.path.dirname(__file__), "template/base_shutdown.html")
    self.response.out.write(template.render(template_path, template_values))

class RedirectToShutdownPage(webapp.RequestHandler):
  def get(self):
    self.redirect("/")

class MainPage(webapp.RequestHandler):
  def get(self):
    today = datetime.datetime.utcnow().replace(tzinfo=timezones.UTC()).astimezone(timezones.UTC1()).replace(hour=0, minute=0, second=0, microsecond=0)
    yesterday = today - datetime.timedelta(1)

    entries_today = earthquake.Earthquake.gql("WHERE time >= :1 AND object_type = :2 ORDER BY time DESC", today, db.Category("Normal"))

    entries_yesterday = earthquake.get_yesterday(limit=5, order="ORDER BY time DESC")

    entries_before = earthquake.get_before(limit = 5)

    entries_special = earthquake.get_special()

    if re.search('highlight_today', self.request.query_string):
      highlight_today = True
    else:
      highlight_today = False

    template_values = {
      'entries_today': entries_today,
      'entries_yesterday': entries_yesterday,
      'entries_before': entries_before,
      'entries_special': entries_special,
      'entries_special_count': earthquake.get_special_count(),
      'entries_today_count': functions.count(entries_today),
      'entries_yesterday_count': earthquake.get_yesterday_count(),
      'today': today,
      'yesterday': yesterday,
      'now': datetime.datetime.utcnow().replace(tzinfo=timezones.UTC()),
      'highlight_today': highlight_today,
      'host_url': self.request.host_url,
      'deployed': functions.deployed(self.request.host_url)
    }

    template_path = os.path.join(os.path.dirname(__file__), "template/base_index.html")
    self.response.out.write(template.render(template_path, template_values))

class EarthquakeManager(webapp.RequestHandler):
  def get(self):
    k = self.request.path.split("/")[2]
    try:
      earthquake = db.get(k)

      if earthquake is None:
        self.redirect(self.request.host)

      today = datetime.datetime.utcnow().replace(tzinfo=timezones.UTC()).astimezone(timezones.UTC1()).replace(hour=0, minute=0, second=0, microsecond=0)
      yesterday = today - datetime.timedelta(1)

      earthquake_time = earthquake.time.replace(tzinfo=timezones.UTC()).astimezone(timezones.UTC1())

      if earthquake_time >= today:
        time_class = "today"
      elif earthquake_time >= yesterday and earthquake_time < today:
        time_class = "yesterday"
      else:
        time_class = "before"

      if earthquake.object_type == db.Category("Special"):
        time_class = "special"

      maps_api = config.Config().google_maps_api_key()

      template_values = {
        'earthquake': earthquake,
        'time_class': time_class,
        'today': today,
        'yesterday': yesterday,
        'maps_api': maps_api,
        'host_url': self.request.host_url,
        'deployed': functions.deployed(self.request.host_url)
      }

      template_path = os.path.join(os.path.dirname(__file__), "template/base_earthquake.html")
      self.response.out.write(template.render(template_path, template_values))
    # if some error happens, just redirect
    except:
      self.redirect('/')

class TimeManager(webapp.RequestHandler):
  def get(self):
    t = self.request.path.split('/')[1]
    q = self.request.query_string

    page = 0
    per_page = 10

    # this piece of code fishes out query strings, and even though it may appear
    # quite scary and confusing, it actually has never been fishing before
    # not for query strings, not even for fishes
    if q:
      if q.find("&") > -1:
        q = q.split("&")
        for i in range(0, len(q)):
          if q[i].find("=") > -1:
            q[i] = q[i].split("=")
            if q[i][0] == 'page' or q[i][0] == 'strana':
              page = int(q[i][1])
            elif q[i][0] == 'per_page' or q[i][0] == 'po_strana':
              per_page = int(q[i][1])
      elif q.find("&") < 0 and q.find("=") > -1:
        q = q.split("=")
        if q[0] == 'page' or q[0] == 'strana':
          page = int(q[1])
        elif q[0] == 'per_page' or q[0] == 'po_strana':
          per_page = int(q[1])

    today = datetime.datetime.utcnow().replace(tzinfo=timezones.UTC()).astimezone(timezones.UTC1()).replace(hour=0, minute=0, second=0, microsecond=0)
    yesterday = today - datetime.timedelta(1)

    time_class = ''

    if t == 'vcera' or t == 'vchera':
      entries_count = earthquake.get_yesterday_count()

      if entries_count > 0:
        entries = earthquake.get_yesterday(
          limit= "%s OFFSET %s" % (per_page, page*per_page),
          order= "ORDER BY time DESC"
        )
      else:
        entries = []

      time_class = 'yesterday'
      time_class_cyr = '\xd0\x92\xd1\x87\xd0\xb5\xd1\x80\xd0\xb0'

    elif t == 'predtoa':
      entries_count = earthquake.get_before_count()

      if entries_count > 0:
        entries = earthquake.get_before(
          limit= "%s OFFSET %s" % (per_page, page*per_page),
          order= "ORDER BY time DESC"
        )
      else:
        entries = []

      time_class = 'before'
      time_class_cyr = '\xd0\x9f\xd1\x80\xd0\xb5\xd0\xb4\xd1\x82\xd0\xbe\xd0\xb0'
    # TODO: add a 'thedayaftertomorrow' timeline option :P

    # some pagination magic!
    if per_page > entries_count:
      per_page = entries_count

    if per_page == 0:
      max_pages = 1
    else:
      max_pages = (entries_count / per_page) - 1

    # if a person lands on an empty airfield,
    # tell his plane to re-land on the other, closest to this one
    # and please, oh please do tell
    # that the person cannot land!
    if page > max_pages:
      self.redirect(self.request.host_url +
        self.request.path +
        "?page=" + str(max_pages) +
        "&per_page=" + str(per_page))

    if page + 1 <= max_pages:
      next_page = page + 1
    else:
      next_page = None

    if page - 1 > -1:
      prev_page = page - 1
    else:
      prev_page = None

    if time_class == 'yesterday':
      simpletime = 1
    else:
      simpletime = None

    template_values = {
      'entries': entries,
      'entries_count': entries_count,
      'time_class': time_class,
      'time_class_cyr': time_class_cyr,
      'next_page': next_page,
      'prev_page': prev_page,
      'per_page': per_page,
      'simpletime': simpletime,
      'yesterday': yesterday,
      'host_url': self.request.host_url,
      'deployed': functions.deployed(self.request.host_url)
    }

    template_path = os.path.join(os.path.dirname(__file__), "template/base_timeline.html")
    self.response.out.write(template.render(template_path, template_values))

class FeedManager(webapp.RequestHandler):
  def get(self):
    last_change = earthquake.Earthquake.gql("ORDER BY time DESC LIMIT 1")
    for chng in last_change:
      last_change = chng
      break

    entries = earthquake.Earthquake.gql("ORDER BY time DESC LIMIT 15")

    template_values = {
      'entries': entries,
      'uri': self.request.uri,
      'last_change': last_change,
      'host_url': self.request.host_url
    }

    template_path = os.path.join(os.path.dirname(__file__), "template/feed/atom.xml")
    self.response.headers['Content-Type'] = 'application/atom+xml'
    self.response.out.write(template.render(template_path, template_values))

class CronUpdate(webapp.RequestHandler):
  def get(self):
    s = seismograph.Seismograph()
    sense_data = s.sense()
    s.add_to_db(sense_data)

class MemcacheStats(webapp.RequestHandler):
  def get(self):
    self.response.out.write(memcache.get_stats())

class MemcacheFlush(webapp.RequestHandler):
  def get(self):
    memcache.flush_all()
    self.redirect('/')

class DeleteEverything(webapp.RequestHandler):
  def get(self):
    everything = db.GqlQuery("SELECT __key__ FROM Earthquake ORDER BY time DESC")
    everything = everything.fetch(1000)
    self.response.out.write("Please wait. Deleting everything!")

    db.delete(everything)

application = webapp.WSGIApplication([('/', MainPage),
                                      #('/atom', FeedManager),
                                      ('/update', CronUpdate),
                                      #(r'/predtoa', TimeManager),
                                      ('/memcache_stats', MemcacheStats),
                                      ('/memcache_flush', MemcacheFlush),
                                      ('/delete_everything', DeleteEverything),
                                      #(r'/.*', RedirectToShutdownPage), # since shutdown
                                      (r'/zemjotres/.*', EarthquakeManager),
                                      (r'/.*', TimeManager)
                                     ],
                                     debug=True)
if __name__ == "__main__":
  logging.getLogger().setLevel(logging.DEBUG)
  run_wsgi_app(application)


import argparse
import time
import random
import numpy as np
import torch
import torch.nn as nn
import torch.optim as optim
from model import CNN
from loss import Energy_Loss
from torch.utils.data import DataLoader
from utils import *

def train(args, model, optimizer, criterion, train_loader, epoch):
    model.train()
    for batch_idx, (input, target) in enumerate(train_loader):
        if args.use_cuda:
            input, target = input.cuda(args.device, non_blocking=True), target.cuda(
                args.device, non_blocking=True)
        optimizer.zero_grad()
        output, _ = model(input)
        loss = criterion(output, target)
        loss.backward()
        optimizer.step()
        if (batch_idx) * train_loader.batch_size % args.log_rate == 0:
            print('\rTrain Epoch: {} [{}/{} ({:.0f}%)] Loss: {:.6f}'.format(
                epoch, (batch_idx) *
                (train_loader.batch_size), len(train_loader.dataset),
                100. * (batch_idx) / len(train_loader), loss.item()/train_loader.batch_size), end='')
    print()

# tests model to make sure the correct word is the lowest energy

def test1(args, model, criterion, test_loader):
    model.eval()
    correct = 0
    total = 0
    test_loss = 0.0
    with torch.no_grad():
        for i, (input, target) in enumerate(test_loader):
            if args.use_cuda:
                input, target = input.cuda(args.device, non_blocking=True), target.cuda(
                    args.device, non_blocking=True)
            outputs, _ = model(input)
            test_loss += criterion(outputs, target)
            v, j = outputs.min(1)
            # correct ones are 0.
            correct += test_loader.batch_size - torch.nonzero(j).size()[0]
            total += test_loader.batch_size
    print("Test 1: Avg Loss: {:.3f}, Accuracy: {:.3f}".format(
        test_loss/total, correct/total))

# test model to compare 5 correct and 5 incorrect words for energy level.

def test2(args, model, criterion, test_loader):
    model.eval()
    correct = 0
    avg_top5 = 0
    total = 0
    with torch.no_grad():
        for i, (input, target) in enumerate(test_loader):
            if args.use_cuda:
                input, target = input.cuda(args.device, non_blocking=True), target.cuda(
                    args.device, non_blocking=True)
            outputs, _ = model(input)
            # ravel index into 1d
            outputs = outputs.view(-1)
            # get the top half.
            v, i = torch.topk(outputs, test_loader.batch_size, largest=False)
            # unravel index and then see if 2nd index set is all 0s
            # meaning smallest energy levels in the first  column.
            i1d = np.unravel_index(i, (test_loader.batch_size, 2))
            if not np.any(i1d[1]):
                correct += 1
            avg_top5 += test_loader.batch_size - np.sum(i1d[1])
            total += 1
    print("Test 2: Accuracy: {:.3f}, Avg # correct in top5: {:.3f}".format(
        correct/total, avg_top5/total))

def main():
    parser = argparse.ArgumentParser(
        description='Training Energy NN for Spell Correction')
    parser.add_argument('--vocab_file', type=str, default="data/wikipedia.vocab.txt",
                        help='vocabulary file path')
    parser.add_argument('--model_save_file', type=str, default='models/energy_cnn',
                        help='model save path')
    parser.add_argument('--ttsplit', action='store_true', default=False,
                        help='enables train/test splitting (80-20)')
    parser.add_argument('--topk', type=int, default=100000,
                        help="train on top k most common words in vocabulary (default: 100000)")
    parser.add_argument('--epochs', type=int, default=25, metavar='N',
                        help='number of epochs to train (default: 25)')
    parser.add_argument('--lr', type=float, default=0.001, metavar='LR',
                        help='learning rate (default: 0.001)')
    parser.add_argument('--train_num_neg', type=int, default=31,
                        help='number of negative examples in each training batch (default: 31)')
    parser.add_argument('--batch_size', type=int, default=25,
                        help='number of examples in each batch (default: 25)')
    parser.add_argument('--test_num_neg', type=int, default=9,
                        help='number of negative examples in each test (default: 9)')
    parser.add_argument('--beta', type=float, default=1, metavar='B',
                        help='Inverse Temperature value for Energy function (default: 1)')
    parser.add_argument('--log_rate', type=float, default=1000,
                        help='number of samples per log (default: 1000)')
    parser.add_argument('--num_workers', type=int, default=1,
                        help='number of dataloader workers (default: 1)')
    parser.add_argument('--no-cuda', action='store_true', default=False,
                        help='disables CUDA training')
    # some settings for training on specific edits.
    parser.add_argument('--edit', type=int, default=0,
                        help='choose a specific edit. 0:all, 1:swap, 2:add/del, 3:replace (default: 0)')
    args = parser.parse_args()
    args.use_cuda = not args.no_cuda and torch.cuda.is_available()
    args.device = torch.device("cuda" if args.use_cuda else "cpu")
    kwargs = {'num_workers': args.num_workers,
              'pin_memory': True} if args.use_cuda else {}
    print("Using Device: {} with {} workers".format(
        args.device, args.num_workers))

    # instantiate CNN, loss, and optimizer.
    print("Initializing Model...")
    model = CNN(n_chars, 10, 1, 256, [1, 2, 3, 4, 5, 6, 7, 8], 0.25, 100, 1).to(
        device=args.device)
    print("Initializing Energy Loss with beta = {}".format(args.beta))
    criterion = Energy_Loss(beta=args.beta)
    print("Initializing Adam optimizer with lr = {}".format(args.lr))
    optimizer = optim.Adam(model.parameters(), lr=args.lr)
    vocab, freq_dict = read_vocab(args.vocab_file, topk=args.topk)
    print("Using wikipedia vocab of size = {}".format(len(vocab)))

    if args.ttsplit:
        print("Train/Test Splitting - Enabled")
        # default use 0.8 train-test split...
        trainset, testset = traintest_split(vocab, p=0.8)
    else:
        print("Train/Test Splitting - Disabled")
        trainset, testset = vocab, vocab

    print("Edit Parameter: {}".format(args.edit))

    # save dataset in the original GloVe format: word freq\n
    write_vocab_to_file(trainset, freq_dict, 'data/train.txt')
    write_vocab_to_file(testset, freq_dict, 'data/test.txt')

    train_dset = Dataset(trainset, num_neg=args.train_num_neg, edit=args.edit)
    train_loader = DataLoader(train_dset, batch_size=args.batch_size,
                              shuffle=True, collate_fn=collate_fn, **kwargs)

    test1_dset = Dataset(testset, num_neg=args.test_num_neg, edit=args.edit)
    test1_loader = DataLoader(test1_dset, batch_size=args.batch_size,
                              shuffle=True, collate_fn=collate_fn, **kwargs)

    test2_dset = Dataset(testset, num_neg=1, edit=args.edit)
    test2_loader = DataLoader(test2_dset, batch_size=5,
                              shuffle=True, collate_fn=collate_fn, **kwargs)

    start = time.time()
    for epoch in range(1, args.epochs + 1):
        train(args, model, optimizer, criterion, train_loader, epoch)
        test1(args, model, criterion, test1_loader)
        test2(args, model, criterion, test2_loader)
        print("Time Elapsed: {} sec".format(time.time()-start))
    print("Saving model to {}".format(args.model_save_file))
    torch.save(model.state_dict(), args.model_save_file)

if __name__ == '__main__':
    main()


from django.shortcuts import render
from django.http import HttpResponseRedirect, HttpResponse
import copy
from .forms import FileForm
from .models import File
from .prediction import *

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

class CustomUnpickler(pickle.Unpickler):

    def find_class(self, module, name):
        if name == 'Vocabulary':
            return Vocabulary
        return super().find_class(module, name)

vocab = CustomUnpickler(open('/home/harshit/Downloads/vocab.pkl', 'rb')).load()

def handle_file(image):
    """process uploaded file"""
    # img = PIL.Image.open(image)
    # print(img.size)
    pass

def index(request):
    """homepage"""
    if request.method == 'POST':
        form = FileForm(request.POST, request.FILES)
        if form.is_valid():
            myfile = File(file=request.FILES['file'])
            form.save()
            file_name = myfile.file  # file attribute of File model object
            print(file_name)
            file_name_original = copy.copy(file_name)  # prevent name modification after saving file
            handle_file(myfile)
            # process image
            output = process(file_name,
                             '/home/harshit/Downloads/pretrained_model/encoder-5-3000.pkl',
                             '/home/harshit/Downloads/pretrained_model/decoder-5-3000.pkl',
                             vocab,
                             256, 512, 1)
            print(output)
            myfile.save()
            print(file_name)
            return render(request, 'captionApp/output.html', {'file_name': file_name,
                                                              'file_name_original': file_name_original,
                                                              'output': output})
            # return HttpResponse('File successfully uploaded!')
        # else:
        #     return HttpResponse('Something Went Wrong!')
    else:
        form = FileForm()
    return render(request, 'captionApp/index.html', {'form': form})

### For heroku  ###
# def index(request):
#     """homepage"""
#     if request.method == 'POST':
#         form = FileForm(request.POST, request.FILES)
#         if form.is_valid():
#             myfile = request.FILES['file']
#             print(myfile)
#             handle_file(myfile)
#             return render(request, 'captionApp/output.html', {'file': myfile})
#             # return HttpResponse('File successfully uploaded!')
#         # else:
#         #     return HttpResponse('Something Went Wrong!')
#     else:
#         form = FileForm()
#     return render(request, 'captionApp/index.html', {'form': form})


"""
# File       : txt2label.py
# Time       ：2023/5/5 22:39
# Author     ：zzx
# version    ：python 3.10
# Description：
"""

import os
import cv2
import json
import json
import numpy as np
from tqdm import tqdm

labels_txt = r'./multi_label.txt'
train_dir = r'../../data/train/train'
save_dir = r'../../data/train/train_crop_img'

os.makedirs(save_dir, exist_ok=True)
f1 = open(labels_txt, 'w')

for img_name in tqdm(os.listdir(train_dir)):
    if not img_name.endswith('jpg'):
        continue

    base_name = img_name.replace('.jpg', '')
    img_path = os.path.join(train_dir, img_name)
    label_path = os.path.join(train_dir, img_name.replace('.jpg', '.txt'))
    img = cv2.imread(img_path)

    H, W, C = img.shape
    with open(label_path, 'r') as f:
        json_data = json.load(f)
        # 可能有多个目标
        for index, label in enumerate(json_data):
            box_points = np.array(label["box_points"])
            box_attribute = label["box_attribute"]

            # print(box_points, box_attribute)

            # 切割出矩形框切割图形
            x_min = np.min(box_points[:, 0])
            x_max = np.max(box_points[:, 0])
            y_min = np.min(box_points[:, 1])
            y_max = np.max(box_points[:, 1])

            # 保存截图
            crop_img = img[y_min:min(y_max+1, H), x_min: min(x_max+1, W), :]
            save_path = os.path.join(save_dir, base_name+"_"+str(index)+".jpg")
            cv2.imwrite(save_path, crop_img)

            # 写入label
            x1, y1 = box_points[0, :]
            x2, y2 = box_points[1, :]
            x3, y3 = box_points[2, :]
            x4, y4 = box_points[3, :]
            rbox = [x1,y1, x2, y2, x3, y3, x4, y4]  # 可能是带旋转的
            rbox = [int(rb) for rb in rbox]

            w_box = x_max - x_min
            h_box = y_max - y_min
            box_ann = [x_min, y_min, w_box, h_box]
            box_ann = [int(b) for b in box_ann]

            red = box_attribute['red']
            green = box_attribute['green']
            blue = box_attribute['blue']
            bold = box_attribute['bold']
            italic = box_attribute['italic']
            delete_line = box_attribute['delete_line']
            underline = box_attribute['underline']

            f1.writelines(
                '{}\t{},{},{},{},{},{},{}\n'.format(base_name+"_"+str(index)+".jpg", red, green, blue, bold, italic, delete_line,
                                                    underline, ))

f1.close()


from collections import Counter

class Solution:
    def topKFrequent(self, nums: List[int], k: int) -> List[int]:
        ans = []
        temp = Counter(nums)

        tt = temp.most_common(k)
       # print(tt)
        for i in range(k):
            ans.append(tt[i][0])

        return ans


import asyncio
import itertools
import functools
import operator

async def aiter(aiterable):
    """The async version of the builtin ``iter``."""
    return await aiterable.__aiter__()

_sentinel = object()
async def anext(aiterable, default=_sentinel):
    """The async version of the builtin ``next``."""
    try:
        return await aiterable.__anext__()
    except StopAsyncIteration:
        if default is _sentinel:
            raise
        return default

def coroutine_iterator(afunc):
    class _CoroutineIteratorType(type):
        def __repr__(cls):
            return "<class '{module}.{name}'>".format(
                module=cls.__module__, name=cls.__name__)

    class CoroutineIterator(metaclass=_CoroutineIteratorType):
        def __init__(self, *args, **kwargs):
            self.__args = args
            self.__kwargs = kwargs
            self.__anext = _sentinel

        async def __aiter__(self):
            return self

        async def __anext__(self):
            if self.__anext is _sentinel:
                self.__anext = await afunc(*self.__args, **self.__kwargs)
                del self.__args, self.__kwargs
            return await self.__anext()

    CoroutineIterator.__name__ = afunc.__name__
    CoroutineIterator.__module__ = afunc.__module__
    return CoroutineIterator

@coroutine_iterator
async def to_aiter(iterable):
    iterator = iter(iterable)
    async def __anext__():
        try:
            return next(iterator)
        except StopIteration as e:
            raise StopAsyncIteration() from e
    return __anext__

def to_async(func):
    @functools.wraps(func)
    async def wrapper(*args, **kwargs):
        return func(*args, **kwargs)
    return wrapper

@coroutine_iterator
async def azip(*aiterables):
    aiters = await asyncio.gather(*tuple(map(aiter, aiterables)))
    async def __anext__():
        return tuple(await asyncio.gather(*tuple(map(anext, aiterables))))
    return __anext__

@coroutine_iterator
async def schedule(aiterable, scheduler):
    azipped = azip(aiterable, scheduler)
    async def __anext__():
        value, _ = await anext(azipped)
        return value
    return __anext__

async def alist(aiterable):
    values = []
    async for value in aiterable:
        values.append(value)
    return values

async def atuple(aiterable):
    return tuple(await alist(aiterable))

def acount(start=0, step=1):
    return to_aiter(itertools.count(start, step))

@coroutine_iterator
async def acycle(aiterable):
    aiterator = await aiter(aiterable)
    completed = False
    cache = []
    async def __anext__():
        nonlocal aiterator, completed
        try:
            value = await anext(aiterator)
            if not completed:
                cache.append(value)
            return value
        except StopAsyncIteration:
            completed = True
            aiterator = to_aiter(cache)
            return await anext(aiterator)
    return __anext__

def arepeat(object, times=_sentinel):
    args = () if times is _sentinel else (times,)
    return to_aiter(itertools.repeat(object, *args))

@coroutine_iterator
async def aaccumulate(aiterable, afunc=to_async(operator.add)):
    aiterator = await aiter(aiterable)
    accumulated = _sentinel
    async def __anext__():
        nonlocal accumulated
        current = await anext(aiterator)
        if accumulated == _sentinel:
            accumulated = current
        else:
            accumulated = await afunc(accumulated, current)
        return accumulated
    return __anext__

@coroutine_iterator
async def achain_from_aiterable(aiterables):
    aiterables = await aiter(aiterables)
    aiterator = _sentinel

    async def __anext__():
        nonlocal aiterator

        if aiterator == _sentinel:
            aiterable = await anext(aiterables)
            aiterator = await aiter(aiterable)

        while True:
            try:
                return await anext(aiterator)
            except StopAsyncIteration:
                aiterable = await anext(aiterables)
                aiterator = await aiter(aiterable)

    return __anext__

def achain(*aiterables):
    return achain_from_aiterable(to_aiter(aiterables))
achain.from_aiterable = achain_from_aiterable


from io import BytesIO
import numpy as np
import requests
import pickle
import base64
import json
import os
import re

class KnnModel(object):
    def __init__(self, models_path, vgg_host):
        self.vgg_host = vgg_host
        self.models_path = models_path
        self.model = self.init_model("knn.pkl")
        self.label_encoder = self.init_model("id2label.pkl")

    def init_model(self, model_name):
        """
        Initializes the machine learning model.

        Returns
        -------
        model: object
            Pre-trained model used
            to make predictions.
        """
        path = os.path.join(self.models_path, model_name)
        return pickle.load(open(path, 'rb'))

    def who_is_it(self, embed):
        """
        Performs the identity search
        using the pre-trained knn model

        Parameters
        ----------
        embed: array
            Face embedding comming from the model.

        Returns
        -------
        dist: float
            distance between the given and
            the target embedding.
        label: str
            Name of the predicted identity.
        """
        dist, label = self.model.kneighbors([embed])
        dist, label = dist[0, 0], label[0, 0]
        if dist > 0.8:
            label = "Unknown"
        else:
            label = self.label_encoder[label]
        return dist, label

    def model_predict(self, data):
        """
        Decodes and preprocess the data, uses the
        pretrained model to make predictions and
        returns a well formatted json output.

        Parameters
        ----------
        data: bytes
            Base64 data comming from request.

        Returns
        -------
        outputs: json
            A json response that contains the output
            from the pre-trained model.
        """
        preds = requests.post(
            url=f'http://{self.vgg_host}/predict/',
            data=data).json()["embedding"]
        dist, label = self.who_is_it(preds)
        label = re.sub('[0-9]', '', label)
        out = {'label': label, 'dist': '{:.3f}'.format(dist)}

        return json.dumps(out)


import os
import sys
import dj_database_url

WEBAPP_DIR = os.path.dirname(os.path.abspath(__file__))
APP_BASEDIR = os.path.abspath(os.path.join(WEBAPP_DIR, os.path.pardir))

DEBUG = os.getenv('DEBUG_MODE', 'true') == 'true'
TEMPLATE_DEBUG = DEBUG

ALLOWED_HOSTS = ['localhost']

ADMINS = (
    ('Stefan Reinhard / Chili', 'chili@gloggi.ch'),
)

MANAGERS = ADMINS

SECRET_KEY = os.environ.get('SECRET_KEY', 'unsecure_dummy')

# Parse database configuration from $DATABASE_URL
DEV_DB = os.path.join(APP_BASEDIR, 'dev.db')
DATABASES = {'default': dj_database_url.config(default='sqlite:///%s' % DEV_DB)}

# Honor the 'X-Forwarded-Proto' header for request.is_secure()
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')

TIME_ZONE = 'Europe/Zurich'

_ = lambda s: s

LANGUAGE_CODE = 'de'

LANGUAGES = (
    ('de', _('German')),
    ('en', _('English')),
)

SITE_ID = 1

USE_I18N = True
USE_L10N = True
USE_TZ = True

MEDIA_ROOT = os.path.join(APP_BASEDIR, 'uploads')
MEDIA_URL = '/uploads/'

STATIC_ROOT = os.path.join(APP_BASEDIR, 'static')
STATIC_URL = '/static/'
STATICFILES_DIRS = (os.path.join(WEBAPP_DIR, 'static'),)

ROOT_URLCONF = 'etat.urls'

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
        'LOCATION': '127.0.0.1:11211',
    }
}

SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db'

if 'runserver' in sys.argv:
    EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'

DEFAULT_FROM_EMAIL = os.getenv('DEFAULT_FROM_EMAIL', 'etat@gloggi.ch')
SERVER_EMAIL = os.getenv('DEFAULT_FROM_EMAIL', 'etat@gloggi.ch')

TEMPLATE_DIRS = (
    os.path.join(WEBAPP_DIR, 'templates')
)

TEMPLATE_LOADERS = (
    'django.template.loaders.filesystem.Loader',
    'django.template.loaders.app_directories.Loader',
)

TEMPLATE_CONTEXT_PROCESSORS = (
    'django.contrib.auth.context_processors.auth',
    'django.core.context_processors.debug',
    'django.core.context_processors.i18n',
    'django.core.context_processors.media',
    'django.core.context_processors.static',
    'django.core.context_processors.request',
    'django.contrib.messages.context_processors.messages',
)

INSTALLED_APPS = (
    'suit',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'django.contrib.admin',
    'django.contrib.admindocs',

    'raven.contrib.django.raven_compat',
    'south',
    'mptt',
    'django_mptt_admin',
    'django_reset',
    'django_countries',
    'django_filters',
    'django_select2',
    'rest_framework',
    'bootstrapform',
    'sorl.thumbnail',

    'etat',
    'etat.departments',
    'etat.members',
)

SUIT_CONFIG = {
    'ADMIN_NAME': 'Etat Admin',
    'SEARCH_URL': 'admin:members_member_changelist',
    'MENU_ICONS': {
        'departments': 'icon-folder-open',
        'members': 'icon-user',
    }
}


import asyncio
import json
from datetime import datetime

from .exception import (
    AioAlipayTimeoutError,
    AioAlipayAuthError,
)
from .util import sign_data

class AioAlipayAuth:

    async def get_oauth_token(self, code):
        timestamp = datetime.now()
        params = {
            'app_id': self.app_id,
            'method': 'alipay.system.oauth.token',
            'charset': 'utf-8',
            'sign_type': 'RSA2',
            'version': '1.0',
            'timestamp': timestamp.strftime("%Y-%m-%d %H:%M:%S"),
            'grant_type': 'authorization_code',
            'code': code,
        }

        sign = sign_data(self.app_private_key, params)
        params['sign'] = sign

        url = 'https://openapi.alipay.com/gateway.do'

        try:
            async with self._session.get(url, params=params,
                                         timeout=self.timeout) as resp:
                resp_text = await resp.text()
                # print(resp_text)
                result = json.loads(resp_text)
                if 'error_response' in result:
                    raise AioAlipayAuthError(result)
                data = result.get('alipay_system_oauth_token_response')
                access_token = data.get('access_token')
                user_id = data.get('user_id')
                return access_token, user_id

        except asyncio.TimeoutError:
            raise AioAlipayTimeoutError()