From 112d972fd93b1fff47921fae671b8f6ec549cf52 Mon Sep 17 00:00:00 2001 From: dx-tan Date: Tue, 12 Dec 2023 11:50:45 +0700 Subject: [PATCH 1/2] Add: Text detection, Text recognition --- cope2n-ai-fi/.gitignore | 6 +- .../basic_ocr/externals/sdsvtd/.gitignore | 6 + .../basic_ocr/externals/sdsvtd/LICENSE | 674 ++++++++++++++++++ .../basic_ocr/externals/sdsvtd/README.md | 76 ++ .../externals/sdsvtd/requirements.txt | 2 + .../externals/sdsvtd/sdsvtd/__init__.py | 3 + .../basic_ocr/externals/sdsvtd/sdsvtd/api.py | 35 + .../externals/sdsvtd/sdsvtd/backbone.py | 395 ++++++++++ .../externals/sdsvtd/sdsvtd/bbox_head.py | 288 ++++++++ .../externals/sdsvtd/sdsvtd/factory.py | 75 ++ .../externals/sdsvtd/sdsvtd/model.py | 151 ++++ .../basic_ocr/externals/sdsvtd/sdsvtd/neck.py | 140 ++++ .../externals/sdsvtd/sdsvtd/priors.py | 225 ++++++ .../externals/sdsvtd/sdsvtd/transform.py | 81 +++ .../externals/sdsvtd/sdsvtd/version.py | 1 + .../basic_ocr/externals/sdsvtd/setup.py | 186 +++++ .../basic_ocr/externals/sdsvtr/.gitignore | 6 + .../basic_ocr/externals/sdsvtr/LICENSE | 674 ++++++++++++++++++ .../basic_ocr/externals/sdsvtr/README.md | 76 ++ .../externals/sdsvtr/requirements.txt | 3 + .../externals/sdsvtr/sdsvtr/__init__.py | 3 + .../basic_ocr/externals/sdsvtr/sdsvtr/api.py | 106 +++ .../externals/sdsvtr/sdsvtr/backbone.py | 159 +++++ .../basic_ocr/externals/sdsvtr/sdsvtr/conv.py | 173 +++++ .../externals/sdsvtr/sdsvtr/converter.py | 152 ++++ .../externals/sdsvtr/sdsvtr/decoder.py | 278 ++++++++ .../externals/sdsvtr/sdsvtr/encoder.py | 317 ++++++++ .../externals/sdsvtr/sdsvtr/factory.py | 57 ++ .../externals/sdsvtr/sdsvtr/fp16_utils.py | 78 ++ .../externals/sdsvtr/sdsvtr/transform.py | 33 + .../externals/sdsvtr/sdsvtr/version.py | 1 + .../basic_ocr/externals/sdsvtr/setup.py | 187 +++++ .../basic_ocr/externals/sdsvtr/test.py | 12 + .../ocr_engine/externals/sdsvtd/.gitignore | 6 + .../ocr_engine/externals/sdsvtd/LICENSE | 674 ++++++++++++++++++ .../ocr_engine/externals/sdsvtd/README.md | 76 ++ .../externals/sdsvtd/requirements.txt | 2 + .../externals/sdsvtd/sdsvtd/__init__.py | 3 + .../ocr_engine/externals/sdsvtd/sdsvtd/api.py | 35 + .../externals/sdsvtd/sdsvtd/backbone.py | 395 ++++++++++ .../externals/sdsvtd/sdsvtd/bbox_head.py | 288 ++++++++ .../externals/sdsvtd/sdsvtd/factory.py | 75 ++ .../externals/sdsvtd/sdsvtd/model.py | 151 ++++ .../externals/sdsvtd/sdsvtd/neck.py | 140 ++++ .../externals/sdsvtd/sdsvtd/priors.py | 225 ++++++ .../externals/sdsvtd/sdsvtd/transform.py | 81 +++ .../externals/sdsvtd/sdsvtd/version.py | 1 + .../ocr_engine/externals/sdsvtd/setup.py | 186 +++++ .../ocr_engine/externals/sdsvtr/.gitignore | 6 + .../ocr_engine/externals/sdsvtr/LICENSE | 674 ++++++++++++++++++ .../ocr_engine/externals/sdsvtr/README.md | 76 ++ .../externals/sdsvtr/requirements.txt | 3 + .../externals/sdsvtr/sdsvtr/__init__.py | 3 + .../ocr_engine/externals/sdsvtr/sdsvtr/api.py | 106 +++ .../externals/sdsvtr/sdsvtr/backbone.py | 159 +++++ .../externals/sdsvtr/sdsvtr/conv.py | 173 +++++ .../externals/sdsvtr/sdsvtr/converter.py | 152 ++++ .../externals/sdsvtr/sdsvtr/decoder.py | 278 ++++++++ .../externals/sdsvtr/sdsvtr/encoder.py | 317 ++++++++ .../externals/sdsvtr/sdsvtr/factory.py | 57 ++ .../externals/sdsvtr/sdsvtr/fp16_utils.py | 78 ++ .../externals/sdsvtr/sdsvtr/transform.py | 33 + .../externals/sdsvtr/sdsvtr/version.py | 1 + .../ocr_engine/externals/sdsvtr/setup.py | 187 +++++ .../ocr_engine/externals/sdsvtr/test.py | 12 + 65 files changed, 9309 insertions(+), 3 deletions(-) create mode 100644 cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtd/.gitignore create mode 100644 cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtd/LICENSE create mode 100644 cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtd/README.md create mode 100644 cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtd/requirements.txt create mode 100644 cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtd/sdsvtd/__init__.py create mode 100644 cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtd/sdsvtd/api.py create mode 100644 cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtd/sdsvtd/backbone.py create mode 100644 cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtd/sdsvtd/bbox_head.py create mode 100644 cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtd/sdsvtd/factory.py create mode 100644 cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtd/sdsvtd/model.py create mode 100644 cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtd/sdsvtd/neck.py create mode 100644 cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtd/sdsvtd/priors.py create mode 100644 cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtd/sdsvtd/transform.py create mode 100644 cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtd/sdsvtd/version.py create mode 100644 cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtd/setup.py create mode 100644 cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtr/.gitignore create mode 100644 cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtr/LICENSE create mode 100644 cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtr/README.md create mode 100644 cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtr/requirements.txt create mode 100644 cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtr/sdsvtr/__init__.py create mode 100644 cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtr/sdsvtr/api.py create mode 100644 cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtr/sdsvtr/backbone.py create mode 100644 cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtr/sdsvtr/conv.py create mode 100644 cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtr/sdsvtr/converter.py create mode 100644 cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtr/sdsvtr/decoder.py create mode 100644 cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtr/sdsvtr/encoder.py create mode 100644 cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtr/sdsvtr/factory.py create mode 100644 cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtr/sdsvtr/fp16_utils.py create mode 100644 cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtr/sdsvtr/transform.py create mode 100644 cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtr/sdsvtr/version.py create mode 100644 cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtr/setup.py create mode 100644 cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtr/test.py create mode 100644 cope2n-ai-fi/modules/ocr_engine/externals/sdsvtd/.gitignore create mode 100644 cope2n-ai-fi/modules/ocr_engine/externals/sdsvtd/LICENSE create mode 100644 cope2n-ai-fi/modules/ocr_engine/externals/sdsvtd/README.md create mode 100644 cope2n-ai-fi/modules/ocr_engine/externals/sdsvtd/requirements.txt create mode 100644 cope2n-ai-fi/modules/ocr_engine/externals/sdsvtd/sdsvtd/__init__.py create mode 100644 cope2n-ai-fi/modules/ocr_engine/externals/sdsvtd/sdsvtd/api.py create mode 100644 cope2n-ai-fi/modules/ocr_engine/externals/sdsvtd/sdsvtd/backbone.py create mode 100644 cope2n-ai-fi/modules/ocr_engine/externals/sdsvtd/sdsvtd/bbox_head.py create mode 100644 cope2n-ai-fi/modules/ocr_engine/externals/sdsvtd/sdsvtd/factory.py create mode 100644 cope2n-ai-fi/modules/ocr_engine/externals/sdsvtd/sdsvtd/model.py create mode 100644 cope2n-ai-fi/modules/ocr_engine/externals/sdsvtd/sdsvtd/neck.py create mode 100644 cope2n-ai-fi/modules/ocr_engine/externals/sdsvtd/sdsvtd/priors.py create mode 100644 cope2n-ai-fi/modules/ocr_engine/externals/sdsvtd/sdsvtd/transform.py create mode 100644 cope2n-ai-fi/modules/ocr_engine/externals/sdsvtd/sdsvtd/version.py create mode 100644 cope2n-ai-fi/modules/ocr_engine/externals/sdsvtd/setup.py create mode 100644 cope2n-ai-fi/modules/ocr_engine/externals/sdsvtr/.gitignore create mode 100644 cope2n-ai-fi/modules/ocr_engine/externals/sdsvtr/LICENSE create mode 100644 cope2n-ai-fi/modules/ocr_engine/externals/sdsvtr/README.md create mode 100644 cope2n-ai-fi/modules/ocr_engine/externals/sdsvtr/requirements.txt create mode 100644 cope2n-ai-fi/modules/ocr_engine/externals/sdsvtr/sdsvtr/__init__.py create mode 100644 cope2n-ai-fi/modules/ocr_engine/externals/sdsvtr/sdsvtr/api.py create mode 100644 cope2n-ai-fi/modules/ocr_engine/externals/sdsvtr/sdsvtr/backbone.py create mode 100644 cope2n-ai-fi/modules/ocr_engine/externals/sdsvtr/sdsvtr/conv.py create mode 100644 cope2n-ai-fi/modules/ocr_engine/externals/sdsvtr/sdsvtr/converter.py create mode 100644 cope2n-ai-fi/modules/ocr_engine/externals/sdsvtr/sdsvtr/decoder.py create mode 100644 cope2n-ai-fi/modules/ocr_engine/externals/sdsvtr/sdsvtr/encoder.py create mode 100644 cope2n-ai-fi/modules/ocr_engine/externals/sdsvtr/sdsvtr/factory.py create mode 100644 cope2n-ai-fi/modules/ocr_engine/externals/sdsvtr/sdsvtr/fp16_utils.py create mode 100644 cope2n-ai-fi/modules/ocr_engine/externals/sdsvtr/sdsvtr/transform.py create mode 100644 cope2n-ai-fi/modules/ocr_engine/externals/sdsvtr/sdsvtr/version.py create mode 100644 cope2n-ai-fi/modules/ocr_engine/externals/sdsvtr/setup.py create mode 100644 cope2n-ai-fi/modules/ocr_engine/externals/sdsvtr/test.py diff --git a/cope2n-ai-fi/.gitignore b/cope2n-ai-fi/.gitignore index f2c8e28..9df20fd 100755 --- a/cope2n-ai-fi/.gitignore +++ b/cope2n-ai-fi/.gitignore @@ -3,9 +3,9 @@ __pycache__ DataBase/image_temp/ DataBase/json_temp/ DataBase/template.db -sdsvtd/ -sdsvtr/ -sdsvkie/ +# sdsvtd/ +# sdsvtr/ +# sdsvkie/ detectron2/ output/ data/ diff --git a/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtd/.gitignore b/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtd/.gitignore new file mode 100644 index 0000000..a8c1759 --- /dev/null +++ b/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtd/.gitignore @@ -0,0 +1,6 @@ +# Builds +*.egg-info +__pycache__ + +# Checkpoint +hub \ No newline at end of file diff --git a/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtd/LICENSE b/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtd/LICENSE new file mode 100644 index 0000000..9e419e0 --- /dev/null +++ b/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtd/LICENSE @@ -0,0 +1,674 @@ +GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. \ No newline at end of file diff --git a/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtd/README.md b/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtd/README.md new file mode 100644 index 0000000..4de145b --- /dev/null +++ b/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtd/README.md @@ -0,0 +1,76 @@ +## Introduction +This repo serve as source code storage for the Standalone YoloX Detection packages. +Installing this package requires 2 additional packages: PyTorch and MMCV. + + +## Installation +```shell +conda create -n sdsvtd-env python=3.8 +conda activate sdsvtd-env +conda install pytorch torchvision pytorch-cuda=11.6 -c pytorch -c nvidia +pip install mmcv-full +git clone https://github.com/moewiee/sdsvtd.git +cd sdsvtd +pip install -v -e . +``` + +## Basic Usage +```python +from sdsvtd import StandaloneYOLOXRunner +runner = StandaloneYOLOXRunner(version='yolox-s-general-text-pretrain-20221226', device='cpu') +``` + +The `version` parameter accepts version names declared in `sdsvtd.factory.online_model_factory` or a local path such as `$DIR\model.pth`. To check for available versions in the hub, run: +```python +import sdsvtd +print(sdsvtd.__hub_available_versions__) +``` + +Naturally, a `StandaloneYOLOXRunner` instance assumes the input to be an instance of `np.ndarray` or an instance of `str` (batch inferece is not supported), for examples: +```python +import numpy as np +from sdsvtd import StandaloneYOLOXRunner +runner = StandaloneYOLOXRunner(version='yolox-s-general-text-pretrain-20221226', device='cpu') + +dummy_input = np.ndarray(500, 500, 3) +result = runner(dummy_input) +``` + +**Note:** Output of `StandaloneYOLOXRunner` instance will be in format `List[np.ndarray]` with each list element corresponds to one class. Each `np.ndarray` will be a 5-d vector `[x1 y1 x2 y2 confident]` with coordinates rescaled to fit the original image size. + +**AutoRotation:** +From version 0.1.0, `sdsvtd` support *AutoRotation* feature which accept a `np.ndarray/str` as input and return an straight rotated image (only available rotation degrees are 90, 180 and 270) of type `np.ndarray` and its bounding boxes of type `List[np.ndarray]`. Usage: +```python +import numpy as np +from sdsvtd import StandaloneYOLOXRunner +runner = StandaloneYOLOXRunner(version='yolox-s-general-text-pretrain-20221226', device='cpu', auto_rotate=True) + +rotated_image, result = runner(cv2.imread('path-to-image')) # or +rotated_image, result = runner(np.ndarray) +``` + +## Version Changelog +* **[0.0.1]** +Initial version with specified features. + +* **[0.0.2]** +Update more versions in model hub. + +* **[0.0.3]** +Update feature to specify running device while initialize runner. [Issue](https://github.com/moewiee/sdsvtd/issues/2) + +* **[0.0.4]** +Fix a minor bugs when existing hub/local version != current hub/local version. + +* **[0.0.5]** +Update model hub with handwritten text line detection version. + +* **[0.1.0]** +Update new feature: Auto Rotation. + +* **[0.1.1]** +Fix a bug in API inference class where return double result with auto_rotate=False. + +* **[0.1.2]** +Fix a bug in rotate feature where rotator_version was ignored. + diff --git a/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtd/requirements.txt b/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtd/requirements.txt new file mode 100644 index 0000000..10f4b05 --- /dev/null +++ b/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtd/requirements.txt @@ -0,0 +1,2 @@ +torch +mmcv-full \ No newline at end of file diff --git a/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtd/sdsvtd/__init__.py b/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtd/sdsvtd/__init__.py new file mode 100644 index 0000000..a3fb997 --- /dev/null +++ b/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtd/sdsvtd/__init__.py @@ -0,0 +1,3 @@ +from .api import StandaloneYOLOXRunner +from .version import __version__ +from .factory import __hub_available_versions__ \ No newline at end of file diff --git a/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtd/sdsvtd/api.py b/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtd/sdsvtd/api.py new file mode 100644 index 0000000..7deca24 --- /dev/null +++ b/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtd/sdsvtd/api.py @@ -0,0 +1,35 @@ +from .model import SingleStageDetector, AutoRotateDetector +import numpy as np + +class StandaloneYOLOXRunner: + + def __init__(self, + version, + device, + auto_rotate=False, + rotator_version=None): + self.model = SingleStageDetector(version, + device) + self.auto_rotate = auto_rotate + if self.auto_rotate: + if rotator_version is None: + rotator_version = version + self.rotator = AutoRotateDetector(rotator_version, + device) + + self.warmup_() + + def warmup_(self): + ''' Call on dummpy input to warm up instance ''' + x = np.ndarray((1280, 1280, 3)).astype(np.uint8) + self.model(x) + if self.auto_rotate: + self.rotator(x) + + + def __call__(self, img): + if self.auto_rotate: + img = self.rotator(img) + result = self.model(img) + + return result if not self.auto_rotate else (img, result) \ No newline at end of file diff --git a/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtd/sdsvtd/backbone.py b/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtd/sdsvtd/backbone.py new file mode 100644 index 0000000..5aadded --- /dev/null +++ b/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtd/sdsvtd/backbone.py @@ -0,0 +1,395 @@ +import torch +import torch.nn as nn +from mmcv.cnn import ConvModule +from torch.nn.modules.batchnorm import _BatchNorm + + +class DarknetBottleneck(nn.Module): + """The basic bottleneck block used in Darknet. + + Each ResBlock consists of two ConvModules and the input is added to the + final output. Each ConvModule is composed of Conv, BN, and LeakyReLU. + The first convLayer has filter size of 1x1 and the second one has the + filter size of 3x3. + + Args: + in_channels (int): The input channels of this Module. + out_channels (int): The output channels of this Module. + expansion (int): The kernel size of the convolution. Default: 0.5 + add_identity (bool): Whether to add identity to the out. + Default: True + use_depthwise (bool): Whether to use depthwise separable convolution. + Default: False + conv_cfg (dict): Config dict for convolution layer. Default: None, + which means using conv2d. + norm_cfg (dict): Config dict for normalization layer. + Default: dict(type='BN'). + act_cfg (dict): Config dict for activation layer. + Default: dict(type='Swish'). + """ + + def __init__(self, + in_channels, + out_channels, + expansion=0.5, + add_identity=True, + use_depthwise=False, + conv_cfg=None, + norm_cfg=dict(type='BN', momentum=0.03, eps=0.001), + act_cfg=dict(type='Swish')): + super().__init__() + hidden_channels = int(out_channels * expansion) + self.conv1 = ConvModule( + in_channels, + hidden_channels, + 1, + conv_cfg=conv_cfg, + norm_cfg=norm_cfg, + act_cfg=act_cfg) + self.conv2 = ConvModule( + hidden_channels, + out_channels, + 3, + stride=1, + padding=1, + conv_cfg=conv_cfg, + norm_cfg=norm_cfg, + act_cfg=act_cfg) + self.add_identity = \ + add_identity and in_channels == out_channels + + def forward(self, x): + identity = x + out = self.conv1(x) + out = self.conv2(out) + + if self.add_identity: + return out + identity + else: + return out + + +class CSPLayer(nn.Module): + """Cross Stage Partial Layer. + + Args: + in_channels (int): The input channels of the CSP layer. + out_channels (int): The output channels of the CSP layer. + expand_ratio (float): Ratio to adjust the number of channels of the + hidden layer. Default: 0.5 + num_blocks (int): Number of blocks. Default: 1 + add_identity (bool): Whether to add identity in blocks. + Default: True + use_depthwise (bool): Whether to depthwise separable convolution in + blocks. Default: False + conv_cfg (dict, optional): Config dict for convolution layer. + Default: None, which means using conv2d. + norm_cfg (dict): Config dict for normalization layer. + Default: dict(type='BN') + act_cfg (dict): Config dict for activation layer. + Default: dict(type='Swish') + """ + + def __init__(self, + in_channels, + out_channels, + expand_ratio=0.5, + num_blocks=1, + add_identity=True, + use_depthwise=False, + conv_cfg=None, + norm_cfg=dict(type='BN', momentum=0.03, eps=0.001), + act_cfg=dict(type='Swish')): + super().__init__() + mid_channels = int(out_channels * expand_ratio) + self.main_conv = ConvModule( + in_channels, + mid_channels, + 1, + conv_cfg=conv_cfg, + norm_cfg=norm_cfg, + act_cfg=act_cfg) + self.short_conv = ConvModule( + in_channels, + mid_channels, + 1, + conv_cfg=conv_cfg, + norm_cfg=norm_cfg, + act_cfg=act_cfg) + self.final_conv = ConvModule( + 2 * mid_channels, + out_channels, + 1, + conv_cfg=conv_cfg, + norm_cfg=norm_cfg, + act_cfg=act_cfg) + + self.blocks = nn.Sequential(*[ + DarknetBottleneck( + mid_channels, + mid_channels, + 1.0, + add_identity, + use_depthwise, + conv_cfg=conv_cfg, + norm_cfg=norm_cfg, + act_cfg=act_cfg) for _ in range(num_blocks) + ]) + + def forward(self, x): + x_short = self.short_conv(x) + + x_main = self.main_conv(x) + x_main = self.blocks(x_main) + + x_final = torch.cat((x_main, x_short), dim=1) + return self.final_conv(x_final) + + + +class Focus(nn.Module): + """Focus width and height information into channel space. + + Args: + in_channels (int): The input channels of this Module. + out_channels (int): The output channels of this Module. + kernel_size (int): The kernel size of the convolution. Default: 1 + stride (int): The stride of the convolution. Default: 1 + conv_cfg (dict): Config dict for convolution layer. Default: None, + which means using conv2d. + norm_cfg (dict): Config dict for normalization layer. + Default: dict(type='BN', momentum=0.03, eps=0.001). + act_cfg (dict): Config dict for activation layer. + Default: dict(type='Swish'). + """ + + def __init__(self, + in_channels, + out_channels, + kernel_size=1, + stride=1, + conv_cfg=None, + norm_cfg=dict(type='BN', momentum=0.03, eps=0.001), + act_cfg=dict(type='Swish')): + super().__init__() + self.conv = ConvModule( + in_channels * 4, + out_channels, + kernel_size, + stride, + padding=(kernel_size - 1) // 2, + conv_cfg=conv_cfg, + norm_cfg=norm_cfg, + act_cfg=act_cfg) + + def forward(self, x): + # shape of x (b,c,w,h) -> y(b,4c,w/2,h/2) + patch_top_left = x[..., ::2, ::2] + patch_top_right = x[..., ::2, 1::2] + patch_bot_left = x[..., 1::2, ::2] + patch_bot_right = x[..., 1::2, 1::2] + x = torch.cat( + ( + patch_top_left, + patch_bot_left, + patch_top_right, + patch_bot_right, + ), + dim=1, + ) + return self.conv(x) + + +class SPPBottleneck(nn.Module): + """Spatial pyramid pooling layer used in YOLOv3-SPP. + + Args: + in_channels (int): The input channels of this Module. + out_channels (int): The output channels of this Module. + kernel_sizes (tuple[int]): Sequential of kernel sizes of pooling + layers. Default: (5, 9, 13). + conv_cfg (dict): Config dict for convolution layer. Default: None, + which means using conv2d. + norm_cfg (dict): Config dict for normalization layer. + Default: dict(type='BN'). + act_cfg (dict): Config dict for activation layer. + Default: dict(type='Swish'). + init_cfg (dict or list[dict], optional): Initialization config dict. + Default: None. + """ + + def __init__(self, + in_channels, + out_channels, + kernel_sizes=(5, 9, 13), + conv_cfg=None, + norm_cfg=dict(type='BN', momentum=0.03, eps=0.001), + act_cfg=dict(type='Swish')): + super().__init__() + mid_channels = in_channels // 2 + self.conv1 = ConvModule( + in_channels, + mid_channels, + 1, + stride=1, + conv_cfg=conv_cfg, + norm_cfg=norm_cfg, + act_cfg=act_cfg) + self.poolings = nn.ModuleList([ + nn.MaxPool2d(kernel_size=ks, stride=1, padding=ks // 2) + for ks in kernel_sizes + ]) + conv2_channels = mid_channels * (len(kernel_sizes) + 1) + self.conv2 = ConvModule( + conv2_channels, + out_channels, + 1, + conv_cfg=conv_cfg, + norm_cfg=norm_cfg, + act_cfg=act_cfg) + + def forward(self, x): + x = self.conv1(x) + x = torch.cat([x] + [pooling(x) for pooling in self.poolings], dim=1) + x = self.conv2(x) + return x + + +class CSPDarknet(nn.Module): + """CSP-Darknet backbone used in YOLOv5 and YOLOX. + + Args: + arch (str): Architecture of CSP-Darknet, from {P5, P6}. + Default: P5. + deepen_factor (float): Depth multiplier, multiply number of + blocks in CSP layer by this amount. Default: 1.0. + widen_factor (float): Width multiplier, multiply number of + channels in each layer by this amount. Default: 1.0. + out_indices (Sequence[int]): Output from which stages. + Default: (2, 3, 4). + frozen_stages (int): Stages to be frozen (stop grad and set eval + mode). -1 means not freezing any parameters. Default: -1. + use_depthwise (bool): Whether to use depthwise separable convolution. + Default: False. + arch_ovewrite(list): Overwrite default arch settings. Default: None. + spp_kernal_sizes: (tuple[int]): Sequential of kernel sizes of SPP + layers. Default: (5, 9, 13). + conv_cfg (dict): Config dict for convolution layer. Default: None. + norm_cfg (dict): Dictionary to construct and config norm layer. + Default: dict(type='BN', requires_grad=True). + act_cfg (dict): Config dict for activation layer. + Default: dict(type='LeakyReLU', negative_slope=0.1). + norm_eval (bool): Whether to set norm layers to eval mode, namely, + freeze running stats (mean and var). Note: Effect on Batch Norm + and its variants only. + """ + # From left to right: + # in_channels, out_channels, num_blocks, add_identity, use_spp + arch_settings = { + 'P5': [[64, 128, 3, True, False], [128, 256, 9, True, False], + [256, 512, 9, True, False], [512, 1024, 3, False, True]], + 'P6': [[64, 128, 3, True, False], [128, 256, 9, True, False], + [256, 512, 9, True, False], [512, 768, 3, True, False], + [768, 1024, 3, False, True]] + } + + def __init__(self, + arch='P5', + deepen_factor=1.0, + widen_factor=1.0, + out_indices=(2, 3, 4), + frozen_stages=-1, + use_depthwise=False, + arch_ovewrite=None, + spp_kernal_sizes=(5, 9, 13), + conv_cfg=None, + norm_cfg=dict(type='BN', momentum=0.03, eps=0.001), + act_cfg=dict(type='Swish'), + norm_eval=False): + super().__init__() + arch_setting = self.arch_settings[arch] + if arch_ovewrite: + arch_setting = arch_ovewrite + assert set(out_indices).issubset( + i for i in range(len(arch_setting) + 1)) + if frozen_stages not in range(-1, len(arch_setting) + 1): + raise ValueError('frozen_stages must be in range(-1, ' + 'len(arch_setting) + 1). But received ' + f'{frozen_stages}') + + self.out_indices = out_indices + self.frozen_stages = frozen_stages + self.use_depthwise = use_depthwise + self.norm_eval = norm_eval + + self.stem = Focus( + 3, + int(arch_setting[0][0] * widen_factor), + kernel_size=3, + conv_cfg=conv_cfg, + norm_cfg=norm_cfg, + act_cfg=act_cfg) + self.layers = ['stem'] + + for i, (in_channels, out_channels, num_blocks, add_identity, + use_spp) in enumerate(arch_setting): + in_channels = int(in_channels * widen_factor) + out_channels = int(out_channels * widen_factor) + num_blocks = max(round(num_blocks * deepen_factor), 1) + stage = [] + conv_layer = ConvModule( + in_channels, + out_channels, + 3, + stride=2, + padding=1, + conv_cfg=conv_cfg, + norm_cfg=norm_cfg, + act_cfg=act_cfg) + stage.append(conv_layer) + if use_spp: + spp = SPPBottleneck( + out_channels, + out_channels, + kernel_sizes=spp_kernal_sizes, + conv_cfg=conv_cfg, + norm_cfg=norm_cfg, + act_cfg=act_cfg) + stage.append(spp) + csp_layer = CSPLayer( + out_channels, + out_channels, + num_blocks=num_blocks, + add_identity=add_identity, + use_depthwise=use_depthwise, + conv_cfg=conv_cfg, + norm_cfg=norm_cfg, + act_cfg=act_cfg) + stage.append(csp_layer) + self.add_module(f'stage{i + 1}', nn.Sequential(*stage)) + self.layers.append(f'stage{i + 1}') + + def _freeze_stages(self): + if self.frozen_stages >= 0: + for i in range(self.frozen_stages + 1): + m = getattr(self, self.layers[i]) + m.eval() + for param in m.parameters(): + param.requires_grad = False + + def train(self, mode=True): + super(CSPDarknet, self).train(mode) + self._freeze_stages() + if mode and self.norm_eval: + for m in self.modules(): + if isinstance(m, _BatchNorm): + m.eval() + + def forward(self, x): + outs = [] + for i, layer_name in enumerate(self.layers): + layer = getattr(self, layer_name) + x = layer(x) + if i in self.out_indices: + outs.append(x) + return tuple(outs) \ No newline at end of file diff --git a/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtd/sdsvtd/bbox_head.py b/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtd/sdsvtd/bbox_head.py new file mode 100644 index 0000000..bb485f2 --- /dev/null +++ b/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtd/sdsvtd/bbox_head.py @@ -0,0 +1,288 @@ +import torch +import torch.nn as nn +from mmcv.cnn import ConvModule +from mmcv.ops.nms import batched_nms +from mmcv.runner import force_fp32 +from functools import partial +from .priors import MlvlPointGenerator + + +def multi_apply(func, *args, **kwargs): + """Apply function to a list of arguments. + + Note: + This function applies the ``func`` to multiple inputs and + map the multiple outputs of the ``func`` into different + list. Each list contains the same type of outputs corresponding + to different inputs. + + Args: + func (Function): A function that will be applied to a list of + arguments + + Returns: + tuple(list): A tuple containing multiple list, each list contains \ + a kind of returned results by the function + """ + pfunc = partial(func, **kwargs) if kwargs else func + map_results = map(pfunc, *args) + return tuple(map(list, zip(*map_results))) + + +class YOLOXHead(nn.Module): + """YOLOXHead head used in `YOLOX `_. + + Args: + num_classes (int): Number of categories excluding the background + category. + in_channels (int): Number of channels in the input feature map. + feat_channels (int): Number of hidden channels in stacking convs. + Default: 256 + stacked_convs (int): Number of stacking convs of the head. + Default: 2. + strides (tuple): Downsample factor of each feature map. + use_depthwise (bool): Whether to depthwise separable convolution in + blocks. Default: False + dcn_on_last_conv (bool): If true, use dcn in the last layer of + towers. Default: False. + conv_bias (bool | str): If specified as `auto`, it will be decided by + the norm_cfg. Bias of conv will be set as True if `norm_cfg` is + None, otherwise False. Default: "auto". + conv_cfg (dict): Config dict for convolution layer. Default: None. + norm_cfg (dict): Config dict for normalization layer. Default: None. + act_cfg (dict): Config dict for activation layer. Default: None. + """ + + def __init__(self, + num_classes, + in_channels, + feat_channels=256, + stacked_convs=2, + strides=[8, 16, 32], + use_depthwise=False, + dcn_on_last_conv=False, + conv_bias='auto', + conv_cfg=None, + norm_cfg=dict(type='BN', momentum=0.03, eps=0.001), + act_cfg=dict(type='Swish'), + nms_score_thr=0.3, + nms_iou_threshold=0.1): + + super().__init__() + self.nms_config = dict(score_thr=nms_score_thr, nms=dict(iou_threshold=nms_iou_threshold)) + self.num_classes = num_classes + self.cls_out_channels = num_classes + self.in_channels = in_channels + self.feat_channels = feat_channels + self.stacked_convs = stacked_convs + self.strides = strides + self.use_depthwise = use_depthwise + self.dcn_on_last_conv = dcn_on_last_conv + assert conv_bias == 'auto' or isinstance(conv_bias, bool) + self.conv_bias = conv_bias + self.use_sigmoid_cls = True + + self.conv_cfg = conv_cfg + self.norm_cfg = norm_cfg + self.act_cfg = act_cfg + + self.prior_generator = MlvlPointGenerator(strides, offset=0) + + self.fp16_enabled = False + self._init_layers() + + def _init_layers(self): + self.multi_level_cls_convs = nn.ModuleList() + self.multi_level_reg_convs = nn.ModuleList() + self.multi_level_conv_cls = nn.ModuleList() + self.multi_level_conv_reg = nn.ModuleList() + self.multi_level_conv_obj = nn.ModuleList() + for _ in self.strides: + self.multi_level_cls_convs.append(self._build_stacked_convs()) + self.multi_level_reg_convs.append(self._build_stacked_convs()) + conv_cls, conv_reg, conv_obj = self._build_predictor() + self.multi_level_conv_cls.append(conv_cls) + self.multi_level_conv_reg.append(conv_reg) + self.multi_level_conv_obj.append(conv_obj) + + def _build_stacked_convs(self): + """Initialize conv layers of a single level head.""" + conv = ConvModule + stacked_convs = [] + for i in range(self.stacked_convs): + chn = self.in_channels if i == 0 else self.feat_channels + if self.dcn_on_last_conv and i == self.stacked_convs - 1: + conv_cfg = dict(type='DCNv2') + else: + conv_cfg = self.conv_cfg + stacked_convs.append( + conv( + chn, + self.feat_channels, + 3, + stride=1, + padding=1, + conv_cfg=conv_cfg, + norm_cfg=self.norm_cfg, + act_cfg=self.act_cfg, + bias=self.conv_bias)) + return nn.Sequential(*stacked_convs) + + def _build_predictor(self): + """Initialize predictor layers of a single level head.""" + conv_cls = nn.Conv2d(self.feat_channels, self.cls_out_channels, 1) + conv_reg = nn.Conv2d(self.feat_channels, 4, 1) + conv_obj = nn.Conv2d(self.feat_channels, 1, 1) + return conv_cls, conv_reg, conv_obj + + def forward_single(self, x, cls_convs, reg_convs, conv_cls, conv_reg, + conv_obj): + """Forward feature of a single scale level.""" + + cls_feat = cls_convs(x) + reg_feat = reg_convs(x) + + cls_score = conv_cls(cls_feat) + bbox_pred = conv_reg(reg_feat) + objectness = conv_obj(reg_feat) + + return cls_score, bbox_pred, objectness + + def forward(self, feats): + """Forward features from the upstream network. + + Args: + feats (tuple[Tensor]): Features from the upstream network, each is + a 4D-tensor. + Returns: + tuple[Tensor]: A tuple of multi-level predication map, each is a + 4D-tensor of shape (batch_size, 5+num_classes, height, width). + """ + + return multi_apply(self.forward_single, feats, + self.multi_level_cls_convs, + self.multi_level_reg_convs, + self.multi_level_conv_cls, + self.multi_level_conv_reg, + self.multi_level_conv_obj) + + @force_fp32(apply_to=('cls_scores', 'bbox_preds', 'objectnesses')) + def get_bboxes(self, + cls_scores, + bbox_preds, + objectnesses, + cfg=None): + """Transform network outputs of a batch into bbox results. + Args: + cls_scores (list[Tensor]): Classification scores for all + scale levels, each is a 4D-tensor, has shape + (batch_size, num_priors * num_classes, H, W). + bbox_preds (list[Tensor]): Box energies / deltas for all + scale levels, each is a 4D-tensor, has shape + (batch_size, num_priors * 4, H, W). + objectnesses (list[Tensor], Optional): Score factor for + all scale level, each is a 4D-tensor, has shape + (batch_size, 1, H, W). + cfg (mmcv.Config, Optional): Test / postprocessing configuration, + if None, test_cfg would be used. Default None. + rescale (bool): If True, return boxes in original image space. + Default False. + with_nms (bool): If True, do nms before return boxes. + Default True. + Returns: + list[list[Tensor, Tensor]]: Each item in result_list is 2-tuple. + The first item is an (n, 5) tensor, where the first 4 columns + are bounding box positions (tl_x, tl_y, br_x, br_y) and the + 5-th column is a score between 0 and 1. The second item is a + (n,) tensor where each item is the predicted class label of + the corresponding box. + """ + assert len(cls_scores) == len(bbox_preds) == len(objectnesses) + cfg = self.nms_config if cfg is None else cfg + + featmap_sizes = [cls_score.shape[2:] for cls_score in cls_scores] + mlvl_priors = self.prior_generator.grid_priors( + featmap_sizes, + dtype=cls_scores[0].dtype, + device=cls_scores[0].device, + with_stride=True) + + # flatten cls_scores, bbox_preds and objectness + flatten_cls_scores = [ + cls_score.permute(0, 2, 3, 1).reshape(1, -1, + self.cls_out_channels) + for cls_score in cls_scores + ] + flatten_bbox_preds = [ + bbox_pred.permute(0, 2, 3, 1).reshape(1, -1, 4) + for bbox_pred in bbox_preds + ] + flatten_objectness = [ + objectness.permute(0, 2, 3, 1).reshape(1, -1) + for objectness in objectnesses + ] + + flatten_cls_scores = torch.cat(flatten_cls_scores, dim=1).sigmoid() + flatten_bbox_preds = torch.cat(flatten_bbox_preds, dim=1) + flatten_objectness = torch.cat(flatten_objectness, dim=1).sigmoid() + flatten_priors = torch.cat(mlvl_priors) + + flatten_bboxes = self._bbox_decode(flatten_priors, flatten_bbox_preds) + + result_list = [] + for img_id in range(1): + cls_scores = flatten_cls_scores[img_id] + score_factor = flatten_objectness[img_id] + bboxes = flatten_bboxes[img_id] + + result_list.append( + self._bboxes_nms(cls_scores, bboxes, score_factor, cfg)) + + return result_list + + def _bbox_decode(self, priors, bbox_preds): + xys = (bbox_preds[..., :2] * priors[:, 2:]) + priors[:, :2] + whs = bbox_preds[..., 2:].exp() * priors[:, 2:] + + tl_x = (xys[..., 0] - whs[..., 0] / 2) + tl_y = (xys[..., 1] - whs[..., 1] / 2) + br_x = (xys[..., 0] + whs[..., 0] / 2) + br_y = (xys[..., 1] + whs[..., 1] / 2) + + decoded_bboxes = torch.stack([tl_x, tl_y, br_x, br_y], -1) + return decoded_bboxes + + def _bboxes_nms(self, cls_scores, bboxes, score_factor, cfg): + max_scores, labels = torch.max(cls_scores, 1) + valid_mask = score_factor * max_scores >= cfg['score_thr'] + bboxes = bboxes[valid_mask] + scores = max_scores[valid_mask] * score_factor[valid_mask] + labels = labels[valid_mask] + + if labels.numel() == 0: + return bboxes, labels + else: + dets, keep = batched_nms(bboxes.float(), scores.float(), labels, cfg['nms']) + return dets, labels[keep] + + def simple_test_bboxes(self, feats): + """Test det bboxes without test-time augmentation, can be applied in + DenseHead except for ``RPNHead`` and its variants, e.g., ``GARPNHead``, + etc. + + Args: + feats (tuple[torch.Tensor]): Multi-level features from the + upstream network, each is a 4D-tensor. + rescale (bool, optional): Whether to rescale the results. + Defaults to False. + + Returns: + list[tuple[Tensor, Tensor]]: Each item in result_list is 2-tuple. + The first item is ``bboxes`` with shape (n, 5), + where 5 represent (tl_x, tl_y, br_x, br_y, score). + The shape of the second tensor in the tuple is ``labels`` + with shape (n,) + """ + outs = self.forward(feats) + results_list = self.get_bboxes(*outs) + return results_list \ No newline at end of file diff --git a/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtd/sdsvtd/factory.py b/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtd/sdsvtd/factory.py new file mode 100644 index 0000000..2b6068f --- /dev/null +++ b/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtd/sdsvtd/factory.py @@ -0,0 +1,75 @@ +import os +import shutil +import hashlib +import warnings + +def sha256sum(filename): + h = hashlib.sha256() + b = bytearray(128*1024) + mv = memoryview(b) + with open(filename, 'rb', buffering=0) as f: + for n in iter(lambda : f.readinto(mv), 0): + h.update(mv[:n]) + return h.hexdigest() + + +online_model_factory = { + 'yolox-s-general-text-pretrain-20221226': { + 'url': 'https://github.com/moewiee/satrn-model-factory/raw/main/62j266xm8r.pth', + 'hash': '89bff792685af454d0cfea5d6d673be6914d614e4c2044e786da6eddf36f8b50'}, + 'yolox-s-checkbox-20220726': { + 'url': 'https://github.com/moewiee/satrn-model-factory/raw/main/1647d7eys7.pth', + 'hash': '7c1e188b7375dcf0b7b9d317675ebd92a86fdc29363558002249867249ee10f8'}, + 'yolox-s-idcard-5c-20221027': { + 'url': 'https://github.com/moewiee/satrn-model-factory/raw/main/jr0egad3ix.pth', + 'hash': '73a7772594c1f6d3f6d6a98b6d6e4097af5026864e3bd50531ad9e635ae795a7'}, + 'yolox-s-handwritten-text-line-20230228': { + 'url': 'https://github.com/moewiee/satrn-model-factory/raw/main/rb07rtwmgi.pth', + 'hash': 'a31d1bf8fc880479d2e11463dad0b4081952a13e553a02919109b634a1190ef1'} +} + +__hub_available_versions__ = online_model_factory.keys() + +def _get_from_hub(file_path, version, version_url): + os.system(f'wget -O {file_path} {version_url}') + assert os.path.exists(file_path), \ + 'wget failed while trying to retrieve from hub.' + downloaded_hash = sha256sum(file_path) + if downloaded_hash != online_model_factory[version]['hash']: + os.remove(file_path) + raise ValueError('sha256 hash doesnt match for version retrieved from hub.') + +def _get(version): + use_online = version in __hub_available_versions__ + + if not use_online and not os.path.exists(version): + raise ValueError(f'Model version {version} not found online and not found local.') + + hub_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'hub') + if not os.path.exists(hub_path): + os.makedirs(hub_path) + if use_online: + version_url = online_model_factory[version]['url'] + file_path = os.path.join(hub_path, os.path.basename(version_url)) + else: + file_path = os.path.join(hub_path, os.path.basename(version)) + + if not os.path.exists(file_path): + if use_online: + _get_from_hub(file_path, version, version_url) + else: + shutil.copy2(version, file_path) + else: + if use_online: + downloaded_hash = sha256sum(file_path) + if downloaded_hash != online_model_factory[version]['hash']: + os.remove(file_path) + warnings.warn('existing hub version sha256 hash doesnt match, now re-download from hub.') + _get_from_hub(file_path, version, version_url) + else: + if sha256sum(file_path) != sha256sum(version): + os.remove(file_path) + warnings.warn('existing local version sha256 hash doesnt match, now replace with new local version.') + shutil.copy2(version, file_path) + + return file_path \ No newline at end of file diff --git a/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtd/sdsvtd/model.py b/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtd/sdsvtd/model.py new file mode 100644 index 0000000..69a26ef --- /dev/null +++ b/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtd/sdsvtd/model.py @@ -0,0 +1,151 @@ +import torch +import torch.nn as nn +import numpy as np +from .backbone import CSPDarknet +from .neck import YOLOXPAFPN +from .bbox_head import YOLOXHead +from .transform import DetectorDataPipeline, AutoRotateDetectorDataPipeline +from .factory import _get as get_version + + +def bbox2result(bboxes, labels, num_classes): + """Convert detection results to a list of numpy arrays. + + Args: + bboxes (torch.Tensor | np.ndarray): shape (n, 5) + labels (torch.Tensor | np.ndarray): shape (n, ) + num_classes (int): class number, including background class + + Returns: + list(ndarray): bbox results of each class + """ + if bboxes.shape[0] == 0: + return [np.zeros((0, 5), dtype=np.float32) for i in range(num_classes)] + else: + if isinstance(bboxes, torch.Tensor): + bboxes = bboxes.detach().cpu().numpy() + labels = labels.detach().cpu().numpy() + return [bboxes[labels == i, :] for i in range(num_classes)] + + +def normalize_bbox(bboxes, scale): + for i in range(len(bboxes)): + bboxes[i][:,:4] /= scale + return bboxes + + +class SingleStageDetector(nn.Module): + + def __init__(self, + version, + device): + super(SingleStageDetector, self).__init__() + + assert 'cpu' in device or 'cuda' in device + + checkpoint = get_version(version) + pt = torch.load(checkpoint, 'cpu') + + self.pipeline = DetectorDataPipeline(**pt['pipeline_args'], device=device) + self.backbone = CSPDarknet(**pt['backbone_args']) + self.neck = YOLOXPAFPN(**pt['neck_args']) + self.bbox_head = YOLOXHead(**pt['bbox_head_args']) + self.load_state_dict(pt['state_dict'], strict=True) + + self.eval() + for param in self.parameters(): + param.requires_grad = False + + self = self.to(device=device) + + print(f'Text detection load from version {version}.') + + def extract_feat(self, img): + """Directly extract features from the backbone + neck.""" + + x = self.backbone(img) + x = self.neck(x) + return x + + def forward(self, img): + """Test function without test-time augmentation. + + Args: + img (np.ndarray): Images with shape (H, W, C) or + img (str): Path to image. + + Returns: + list[list[np.ndarray]]: BBox results of each image and classes. + The list corresponds to each class. + """ + img, origin_shape, new_shape = self.pipeline(img) + scale = min(new_shape / origin_shape) + feat = self.extract_feat(img) + results_list = self.bbox_head.simple_test_bboxes(feat) + bbox_results = [ + bbox2result(det_bboxes, det_labels, self.bbox_head.num_classes) + for det_bboxes, det_labels in results_list + ][0] + bbox_results = normalize_bbox(bbox_results, scale) + return bbox_results + + +class AutoRotateDetector(nn.Module): + def __init__(self, + version, + device): + super(AutoRotateDetector, self).__init__() + + assert 'cpu' in device or 'cuda' in device + + checkpoint = get_version(version) + pt = torch.load(checkpoint, 'cpu') + + self.pipeline = AutoRotateDetectorDataPipeline(**pt['pipeline_args'], device=device) + self.backbone = CSPDarknet(**pt['backbone_args']) + self.neck = YOLOXPAFPN(**pt['neck_args']) + self.bbox_head = YOLOXHead(**pt['bbox_head_args'], nms_score_thr=0.8) + self.load_state_dict(pt['state_dict'], strict=True) + + self.eval() + for param in self.parameters(): + param.requires_grad = False + + self = self.to(device=device) + + print(f'Auto rotate detector load from version {version}.') + + def extract_feat(self, img): + """Directly extract features from the backbone + neck.""" + + x = self.backbone(img) + x = self.neck(x) + return x + + def forward(self, img): + """Test function without test-time augmentation. + + Args: + img (np.ndarray): Images with shape (H, W, C) or + img (str): Path to image. + + Returns: + np.ndarray: Straight rotated image. + """ + imgs, imgs_np = self.pipeline(img) + maxCount = -1 + maxCountRot = None + for idx, img in enumerate(imgs): + currentCount = 0 + feat = self.extract_feat(img) + results_list = self.bbox_head.simple_test_bboxes(feat) + bbox_results = [ + bbox2result(det_bboxes, det_labels, self.bbox_head.num_classes) + for det_bboxes, det_labels in results_list + ][0] + for class_result in bbox_results: + currentCount += len(class_result) + if currentCount > maxCount: + maxCount = currentCount + maxCountRot = idx + return imgs_np[maxCountRot] \ No newline at end of file diff --git a/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtd/sdsvtd/neck.py b/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtd/sdsvtd/neck.py new file mode 100644 index 0000000..2b11e36 --- /dev/null +++ b/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtd/sdsvtd/neck.py @@ -0,0 +1,140 @@ +import torch +import torch.nn as nn +from mmcv.cnn import ConvModule +from .backbone import CSPLayer + + +class YOLOXPAFPN(nn.Module): + """Path Aggregation Network used in YOLOX. + + Args: + in_channels (List[int]): Number of input channels per scale. + out_channels (int): Number of output channels (used at each scale) + num_csp_blocks (int): Number of bottlenecks in CSPLayer. Default: 3 + use_depthwise (bool): Whether to depthwise separable convolution in + blocks. Default: False + upsample_cfg (dict): Config dict for interpolate layer. + Default: `dict(scale_factor=2, mode='nearest')` + conv_cfg (dict, optional): Config dict for convolution layer. + Default: None, which means using conv2d. + norm_cfg (dict): Config dict for normalization layer. + Default: dict(type='BN') + act_cfg (dict): Config dict for activation layer. + Default: dict(type='Swish') + init_cfg (dict or list[dict], optional): Initialization config dict. + Default: None. + """ + + def __init__(self, + in_channels, + out_channels, + num_csp_blocks=3, + use_depthwise=False, + upsample_cfg=dict(scale_factor=2, mode='nearest'), + conv_cfg=None, + norm_cfg=dict(type='BN', momentum=0.03, eps=0.001), + act_cfg=dict(type='Swish')): + super(YOLOXPAFPN, self).__init__() + self.in_channels = in_channels + self.out_channels = out_channels + + # build top-down blocks + self.upsample = nn.Upsample(**upsample_cfg) + self.reduce_layers = nn.ModuleList() + self.top_down_blocks = nn.ModuleList() + for idx in range(len(in_channels) - 1, 0, -1): + self.reduce_layers.append( + ConvModule( + in_channels[idx], + in_channels[idx - 1], + 1, + conv_cfg=conv_cfg, + norm_cfg=norm_cfg, + act_cfg=act_cfg)) + self.top_down_blocks.append( + CSPLayer( + in_channels[idx - 1] * 2, + in_channels[idx - 1], + num_blocks=num_csp_blocks, + add_identity=False, + use_depthwise=use_depthwise, + conv_cfg=conv_cfg, + norm_cfg=norm_cfg, + act_cfg=act_cfg)) + + # build bottom-up blocks + self.downsamples = nn.ModuleList() + self.bottom_up_blocks = nn.ModuleList() + for idx in range(len(in_channels) - 1): + self.downsamples.append( + ConvModule( + in_channels[idx], + in_channels[idx], + 3, + stride=2, + padding=1, + conv_cfg=conv_cfg, + norm_cfg=norm_cfg, + act_cfg=act_cfg)) + self.bottom_up_blocks.append( + CSPLayer( + in_channels[idx] * 2, + in_channels[idx + 1], + num_blocks=num_csp_blocks, + add_identity=False, + use_depthwise=use_depthwise, + conv_cfg=conv_cfg, + norm_cfg=norm_cfg, + act_cfg=act_cfg)) + + self.out_convs = nn.ModuleList() + for i in range(len(in_channels)): + self.out_convs.append( + ConvModule( + in_channels[i], + out_channels, + 1, + conv_cfg=conv_cfg, + norm_cfg=norm_cfg, + act_cfg=act_cfg)) + + def forward(self, inputs): + """ + Args: + inputs (tuple[Tensor]): input features. + + Returns: + tuple[Tensor]: YOLOXPAFPN features. + """ + assert len(inputs) == len(self.in_channels) + + # top-down path + inner_outs = [inputs[-1]] + for idx in range(len(self.in_channels) - 1, 0, -1): + feat_heigh = inner_outs[0] + feat_low = inputs[idx - 1] + feat_heigh = self.reduce_layers[len(self.in_channels) - 1 - idx]( + feat_heigh) + inner_outs[0] = feat_heigh + + upsample_feat = self.upsample(feat_heigh) + + inner_out = self.top_down_blocks[len(self.in_channels) - 1 - idx]( + torch.cat([upsample_feat, feat_low], 1)) + inner_outs.insert(0, inner_out) + + # bottom-up path + outs = [inner_outs[0]] + for idx in range(len(self.in_channels) - 1): + feat_low = outs[-1] + feat_height = inner_outs[idx + 1] + downsample_feat = self.downsamples[idx](feat_low) + out = self.bottom_up_blocks[idx]( + torch.cat([downsample_feat, feat_height], 1)) + outs.append(out) + + # out convs + for idx, conv in enumerate(self.out_convs): + outs[idx] = conv(outs[idx]) + + return tuple(outs) diff --git a/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtd/sdsvtd/priors.py b/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtd/sdsvtd/priors.py new file mode 100644 index 0000000..8eb2fde --- /dev/null +++ b/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtd/sdsvtd/priors.py @@ -0,0 +1,225 @@ +import torch +import numpy as np +from torch.nn.modules.utils import _pair + + +class MlvlPointGenerator: + """Standard points generator for multi-level (Mlvl) feature maps in 2D + points-based detectors. + + Args: + strides (list[int] | list[tuple[int, int]]): Strides of anchors + in multiple feature levels in order (w, h). + offset (float): The offset of points, the value is normalized with + corresponding stride. Defaults to 0.5. + """ + + def __init__(self, strides, offset=0.5): + self.strides = [_pair(stride) for stride in strides] + self.offset = offset + + @property + def num_levels(self): + """int: number of feature levels that the generator will be applied""" + return len(self.strides) + + @property + def num_base_priors(self): + """list[int]: The number of priors (points) at a point + on the feature grid""" + return [1 for _ in range(len(self.strides))] + + def _meshgrid(self, x, y, row_major=True): + yy, xx = torch.meshgrid(y, x) + if row_major: + # warning .flatten() would cause error in ONNX exporting + # have to use reshape here + return xx.flatten(), yy.flatten() + + else: + return yy.flatten(), xx.flatten() + + def grid_priors(self, + featmap_sizes, + dtype=torch.float32, + device='cuda', + with_stride=False): + """Generate grid points of multiple feature levels. + + Args: + featmap_sizes (list[tuple]): List of feature map sizes in + multiple feature levels, each size arrange as + as (h, w). + dtype (:obj:`dtype`): Dtype of priors. Default: torch.float32. + device (str): The device where the anchors will be put on. + with_stride (bool): Whether to concatenate the stride to + the last dimension of points. + + Return: + list[torch.Tensor]: Points of multiple feature levels. + The sizes of each tensor should be (N, 2) when with stride is + ``False``, where N = width * height, width and height + are the sizes of the corresponding feature level, + and the last dimension 2 represent (coord_x, coord_y), + otherwise the shape should be (N, 4), + and the last dimension 4 represent + (coord_x, coord_y, stride_w, stride_h). + """ + + assert self.num_levels == len(featmap_sizes) + multi_level_priors = [] + for i in range(self.num_levels): + priors = self.single_level_grid_priors( + featmap_sizes[i], + level_idx=i, + dtype=dtype, + device=device, + with_stride=with_stride) + multi_level_priors.append(priors) + return multi_level_priors + + def single_level_grid_priors(self, + featmap_size, + level_idx, + dtype=torch.float32, + device='cuda', + with_stride=False): + """Generate grid Points of a single level. + + Note: + This function is usually called by method ``self.grid_priors``. + + Args: + featmap_size (tuple[int]): Size of the feature maps, arrange as + (h, w). + level_idx (int): The index of corresponding feature map level. + dtype (:obj:`dtype`): Dtype of priors. Default: torch.float32. + device (str, optional): The device the tensor will be put on. + Defaults to 'cuda'. + with_stride (bool): Concatenate the stride to the last dimension + of points. + + Return: + Tensor: Points of single feature levels. + The shape of tensor should be (N, 2) when with stride is + ``False``, where N = width * height, width and height + are the sizes of the corresponding feature level, + and the last dimension 2 represent (coord_x, coord_y), + otherwise the shape should be (N, 4), + and the last dimension 4 represent + (coord_x, coord_y, stride_w, stride_h). + """ + feat_h, feat_w = featmap_size + stride_w, stride_h = self.strides[level_idx] + shift_x = (torch.arange(0, feat_w, device=device) + + self.offset) * stride_w + # keep featmap_size as Tensor instead of int, so that we + # can convert to ONNX correctly + shift_x = shift_x.to(dtype) + + shift_y = (torch.arange(0, feat_h, device=device) + + self.offset) * stride_h + # keep featmap_size as Tensor instead of int, so that we + # can convert to ONNX correctly + shift_y = shift_y.to(dtype) + shift_xx, shift_yy = self._meshgrid(shift_x, shift_y) + if not with_stride: + shifts = torch.stack([shift_xx, shift_yy], dim=-1) + else: + # use `shape[0]` instead of `len(shift_xx)` for ONNX export + stride_w = shift_xx.new_full((shift_xx.shape[0], ), + stride_w).to(dtype) + stride_h = shift_xx.new_full((shift_yy.shape[0], ), + stride_h).to(dtype) + shifts = torch.stack([shift_xx, shift_yy, stride_w, stride_h], + dim=-1) + all_points = shifts.to(device) + return all_points + + def valid_flags(self, featmap_sizes, pad_shape, device='cuda'): + """Generate valid flags of points of multiple feature levels. + + Args: + featmap_sizes (list(tuple)): List of feature map sizes in + multiple feature levels, each size arrange as + as (h, w). + pad_shape (tuple(int)): The padded shape of the image, + arrange as (h, w). + device (str): The device where the anchors will be put on. + + Return: + list(torch.Tensor): Valid flags of points of multiple levels. + """ + assert self.num_levels == len(featmap_sizes) + multi_level_flags = [] + for i in range(self.num_levels): + point_stride = self.strides[i] + feat_h, feat_w = featmap_sizes[i] + h, w = pad_shape[:2] + valid_feat_h = min(int(np.ceil(h / point_stride[1])), feat_h) + valid_feat_w = min(int(np.ceil(w / point_stride[0])), feat_w) + flags = self.single_level_valid_flags((feat_h, feat_w), + (valid_feat_h, valid_feat_w), + device=device) + multi_level_flags.append(flags) + return multi_level_flags + + def single_level_valid_flags(self, + featmap_size, + valid_size, + device='cuda'): + """Generate the valid flags of points of a single feature map. + + Args: + featmap_size (tuple[int]): The size of feature maps, arrange as + as (h, w). + valid_size (tuple[int]): The valid size of the feature maps. + The size arrange as as (h, w). + device (str, optional): The device where the flags will be put on. + Defaults to 'cuda'. + + Returns: + torch.Tensor: The valid flags of each points in a single level \ + feature map. + """ + feat_h, feat_w = featmap_size + valid_h, valid_w = valid_size + assert valid_h <= feat_h and valid_w <= feat_w + valid_x = torch.zeros(feat_w, dtype=torch.bool, device=device) + valid_y = torch.zeros(feat_h, dtype=torch.bool, device=device) + valid_x[:valid_w] = 1 + valid_y[:valid_h] = 1 + valid_xx, valid_yy = self._meshgrid(valid_x, valid_y) + valid = valid_xx & valid_yy + return valid + + def sparse_priors(self, + prior_idxs, + featmap_size, + level_idx, + dtype=torch.float32, + device='cuda'): + """Generate sparse points according to the ``prior_idxs``. + + Args: + prior_idxs (Tensor): The index of corresponding anchors + in the feature map. + featmap_size (tuple[int]): feature map size arrange as (w, h). + level_idx (int): The level index of corresponding feature + map. + dtype (obj:`torch.dtype`): Date type of points. Defaults to + ``torch.float32``. + device (obj:`torch.device`): The device where the points is + located. + Returns: + Tensor: Anchor with shape (N, 2), N should be equal to + the length of ``prior_idxs``. And last dimension + 2 represent (coord_x, coord_y). + """ + height, width = featmap_size + x = (prior_idxs % width + self.offset) * self.strides[level_idx][0] + y = ((prior_idxs // width) % height + + self.offset) * self.strides[level_idx][1] + prioris = torch.stack([x, y], 1).to(dtype) + prioris = prioris.to(device) + return prioris \ No newline at end of file diff --git a/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtd/sdsvtd/transform.py b/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtd/sdsvtd/transform.py new file mode 100644 index 0000000..fda7ab9 --- /dev/null +++ b/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtd/sdsvtd/transform.py @@ -0,0 +1,81 @@ +import mmcv +import numpy as np +import cv2 +import torch + + +class DetectorDataPipeline: + + def __init__(self, + img_scale, + device): + self.scale = img_scale + self.device = device + + def load(self, img): + if isinstance(img, str): + return cv2.imread(img) + elif isinstance(img, np.ndarray): + return img + else: + raise ValueError(f'img input must be a str/np.ndarray, got {type(img)}') + + def resize(self, img): + origin_shape = img.shape[:2] + img = mmcv.imrescale(img, + self.scale, + return_scale=False, + interpolation='bilinear', + backend='cv2') + + return img, origin_shape, np.array(self.scale) + + def pad(self, img): + if self.scale is not None: + width = max(self.scale[1] - img.shape[1], 0) + height = max(self.scale[0] - img.shape[0], 0) + padding = (0, 0, width, height) + + img = cv2.copyMakeBorder(img, + padding[1], + padding[3], + padding[0], + padding[2], + cv2.BORDER_CONSTANT, + value=(114, 114, 114,)) + + return img + + def to_tensor(self, img): + + img = torch.from_numpy(img.astype(np.float32)).permute(2,0,1).unsqueeze(0) + img = img.to(device=self.device) + + return img + + def __call__(self, img): + img = self.load(img) + img, origin_shape, new_shape = self.resize(img) + img = self.pad(img) + img = self.to_tensor(img) + + return img, origin_shape, new_shape + + +class AutoRotateDetectorDataPipeline(DetectorDataPipeline): + + def __call__(self, img): + img = self.load(img) + imgs = [] + imgs_np = [] + + for flag in (None, cv2.ROTATE_90_CLOCKWISE, cv2.ROTATE_180, cv2.ROTATE_90_COUNTERCLOCKWISE): + img_t = img if flag is None else cv2.rotate(img, flag) + imgs_np.append(img_t) + img_t, _, _ = self.resize(img_t) + img_t = self.pad(img_t) + img_t = self.to_tensor(img_t) + + imgs.append(img_t) + + return imgs, imgs_np \ No newline at end of file diff --git a/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtd/sdsvtd/version.py b/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtd/sdsvtd/version.py new file mode 100644 index 0000000..10939f0 --- /dev/null +++ b/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtd/sdsvtd/version.py @@ -0,0 +1 @@ +__version__ = '0.1.2' diff --git a/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtd/setup.py b/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtd/setup.py new file mode 100644 index 0000000..a2e04db --- /dev/null +++ b/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtd/setup.py @@ -0,0 +1,186 @@ +import os +import os.path as osp +import shutil +import sys +import warnings +from setuptools import find_packages, setup + + +def readme(): + with open('README.md', encoding='utf-8') as f: + content = f.read() + return content + + +version_file = 'sdsvtd/version.py' +is_windows = sys.platform == 'win32' + + +def add_mim_extention(): + """Add extra files that are required to support MIM into the package. + + These files will be added by creating a symlink to the originals if the + package is installed in `editable` mode (e.g. pip install -e .), or by + copying from the originals otherwise. + """ + + # parse installment mode + if 'develop' in sys.argv: + # installed by `pip install -e .` + mode = 'symlink' + elif 'sdist' in sys.argv or 'bdist_wheel' in sys.argv: + # installed by `pip install .` + # or create source distribution by `python setup.py sdist` + mode = 'copy' + else: + return + + filenames = ['tools', 'configs', 'model-index.yml'] + repo_path = osp.dirname(__file__) + mim_path = osp.join(repo_path, 'mmocr', '.mim') + os.makedirs(mim_path, exist_ok=True) + + for filename in filenames: + if osp.exists(filename): + src_path = osp.join(repo_path, filename) + tar_path = osp.join(mim_path, filename) + + if osp.isfile(tar_path) or osp.islink(tar_path): + os.remove(tar_path) + elif osp.isdir(tar_path): + shutil.rmtree(tar_path) + + if mode == 'symlink': + src_relpath = osp.relpath(src_path, osp.dirname(tar_path)) + try: + os.symlink(src_relpath, tar_path) + except OSError: + # Creating a symbolic link on windows may raise an + # `OSError: [WinError 1314]` due to privilege. If + # the error happens, the src file will be copied + mode = 'copy' + warnings.warn( + f'Failed to create a symbolic link for {src_relpath}, ' + f'and it will be copied to {tar_path}') + else: + continue + + if mode == 'copy': + if osp.isfile(src_path): + shutil.copyfile(src_path, tar_path) + elif osp.isdir(src_path): + shutil.copytree(src_path, tar_path) + else: + warnings.warn(f'Cannot copy file {src_path}.') + else: + raise ValueError(f'Invalid mode {mode}') + + +def get_version(): + with open(version_file, 'r') as f: + exec(compile(f.read(), version_file, 'exec')) + import sys + + # return short version for sdist + if 'sdist' in sys.argv or 'bdist_wheel' in sys.argv: + return locals()['short_version'] + else: + return locals()['__version__'] + + +def parse_requirements(fname='requirements.txt', with_version=True): + """Parse the package dependencies listed in a requirements file but strip + specific version information. + + Args: + fname (str): Path to requirements file. + with_version (bool, default=False): If True, include version specs. + Returns: + info (list[str]): List of requirements items. + CommandLine: + python -c "import setup; print(setup.parse_requirements())" + """ + import re + import sys + from os.path import exists + require_fpath = fname + + def parse_line(line): + """Parse information from a line in a requirements text file.""" + if line.startswith('-r '): + # Allow specifying requirements in other files + target = line.split(' ')[1] + for info in parse_require_file(target): + yield info + else: + info = {'line': line} + if line.startswith('-e '): + info['package'] = line.split('#egg=')[1] + else: + # Remove versioning from the package + pat = '(' + '|'.join(['>=', '==', '>']) + ')' + parts = re.split(pat, line, maxsplit=1) + parts = [p.strip() for p in parts] + + info['package'] = parts[0] + if len(parts) > 1: + op, rest = parts[1:] + if ';' in rest: + # Handle platform specific dependencies + # http://setuptools.readthedocs.io/en/latest/setuptools.html#declaring-platform-specific-dependencies + version, platform_deps = map(str.strip, + rest.split(';')) + info['platform_deps'] = platform_deps + else: + version = rest # NOQA + info['version'] = (op, version) + yield info + + def parse_require_file(fpath): + with open(fpath, 'r') as f: + for line in f.readlines(): + line = line.strip() + if line and not line.startswith('#'): + for info in parse_line(line): + yield info + + def gen_packages_items(): + if exists(require_fpath): + for info in parse_require_file(require_fpath): + parts = [info['package']] + if with_version and 'version' in info: + parts.extend(info['version']) + if not sys.version.startswith('3.4'): + # apparently package_deps are broken in 3.4 + platform_deps = info.get('platform_deps') + if platform_deps is not None: + parts.append(';' + platform_deps) + item = ''.join(parts) + yield item + + packages = list(gen_packages_items()) + return packages + + +if __name__ == '__main__': + setup( + name='sdsvtd', + version=get_version(), + description='SDSV OCR Team Text Detection', + long_description=readme(), + long_description_content_type='text/markdown', + packages=find_packages(exclude=('configs', 'tools', 'demo')), + include_package_data=True, + classifiers=[ + 'Development Status :: 4 - Beta', + 'License :: OSI Approved :: Apache Software License', + 'Operating System :: OS Independent', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', + 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', + ], + license='Apache License 2.0', + install_requires=parse_requirements('requirements.txt'), + zip_safe=False) diff --git a/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtr/.gitignore b/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtr/.gitignore new file mode 100644 index 0000000..a8c1759 --- /dev/null +++ b/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtr/.gitignore @@ -0,0 +1,6 @@ +# Builds +*.egg-info +__pycache__ + +# Checkpoint +hub \ No newline at end of file diff --git a/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtr/LICENSE b/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtr/LICENSE new file mode 100644 index 0000000..92b370f --- /dev/null +++ b/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtr/LICENSE @@ -0,0 +1,674 @@ +GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtr/README.md b/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtr/README.md new file mode 100644 index 0000000..2cabc83 --- /dev/null +++ b/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtr/README.md @@ -0,0 +1,76 @@ +## Introduction +This repo serve as source code storage for the Standalone SATRN Text Recognizer packages. +Installing this package requires 3 additional packages: PyTorch, MMCV, and colorama. + + +## Installation +```shell +conda create -n sdsvtr-env python=3.8 +conda activate sdsvtr-env +conda install pytorch torchvision pytorch-cuda=11.6 -c pytorch -c nvidia +pip install -U openmim +mim install mmcv-full +pip install colorama +git clone https://github.com/moewiee/sdsvtr.git +cd sdsvtr +pip install -v -e . +``` + +## Basic Usage +```python +from sdsvtr import StandaloneSATRNRunner +runner = StandaloneSATRNRunner(version='satrn-lite-general-pretrain-20230106', return_confident=False, use_cuda=False) +``` + +The `version` parameter accepts version names declared in `sdsvtr.factory.online_model_factory` or a local path such as `$DIR\model.pth`. To check for available versions in the hub, run: +```python +import sdsvtr +print(sdsvtr.__hub_available_versions__) +``` + +Naturally, a `StandaloneSATRNRunner` instance assumes the input to be one of the following: an instance of `np.ndarray`, an instance of `str`, a list of `np.ndarray`, or a list of `str`, for examples: +```python +import numpy as np +from sdsvtr import StandaloneSATRNRunner +runner = StandaloneSATRNRunner(version='satrn-lite-general-pretrain-20230106', return_confident=False, use_cuda=False) + +dummy_list = [np.ndarray((32,128,3)) for _ in range(100)] +result = runner(dummy_list) +``` + +To run with a specific batchsize, try: +```python +import numpy as np +from sdsvtr import StandaloneSATRNRunner +runner = StandaloneSATRNRunner(version='satrn-lite-general-pretrain-20230106', return_confident=False, device='cuda:0') + +dummy_list = [np.ndarray(1,3,32,128) for _ in range(100)] +bs = min(32, len(imageFiles)) # batchsize = 32 + +all_results = [] +while len(dummy_list) > 0: + dummy_batch = dummy_list[:bs] + dummy_list = dummy_list[bs:] + all_results += runner(dummy_batch) +``` + +## Version Changelog +* **[0.0.1]** +Initial version with specified features. + + +* **[0.0.2]** +Update online model hub. + + +* **[0.0.3]** +Update API now able to inference with 4 types of inputs: list/instance of `np.ndarray`/`str` +Update API interface with `return_confident` parameter. +Update `wget` check and `sha256` check for model hub retrieval. + +* **[0.0.4]** +Update decoder module with EarlyStopping mechanism to possibly improve inference speed on short sequences. +Update API interface with optional argument `max_seq_len_overwrite` to overwrite checkpoint's `max_seq_len` config. + +* **[0.0.5]** +Allow inference on a specific device diff --git a/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtr/requirements.txt b/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtr/requirements.txt new file mode 100644 index 0000000..f4a74db --- /dev/null +++ b/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtr/requirements.txt @@ -0,0 +1,3 @@ +torch +colorama +mmcv-full \ No newline at end of file diff --git a/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtr/sdsvtr/__init__.py b/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtr/sdsvtr/__init__.py new file mode 100644 index 0000000..dd8470d --- /dev/null +++ b/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtr/sdsvtr/__init__.py @@ -0,0 +1,3 @@ +from .api import StandaloneSATRNRunner +from .version import __version__ +from .factory import __hub_available_versions__ \ No newline at end of file diff --git a/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtr/sdsvtr/api.py b/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtr/sdsvtr/api.py new file mode 100644 index 0000000..566a904 --- /dev/null +++ b/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtr/sdsvtr/api.py @@ -0,0 +1,106 @@ + +import torch +import torch.nn as nn + +from colorama import Fore, Style + +from .converter import AttnConvertor +from .backbone import ResNetABI +from .encoder import SatrnEncoder +from .decoder import NRTRDecoder +from .transform import DataPipelineSATRN +from .fp16_utils import patch_norm_fp32 +from .factory import _get as get_version + + +class SATRN(nn.Module): + """Standalone implementation for SATRN encode-decode recognizer.""" + + def __init__(self, + version, + return_confident=False, + device='cpu', + max_seq_len_overwrite=None): + + super().__init__() + + checkpoint = get_version(version) + + pt = torch.load(checkpoint, 'cpu') + if device == 'cpu': + print(Fore.RED + 'Warning: You are using CPU inference method. Init with device=cuda: to run with CUDA method.' + Style.RESET_ALL) + + self.pipeline = DataPipelineSATRN(**pt['pipeline_args'], device=device) + + # Convertor + self.label_convertor = AttnConvertor(**pt['label_convertor_args'], return_confident=return_confident) + + # Backbone + self.backbone = ResNetABI(**pt['backbone_args']) + + # Encoder module + self.encoder = SatrnEncoder(**pt['encoder_args']) + + # Decoder module + decoder_max_seq_len = max_seq_len_overwrite if max_seq_len_overwrite is not None else pt['max_seq_len'] + self.decoder = NRTRDecoder( + **pt['decoder_args'], + max_seq_len=decoder_max_seq_len, + num_classes=self.label_convertor.num_classes(), + start_idx=self.label_convertor.start_idx, + padding_idx=self.label_convertor.padding_idx, + return_confident=return_confident, + end_idx=self.label_convertor.end_idx + ) + + self.load_state_dict(pt['state_dict'], strict=True) + print(f'Text recognition from version {version}.') + + if device != 'cpu': + self = self.to(device) + self = self.half() + patch_norm_fp32(self) + + self.eval() + for param in self.parameters(): + param.requires_grad = False + + def extract_feat(self, img): + x = self.backbone(img) + + return x + + def forward(self, img): + """Test function with test time augmentation. + + Args: + imgs (torch.Tensor): Image input tensor. + + Returns: + list[str]: Text label result of each image. + """ + img = self.pipeline(img) + feat = self.extract_feat(img) + out_enc = self.encoder(feat) + out_dec = self.decoder(out_enc).cpu().numpy() + label_strings = self.label_convertor(out_dec) + + return label_strings + + +class StandaloneSATRNRunner: + def __init__(self, + version, + return_confident, + device='cpu', + max_seq_len_overwrite=None): + self.device = device + self.model = SATRN(version=version, + return_confident=return_confident, + device=self.device, + max_seq_len_overwrite=max_seq_len_overwrite) + + def __call__(self, imgs): + results = self.model(imgs) + + return results \ No newline at end of file diff --git a/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtr/sdsvtr/backbone.py b/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtr/sdsvtr/backbone.py new file mode 100644 index 0000000..29c2509 --- /dev/null +++ b/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtr/sdsvtr/backbone.py @@ -0,0 +1,159 @@ +import torch.nn as nn + +def conv3x3(in_planes, out_planes, stride=1): + """3x3 convolution with padding.""" + return nn.Conv2d( + in_planes, + out_planes, + kernel_size=3, + stride=stride, + padding=1, + bias=False) + + +def conv1x1(in_planes, out_planes): + """1x1 convolution with padding.""" + return nn.Conv2d( + in_planes, out_planes, kernel_size=1, stride=1, padding=0, bias=False) + + +class BasicBlock(nn.Module): + + expansion = 1 + + def __init__(self, + inplanes, + planes, + stride=1, + downsample=None, + use_conv1x1=False): + super(BasicBlock, self).__init__() + + if use_conv1x1: + self.conv1 = conv1x1(inplanes, planes) + self.conv2 = conv3x3(planes, planes * self.expansion, stride) + else: + self.conv1 = conv3x3(inplanes, planes, stride) + self.conv2 = conv3x3(planes, planes * self.expansion) + + self.planes = planes + self.bn1 = nn.BatchNorm2d(planes) + self.relu = nn.ReLU(inplace=True) + self.bn2 = nn.BatchNorm2d(planes * self.expansion) + self.downsample = downsample + self.stride = stride + + def forward(self, x): + residual = x + out = self.conv1(x) + out = self.bn1(out) + out = self.relu(out) + out = self.conv2(out) + out = self.bn2(out) + if self.downsample is not None: + residual = self.downsample(x) + out += residual + out = self.relu(out) + + return out + +class ResNetABI(nn.Module): + """Implement ResNet backbone for text recognition, modified from `ResNet. + + `_ and + ``_ + + Args: + in_channels (int): Number of channels of input image tensor. + stem_channels (int): Number of stem channels. + base_channels (int): Number of base channels. + arch_settings (list[int]): List of BasicBlock number for each stage. + strides (Sequence[int]): Strides of the first block of each stage. + out_indices (None | Sequence[int]): Indices of output stages. If not + specified, only the last stage will be returned. + last_stage_pool (bool): If True, add `MaxPool2d` layer to last stage. + """ + + def __init__(self, + in_channels=3, + stem_channels=32, + base_channels=32, + arch_settings=[3, 4, 6, 6, 3], + strides=[2, 1, 2, 1, 1], + out_indices=None, + last_stage_pool=False): + super().__init__() + + self.out_indices = out_indices + self.last_stage_pool = last_stage_pool + self.block = BasicBlock + self.inplanes = stem_channels + + self._make_stem_layer(in_channels, stem_channels) + + self.res_layers = [] + planes = base_channels + for i, num_blocks in enumerate(arch_settings): + stride = strides[i] + res_layer = self._make_layer( + block=self.block, + inplanes=self.inplanes, + planes=planes, + blocks=num_blocks, + stride=stride) + self.inplanes = planes * self.block.expansion + planes *= 2 + layer_name = f'layer{i + 1}' + self.add_module(layer_name, res_layer) + self.res_layers.append(layer_name) + + def _make_layer(self, block, inplanes, planes, blocks, stride=1): + layers = [] + downsample = None + if stride != 1 or inplanes != planes: + downsample = nn.Sequential( + nn.Conv2d(inplanes, planes, 1, stride, bias=False), + nn.BatchNorm2d(planes), + ) + layers.append( + block( + inplanes, + planes, + use_conv1x1=True, + stride=stride, + downsample=downsample)) + inplanes = planes + for _ in range(1, blocks): + layers.append(block(inplanes, planes, use_conv1x1=True)) + + return nn.Sequential(*layers) + + def _make_stem_layer(self, in_channels, stem_channels): + self.conv1 = nn.Conv2d( + in_channels, stem_channels, kernel_size=3, stride=1, padding=1) + self.bn1 = nn.BatchNorm2d(stem_channels) + self.relu1 = nn.ReLU(inplace=True) + + def forward(self, x): + """ + Args: + x (Tensor): Image tensor of shape :math:`(N, 3, H, W)`. + + Returns: + Tensor or list[Tensor]: Feature tensor. Its shape depends on + ResNetABI's config. It can be a list of feature outputs at specific + layers if ``out_indices`` is specified. + """ + + x = self.conv1(x) + x = self.bn1(x) + x = self.relu1(x) + + outs = [] + for i, layer_name in enumerate(self.res_layers): + res_layer = getattr(self, layer_name) + x = res_layer(x) + if self.out_indices and i in self.out_indices: + outs.append(x) + + return tuple(outs) if self.out_indices else x diff --git a/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtr/sdsvtr/conv.py b/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtr/sdsvtr/conv.py new file mode 100644 index 0000000..950ec0c --- /dev/null +++ b/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtr/sdsvtr/conv.py @@ -0,0 +1,173 @@ +import warnings +import torch.nn as nn +from torch.nn.modules.instancenorm import _InstanceNorm +from torch.nn.modules.batchnorm import _BatchNorm +from mmcv.cnn import build_padding_layer, build_conv_layer, build_norm_layer, build_activation_layer + +class ConvModule(nn.Module): + """A conv block that bundles conv/norm/activation layers. + + This block simplifies the usage of convolution layers, which are commonly + used with a norm layer (e.g., BatchNorm) and activation layer (e.g., ReLU). + It is based upon three build methods: `build_conv_layer()`, + `build_norm_layer()` and `build_activation_layer()`. + + Besides, we add some additional features in this module. + 1. Automatically set `bias` of the conv layer. + 2. Spectral norm is supported. + 3. More padding modes are supported. Before PyTorch 1.5, nn.Conv2d only + supports zero and circular padding, and we add "reflect" padding mode. + + Args: + in_channels (int): Number of channels in the input feature map. + Same as that in ``nn._ConvNd``. + out_channels (int): Number of channels produced by the convolution. + Same as that in ``nn._ConvNd``. + kernel_size (int | tuple[int]): Size of the convolving kernel. + Same as that in ``nn._ConvNd``. + stride (int | tuple[int]): Stride of the convolution. + Same as that in ``nn._ConvNd``. + padding (int | tuple[int]): Zero-padding added to both sides of + the input. Same as that in ``nn._ConvNd``. + dilation (int | tuple[int]): Spacing between kernel elements. + Same as that in ``nn._ConvNd``. + groups (int): Number of blocked connections from input channels to + output channels. Same as that in ``nn._ConvNd``. + bias (bool | str): If specified as `auto`, it will be decided by the + norm_cfg. Bias will be set as True if `norm_cfg` is None, otherwise + False. Default: "auto". + conv_cfg (dict): Config dict for convolution layer. Default: None, + which means using conv2d. + norm_cfg (dict): Config dict for normalization layer. Default: None. + act_cfg (dict): Config dict for activation layer. + Default: dict(type='ReLU'). + inplace (bool): Whether to use inplace mode for activation. + Default: True. + with_spectral_norm (bool): Whether use spectral norm in conv module. + Default: False. + padding_mode (str): If the `padding_mode` has not been supported by + current `Conv2d` in PyTorch, we will use our own padding layer + instead. Currently, we support ['zeros', 'circular'] with official + implementation and ['reflect'] with our own implementation. + Default: 'zeros'. + order (tuple[str]): The order of conv/norm/activation layers. It is a + sequence of "conv", "norm" and "act". Common examples are + ("conv", "norm", "act") and ("act", "conv", "norm"). + Default: ('conv', 'norm', 'act'). + """ + + _abbr_ = 'conv_block' + + def __init__(self, + in_channels, + out_channels, + kernel_size, + stride=1, + padding=0, + dilation=1, + groups=1, + bias='auto', + conv_cfg=None, + norm_cfg=None, + act_cfg=dict(type='ReLU'), + inplace=True, + with_spectral_norm=False, + padding_mode='zeros', + order=('conv', 'norm', 'act')): + super(ConvModule, self).__init__() + assert conv_cfg is None or isinstance(conv_cfg, dict) + assert norm_cfg is None or isinstance(norm_cfg, dict) + assert act_cfg is None or isinstance(act_cfg, dict) + official_padding_mode = ['zeros', 'circular'] + self.conv_cfg = conv_cfg + self.norm_cfg = norm_cfg + self.act_cfg = act_cfg + self.inplace = inplace + self.with_spectral_norm = with_spectral_norm + self.with_explicit_padding = padding_mode not in official_padding_mode + self.order = order + assert isinstance(self.order, tuple) and len(self.order) == 3 + assert set(order) == set(['conv', 'norm', 'act']) + + self.with_norm = norm_cfg is not None + self.with_activation = act_cfg is not None + # if the conv layer is before a norm layer, bias is unnecessary. + if bias == 'auto': + bias = not self.with_norm + self.with_bias = bias + + if self.with_explicit_padding: + pad_cfg = dict(type=padding_mode) + self.padding_layer = build_padding_layer(pad_cfg, padding) + + # reset padding to 0 for conv module + conv_padding = 0 if self.with_explicit_padding else padding + # build convolution layer + self.conv = build_conv_layer( + conv_cfg, + in_channels, + out_channels, + kernel_size, + stride=stride, + padding=conv_padding, + dilation=dilation, + groups=groups, + bias=bias) + # export the attributes of self.conv to a higher level for convenience + self.in_channels = self.conv.in_channels + self.out_channels = self.conv.out_channels + self.kernel_size = self.conv.kernel_size + self.stride = self.conv.stride + self.padding = padding + self.dilation = self.conv.dilation + self.transposed = self.conv.transposed + self.output_padding = self.conv.output_padding + self.groups = self.conv.groups + + if self.with_spectral_norm: + self.conv = nn.utils.spectral_norm(self.conv) + + # build normalization layers + if self.with_norm: + # norm layer is after conv layer + if order.index('norm') > order.index('conv'): + norm_channels = out_channels + else: + norm_channels = in_channels + self.norm_name, norm = build_norm_layer(norm_cfg, norm_channels) + self.add_module(self.norm_name, norm) + if self.with_bias: + if isinstance(norm, (_BatchNorm, _InstanceNorm)): + warnings.warn( + 'Unnecessary conv bias before batch/instance norm') + else: + self.norm_name = None + + # build activation layer + if self.with_activation: + act_cfg_ = act_cfg.copy() + # nn.Tanh has no 'inplace' argument + if act_cfg_['type'] not in [ + 'Tanh', 'PReLU', 'Sigmoid', 'HSigmoid', 'Swish' + ]: + act_cfg_.setdefault('inplace', inplace) + self.activate = build_activation_layer(act_cfg_) + + @property + def norm(self): + if self.norm_name: + return getattr(self, self.norm_name) + else: + return None + + def forward(self, x, activate=True, norm=True): + for layer in self.order: + if layer == 'conv': + if self.with_explicit_padding: + x = self.padding_layer(x) + x = self.conv(x) + elif layer == 'norm' and norm and self.with_norm: + x = self.norm(x) + elif layer == 'act' and activate and self.with_activation: + x = self.activate(x) + return x \ No newline at end of file diff --git a/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtr/sdsvtr/converter.py b/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtr/sdsvtr/converter.py new file mode 100644 index 0000000..4d9bf82 --- /dev/null +++ b/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtr/sdsvtr/converter.py @@ -0,0 +1,152 @@ +import torch +import numpy as np + +class BaseConvertor: + """Convert between text, index and tensor for text recognize pipeline. + + Args: + dict_type (str): Type of dict, options are 'DICT36', 'DICT37', 'DICT90' + and 'DICT91'. + dict_file (None|str): Character dict file path. If not none, + the dict_file is of higher priority than dict_type. + dict_list (None|list[str]): Character list. If not none, the list + is of higher priority than dict_type, but lower than dict_file. + """ + start_idx = end_idx = padding_idx = 0 + unknown_idx = None + lower = False + + DICT36 = tuple('0123456789abcdefghijklmnopqrstuvwxyz') + DICT63 = tuple('0123456789abcdefghijklmnopqrstuvwxyz' + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ') + DICT90 = tuple('0123456789abcdefghijklmnopqrstuvwxyz' + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'()' + '*+,-./:;<=>?@[\\]_`~') + DICT131 = tuple('0123456789abcdefghijklmnopqrstuvwxyz' + '!"#$%&\'()' + '*+,-./:;<=>?@[\\]_`~' + 'ạảãàáâậầấẩẫăắằặẳẵóòọõỏôộổỗồốơờớợởỡéèẻẹẽêếềệểễúùụủũưựữửừứíìịỉĩýỳỷỵỹđ') + DICT224 = tuple('0123456789abcdefghijklmnopqrstuvwxyz' + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'()' + '*+,-./:;<=>?@[\\]_`~{}|^ ̂' + 'ạảãàáâậầấẩẫăắằặẳẵóòọõỏôộổỗồốơờớợởỡéèẻẹẽêếềệểễúùụủũưựữửừứíìịỉĩýỳỷỵỹđ' + 'ẠẢÃÀÁÂẬẦẤẨẪĂẮẰẶẲẴÓÒỌÕỎÔỘỔỖỒỐƠỜỚỢỞỠÉÈẺẸẼÊẾỀỆỂỄÚÙỤỦŨƯỰỮỬỪỨÍÌỊỈĨÝỲỶỴỸĐ✪') + + def __init__(self, dict_type='DICT90'): + assert dict_type in ('DICT36', 'DICT63', 'DICT90', 'DICT131', 'DICT224') + self.idx2char = [] + + if dict_type == 'DICT36': + self.idx2char = list(self.DICT36) + elif dict_type == 'DICT63': + self.idx2char = list(self.DICT63) + elif dict_type == 'DICT90': + self.idx2char = list(self.DICT90) + elif dict_type == 'DICT131': + self.idx2char = list(self.DICT131) + elif dict_type == 'DICT224': + self.idx2char = list(self.DICT224) + else: + raise ('Dictonary not implemented') + + assert len(set(self.idx2char)) == len(self.idx2char), \ + 'Invalid dictionary: Has duplicated characters.' + + self.char2idx = {char: idx for idx, char in enumerate(self.idx2char)} + + def num_classes(self): + """Number of output classes.""" + return len(self.idx2char) + + +class AttnConvertor(BaseConvertor): + """Convert between text, index and tensor for encoder-decoder based + pipeline. + + Args: + dict_type (str): Type of dict, should be one of {'DICT36', 'DICT90'}. + dict_file (None|str): Character dict file path. If not none, + higher priority than dict_type. + dict_list (None|list[str]): Character list. If not none, higher + priority than dict_type, but lower than dict_file. + with_unknown (bool): If True, add `UKN` token to class. + max_seq_len (int): Maximum sequence length of label. + lower (bool): If True, convert original string to lower case. + start_end_same (bool): Whether use the same index for + start and end token or not. Default: True. + """ + + def __init__(self, + dict_type='DICT90', + with_unknown=True, + max_seq_len=40, + lower=False, + start_end_same=True, + return_confident=False, + **kwargs): + super().__init__(dict_type) + assert isinstance(with_unknown, bool) + assert isinstance(max_seq_len, int) + assert isinstance(lower, bool) + + self.with_unknown = with_unknown + self.max_seq_len = max_seq_len + self.lower = lower + self.start_end_same = start_end_same + self.return_confident = return_confident + + self.update_dict() + + def update_dict(self): + start_end_token = '' + unknown_token = '' + padding_token = '' + + # unknown + self.unknown_idx = None + if self.with_unknown: + self.idx2char.append(unknown_token) + self.unknown_idx = len(self.idx2char) - 1 + + # BOS/EOS + self.idx2char.append(start_end_token) + self.start_idx = len(self.idx2char) - 1 + if not self.start_end_same: + self.idx2char.append(start_end_token) + self.end_idx = len(self.idx2char) - 1 + + # padding + self.idx2char.append(padding_token) + self.padding_idx = len(self.idx2char) - 1 + + # update char2idx + self.char2idx = {} + for idx, char in enumerate(self.idx2char): + self.char2idx[char] = idx + + def __call__(self, indexes): + strings = [] + confidents = [] + if self.return_confident: + b,sq,_ = indexes.shape + for idx in range(b): + index = indexes[idx, :, :] + chars = index.argmax(-1) + confident = index.max(-1) + i = 0 + while i < sq and chars[i] != self.end_idx and chars[i] != self.padding_idx: i += 1 + chars = chars[:i] + confident = confident[:i].min() + string = [self.idx2char[i] for i in chars] + strings.append(''.join(string)) + confidents.append(confident) + + return strings, confidents + else: + for index in indexes: + i, l = 0, len(index) + while i < l and index[i] != self.end_idx and index[i] != self.padding_idx: i += 1 + index = index[:i] + string = [self.idx2char[i] for i in index] + strings.append(''.join(string)) + return strings \ No newline at end of file diff --git a/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtr/sdsvtr/decoder.py b/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtr/sdsvtr/decoder.py new file mode 100644 index 0000000..b4ec51a --- /dev/null +++ b/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtr/sdsvtr/decoder.py @@ -0,0 +1,278 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F +import math +import numpy as np +from .encoder import MultiHeadAttention + + +class PositionwiseFeedForward(nn.Module): + """Two-layer feed-forward module. + + Args: + d_in (int): The dimension of the input for feedforward + network model. + d_hid (int): The dimension of the feedforward + network model. + dropout (float): Dropout layer on feedforward output. + act_cfg (dict): Activation cfg for feedforward module. + """ + + def __init__(self, d_in, d_hid, dropout=0.1): + super().__init__() + self.w_1 = nn.Linear(d_in, d_hid) + self.w_2 = nn.Linear(d_hid, d_in) + self.act = nn.GELU() + self.dropout = nn.Dropout(dropout) + + def forward(self, x): + x = self.w_1(x) + x = self.act(x) + x = self.w_2(x) + x = self.dropout(x) + + return x + + +class PositionalEncoding(nn.Module): + """Fixed positional encoding with sine and cosine functions.""" + + def __init__(self, d_hid=512, n_position=200): + super().__init__() + + # Not a parameter + # Position table of shape (1, n_position, d_hid) + self.register_buffer( + 'position_table', + self._get_sinusoid_encoding_table(n_position, d_hid)) + + def _get_sinusoid_encoding_table(self, n_position, d_hid): + """Sinusoid position encoding table.""" + denominator = torch.Tensor([ + 1.0 / np.power(10000, 2 * (hid_j // 2) / d_hid) + for hid_j in range(d_hid) + ]) + denominator = denominator.view(1, -1) + pos_tensor = torch.arange(n_position).unsqueeze(-1).float() + sinusoid_table = pos_tensor * denominator + sinusoid_table[:, 0::2] = torch.sin(sinusoid_table[:, 0::2]) + sinusoid_table[:, 1::2] = torch.cos(sinusoid_table[:, 1::2]) + + return sinusoid_table.unsqueeze(0) + + def forward(self, x): + """ + Args: + x (Tensor): Tensor of shape (batch_size, pos_len, d_hid, ...) + """ + self.device = x.device + x = x + self.position_table[:, :x.size(1)].clone().detach() + return x + + + +class TFDecoderLayer(nn.Module): + """Transformer Decoder Layer. + + Args: + d_model (int): The number of expected features + in the decoder inputs (default=512). + d_inner (int): The dimension of the feedforward + network model (default=256). + n_head (int): The number of heads in the + multiheadattention models (default=8). + d_k (int): Total number of features in key. + d_v (int): Total number of features in value. + dropout (float): Dropout layer on attn_output_weights. + qkv_bias (bool): Add bias in projection layer. Default: False. + act_cfg (dict): Activation cfg for feedforward module. + operation_order (tuple[str]): The execution order of operation + in transformer. Such as ('self_attn', 'norm', 'enc_dec_attn', + 'norm', 'ffn', 'norm') or ('norm', 'self_attn', 'norm', + 'enc_dec_attn', 'norm', 'ffn'). + Default:None. + """ + + def __init__(self, + d_model=512, + d_inner=256, + n_head=8, + d_k=64, + d_v=64, + dropout=0.1, + qkv_bias=False): + super().__init__() + + self.norm1 = nn.LayerNorm(d_model) + self.norm2 = nn.LayerNorm(d_model) + self.norm3 = nn.LayerNorm(d_model) + + self.self_attn = MultiHeadAttention( + n_head, d_model, d_k, d_v, dropout=dropout, qkv_bias=qkv_bias) + + self.enc_attn = MultiHeadAttention( + n_head, d_model, d_k, d_v, dropout=dropout, qkv_bias=qkv_bias) + + self.mlp = PositionwiseFeedForward( + d_model, d_inner, dropout=dropout) + + def forward(self, + dec_input, + enc_output, + self_attn_mask=None, + dec_enc_attn_mask=None): + dec_input_norm = self.norm1(dec_input) + dec_attn_out = self.self_attn(dec_input_norm, dec_input_norm, + dec_input_norm, self_attn_mask) + dec_attn_out += dec_input + + enc_dec_attn_in = self.norm2(dec_attn_out) + enc_dec_attn_out = self.enc_attn(enc_dec_attn_in, enc_output, + enc_output, dec_enc_attn_mask) + enc_dec_attn_out += dec_attn_out + + mlp_out = self.mlp(self.norm3(enc_dec_attn_out)) + mlp_out += enc_dec_attn_out + + return mlp_out + +class NRTRDecoder(nn.Module): + """Transformer Decoder block with self attention mechanism. + + Args: + n_layers (int): Number of attention layers. + d_embedding (int): Language embedding dimension. + n_head (int): Number of parallel attention heads. + d_k (int): Dimension of the key vector. + d_v (int): Dimension of the value vector. + d_model (int): Dimension :math:`D_m` of the input from previous model. + d_inner (int): Hidden dimension of feedforward layers. + n_position (int): Length of the positional encoding vector. Must be + greater than ``max_seq_len``. + dropout (float): Dropout rate. + num_classes (int): Number of output classes :math:`C`. + max_seq_len (int): Maximum output sequence length :math:`T`. + start_idx (int): The index of ``. + padding_idx (int): The index of ``. + init_cfg (dict or list[dict], optional): Initialization configs. + + Warning: + This decoder will not predict the final class which is assumed to be + ``. Therefore, its output size is always :math:`C - 1`. `` + is also ignored by loss as specified in + :obj:`mmocr.models.textrecog.recognizer.EncodeDecodeRecognizer`. + """ + + def __init__(self, + n_layers=6, + d_embedding=512, + n_head=8, + d_k=64, + d_v=64, + d_model=512, + d_inner=256, + n_position=200, + dropout=0.1, + num_classes=93, + max_seq_len=40, + start_idx=1, + padding_idx=92, + return_confident=False, + end_idx=None, + **kwargs): + super().__init__() + + self.padding_idx = padding_idx + self.start_idx = start_idx + self.max_seq_len = max_seq_len + + self.trg_word_emb = nn.Embedding( + num_classes, d_embedding, padding_idx=padding_idx) + + self.position_enc = PositionalEncoding( + d_embedding, n_position=n_position) + + self.layer_stack = nn.ModuleList([ + TFDecoderLayer( + d_model, d_inner, n_head, d_k, d_v, dropout=dropout, **kwargs) + for _ in range(n_layers) + ]) + self.layer_norm = nn.LayerNorm(d_model, eps=1e-6) + + pred_num_class = num_classes - 1 # ignore padding_idx + self.classifier = nn.Linear(d_model, pred_num_class) + + self.return_confident = return_confident + self.end_idx = end_idx + + @staticmethod + def get_pad_mask(seq, pad_idx): + + return (seq != pad_idx).unsqueeze(-2) + + @staticmethod + def get_subsequent_mask(seq): + """For masking out the subsequent info.""" + len_s = seq.size(1) + subsequent_mask = 1 - torch.triu( + torch.ones((len_s, len_s), device=seq.device), diagonal=1) + subsequent_mask = subsequent_mask.unsqueeze(0).bool() + + return subsequent_mask + + def _attention(self, trg_seq, src, src_mask=None): + trg_embedding = self.trg_word_emb(trg_seq) + trg_pos_encoded = self.position_enc(trg_embedding) + trg_mask = self.get_pad_mask( + trg_seq, + pad_idx=self.padding_idx) & self.get_subsequent_mask(trg_seq) + output = trg_pos_encoded + for dec_layer in self.layer_stack: + output = dec_layer( + output, + src, + self_attn_mask=trg_mask, + dec_enc_attn_mask=src_mask) + output = self.layer_norm(output) + + return output + + def _get_mask(self, logit): + N, T, _ = logit.size() + mask = logit.new_ones((N, T)) + + return mask + + def forward(self, out_enc): + src_mask = self._get_mask(out_enc) + N = out_enc.size(0) + init_target_seq = torch.full((N, self.max_seq_len + 1), + self.padding_idx, + device=out_enc.device, + dtype=torch.long) + # bsz * seq_len + init_target_seq[:, 0] = self.start_idx + + outputs = [] + for step in range(0, self.max_seq_len): + decoder_output = self._attention( + trg_seq=init_target_seq, + src=out_enc, + src_mask=src_mask) + if self.return_confident: + step_result = torch.softmax(self.classifier(decoder_output[:, step, :]), -1) + next_step_init = step_result.argmax(-1) + init_target_seq[:, step + 1] = next_step_init + if next_step_init.min() >= self.end_idx: + break + else: + step_result = self.classifier(decoder_output[:, step, :]).argmax(-1) + init_target_seq[:, step + 1] = step_result + if step_result.min() >= self.end_idx: + break + + outputs.append(step_result) + + outputs = torch.stack(outputs, dim=1) + + return outputs \ No newline at end of file diff --git a/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtr/sdsvtr/encoder.py b/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtr/sdsvtr/encoder.py new file mode 100644 index 0000000..6ccb612 --- /dev/null +++ b/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtr/sdsvtr/encoder.py @@ -0,0 +1,317 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F +import numpy as np +import math +from .conv import ConvModule + + +class LocalityAwareFeedforward(nn.Module): + """Locality-aware feedforward layer in SATRN, see `SATRN. + + `_ + """ + + def __init__(self, + d_in, + d_hid, + dropout=0.1): + super().__init__() + self.conv1 = ConvModule( + d_in, + d_hid, + kernel_size=1, + padding=0, + bias=False, + norm_cfg=dict(type='BN'), + act_cfg=dict(type='ReLU')) + + self.depthwise_conv = ConvModule( + d_hid, + d_hid, + kernel_size=3, + padding=1, + bias=False, + groups=d_hid, + norm_cfg=dict(type='BN'), + act_cfg=dict(type='ReLU')) + + self.conv2 = ConvModule( + d_hid, + d_in, + kernel_size=1, + padding=0, + bias=False, + norm_cfg=dict(type='BN'), + act_cfg=dict(type='ReLU')) + + def forward(self, x): + x = self.conv1(x) + x = self.depthwise_conv(x) + x = self.conv2(x) + + return x + + +class ScaledDotProductAttention(nn.Module): + """Scaled Dot-Product Attention Module. This code is adopted from + https://github.com/jadore801120/attention-is-all-you-need-pytorch. + + Args: + temperature (float): The scale factor for softmax input. + attn_dropout (float): Dropout layer on attn_output_weights. + """ + + def __init__(self, temperature, attn_dropout=0.1): + super().__init__() + self.temperature = temperature + self.dropout = nn.Dropout(attn_dropout) + + def forward(self, q, k, v, mask=None): + + attn = torch.matmul(q / self.temperature, k.transpose(2, 3)) + + if mask is not None: + attn = attn.masked_fill(mask == 0, float('-inf')) + + attn = self.dropout(F.softmax(attn, dim=-1)) + output = torch.matmul(attn, v) + + return output, attn + + +class MultiHeadAttention(nn.Module): + """Multi-Head Attention module. + + Args: + n_head (int): The number of heads in the + multiheadattention models (default=8). + d_model (int): The number of expected features + in the decoder inputs (default=512). + d_k (int): Total number of features in key. + d_v (int): Total number of features in value. + dropout (float): Dropout layer on attn_output_weights. + qkv_bias (bool): Add bias in projection layer. Default: False. + """ + + def __init__(self, + n_head=8, + d_model=512, + d_k=64, + d_v=64, + dropout=0.1, + qkv_bias=False): + super().__init__() + self.n_head = n_head + self.d_k = d_k + self.d_v = d_v + + self.dim_k = n_head * d_k + self.dim_v = n_head * d_v + + self.linear_q = nn.Linear(self.dim_k, self.dim_k, bias=qkv_bias) + self.linear_k = nn.Linear(self.dim_k, self.dim_k, bias=qkv_bias) + self.linear_v = nn.Linear(self.dim_v, self.dim_v, bias=qkv_bias) + + self.attention = ScaledDotProductAttention(d_k**0.5, dropout) + + self.fc = nn.Linear(self.dim_v, d_model, bias=qkv_bias) + self.proj_drop = nn.Dropout(dropout) + + def forward(self, q, k, v, mask=None): + batch_size, len_q, _ = q.size() + _, len_k, _ = k.size() + + q = self.linear_q(q).view(batch_size, len_q, self.n_head, self.d_k) + k = self.linear_k(k).view(batch_size, len_k, self.n_head, self.d_k) + v = self.linear_v(v).view(batch_size, len_k, self.n_head, self.d_v) + + q, k, v = q.transpose(1, 2), k.transpose(1, 2), v.transpose(1, 2) + + if mask is not None: + if mask.dim() == 3: + mask = mask.unsqueeze(1) + elif mask.dim() == 2: + mask = mask.unsqueeze(1).unsqueeze(1) + + attn_out, _ = self.attention(q, k, v, mask=mask) + + attn_out = attn_out.transpose(1, 2).contiguous().view( + batch_size, len_q, self.dim_v) + + attn_out = self.fc(attn_out) + attn_out = self.proj_drop(attn_out) + + return attn_out + + +class SatrnEncoderLayer(nn.Module): + """""" + + def __init__(self, + d_model=512, + d_inner=512, + n_head=8, + d_k=64, + d_v=64, + dropout=0.1, + qkv_bias=False): + super().__init__() + self.norm1 = nn.LayerNorm(d_model) + self.attn = MultiHeadAttention( + n_head, d_model, d_k, d_v, qkv_bias=qkv_bias, dropout=dropout) + self.norm2 = nn.LayerNorm(d_model) + self.feed_forward = LocalityAwareFeedforward( + d_model, d_inner, dropout=dropout) + + def forward(self, x, h, w, mask=None): + n, hw, c = x.size() + residual = x + x = self.norm1(x) + x = residual + self.attn(x, x, x, mask) + residual = x + x = self.norm2(x) + x = x.transpose(1, 2).contiguous().view(n, c, h, w) + x = self.feed_forward(x) + x = x.view(n, c, hw).transpose(1, 2) + x = residual + x + return x + + +class Adaptive2DPositionalEncoding(nn.Module): + """Implement Adaptive 2D positional encoder for SATRN, see + `SATRN `_ + Modified from https://github.com/Media-Smart/vedastr + Licensed under the Apache License, Version 2.0 (the "License"); + Args: + d_hid (int): Dimensions of hidden layer. + n_height (int): Max height of the 2D feature output. + n_width (int): Max width of the 2D feature output. + dropout (int): Size of hidden layers of the model. + """ + + def __init__(self, + d_hid=512, + n_height=100, + n_width=100, + dropout=0.1): + super().__init__() + + h_position_encoder = self._get_sinusoid_encoding_table(n_height, d_hid) + h_position_encoder = h_position_encoder.transpose(0, 1) + h_position_encoder = h_position_encoder.view(1, d_hid, n_height, 1) + + w_position_encoder = self._get_sinusoid_encoding_table(n_width, d_hid) + w_position_encoder = w_position_encoder.transpose(0, 1) + w_position_encoder = w_position_encoder.view(1, d_hid, 1, n_width) + + self.register_buffer('h_position_encoder', h_position_encoder) + self.register_buffer('w_position_encoder', w_position_encoder) + + self.h_scale = self.scale_factor_generate(d_hid) + self.w_scale = self.scale_factor_generate(d_hid) + self.pool = nn.AdaptiveAvgPool2d(1) + self.dropout = nn.Dropout(p=dropout) + + def _get_sinusoid_encoding_table(self, n_position, d_hid): + """Sinusoid position encoding table.""" + denominator = torch.Tensor([ + 1.0 / np.power(10000, 2 * (hid_j // 2) / d_hid) + for hid_j in range(d_hid) + ]) + denominator = denominator.view(1, -1) + pos_tensor = torch.arange(n_position).unsqueeze(-1).float() + sinusoid_table = pos_tensor * denominator + sinusoid_table[:, 0::2] = torch.sin(sinusoid_table[:, 0::2]) + sinusoid_table[:, 1::2] = torch.cos(sinusoid_table[:, 1::2]) + + return sinusoid_table + + def scale_factor_generate(self, d_hid): + scale_factor = nn.Sequential( + nn.Conv2d(d_hid, d_hid, kernel_size=1), nn.ReLU(inplace=True), + nn.Conv2d(d_hid, d_hid, kernel_size=1), nn.Sigmoid()) + + return scale_factor + + def forward(self, x): + b, c, h, w = x.size() + + avg_pool = self.pool(x) + + h_pos_encoding = \ + self.h_scale(avg_pool) * self.h_position_encoder[:, :, :h, :] + w_pos_encoding = \ + self.w_scale(avg_pool) * self.w_position_encoder[:, :, :, :w] + + out = x + h_pos_encoding + w_pos_encoding + + out = self.dropout(out) + + return out + + +class SatrnEncoder(nn.Module): + """Implement encoder for SATRN, see `SATRN. + + `_. + + Args: + n_layers (int): Number of attention layers. + n_head (int): Number of parallel attention heads. + d_k (int): Dimension of the key vector. + d_v (int): Dimension of the value vector. + d_model (int): Dimension :math:`D_m` of the input from previous model. + n_position (int): Length of the positional encoding vector. Must be + greater than ``max_seq_len``. + d_inner (int): Hidden dimension of feedforward layers. + dropout (float): Dropout rate. + init_cfg (dict or list[dict], optional): Initialization configs. + """ + + def __init__(self, + n_layers=12, + n_head=8, + d_k=64, + d_v=64, + d_model=512, + n_position=100, + d_inner=256, + dropout=0.1, + **kwargs): + super().__init__() + self.d_model = d_model + self.position_enc = Adaptive2DPositionalEncoding( + d_hid=d_model, + n_height=n_position, + n_width=n_position, + dropout=dropout) + self.layer_stack = nn.ModuleList([ + SatrnEncoderLayer( + d_model, d_inner, n_head, d_k, d_v, dropout=dropout) + for _ in range(n_layers) + ]) + self.layer_norm = nn.LayerNorm(d_model) + + def forward(self, feat): + """ + Args: + feat (Tensor): Feature tensor of shape :math:`(N, D_m, H, W)`. + + Returns: + Tensor: A tensor of shape :math:`(N, T, D_m)`. + """ + feat = feat + self.position_enc(feat) + n, c, h, w = feat.size() + mask = feat.new_zeros((n, h, w)) + mask[:,:,:w] = 1 + + mask = mask.view(n, h * w) + feat = feat.view(n, c, h * w) + + output = feat.permute(0, 2, 1).contiguous() + for enc_layer in self.layer_stack: + output = enc_layer(output, h, w, mask) + output = self.layer_norm(output) + + return output \ No newline at end of file diff --git a/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtr/sdsvtr/factory.py b/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtr/sdsvtr/factory.py new file mode 100644 index 0000000..773d5a0 --- /dev/null +++ b/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtr/sdsvtr/factory.py @@ -0,0 +1,57 @@ +import os +import shutil +import colorama +import hashlib + +def sha256sum(filename): + h = hashlib.sha256() + b = bytearray(128*1024) + mv = memoryview(b) + with open(filename, 'rb', buffering=0) as f: + for n in iter(lambda : f.readinto(mv), 0): + h.update(mv[:n]) + return h.hexdigest() + + +online_model_factory = { + 'satrn-lite-general-pretrain-20230106': { + 'url': 'https://github.com/moewiee/satrn-model-factory/raw/main/jxqhbem4to.pth', + 'hash': 'b0069a72bf6fc080ad5d431d5ce650c3bfbab535141adef1631fce331cb1471c'}, + 'satrn-lite-captcha-finetune-20230108': { + 'url': 'https://github.com/moewiee/satrn-model-factory/raw/main/l27vitogmc.pth', + 'hash': 'efcbcf2955b6b21125b073f83828d2719e908c7303b0d9901e94be5a8efba916'}, + 'satrn-lite-handwritten-finetune-20230108': { + 'url': 'https://github.com/moewiee/satrn-model-factory/raw/main/lj9gkwelns.pth', + 'hash': 'bccd8e985b131fcd4701114af5ceaef098f2eac50654bbb1d828e7f829e711dd'}, +} + +__hub_available_versions__ = online_model_factory.keys() + +def _get(version): + use_online = version in __hub_available_versions__ + + if not use_online and not os.path.exists(version): + raise ValueError(f'Model version {version} not found online and not found local.') + + hub_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'hub') + if not os.path.exists(hub_path): + os.makedirs(hub_path) + if use_online: + version_url = online_model_factory[version]['url'] + file_path = os.path.join(hub_path, os.path.basename(version_url)) + else: + file_path = os.path.join(hub_path, os.path.basename(version)) + + if not os.path.exists(file_path): + if use_online: + os.system(f'wget -O {file_path} {version_url}') + assert os.path.exists(file_path), \ + colorama.Fore.RED + 'wget failed while trying to retrieve from hub.' + colorama.Style.RESET_ALL + downloaded_hash = sha256sum(file_path) + if downloaded_hash != online_model_factory[version]['hash']: + os.remove(file_path) + raise ValueError(colorama.Fore.RED + 'sha256 hash doesnt match for version retrieved from hub.' + colorama.Style.RESET_ALL) + else: + shutil.copy2(version, file_path) + + return file_path \ No newline at end of file diff --git a/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtr/sdsvtr/fp16_utils.py b/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtr/sdsvtr/fp16_utils.py new file mode 100644 index 0000000..126ff02 --- /dev/null +++ b/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtr/sdsvtr/fp16_utils.py @@ -0,0 +1,78 @@ +import torch +import torch.nn as nn +import numpy as np +from collections import abc + + +def cast_tensor_type(inputs, src_type, dst_type): + """Recursively convert Tensor in inputs from src_type to dst_type. + + Args: + inputs: Inputs that to be casted. + src_type (torch.dtype): Source type.. + dst_type (torch.dtype): Destination type. + + Returns: + The same type with inputs, but all contained Tensors have been cast. + """ + if isinstance(inputs, nn.Module): + return inputs + elif isinstance(inputs, torch.Tensor): + return inputs.to(dst_type) + elif isinstance(inputs, str): + return inputs + elif isinstance(inputs, np.ndarray): + return inputs + elif isinstance(inputs, abc.Mapping): + return type(inputs)({ + k: cast_tensor_type(v, src_type, dst_type) + for k, v in inputs.items() + }) + elif isinstance(inputs, abc.Iterable): + return type(inputs)( + cast_tensor_type(item, src_type, dst_type) for item in inputs) + else: + return inputs + + +def patch_forward_method(func, src_type, dst_type, convert_output=True): + """Patch the forward method of a module. + + Args: + func (callable): The original forward method. + src_type (torch.dtype): Type of input arguments to be converted from. + dst_type (torch.dtype): Type of input arguments to be converted to. + convert_output (bool): Whether to convert the output back to src_type. + + Returns: + callable: The patched forward method. + """ + + def new_forward(*args, **kwargs): + output = func(*cast_tensor_type(args, src_type, dst_type), + **cast_tensor_type(kwargs, src_type, dst_type)) + if convert_output: + output = cast_tensor_type(output, dst_type, src_type) + return output + + return new_forward + + +def patch_norm_fp32(module): + """Recursively convert normalization layers from FP16 to FP32. + + Args: + module (nn.Module): The modules to be converted in FP16. + + Returns: + nn.Module: The converted module, the normalization layers have been + converted to FP32. + """ + if isinstance(module, (nn.modules.batchnorm._BatchNorm, nn.GroupNorm)): + module.float() + if isinstance(module, nn.GroupNorm) or torch.__version__ < '1.3': + module.forward = patch_forward_method(module.forward, torch.half, + torch.float) + for child in module.children(): + patch_norm_fp32(child) + return module \ No newline at end of file diff --git a/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtr/sdsvtr/transform.py b/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtr/sdsvtr/transform.py new file mode 100644 index 0000000..e366a4c --- /dev/null +++ b/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtr/sdsvtr/transform.py @@ -0,0 +1,33 @@ +import torchvision.transforms.functional as TF +import cv2 +import torch + +class DataPipelineSATRN: + def __init__(self, + resize_height, + resize_width, + norm_mean, + norm_std, + device='cpu'): + self.resize_height = resize_height + self.resize_width = resize_width + self.norm_mean = norm_mean + self.norm_std = norm_std + self.device = device + + def __call__(self, imgs): + if not isinstance(imgs, list): + imgs = [imgs] + datas = [] + for img in imgs: + if isinstance(img, str): + img = cv2.imread(img) + data = torch.from_numpy(cv2.resize(img, (self.resize_width, self.resize_height), interpolation=cv2.INTER_LINEAR)) + datas.append(data) + + data = torch.stack(datas, dim=0) + data = data.to(self.device) + data = data.float().div_(255.).permute((0,3,1,2)) + TF.normalize(data, mean=self.norm_mean, std=self.norm_std, inplace=True) + + return data.half() if self.device != 'cpu' else data \ No newline at end of file diff --git a/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtr/sdsvtr/version.py b/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtr/sdsvtr/version.py new file mode 100644 index 0000000..a55ccd2 --- /dev/null +++ b/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtr/sdsvtr/version.py @@ -0,0 +1 @@ +__version__ = '0.0.5' \ No newline at end of file diff --git a/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtr/setup.py b/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtr/setup.py new file mode 100644 index 0000000..4df1557 --- /dev/null +++ b/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtr/setup.py @@ -0,0 +1,187 @@ +import os +import os.path as osp +import shutil +import sys +import warnings +from setuptools import find_packages, setup + + +def readme(): + with open('README.md', encoding='utf-8') as f: + content = f.read() + return content + + +version_file = 'sdsvtr/version.py' +is_windows = sys.platform == 'win32' + + +def add_mim_extention(): + """Add extra files that are required to support MIM into the package. + + These files will be added by creating a symlink to the originals if the + package is installed in `editable` mode (e.g. pip install -e .), or by + copying from the originals otherwise. + """ + + # parse installment mode + if 'develop' in sys.argv: + # installed by `pip install -e .` + mode = 'symlink' + elif 'sdist' in sys.argv or 'bdist_wheel' in sys.argv: + # installed by `pip install .` + # or create source distribution by `python setup.py sdist` + mode = 'copy' + else: + return + + filenames = ['tools', 'configs', 'model-index.yml'] + repo_path = osp.dirname(__file__) + mim_path = osp.join(repo_path, 'mmocr', '.mim') + os.makedirs(mim_path, exist_ok=True) + + for filename in filenames: + if osp.exists(filename): + src_path = osp.join(repo_path, filename) + tar_path = osp.join(mim_path, filename) + + if osp.isfile(tar_path) or osp.islink(tar_path): + os.remove(tar_path) + elif osp.isdir(tar_path): + shutil.rmtree(tar_path) + + if mode == 'symlink': + src_relpath = osp.relpath(src_path, osp.dirname(tar_path)) + try: + os.symlink(src_relpath, tar_path) + except OSError: + # Creating a symbolic link on windows may raise an + # `OSError: [WinError 1314]` due to privilege. If + # the error happens, the src file will be copied + mode = 'copy' + warnings.warn( + f'Failed to create a symbolic link for {src_relpath}, ' + f'and it will be copied to {tar_path}') + else: + continue + + if mode == 'copy': + if osp.isfile(src_path): + shutil.copyfile(src_path, tar_path) + elif osp.isdir(src_path): + shutil.copytree(src_path, tar_path) + else: + warnings.warn(f'Cannot copy file {src_path}.') + else: + raise ValueError(f'Invalid mode {mode}') + + +def get_version(): + with open(version_file, 'r') as f: + exec(compile(f.read(), version_file, 'exec')) + import sys + + # return short version for sdist + if 'sdist' in sys.argv or 'bdist_wheel' in sys.argv: + return locals()['short_version'] + else: + return locals()['__version__'] + + +def parse_requirements(fname='requirements.txt', with_version=True): + """Parse the package dependencies listed in a requirements file but strip + specific version information. + + Args: + fname (str): Path to requirements file. + with_version (bool, default=False): If True, include version specs. + Returns: + info (list[str]): List of requirements items. + CommandLine: + python -c "import setup; print(setup.parse_requirements())" + """ + import re + import sys + from os.path import exists + require_fpath = fname + + def parse_line(line): + """Parse information from a line in a requirements text file.""" + if line.startswith('-r '): + # Allow specifying requirements in other files + target = line.split(' ')[1] + for info in parse_require_file(target): + yield info + else: + info = {'line': line} + if line.startswith('-e '): + info['package'] = line.split('#egg=')[1] + else: + # Remove versioning from the package + pat = '(' + '|'.join(['>=', '==', '>']) + ')' + parts = re.split(pat, line, maxsplit=1) + parts = [p.strip() for p in parts] + + info['package'] = parts[0] + if len(parts) > 1: + op, rest = parts[1:] + if ';' in rest: + # Handle platform specific dependencies + # http://setuptools.readthedocs.io/en/latest/setuptools.html#declaring-platform-specific-dependencies + version, platform_deps = map(str.strip, + rest.split(';')) + info['platform_deps'] = platform_deps + else: + version = rest # NOQA + info['version'] = (op, version) + yield info + + def parse_require_file(fpath): + with open(fpath, 'r') as f: + for line in f.readlines(): + line = line.strip() + if line and not line.startswith('#'): + for info in parse_line(line): + yield info + + def gen_packages_items(): + if exists(require_fpath): + for info in parse_require_file(require_fpath): + parts = [info['package']] + if with_version and 'version' in info: + parts.extend(info['version']) + if not sys.version.startswith('3.4'): + # apparently package_deps are broken in 3.4 + platform_deps = info.get('platform_deps') + if platform_deps is not None: + parts.append(';' + platform_deps) + item = ''.join(parts) + yield item + + packages = list(gen_packages_items()) + return packages + + +if __name__ == '__main__': + setup( + name='sdsvtr', + version=get_version(), + description='SDSV OCR Team Text Recognizer', + long_description=readme(), + long_description_content_type='text/markdown', + packages=find_packages(exclude=('configs', 'tools', 'demo')), + include_package_data=True, + url='https://github.com/open-mmlab/mmocr', + classifiers=[ + 'Development Status :: 4 - Beta', + 'License :: OSI Approved :: Apache Software License', + 'Operating System :: OS Independent', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', + 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', + ], + license='Apache License 2.0', + install_requires=parse_requirements('requirements.txt'), + zip_safe=False) diff --git a/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtr/test.py b/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtr/test.py new file mode 100644 index 0000000..b929e7e --- /dev/null +++ b/cope2n-ai-fi/modules/_sdsvkvu/sdsvkvu/externals/basic_ocr/externals/sdsvtr/test.py @@ -0,0 +1,12 @@ +import numpy as np +from sdsvtr import StandaloneSATRNRunner +runner = StandaloneSATRNRunner(version='satrn-lite-general-pretrain-20230106', return_confident=False, device='cuda:1') + +dummy_list = [np.ndarray((32,128,3)) for _ in range(100)] +bs = 32 + +all_results = [] +while len(dummy_list) > 0: + dummy_batch = dummy_list[:bs] + dummy_list = dummy_list[bs:] + all_results += runner(dummy_batch) \ No newline at end of file diff --git a/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtd/.gitignore b/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtd/.gitignore new file mode 100644 index 0000000..a8c1759 --- /dev/null +++ b/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtd/.gitignore @@ -0,0 +1,6 @@ +# Builds +*.egg-info +__pycache__ + +# Checkpoint +hub \ No newline at end of file diff --git a/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtd/LICENSE b/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtd/LICENSE new file mode 100644 index 0000000..9e419e0 --- /dev/null +++ b/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtd/LICENSE @@ -0,0 +1,674 @@ +GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. \ No newline at end of file diff --git a/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtd/README.md b/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtd/README.md new file mode 100644 index 0000000..4de145b --- /dev/null +++ b/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtd/README.md @@ -0,0 +1,76 @@ +## Introduction +This repo serve as source code storage for the Standalone YoloX Detection packages. +Installing this package requires 2 additional packages: PyTorch and MMCV. + + +## Installation +```shell +conda create -n sdsvtd-env python=3.8 +conda activate sdsvtd-env +conda install pytorch torchvision pytorch-cuda=11.6 -c pytorch -c nvidia +pip install mmcv-full +git clone https://github.com/moewiee/sdsvtd.git +cd sdsvtd +pip install -v -e . +``` + +## Basic Usage +```python +from sdsvtd import StandaloneYOLOXRunner +runner = StandaloneYOLOXRunner(version='yolox-s-general-text-pretrain-20221226', device='cpu') +``` + +The `version` parameter accepts version names declared in `sdsvtd.factory.online_model_factory` or a local path such as `$DIR\model.pth`. To check for available versions in the hub, run: +```python +import sdsvtd +print(sdsvtd.__hub_available_versions__) +``` + +Naturally, a `StandaloneYOLOXRunner` instance assumes the input to be an instance of `np.ndarray` or an instance of `str` (batch inferece is not supported), for examples: +```python +import numpy as np +from sdsvtd import StandaloneYOLOXRunner +runner = StandaloneYOLOXRunner(version='yolox-s-general-text-pretrain-20221226', device='cpu') + +dummy_input = np.ndarray(500, 500, 3) +result = runner(dummy_input) +``` + +**Note:** Output of `StandaloneYOLOXRunner` instance will be in format `List[np.ndarray]` with each list element corresponds to one class. Each `np.ndarray` will be a 5-d vector `[x1 y1 x2 y2 confident]` with coordinates rescaled to fit the original image size. + +**AutoRotation:** +From version 0.1.0, `sdsvtd` support *AutoRotation* feature which accept a `np.ndarray/str` as input and return an straight rotated image (only available rotation degrees are 90, 180 and 270) of type `np.ndarray` and its bounding boxes of type `List[np.ndarray]`. Usage: +```python +import numpy as np +from sdsvtd import StandaloneYOLOXRunner +runner = StandaloneYOLOXRunner(version='yolox-s-general-text-pretrain-20221226', device='cpu', auto_rotate=True) + +rotated_image, result = runner(cv2.imread('path-to-image')) # or +rotated_image, result = runner(np.ndarray) +``` + +## Version Changelog +* **[0.0.1]** +Initial version with specified features. + +* **[0.0.2]** +Update more versions in model hub. + +* **[0.0.3]** +Update feature to specify running device while initialize runner. [Issue](https://github.com/moewiee/sdsvtd/issues/2) + +* **[0.0.4]** +Fix a minor bugs when existing hub/local version != current hub/local version. + +* **[0.0.5]** +Update model hub with handwritten text line detection version. + +* **[0.1.0]** +Update new feature: Auto Rotation. + +* **[0.1.1]** +Fix a bug in API inference class where return double result with auto_rotate=False. + +* **[0.1.2]** +Fix a bug in rotate feature where rotator_version was ignored. + diff --git a/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtd/requirements.txt b/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtd/requirements.txt new file mode 100644 index 0000000..10f4b05 --- /dev/null +++ b/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtd/requirements.txt @@ -0,0 +1,2 @@ +torch +mmcv-full \ No newline at end of file diff --git a/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtd/sdsvtd/__init__.py b/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtd/sdsvtd/__init__.py new file mode 100644 index 0000000..a3fb997 --- /dev/null +++ b/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtd/sdsvtd/__init__.py @@ -0,0 +1,3 @@ +from .api import StandaloneYOLOXRunner +from .version import __version__ +from .factory import __hub_available_versions__ \ No newline at end of file diff --git a/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtd/sdsvtd/api.py b/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtd/sdsvtd/api.py new file mode 100644 index 0000000..7deca24 --- /dev/null +++ b/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtd/sdsvtd/api.py @@ -0,0 +1,35 @@ +from .model import SingleStageDetector, AutoRotateDetector +import numpy as np + +class StandaloneYOLOXRunner: + + def __init__(self, + version, + device, + auto_rotate=False, + rotator_version=None): + self.model = SingleStageDetector(version, + device) + self.auto_rotate = auto_rotate + if self.auto_rotate: + if rotator_version is None: + rotator_version = version + self.rotator = AutoRotateDetector(rotator_version, + device) + + self.warmup_() + + def warmup_(self): + ''' Call on dummpy input to warm up instance ''' + x = np.ndarray((1280, 1280, 3)).astype(np.uint8) + self.model(x) + if self.auto_rotate: + self.rotator(x) + + + def __call__(self, img): + if self.auto_rotate: + img = self.rotator(img) + result = self.model(img) + + return result if not self.auto_rotate else (img, result) \ No newline at end of file diff --git a/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtd/sdsvtd/backbone.py b/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtd/sdsvtd/backbone.py new file mode 100644 index 0000000..5aadded --- /dev/null +++ b/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtd/sdsvtd/backbone.py @@ -0,0 +1,395 @@ +import torch +import torch.nn as nn +from mmcv.cnn import ConvModule +from torch.nn.modules.batchnorm import _BatchNorm + + +class DarknetBottleneck(nn.Module): + """The basic bottleneck block used in Darknet. + + Each ResBlock consists of two ConvModules and the input is added to the + final output. Each ConvModule is composed of Conv, BN, and LeakyReLU. + The first convLayer has filter size of 1x1 and the second one has the + filter size of 3x3. + + Args: + in_channels (int): The input channels of this Module. + out_channels (int): The output channels of this Module. + expansion (int): The kernel size of the convolution. Default: 0.5 + add_identity (bool): Whether to add identity to the out. + Default: True + use_depthwise (bool): Whether to use depthwise separable convolution. + Default: False + conv_cfg (dict): Config dict for convolution layer. Default: None, + which means using conv2d. + norm_cfg (dict): Config dict for normalization layer. + Default: dict(type='BN'). + act_cfg (dict): Config dict for activation layer. + Default: dict(type='Swish'). + """ + + def __init__(self, + in_channels, + out_channels, + expansion=0.5, + add_identity=True, + use_depthwise=False, + conv_cfg=None, + norm_cfg=dict(type='BN', momentum=0.03, eps=0.001), + act_cfg=dict(type='Swish')): + super().__init__() + hidden_channels = int(out_channels * expansion) + self.conv1 = ConvModule( + in_channels, + hidden_channels, + 1, + conv_cfg=conv_cfg, + norm_cfg=norm_cfg, + act_cfg=act_cfg) + self.conv2 = ConvModule( + hidden_channels, + out_channels, + 3, + stride=1, + padding=1, + conv_cfg=conv_cfg, + norm_cfg=norm_cfg, + act_cfg=act_cfg) + self.add_identity = \ + add_identity and in_channels == out_channels + + def forward(self, x): + identity = x + out = self.conv1(x) + out = self.conv2(out) + + if self.add_identity: + return out + identity + else: + return out + + +class CSPLayer(nn.Module): + """Cross Stage Partial Layer. + + Args: + in_channels (int): The input channels of the CSP layer. + out_channels (int): The output channels of the CSP layer. + expand_ratio (float): Ratio to adjust the number of channels of the + hidden layer. Default: 0.5 + num_blocks (int): Number of blocks. Default: 1 + add_identity (bool): Whether to add identity in blocks. + Default: True + use_depthwise (bool): Whether to depthwise separable convolution in + blocks. Default: False + conv_cfg (dict, optional): Config dict for convolution layer. + Default: None, which means using conv2d. + norm_cfg (dict): Config dict for normalization layer. + Default: dict(type='BN') + act_cfg (dict): Config dict for activation layer. + Default: dict(type='Swish') + """ + + def __init__(self, + in_channels, + out_channels, + expand_ratio=0.5, + num_blocks=1, + add_identity=True, + use_depthwise=False, + conv_cfg=None, + norm_cfg=dict(type='BN', momentum=0.03, eps=0.001), + act_cfg=dict(type='Swish')): + super().__init__() + mid_channels = int(out_channels * expand_ratio) + self.main_conv = ConvModule( + in_channels, + mid_channels, + 1, + conv_cfg=conv_cfg, + norm_cfg=norm_cfg, + act_cfg=act_cfg) + self.short_conv = ConvModule( + in_channels, + mid_channels, + 1, + conv_cfg=conv_cfg, + norm_cfg=norm_cfg, + act_cfg=act_cfg) + self.final_conv = ConvModule( + 2 * mid_channels, + out_channels, + 1, + conv_cfg=conv_cfg, + norm_cfg=norm_cfg, + act_cfg=act_cfg) + + self.blocks = nn.Sequential(*[ + DarknetBottleneck( + mid_channels, + mid_channels, + 1.0, + add_identity, + use_depthwise, + conv_cfg=conv_cfg, + norm_cfg=norm_cfg, + act_cfg=act_cfg) for _ in range(num_blocks) + ]) + + def forward(self, x): + x_short = self.short_conv(x) + + x_main = self.main_conv(x) + x_main = self.blocks(x_main) + + x_final = torch.cat((x_main, x_short), dim=1) + return self.final_conv(x_final) + + + +class Focus(nn.Module): + """Focus width and height information into channel space. + + Args: + in_channels (int): The input channels of this Module. + out_channels (int): The output channels of this Module. + kernel_size (int): The kernel size of the convolution. Default: 1 + stride (int): The stride of the convolution. Default: 1 + conv_cfg (dict): Config dict for convolution layer. Default: None, + which means using conv2d. + norm_cfg (dict): Config dict for normalization layer. + Default: dict(type='BN', momentum=0.03, eps=0.001). + act_cfg (dict): Config dict for activation layer. + Default: dict(type='Swish'). + """ + + def __init__(self, + in_channels, + out_channels, + kernel_size=1, + stride=1, + conv_cfg=None, + norm_cfg=dict(type='BN', momentum=0.03, eps=0.001), + act_cfg=dict(type='Swish')): + super().__init__() + self.conv = ConvModule( + in_channels * 4, + out_channels, + kernel_size, + stride, + padding=(kernel_size - 1) // 2, + conv_cfg=conv_cfg, + norm_cfg=norm_cfg, + act_cfg=act_cfg) + + def forward(self, x): + # shape of x (b,c,w,h) -> y(b,4c,w/2,h/2) + patch_top_left = x[..., ::2, ::2] + patch_top_right = x[..., ::2, 1::2] + patch_bot_left = x[..., 1::2, ::2] + patch_bot_right = x[..., 1::2, 1::2] + x = torch.cat( + ( + patch_top_left, + patch_bot_left, + patch_top_right, + patch_bot_right, + ), + dim=1, + ) + return self.conv(x) + + +class SPPBottleneck(nn.Module): + """Spatial pyramid pooling layer used in YOLOv3-SPP. + + Args: + in_channels (int): The input channels of this Module. + out_channels (int): The output channels of this Module. + kernel_sizes (tuple[int]): Sequential of kernel sizes of pooling + layers. Default: (5, 9, 13). + conv_cfg (dict): Config dict for convolution layer. Default: None, + which means using conv2d. + norm_cfg (dict): Config dict for normalization layer. + Default: dict(type='BN'). + act_cfg (dict): Config dict for activation layer. + Default: dict(type='Swish'). + init_cfg (dict or list[dict], optional): Initialization config dict. + Default: None. + """ + + def __init__(self, + in_channels, + out_channels, + kernel_sizes=(5, 9, 13), + conv_cfg=None, + norm_cfg=dict(type='BN', momentum=0.03, eps=0.001), + act_cfg=dict(type='Swish')): + super().__init__() + mid_channels = in_channels // 2 + self.conv1 = ConvModule( + in_channels, + mid_channels, + 1, + stride=1, + conv_cfg=conv_cfg, + norm_cfg=norm_cfg, + act_cfg=act_cfg) + self.poolings = nn.ModuleList([ + nn.MaxPool2d(kernel_size=ks, stride=1, padding=ks // 2) + for ks in kernel_sizes + ]) + conv2_channels = mid_channels * (len(kernel_sizes) + 1) + self.conv2 = ConvModule( + conv2_channels, + out_channels, + 1, + conv_cfg=conv_cfg, + norm_cfg=norm_cfg, + act_cfg=act_cfg) + + def forward(self, x): + x = self.conv1(x) + x = torch.cat([x] + [pooling(x) for pooling in self.poolings], dim=1) + x = self.conv2(x) + return x + + +class CSPDarknet(nn.Module): + """CSP-Darknet backbone used in YOLOv5 and YOLOX. + + Args: + arch (str): Architecture of CSP-Darknet, from {P5, P6}. + Default: P5. + deepen_factor (float): Depth multiplier, multiply number of + blocks in CSP layer by this amount. Default: 1.0. + widen_factor (float): Width multiplier, multiply number of + channels in each layer by this amount. Default: 1.0. + out_indices (Sequence[int]): Output from which stages. + Default: (2, 3, 4). + frozen_stages (int): Stages to be frozen (stop grad and set eval + mode). -1 means not freezing any parameters. Default: -1. + use_depthwise (bool): Whether to use depthwise separable convolution. + Default: False. + arch_ovewrite(list): Overwrite default arch settings. Default: None. + spp_kernal_sizes: (tuple[int]): Sequential of kernel sizes of SPP + layers. Default: (5, 9, 13). + conv_cfg (dict): Config dict for convolution layer. Default: None. + norm_cfg (dict): Dictionary to construct and config norm layer. + Default: dict(type='BN', requires_grad=True). + act_cfg (dict): Config dict for activation layer. + Default: dict(type='LeakyReLU', negative_slope=0.1). + norm_eval (bool): Whether to set norm layers to eval mode, namely, + freeze running stats (mean and var). Note: Effect on Batch Norm + and its variants only. + """ + # From left to right: + # in_channels, out_channels, num_blocks, add_identity, use_spp + arch_settings = { + 'P5': [[64, 128, 3, True, False], [128, 256, 9, True, False], + [256, 512, 9, True, False], [512, 1024, 3, False, True]], + 'P6': [[64, 128, 3, True, False], [128, 256, 9, True, False], + [256, 512, 9, True, False], [512, 768, 3, True, False], + [768, 1024, 3, False, True]] + } + + def __init__(self, + arch='P5', + deepen_factor=1.0, + widen_factor=1.0, + out_indices=(2, 3, 4), + frozen_stages=-1, + use_depthwise=False, + arch_ovewrite=None, + spp_kernal_sizes=(5, 9, 13), + conv_cfg=None, + norm_cfg=dict(type='BN', momentum=0.03, eps=0.001), + act_cfg=dict(type='Swish'), + norm_eval=False): + super().__init__() + arch_setting = self.arch_settings[arch] + if arch_ovewrite: + arch_setting = arch_ovewrite + assert set(out_indices).issubset( + i for i in range(len(arch_setting) + 1)) + if frozen_stages not in range(-1, len(arch_setting) + 1): + raise ValueError('frozen_stages must be in range(-1, ' + 'len(arch_setting) + 1). But received ' + f'{frozen_stages}') + + self.out_indices = out_indices + self.frozen_stages = frozen_stages + self.use_depthwise = use_depthwise + self.norm_eval = norm_eval + + self.stem = Focus( + 3, + int(arch_setting[0][0] * widen_factor), + kernel_size=3, + conv_cfg=conv_cfg, + norm_cfg=norm_cfg, + act_cfg=act_cfg) + self.layers = ['stem'] + + for i, (in_channels, out_channels, num_blocks, add_identity, + use_spp) in enumerate(arch_setting): + in_channels = int(in_channels * widen_factor) + out_channels = int(out_channels * widen_factor) + num_blocks = max(round(num_blocks * deepen_factor), 1) + stage = [] + conv_layer = ConvModule( + in_channels, + out_channels, + 3, + stride=2, + padding=1, + conv_cfg=conv_cfg, + norm_cfg=norm_cfg, + act_cfg=act_cfg) + stage.append(conv_layer) + if use_spp: + spp = SPPBottleneck( + out_channels, + out_channels, + kernel_sizes=spp_kernal_sizes, + conv_cfg=conv_cfg, + norm_cfg=norm_cfg, + act_cfg=act_cfg) + stage.append(spp) + csp_layer = CSPLayer( + out_channels, + out_channels, + num_blocks=num_blocks, + add_identity=add_identity, + use_depthwise=use_depthwise, + conv_cfg=conv_cfg, + norm_cfg=norm_cfg, + act_cfg=act_cfg) + stage.append(csp_layer) + self.add_module(f'stage{i + 1}', nn.Sequential(*stage)) + self.layers.append(f'stage{i + 1}') + + def _freeze_stages(self): + if self.frozen_stages >= 0: + for i in range(self.frozen_stages + 1): + m = getattr(self, self.layers[i]) + m.eval() + for param in m.parameters(): + param.requires_grad = False + + def train(self, mode=True): + super(CSPDarknet, self).train(mode) + self._freeze_stages() + if mode and self.norm_eval: + for m in self.modules(): + if isinstance(m, _BatchNorm): + m.eval() + + def forward(self, x): + outs = [] + for i, layer_name in enumerate(self.layers): + layer = getattr(self, layer_name) + x = layer(x) + if i in self.out_indices: + outs.append(x) + return tuple(outs) \ No newline at end of file diff --git a/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtd/sdsvtd/bbox_head.py b/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtd/sdsvtd/bbox_head.py new file mode 100644 index 0000000..bb485f2 --- /dev/null +++ b/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtd/sdsvtd/bbox_head.py @@ -0,0 +1,288 @@ +import torch +import torch.nn as nn +from mmcv.cnn import ConvModule +from mmcv.ops.nms import batched_nms +from mmcv.runner import force_fp32 +from functools import partial +from .priors import MlvlPointGenerator + + +def multi_apply(func, *args, **kwargs): + """Apply function to a list of arguments. + + Note: + This function applies the ``func`` to multiple inputs and + map the multiple outputs of the ``func`` into different + list. Each list contains the same type of outputs corresponding + to different inputs. + + Args: + func (Function): A function that will be applied to a list of + arguments + + Returns: + tuple(list): A tuple containing multiple list, each list contains \ + a kind of returned results by the function + """ + pfunc = partial(func, **kwargs) if kwargs else func + map_results = map(pfunc, *args) + return tuple(map(list, zip(*map_results))) + + +class YOLOXHead(nn.Module): + """YOLOXHead head used in `YOLOX `_. + + Args: + num_classes (int): Number of categories excluding the background + category. + in_channels (int): Number of channels in the input feature map. + feat_channels (int): Number of hidden channels in stacking convs. + Default: 256 + stacked_convs (int): Number of stacking convs of the head. + Default: 2. + strides (tuple): Downsample factor of each feature map. + use_depthwise (bool): Whether to depthwise separable convolution in + blocks. Default: False + dcn_on_last_conv (bool): If true, use dcn in the last layer of + towers. Default: False. + conv_bias (bool | str): If specified as `auto`, it will be decided by + the norm_cfg. Bias of conv will be set as True if `norm_cfg` is + None, otherwise False. Default: "auto". + conv_cfg (dict): Config dict for convolution layer. Default: None. + norm_cfg (dict): Config dict for normalization layer. Default: None. + act_cfg (dict): Config dict for activation layer. Default: None. + """ + + def __init__(self, + num_classes, + in_channels, + feat_channels=256, + stacked_convs=2, + strides=[8, 16, 32], + use_depthwise=False, + dcn_on_last_conv=False, + conv_bias='auto', + conv_cfg=None, + norm_cfg=dict(type='BN', momentum=0.03, eps=0.001), + act_cfg=dict(type='Swish'), + nms_score_thr=0.3, + nms_iou_threshold=0.1): + + super().__init__() + self.nms_config = dict(score_thr=nms_score_thr, nms=dict(iou_threshold=nms_iou_threshold)) + self.num_classes = num_classes + self.cls_out_channels = num_classes + self.in_channels = in_channels + self.feat_channels = feat_channels + self.stacked_convs = stacked_convs + self.strides = strides + self.use_depthwise = use_depthwise + self.dcn_on_last_conv = dcn_on_last_conv + assert conv_bias == 'auto' or isinstance(conv_bias, bool) + self.conv_bias = conv_bias + self.use_sigmoid_cls = True + + self.conv_cfg = conv_cfg + self.norm_cfg = norm_cfg + self.act_cfg = act_cfg + + self.prior_generator = MlvlPointGenerator(strides, offset=0) + + self.fp16_enabled = False + self._init_layers() + + def _init_layers(self): + self.multi_level_cls_convs = nn.ModuleList() + self.multi_level_reg_convs = nn.ModuleList() + self.multi_level_conv_cls = nn.ModuleList() + self.multi_level_conv_reg = nn.ModuleList() + self.multi_level_conv_obj = nn.ModuleList() + for _ in self.strides: + self.multi_level_cls_convs.append(self._build_stacked_convs()) + self.multi_level_reg_convs.append(self._build_stacked_convs()) + conv_cls, conv_reg, conv_obj = self._build_predictor() + self.multi_level_conv_cls.append(conv_cls) + self.multi_level_conv_reg.append(conv_reg) + self.multi_level_conv_obj.append(conv_obj) + + def _build_stacked_convs(self): + """Initialize conv layers of a single level head.""" + conv = ConvModule + stacked_convs = [] + for i in range(self.stacked_convs): + chn = self.in_channels if i == 0 else self.feat_channels + if self.dcn_on_last_conv and i == self.stacked_convs - 1: + conv_cfg = dict(type='DCNv2') + else: + conv_cfg = self.conv_cfg + stacked_convs.append( + conv( + chn, + self.feat_channels, + 3, + stride=1, + padding=1, + conv_cfg=conv_cfg, + norm_cfg=self.norm_cfg, + act_cfg=self.act_cfg, + bias=self.conv_bias)) + return nn.Sequential(*stacked_convs) + + def _build_predictor(self): + """Initialize predictor layers of a single level head.""" + conv_cls = nn.Conv2d(self.feat_channels, self.cls_out_channels, 1) + conv_reg = nn.Conv2d(self.feat_channels, 4, 1) + conv_obj = nn.Conv2d(self.feat_channels, 1, 1) + return conv_cls, conv_reg, conv_obj + + def forward_single(self, x, cls_convs, reg_convs, conv_cls, conv_reg, + conv_obj): + """Forward feature of a single scale level.""" + + cls_feat = cls_convs(x) + reg_feat = reg_convs(x) + + cls_score = conv_cls(cls_feat) + bbox_pred = conv_reg(reg_feat) + objectness = conv_obj(reg_feat) + + return cls_score, bbox_pred, objectness + + def forward(self, feats): + """Forward features from the upstream network. + + Args: + feats (tuple[Tensor]): Features from the upstream network, each is + a 4D-tensor. + Returns: + tuple[Tensor]: A tuple of multi-level predication map, each is a + 4D-tensor of shape (batch_size, 5+num_classes, height, width). + """ + + return multi_apply(self.forward_single, feats, + self.multi_level_cls_convs, + self.multi_level_reg_convs, + self.multi_level_conv_cls, + self.multi_level_conv_reg, + self.multi_level_conv_obj) + + @force_fp32(apply_to=('cls_scores', 'bbox_preds', 'objectnesses')) + def get_bboxes(self, + cls_scores, + bbox_preds, + objectnesses, + cfg=None): + """Transform network outputs of a batch into bbox results. + Args: + cls_scores (list[Tensor]): Classification scores for all + scale levels, each is a 4D-tensor, has shape + (batch_size, num_priors * num_classes, H, W). + bbox_preds (list[Tensor]): Box energies / deltas for all + scale levels, each is a 4D-tensor, has shape + (batch_size, num_priors * 4, H, W). + objectnesses (list[Tensor], Optional): Score factor for + all scale level, each is a 4D-tensor, has shape + (batch_size, 1, H, W). + cfg (mmcv.Config, Optional): Test / postprocessing configuration, + if None, test_cfg would be used. Default None. + rescale (bool): If True, return boxes in original image space. + Default False. + with_nms (bool): If True, do nms before return boxes. + Default True. + Returns: + list[list[Tensor, Tensor]]: Each item in result_list is 2-tuple. + The first item is an (n, 5) tensor, where the first 4 columns + are bounding box positions (tl_x, tl_y, br_x, br_y) and the + 5-th column is a score between 0 and 1. The second item is a + (n,) tensor where each item is the predicted class label of + the corresponding box. + """ + assert len(cls_scores) == len(bbox_preds) == len(objectnesses) + cfg = self.nms_config if cfg is None else cfg + + featmap_sizes = [cls_score.shape[2:] for cls_score in cls_scores] + mlvl_priors = self.prior_generator.grid_priors( + featmap_sizes, + dtype=cls_scores[0].dtype, + device=cls_scores[0].device, + with_stride=True) + + # flatten cls_scores, bbox_preds and objectness + flatten_cls_scores = [ + cls_score.permute(0, 2, 3, 1).reshape(1, -1, + self.cls_out_channels) + for cls_score in cls_scores + ] + flatten_bbox_preds = [ + bbox_pred.permute(0, 2, 3, 1).reshape(1, -1, 4) + for bbox_pred in bbox_preds + ] + flatten_objectness = [ + objectness.permute(0, 2, 3, 1).reshape(1, -1) + for objectness in objectnesses + ] + + flatten_cls_scores = torch.cat(flatten_cls_scores, dim=1).sigmoid() + flatten_bbox_preds = torch.cat(flatten_bbox_preds, dim=1) + flatten_objectness = torch.cat(flatten_objectness, dim=1).sigmoid() + flatten_priors = torch.cat(mlvl_priors) + + flatten_bboxes = self._bbox_decode(flatten_priors, flatten_bbox_preds) + + result_list = [] + for img_id in range(1): + cls_scores = flatten_cls_scores[img_id] + score_factor = flatten_objectness[img_id] + bboxes = flatten_bboxes[img_id] + + result_list.append( + self._bboxes_nms(cls_scores, bboxes, score_factor, cfg)) + + return result_list + + def _bbox_decode(self, priors, bbox_preds): + xys = (bbox_preds[..., :2] * priors[:, 2:]) + priors[:, :2] + whs = bbox_preds[..., 2:].exp() * priors[:, 2:] + + tl_x = (xys[..., 0] - whs[..., 0] / 2) + tl_y = (xys[..., 1] - whs[..., 1] / 2) + br_x = (xys[..., 0] + whs[..., 0] / 2) + br_y = (xys[..., 1] + whs[..., 1] / 2) + + decoded_bboxes = torch.stack([tl_x, tl_y, br_x, br_y], -1) + return decoded_bboxes + + def _bboxes_nms(self, cls_scores, bboxes, score_factor, cfg): + max_scores, labels = torch.max(cls_scores, 1) + valid_mask = score_factor * max_scores >= cfg['score_thr'] + bboxes = bboxes[valid_mask] + scores = max_scores[valid_mask] * score_factor[valid_mask] + labels = labels[valid_mask] + + if labels.numel() == 0: + return bboxes, labels + else: + dets, keep = batched_nms(bboxes.float(), scores.float(), labels, cfg['nms']) + return dets, labels[keep] + + def simple_test_bboxes(self, feats): + """Test det bboxes without test-time augmentation, can be applied in + DenseHead except for ``RPNHead`` and its variants, e.g., ``GARPNHead``, + etc. + + Args: + feats (tuple[torch.Tensor]): Multi-level features from the + upstream network, each is a 4D-tensor. + rescale (bool, optional): Whether to rescale the results. + Defaults to False. + + Returns: + list[tuple[Tensor, Tensor]]: Each item in result_list is 2-tuple. + The first item is ``bboxes`` with shape (n, 5), + where 5 represent (tl_x, tl_y, br_x, br_y, score). + The shape of the second tensor in the tuple is ``labels`` + with shape (n,) + """ + outs = self.forward(feats) + results_list = self.get_bboxes(*outs) + return results_list \ No newline at end of file diff --git a/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtd/sdsvtd/factory.py b/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtd/sdsvtd/factory.py new file mode 100644 index 0000000..2b6068f --- /dev/null +++ b/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtd/sdsvtd/factory.py @@ -0,0 +1,75 @@ +import os +import shutil +import hashlib +import warnings + +def sha256sum(filename): + h = hashlib.sha256() + b = bytearray(128*1024) + mv = memoryview(b) + with open(filename, 'rb', buffering=0) as f: + for n in iter(lambda : f.readinto(mv), 0): + h.update(mv[:n]) + return h.hexdigest() + + +online_model_factory = { + 'yolox-s-general-text-pretrain-20221226': { + 'url': 'https://github.com/moewiee/satrn-model-factory/raw/main/62j266xm8r.pth', + 'hash': '89bff792685af454d0cfea5d6d673be6914d614e4c2044e786da6eddf36f8b50'}, + 'yolox-s-checkbox-20220726': { + 'url': 'https://github.com/moewiee/satrn-model-factory/raw/main/1647d7eys7.pth', + 'hash': '7c1e188b7375dcf0b7b9d317675ebd92a86fdc29363558002249867249ee10f8'}, + 'yolox-s-idcard-5c-20221027': { + 'url': 'https://github.com/moewiee/satrn-model-factory/raw/main/jr0egad3ix.pth', + 'hash': '73a7772594c1f6d3f6d6a98b6d6e4097af5026864e3bd50531ad9e635ae795a7'}, + 'yolox-s-handwritten-text-line-20230228': { + 'url': 'https://github.com/moewiee/satrn-model-factory/raw/main/rb07rtwmgi.pth', + 'hash': 'a31d1bf8fc880479d2e11463dad0b4081952a13e553a02919109b634a1190ef1'} +} + +__hub_available_versions__ = online_model_factory.keys() + +def _get_from_hub(file_path, version, version_url): + os.system(f'wget -O {file_path} {version_url}') + assert os.path.exists(file_path), \ + 'wget failed while trying to retrieve from hub.' + downloaded_hash = sha256sum(file_path) + if downloaded_hash != online_model_factory[version]['hash']: + os.remove(file_path) + raise ValueError('sha256 hash doesnt match for version retrieved from hub.') + +def _get(version): + use_online = version in __hub_available_versions__ + + if not use_online and not os.path.exists(version): + raise ValueError(f'Model version {version} not found online and not found local.') + + hub_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'hub') + if not os.path.exists(hub_path): + os.makedirs(hub_path) + if use_online: + version_url = online_model_factory[version]['url'] + file_path = os.path.join(hub_path, os.path.basename(version_url)) + else: + file_path = os.path.join(hub_path, os.path.basename(version)) + + if not os.path.exists(file_path): + if use_online: + _get_from_hub(file_path, version, version_url) + else: + shutil.copy2(version, file_path) + else: + if use_online: + downloaded_hash = sha256sum(file_path) + if downloaded_hash != online_model_factory[version]['hash']: + os.remove(file_path) + warnings.warn('existing hub version sha256 hash doesnt match, now re-download from hub.') + _get_from_hub(file_path, version, version_url) + else: + if sha256sum(file_path) != sha256sum(version): + os.remove(file_path) + warnings.warn('existing local version sha256 hash doesnt match, now replace with new local version.') + shutil.copy2(version, file_path) + + return file_path \ No newline at end of file diff --git a/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtd/sdsvtd/model.py b/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtd/sdsvtd/model.py new file mode 100644 index 0000000..69a26ef --- /dev/null +++ b/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtd/sdsvtd/model.py @@ -0,0 +1,151 @@ +import torch +import torch.nn as nn +import numpy as np +from .backbone import CSPDarknet +from .neck import YOLOXPAFPN +from .bbox_head import YOLOXHead +from .transform import DetectorDataPipeline, AutoRotateDetectorDataPipeline +from .factory import _get as get_version + + +def bbox2result(bboxes, labels, num_classes): + """Convert detection results to a list of numpy arrays. + + Args: + bboxes (torch.Tensor | np.ndarray): shape (n, 5) + labels (torch.Tensor | np.ndarray): shape (n, ) + num_classes (int): class number, including background class + + Returns: + list(ndarray): bbox results of each class + """ + if bboxes.shape[0] == 0: + return [np.zeros((0, 5), dtype=np.float32) for i in range(num_classes)] + else: + if isinstance(bboxes, torch.Tensor): + bboxes = bboxes.detach().cpu().numpy() + labels = labels.detach().cpu().numpy() + return [bboxes[labels == i, :] for i in range(num_classes)] + + +def normalize_bbox(bboxes, scale): + for i in range(len(bboxes)): + bboxes[i][:,:4] /= scale + return bboxes + + +class SingleStageDetector(nn.Module): + + def __init__(self, + version, + device): + super(SingleStageDetector, self).__init__() + + assert 'cpu' in device or 'cuda' in device + + checkpoint = get_version(version) + pt = torch.load(checkpoint, 'cpu') + + self.pipeline = DetectorDataPipeline(**pt['pipeline_args'], device=device) + self.backbone = CSPDarknet(**pt['backbone_args']) + self.neck = YOLOXPAFPN(**pt['neck_args']) + self.bbox_head = YOLOXHead(**pt['bbox_head_args']) + self.load_state_dict(pt['state_dict'], strict=True) + + self.eval() + for param in self.parameters(): + param.requires_grad = False + + self = self.to(device=device) + + print(f'Text detection load from version {version}.') + + def extract_feat(self, img): + """Directly extract features from the backbone + neck.""" + + x = self.backbone(img) + x = self.neck(x) + return x + + def forward(self, img): + """Test function without test-time augmentation. + + Args: + img (np.ndarray): Images with shape (H, W, C) or + img (str): Path to image. + + Returns: + list[list[np.ndarray]]: BBox results of each image and classes. + The list corresponds to each class. + """ + img, origin_shape, new_shape = self.pipeline(img) + scale = min(new_shape / origin_shape) + feat = self.extract_feat(img) + results_list = self.bbox_head.simple_test_bboxes(feat) + bbox_results = [ + bbox2result(det_bboxes, det_labels, self.bbox_head.num_classes) + for det_bboxes, det_labels in results_list + ][0] + bbox_results = normalize_bbox(bbox_results, scale) + return bbox_results + + +class AutoRotateDetector(nn.Module): + def __init__(self, + version, + device): + super(AutoRotateDetector, self).__init__() + + assert 'cpu' in device or 'cuda' in device + + checkpoint = get_version(version) + pt = torch.load(checkpoint, 'cpu') + + self.pipeline = AutoRotateDetectorDataPipeline(**pt['pipeline_args'], device=device) + self.backbone = CSPDarknet(**pt['backbone_args']) + self.neck = YOLOXPAFPN(**pt['neck_args']) + self.bbox_head = YOLOXHead(**pt['bbox_head_args'], nms_score_thr=0.8) + self.load_state_dict(pt['state_dict'], strict=True) + + self.eval() + for param in self.parameters(): + param.requires_grad = False + + self = self.to(device=device) + + print(f'Auto rotate detector load from version {version}.') + + def extract_feat(self, img): + """Directly extract features from the backbone + neck.""" + + x = self.backbone(img) + x = self.neck(x) + return x + + def forward(self, img): + """Test function without test-time augmentation. + + Args: + img (np.ndarray): Images with shape (H, W, C) or + img (str): Path to image. + + Returns: + np.ndarray: Straight rotated image. + """ + imgs, imgs_np = self.pipeline(img) + maxCount = -1 + maxCountRot = None + for idx, img in enumerate(imgs): + currentCount = 0 + feat = self.extract_feat(img) + results_list = self.bbox_head.simple_test_bboxes(feat) + bbox_results = [ + bbox2result(det_bboxes, det_labels, self.bbox_head.num_classes) + for det_bboxes, det_labels in results_list + ][0] + for class_result in bbox_results: + currentCount += len(class_result) + if currentCount > maxCount: + maxCount = currentCount + maxCountRot = idx + return imgs_np[maxCountRot] \ No newline at end of file diff --git a/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtd/sdsvtd/neck.py b/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtd/sdsvtd/neck.py new file mode 100644 index 0000000..2b11e36 --- /dev/null +++ b/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtd/sdsvtd/neck.py @@ -0,0 +1,140 @@ +import torch +import torch.nn as nn +from mmcv.cnn import ConvModule +from .backbone import CSPLayer + + +class YOLOXPAFPN(nn.Module): + """Path Aggregation Network used in YOLOX. + + Args: + in_channels (List[int]): Number of input channels per scale. + out_channels (int): Number of output channels (used at each scale) + num_csp_blocks (int): Number of bottlenecks in CSPLayer. Default: 3 + use_depthwise (bool): Whether to depthwise separable convolution in + blocks. Default: False + upsample_cfg (dict): Config dict for interpolate layer. + Default: `dict(scale_factor=2, mode='nearest')` + conv_cfg (dict, optional): Config dict for convolution layer. + Default: None, which means using conv2d. + norm_cfg (dict): Config dict for normalization layer. + Default: dict(type='BN') + act_cfg (dict): Config dict for activation layer. + Default: dict(type='Swish') + init_cfg (dict or list[dict], optional): Initialization config dict. + Default: None. + """ + + def __init__(self, + in_channels, + out_channels, + num_csp_blocks=3, + use_depthwise=False, + upsample_cfg=dict(scale_factor=2, mode='nearest'), + conv_cfg=None, + norm_cfg=dict(type='BN', momentum=0.03, eps=0.001), + act_cfg=dict(type='Swish')): + super(YOLOXPAFPN, self).__init__() + self.in_channels = in_channels + self.out_channels = out_channels + + # build top-down blocks + self.upsample = nn.Upsample(**upsample_cfg) + self.reduce_layers = nn.ModuleList() + self.top_down_blocks = nn.ModuleList() + for idx in range(len(in_channels) - 1, 0, -1): + self.reduce_layers.append( + ConvModule( + in_channels[idx], + in_channels[idx - 1], + 1, + conv_cfg=conv_cfg, + norm_cfg=norm_cfg, + act_cfg=act_cfg)) + self.top_down_blocks.append( + CSPLayer( + in_channels[idx - 1] * 2, + in_channels[idx - 1], + num_blocks=num_csp_blocks, + add_identity=False, + use_depthwise=use_depthwise, + conv_cfg=conv_cfg, + norm_cfg=norm_cfg, + act_cfg=act_cfg)) + + # build bottom-up blocks + self.downsamples = nn.ModuleList() + self.bottom_up_blocks = nn.ModuleList() + for idx in range(len(in_channels) - 1): + self.downsamples.append( + ConvModule( + in_channels[idx], + in_channels[idx], + 3, + stride=2, + padding=1, + conv_cfg=conv_cfg, + norm_cfg=norm_cfg, + act_cfg=act_cfg)) + self.bottom_up_blocks.append( + CSPLayer( + in_channels[idx] * 2, + in_channels[idx + 1], + num_blocks=num_csp_blocks, + add_identity=False, + use_depthwise=use_depthwise, + conv_cfg=conv_cfg, + norm_cfg=norm_cfg, + act_cfg=act_cfg)) + + self.out_convs = nn.ModuleList() + for i in range(len(in_channels)): + self.out_convs.append( + ConvModule( + in_channels[i], + out_channels, + 1, + conv_cfg=conv_cfg, + norm_cfg=norm_cfg, + act_cfg=act_cfg)) + + def forward(self, inputs): + """ + Args: + inputs (tuple[Tensor]): input features. + + Returns: + tuple[Tensor]: YOLOXPAFPN features. + """ + assert len(inputs) == len(self.in_channels) + + # top-down path + inner_outs = [inputs[-1]] + for idx in range(len(self.in_channels) - 1, 0, -1): + feat_heigh = inner_outs[0] + feat_low = inputs[idx - 1] + feat_heigh = self.reduce_layers[len(self.in_channels) - 1 - idx]( + feat_heigh) + inner_outs[0] = feat_heigh + + upsample_feat = self.upsample(feat_heigh) + + inner_out = self.top_down_blocks[len(self.in_channels) - 1 - idx]( + torch.cat([upsample_feat, feat_low], 1)) + inner_outs.insert(0, inner_out) + + # bottom-up path + outs = [inner_outs[0]] + for idx in range(len(self.in_channels) - 1): + feat_low = outs[-1] + feat_height = inner_outs[idx + 1] + downsample_feat = self.downsamples[idx](feat_low) + out = self.bottom_up_blocks[idx]( + torch.cat([downsample_feat, feat_height], 1)) + outs.append(out) + + # out convs + for idx, conv in enumerate(self.out_convs): + outs[idx] = conv(outs[idx]) + + return tuple(outs) diff --git a/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtd/sdsvtd/priors.py b/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtd/sdsvtd/priors.py new file mode 100644 index 0000000..8eb2fde --- /dev/null +++ b/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtd/sdsvtd/priors.py @@ -0,0 +1,225 @@ +import torch +import numpy as np +from torch.nn.modules.utils import _pair + + +class MlvlPointGenerator: + """Standard points generator for multi-level (Mlvl) feature maps in 2D + points-based detectors. + + Args: + strides (list[int] | list[tuple[int, int]]): Strides of anchors + in multiple feature levels in order (w, h). + offset (float): The offset of points, the value is normalized with + corresponding stride. Defaults to 0.5. + """ + + def __init__(self, strides, offset=0.5): + self.strides = [_pair(stride) for stride in strides] + self.offset = offset + + @property + def num_levels(self): + """int: number of feature levels that the generator will be applied""" + return len(self.strides) + + @property + def num_base_priors(self): + """list[int]: The number of priors (points) at a point + on the feature grid""" + return [1 for _ in range(len(self.strides))] + + def _meshgrid(self, x, y, row_major=True): + yy, xx = torch.meshgrid(y, x) + if row_major: + # warning .flatten() would cause error in ONNX exporting + # have to use reshape here + return xx.flatten(), yy.flatten() + + else: + return yy.flatten(), xx.flatten() + + def grid_priors(self, + featmap_sizes, + dtype=torch.float32, + device='cuda', + with_stride=False): + """Generate grid points of multiple feature levels. + + Args: + featmap_sizes (list[tuple]): List of feature map sizes in + multiple feature levels, each size arrange as + as (h, w). + dtype (:obj:`dtype`): Dtype of priors. Default: torch.float32. + device (str): The device where the anchors will be put on. + with_stride (bool): Whether to concatenate the stride to + the last dimension of points. + + Return: + list[torch.Tensor]: Points of multiple feature levels. + The sizes of each tensor should be (N, 2) when with stride is + ``False``, where N = width * height, width and height + are the sizes of the corresponding feature level, + and the last dimension 2 represent (coord_x, coord_y), + otherwise the shape should be (N, 4), + and the last dimension 4 represent + (coord_x, coord_y, stride_w, stride_h). + """ + + assert self.num_levels == len(featmap_sizes) + multi_level_priors = [] + for i in range(self.num_levels): + priors = self.single_level_grid_priors( + featmap_sizes[i], + level_idx=i, + dtype=dtype, + device=device, + with_stride=with_stride) + multi_level_priors.append(priors) + return multi_level_priors + + def single_level_grid_priors(self, + featmap_size, + level_idx, + dtype=torch.float32, + device='cuda', + with_stride=False): + """Generate grid Points of a single level. + + Note: + This function is usually called by method ``self.grid_priors``. + + Args: + featmap_size (tuple[int]): Size of the feature maps, arrange as + (h, w). + level_idx (int): The index of corresponding feature map level. + dtype (:obj:`dtype`): Dtype of priors. Default: torch.float32. + device (str, optional): The device the tensor will be put on. + Defaults to 'cuda'. + with_stride (bool): Concatenate the stride to the last dimension + of points. + + Return: + Tensor: Points of single feature levels. + The shape of tensor should be (N, 2) when with stride is + ``False``, where N = width * height, width and height + are the sizes of the corresponding feature level, + and the last dimension 2 represent (coord_x, coord_y), + otherwise the shape should be (N, 4), + and the last dimension 4 represent + (coord_x, coord_y, stride_w, stride_h). + """ + feat_h, feat_w = featmap_size + stride_w, stride_h = self.strides[level_idx] + shift_x = (torch.arange(0, feat_w, device=device) + + self.offset) * stride_w + # keep featmap_size as Tensor instead of int, so that we + # can convert to ONNX correctly + shift_x = shift_x.to(dtype) + + shift_y = (torch.arange(0, feat_h, device=device) + + self.offset) * stride_h + # keep featmap_size as Tensor instead of int, so that we + # can convert to ONNX correctly + shift_y = shift_y.to(dtype) + shift_xx, shift_yy = self._meshgrid(shift_x, shift_y) + if not with_stride: + shifts = torch.stack([shift_xx, shift_yy], dim=-1) + else: + # use `shape[0]` instead of `len(shift_xx)` for ONNX export + stride_w = shift_xx.new_full((shift_xx.shape[0], ), + stride_w).to(dtype) + stride_h = shift_xx.new_full((shift_yy.shape[0], ), + stride_h).to(dtype) + shifts = torch.stack([shift_xx, shift_yy, stride_w, stride_h], + dim=-1) + all_points = shifts.to(device) + return all_points + + def valid_flags(self, featmap_sizes, pad_shape, device='cuda'): + """Generate valid flags of points of multiple feature levels. + + Args: + featmap_sizes (list(tuple)): List of feature map sizes in + multiple feature levels, each size arrange as + as (h, w). + pad_shape (tuple(int)): The padded shape of the image, + arrange as (h, w). + device (str): The device where the anchors will be put on. + + Return: + list(torch.Tensor): Valid flags of points of multiple levels. + """ + assert self.num_levels == len(featmap_sizes) + multi_level_flags = [] + for i in range(self.num_levels): + point_stride = self.strides[i] + feat_h, feat_w = featmap_sizes[i] + h, w = pad_shape[:2] + valid_feat_h = min(int(np.ceil(h / point_stride[1])), feat_h) + valid_feat_w = min(int(np.ceil(w / point_stride[0])), feat_w) + flags = self.single_level_valid_flags((feat_h, feat_w), + (valid_feat_h, valid_feat_w), + device=device) + multi_level_flags.append(flags) + return multi_level_flags + + def single_level_valid_flags(self, + featmap_size, + valid_size, + device='cuda'): + """Generate the valid flags of points of a single feature map. + + Args: + featmap_size (tuple[int]): The size of feature maps, arrange as + as (h, w). + valid_size (tuple[int]): The valid size of the feature maps. + The size arrange as as (h, w). + device (str, optional): The device where the flags will be put on. + Defaults to 'cuda'. + + Returns: + torch.Tensor: The valid flags of each points in a single level \ + feature map. + """ + feat_h, feat_w = featmap_size + valid_h, valid_w = valid_size + assert valid_h <= feat_h and valid_w <= feat_w + valid_x = torch.zeros(feat_w, dtype=torch.bool, device=device) + valid_y = torch.zeros(feat_h, dtype=torch.bool, device=device) + valid_x[:valid_w] = 1 + valid_y[:valid_h] = 1 + valid_xx, valid_yy = self._meshgrid(valid_x, valid_y) + valid = valid_xx & valid_yy + return valid + + def sparse_priors(self, + prior_idxs, + featmap_size, + level_idx, + dtype=torch.float32, + device='cuda'): + """Generate sparse points according to the ``prior_idxs``. + + Args: + prior_idxs (Tensor): The index of corresponding anchors + in the feature map. + featmap_size (tuple[int]): feature map size arrange as (w, h). + level_idx (int): The level index of corresponding feature + map. + dtype (obj:`torch.dtype`): Date type of points. Defaults to + ``torch.float32``. + device (obj:`torch.device`): The device where the points is + located. + Returns: + Tensor: Anchor with shape (N, 2), N should be equal to + the length of ``prior_idxs``. And last dimension + 2 represent (coord_x, coord_y). + """ + height, width = featmap_size + x = (prior_idxs % width + self.offset) * self.strides[level_idx][0] + y = ((prior_idxs // width) % height + + self.offset) * self.strides[level_idx][1] + prioris = torch.stack([x, y], 1).to(dtype) + prioris = prioris.to(device) + return prioris \ No newline at end of file diff --git a/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtd/sdsvtd/transform.py b/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtd/sdsvtd/transform.py new file mode 100644 index 0000000..fda7ab9 --- /dev/null +++ b/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtd/sdsvtd/transform.py @@ -0,0 +1,81 @@ +import mmcv +import numpy as np +import cv2 +import torch + + +class DetectorDataPipeline: + + def __init__(self, + img_scale, + device): + self.scale = img_scale + self.device = device + + def load(self, img): + if isinstance(img, str): + return cv2.imread(img) + elif isinstance(img, np.ndarray): + return img + else: + raise ValueError(f'img input must be a str/np.ndarray, got {type(img)}') + + def resize(self, img): + origin_shape = img.shape[:2] + img = mmcv.imrescale(img, + self.scale, + return_scale=False, + interpolation='bilinear', + backend='cv2') + + return img, origin_shape, np.array(self.scale) + + def pad(self, img): + if self.scale is not None: + width = max(self.scale[1] - img.shape[1], 0) + height = max(self.scale[0] - img.shape[0], 0) + padding = (0, 0, width, height) + + img = cv2.copyMakeBorder(img, + padding[1], + padding[3], + padding[0], + padding[2], + cv2.BORDER_CONSTANT, + value=(114, 114, 114,)) + + return img + + def to_tensor(self, img): + + img = torch.from_numpy(img.astype(np.float32)).permute(2,0,1).unsqueeze(0) + img = img.to(device=self.device) + + return img + + def __call__(self, img): + img = self.load(img) + img, origin_shape, new_shape = self.resize(img) + img = self.pad(img) + img = self.to_tensor(img) + + return img, origin_shape, new_shape + + +class AutoRotateDetectorDataPipeline(DetectorDataPipeline): + + def __call__(self, img): + img = self.load(img) + imgs = [] + imgs_np = [] + + for flag in (None, cv2.ROTATE_90_CLOCKWISE, cv2.ROTATE_180, cv2.ROTATE_90_COUNTERCLOCKWISE): + img_t = img if flag is None else cv2.rotate(img, flag) + imgs_np.append(img_t) + img_t, _, _ = self.resize(img_t) + img_t = self.pad(img_t) + img_t = self.to_tensor(img_t) + + imgs.append(img_t) + + return imgs, imgs_np \ No newline at end of file diff --git a/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtd/sdsvtd/version.py b/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtd/sdsvtd/version.py new file mode 100644 index 0000000..10939f0 --- /dev/null +++ b/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtd/sdsvtd/version.py @@ -0,0 +1 @@ +__version__ = '0.1.2' diff --git a/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtd/setup.py b/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtd/setup.py new file mode 100644 index 0000000..a2e04db --- /dev/null +++ b/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtd/setup.py @@ -0,0 +1,186 @@ +import os +import os.path as osp +import shutil +import sys +import warnings +from setuptools import find_packages, setup + + +def readme(): + with open('README.md', encoding='utf-8') as f: + content = f.read() + return content + + +version_file = 'sdsvtd/version.py' +is_windows = sys.platform == 'win32' + + +def add_mim_extention(): + """Add extra files that are required to support MIM into the package. + + These files will be added by creating a symlink to the originals if the + package is installed in `editable` mode (e.g. pip install -e .), or by + copying from the originals otherwise. + """ + + # parse installment mode + if 'develop' in sys.argv: + # installed by `pip install -e .` + mode = 'symlink' + elif 'sdist' in sys.argv or 'bdist_wheel' in sys.argv: + # installed by `pip install .` + # or create source distribution by `python setup.py sdist` + mode = 'copy' + else: + return + + filenames = ['tools', 'configs', 'model-index.yml'] + repo_path = osp.dirname(__file__) + mim_path = osp.join(repo_path, 'mmocr', '.mim') + os.makedirs(mim_path, exist_ok=True) + + for filename in filenames: + if osp.exists(filename): + src_path = osp.join(repo_path, filename) + tar_path = osp.join(mim_path, filename) + + if osp.isfile(tar_path) or osp.islink(tar_path): + os.remove(tar_path) + elif osp.isdir(tar_path): + shutil.rmtree(tar_path) + + if mode == 'symlink': + src_relpath = osp.relpath(src_path, osp.dirname(tar_path)) + try: + os.symlink(src_relpath, tar_path) + except OSError: + # Creating a symbolic link on windows may raise an + # `OSError: [WinError 1314]` due to privilege. If + # the error happens, the src file will be copied + mode = 'copy' + warnings.warn( + f'Failed to create a symbolic link for {src_relpath}, ' + f'and it will be copied to {tar_path}') + else: + continue + + if mode == 'copy': + if osp.isfile(src_path): + shutil.copyfile(src_path, tar_path) + elif osp.isdir(src_path): + shutil.copytree(src_path, tar_path) + else: + warnings.warn(f'Cannot copy file {src_path}.') + else: + raise ValueError(f'Invalid mode {mode}') + + +def get_version(): + with open(version_file, 'r') as f: + exec(compile(f.read(), version_file, 'exec')) + import sys + + # return short version for sdist + if 'sdist' in sys.argv or 'bdist_wheel' in sys.argv: + return locals()['short_version'] + else: + return locals()['__version__'] + + +def parse_requirements(fname='requirements.txt', with_version=True): + """Parse the package dependencies listed in a requirements file but strip + specific version information. + + Args: + fname (str): Path to requirements file. + with_version (bool, default=False): If True, include version specs. + Returns: + info (list[str]): List of requirements items. + CommandLine: + python -c "import setup; print(setup.parse_requirements())" + """ + import re + import sys + from os.path import exists + require_fpath = fname + + def parse_line(line): + """Parse information from a line in a requirements text file.""" + if line.startswith('-r '): + # Allow specifying requirements in other files + target = line.split(' ')[1] + for info in parse_require_file(target): + yield info + else: + info = {'line': line} + if line.startswith('-e '): + info['package'] = line.split('#egg=')[1] + else: + # Remove versioning from the package + pat = '(' + '|'.join(['>=', '==', '>']) + ')' + parts = re.split(pat, line, maxsplit=1) + parts = [p.strip() for p in parts] + + info['package'] = parts[0] + if len(parts) > 1: + op, rest = parts[1:] + if ';' in rest: + # Handle platform specific dependencies + # http://setuptools.readthedocs.io/en/latest/setuptools.html#declaring-platform-specific-dependencies + version, platform_deps = map(str.strip, + rest.split(';')) + info['platform_deps'] = platform_deps + else: + version = rest # NOQA + info['version'] = (op, version) + yield info + + def parse_require_file(fpath): + with open(fpath, 'r') as f: + for line in f.readlines(): + line = line.strip() + if line and not line.startswith('#'): + for info in parse_line(line): + yield info + + def gen_packages_items(): + if exists(require_fpath): + for info in parse_require_file(require_fpath): + parts = [info['package']] + if with_version and 'version' in info: + parts.extend(info['version']) + if not sys.version.startswith('3.4'): + # apparently package_deps are broken in 3.4 + platform_deps = info.get('platform_deps') + if platform_deps is not None: + parts.append(';' + platform_deps) + item = ''.join(parts) + yield item + + packages = list(gen_packages_items()) + return packages + + +if __name__ == '__main__': + setup( + name='sdsvtd', + version=get_version(), + description='SDSV OCR Team Text Detection', + long_description=readme(), + long_description_content_type='text/markdown', + packages=find_packages(exclude=('configs', 'tools', 'demo')), + include_package_data=True, + classifiers=[ + 'Development Status :: 4 - Beta', + 'License :: OSI Approved :: Apache Software License', + 'Operating System :: OS Independent', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', + 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', + ], + license='Apache License 2.0', + install_requires=parse_requirements('requirements.txt'), + zip_safe=False) diff --git a/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtr/.gitignore b/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtr/.gitignore new file mode 100644 index 0000000..a8c1759 --- /dev/null +++ b/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtr/.gitignore @@ -0,0 +1,6 @@ +# Builds +*.egg-info +__pycache__ + +# Checkpoint +hub \ No newline at end of file diff --git a/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtr/LICENSE b/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtr/LICENSE new file mode 100644 index 0000000..92b370f --- /dev/null +++ b/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtr/LICENSE @@ -0,0 +1,674 @@ +GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtr/README.md b/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtr/README.md new file mode 100644 index 0000000..2cabc83 --- /dev/null +++ b/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtr/README.md @@ -0,0 +1,76 @@ +## Introduction +This repo serve as source code storage for the Standalone SATRN Text Recognizer packages. +Installing this package requires 3 additional packages: PyTorch, MMCV, and colorama. + + +## Installation +```shell +conda create -n sdsvtr-env python=3.8 +conda activate sdsvtr-env +conda install pytorch torchvision pytorch-cuda=11.6 -c pytorch -c nvidia +pip install -U openmim +mim install mmcv-full +pip install colorama +git clone https://github.com/moewiee/sdsvtr.git +cd sdsvtr +pip install -v -e . +``` + +## Basic Usage +```python +from sdsvtr import StandaloneSATRNRunner +runner = StandaloneSATRNRunner(version='satrn-lite-general-pretrain-20230106', return_confident=False, use_cuda=False) +``` + +The `version` parameter accepts version names declared in `sdsvtr.factory.online_model_factory` or a local path such as `$DIR\model.pth`. To check for available versions in the hub, run: +```python +import sdsvtr +print(sdsvtr.__hub_available_versions__) +``` + +Naturally, a `StandaloneSATRNRunner` instance assumes the input to be one of the following: an instance of `np.ndarray`, an instance of `str`, a list of `np.ndarray`, or a list of `str`, for examples: +```python +import numpy as np +from sdsvtr import StandaloneSATRNRunner +runner = StandaloneSATRNRunner(version='satrn-lite-general-pretrain-20230106', return_confident=False, use_cuda=False) + +dummy_list = [np.ndarray((32,128,3)) for _ in range(100)] +result = runner(dummy_list) +``` + +To run with a specific batchsize, try: +```python +import numpy as np +from sdsvtr import StandaloneSATRNRunner +runner = StandaloneSATRNRunner(version='satrn-lite-general-pretrain-20230106', return_confident=False, device='cuda:0') + +dummy_list = [np.ndarray(1,3,32,128) for _ in range(100)] +bs = min(32, len(imageFiles)) # batchsize = 32 + +all_results = [] +while len(dummy_list) > 0: + dummy_batch = dummy_list[:bs] + dummy_list = dummy_list[bs:] + all_results += runner(dummy_batch) +``` + +## Version Changelog +* **[0.0.1]** +Initial version with specified features. + + +* **[0.0.2]** +Update online model hub. + + +* **[0.0.3]** +Update API now able to inference with 4 types of inputs: list/instance of `np.ndarray`/`str` +Update API interface with `return_confident` parameter. +Update `wget` check and `sha256` check for model hub retrieval. + +* **[0.0.4]** +Update decoder module with EarlyStopping mechanism to possibly improve inference speed on short sequences. +Update API interface with optional argument `max_seq_len_overwrite` to overwrite checkpoint's `max_seq_len` config. + +* **[0.0.5]** +Allow inference on a specific device diff --git a/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtr/requirements.txt b/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtr/requirements.txt new file mode 100644 index 0000000..f4a74db --- /dev/null +++ b/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtr/requirements.txt @@ -0,0 +1,3 @@ +torch +colorama +mmcv-full \ No newline at end of file diff --git a/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtr/sdsvtr/__init__.py b/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtr/sdsvtr/__init__.py new file mode 100644 index 0000000..dd8470d --- /dev/null +++ b/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtr/sdsvtr/__init__.py @@ -0,0 +1,3 @@ +from .api import StandaloneSATRNRunner +from .version import __version__ +from .factory import __hub_available_versions__ \ No newline at end of file diff --git a/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtr/sdsvtr/api.py b/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtr/sdsvtr/api.py new file mode 100644 index 0000000..566a904 --- /dev/null +++ b/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtr/sdsvtr/api.py @@ -0,0 +1,106 @@ + +import torch +import torch.nn as nn + +from colorama import Fore, Style + +from .converter import AttnConvertor +from .backbone import ResNetABI +from .encoder import SatrnEncoder +from .decoder import NRTRDecoder +from .transform import DataPipelineSATRN +from .fp16_utils import patch_norm_fp32 +from .factory import _get as get_version + + +class SATRN(nn.Module): + """Standalone implementation for SATRN encode-decode recognizer.""" + + def __init__(self, + version, + return_confident=False, + device='cpu', + max_seq_len_overwrite=None): + + super().__init__() + + checkpoint = get_version(version) + + pt = torch.load(checkpoint, 'cpu') + if device == 'cpu': + print(Fore.RED + 'Warning: You are using CPU inference method. Init with device=cuda: to run with CUDA method.' + Style.RESET_ALL) + + self.pipeline = DataPipelineSATRN(**pt['pipeline_args'], device=device) + + # Convertor + self.label_convertor = AttnConvertor(**pt['label_convertor_args'], return_confident=return_confident) + + # Backbone + self.backbone = ResNetABI(**pt['backbone_args']) + + # Encoder module + self.encoder = SatrnEncoder(**pt['encoder_args']) + + # Decoder module + decoder_max_seq_len = max_seq_len_overwrite if max_seq_len_overwrite is not None else pt['max_seq_len'] + self.decoder = NRTRDecoder( + **pt['decoder_args'], + max_seq_len=decoder_max_seq_len, + num_classes=self.label_convertor.num_classes(), + start_idx=self.label_convertor.start_idx, + padding_idx=self.label_convertor.padding_idx, + return_confident=return_confident, + end_idx=self.label_convertor.end_idx + ) + + self.load_state_dict(pt['state_dict'], strict=True) + print(f'Text recognition from version {version}.') + + if device != 'cpu': + self = self.to(device) + self = self.half() + patch_norm_fp32(self) + + self.eval() + for param in self.parameters(): + param.requires_grad = False + + def extract_feat(self, img): + x = self.backbone(img) + + return x + + def forward(self, img): + """Test function with test time augmentation. + + Args: + imgs (torch.Tensor): Image input tensor. + + Returns: + list[str]: Text label result of each image. + """ + img = self.pipeline(img) + feat = self.extract_feat(img) + out_enc = self.encoder(feat) + out_dec = self.decoder(out_enc).cpu().numpy() + label_strings = self.label_convertor(out_dec) + + return label_strings + + +class StandaloneSATRNRunner: + def __init__(self, + version, + return_confident, + device='cpu', + max_seq_len_overwrite=None): + self.device = device + self.model = SATRN(version=version, + return_confident=return_confident, + device=self.device, + max_seq_len_overwrite=max_seq_len_overwrite) + + def __call__(self, imgs): + results = self.model(imgs) + + return results \ No newline at end of file diff --git a/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtr/sdsvtr/backbone.py b/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtr/sdsvtr/backbone.py new file mode 100644 index 0000000..29c2509 --- /dev/null +++ b/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtr/sdsvtr/backbone.py @@ -0,0 +1,159 @@ +import torch.nn as nn + +def conv3x3(in_planes, out_planes, stride=1): + """3x3 convolution with padding.""" + return nn.Conv2d( + in_planes, + out_planes, + kernel_size=3, + stride=stride, + padding=1, + bias=False) + + +def conv1x1(in_planes, out_planes): + """1x1 convolution with padding.""" + return nn.Conv2d( + in_planes, out_planes, kernel_size=1, stride=1, padding=0, bias=False) + + +class BasicBlock(nn.Module): + + expansion = 1 + + def __init__(self, + inplanes, + planes, + stride=1, + downsample=None, + use_conv1x1=False): + super(BasicBlock, self).__init__() + + if use_conv1x1: + self.conv1 = conv1x1(inplanes, planes) + self.conv2 = conv3x3(planes, planes * self.expansion, stride) + else: + self.conv1 = conv3x3(inplanes, planes, stride) + self.conv2 = conv3x3(planes, planes * self.expansion) + + self.planes = planes + self.bn1 = nn.BatchNorm2d(planes) + self.relu = nn.ReLU(inplace=True) + self.bn2 = nn.BatchNorm2d(planes * self.expansion) + self.downsample = downsample + self.stride = stride + + def forward(self, x): + residual = x + out = self.conv1(x) + out = self.bn1(out) + out = self.relu(out) + out = self.conv2(out) + out = self.bn2(out) + if self.downsample is not None: + residual = self.downsample(x) + out += residual + out = self.relu(out) + + return out + +class ResNetABI(nn.Module): + """Implement ResNet backbone for text recognition, modified from `ResNet. + + `_ and + ``_ + + Args: + in_channels (int): Number of channels of input image tensor. + stem_channels (int): Number of stem channels. + base_channels (int): Number of base channels. + arch_settings (list[int]): List of BasicBlock number for each stage. + strides (Sequence[int]): Strides of the first block of each stage. + out_indices (None | Sequence[int]): Indices of output stages. If not + specified, only the last stage will be returned. + last_stage_pool (bool): If True, add `MaxPool2d` layer to last stage. + """ + + def __init__(self, + in_channels=3, + stem_channels=32, + base_channels=32, + arch_settings=[3, 4, 6, 6, 3], + strides=[2, 1, 2, 1, 1], + out_indices=None, + last_stage_pool=False): + super().__init__() + + self.out_indices = out_indices + self.last_stage_pool = last_stage_pool + self.block = BasicBlock + self.inplanes = stem_channels + + self._make_stem_layer(in_channels, stem_channels) + + self.res_layers = [] + planes = base_channels + for i, num_blocks in enumerate(arch_settings): + stride = strides[i] + res_layer = self._make_layer( + block=self.block, + inplanes=self.inplanes, + planes=planes, + blocks=num_blocks, + stride=stride) + self.inplanes = planes * self.block.expansion + planes *= 2 + layer_name = f'layer{i + 1}' + self.add_module(layer_name, res_layer) + self.res_layers.append(layer_name) + + def _make_layer(self, block, inplanes, planes, blocks, stride=1): + layers = [] + downsample = None + if stride != 1 or inplanes != planes: + downsample = nn.Sequential( + nn.Conv2d(inplanes, planes, 1, stride, bias=False), + nn.BatchNorm2d(planes), + ) + layers.append( + block( + inplanes, + planes, + use_conv1x1=True, + stride=stride, + downsample=downsample)) + inplanes = planes + for _ in range(1, blocks): + layers.append(block(inplanes, planes, use_conv1x1=True)) + + return nn.Sequential(*layers) + + def _make_stem_layer(self, in_channels, stem_channels): + self.conv1 = nn.Conv2d( + in_channels, stem_channels, kernel_size=3, stride=1, padding=1) + self.bn1 = nn.BatchNorm2d(stem_channels) + self.relu1 = nn.ReLU(inplace=True) + + def forward(self, x): + """ + Args: + x (Tensor): Image tensor of shape :math:`(N, 3, H, W)`. + + Returns: + Tensor or list[Tensor]: Feature tensor. Its shape depends on + ResNetABI's config. It can be a list of feature outputs at specific + layers if ``out_indices`` is specified. + """ + + x = self.conv1(x) + x = self.bn1(x) + x = self.relu1(x) + + outs = [] + for i, layer_name in enumerate(self.res_layers): + res_layer = getattr(self, layer_name) + x = res_layer(x) + if self.out_indices and i in self.out_indices: + outs.append(x) + + return tuple(outs) if self.out_indices else x diff --git a/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtr/sdsvtr/conv.py b/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtr/sdsvtr/conv.py new file mode 100644 index 0000000..950ec0c --- /dev/null +++ b/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtr/sdsvtr/conv.py @@ -0,0 +1,173 @@ +import warnings +import torch.nn as nn +from torch.nn.modules.instancenorm import _InstanceNorm +from torch.nn.modules.batchnorm import _BatchNorm +from mmcv.cnn import build_padding_layer, build_conv_layer, build_norm_layer, build_activation_layer + +class ConvModule(nn.Module): + """A conv block that bundles conv/norm/activation layers. + + This block simplifies the usage of convolution layers, which are commonly + used with a norm layer (e.g., BatchNorm) and activation layer (e.g., ReLU). + It is based upon three build methods: `build_conv_layer()`, + `build_norm_layer()` and `build_activation_layer()`. + + Besides, we add some additional features in this module. + 1. Automatically set `bias` of the conv layer. + 2. Spectral norm is supported. + 3. More padding modes are supported. Before PyTorch 1.5, nn.Conv2d only + supports zero and circular padding, and we add "reflect" padding mode. + + Args: + in_channels (int): Number of channels in the input feature map. + Same as that in ``nn._ConvNd``. + out_channels (int): Number of channels produced by the convolution. + Same as that in ``nn._ConvNd``. + kernel_size (int | tuple[int]): Size of the convolving kernel. + Same as that in ``nn._ConvNd``. + stride (int | tuple[int]): Stride of the convolution. + Same as that in ``nn._ConvNd``. + padding (int | tuple[int]): Zero-padding added to both sides of + the input. Same as that in ``nn._ConvNd``. + dilation (int | tuple[int]): Spacing between kernel elements. + Same as that in ``nn._ConvNd``. + groups (int): Number of blocked connections from input channels to + output channels. Same as that in ``nn._ConvNd``. + bias (bool | str): If specified as `auto`, it will be decided by the + norm_cfg. Bias will be set as True if `norm_cfg` is None, otherwise + False. Default: "auto". + conv_cfg (dict): Config dict for convolution layer. Default: None, + which means using conv2d. + norm_cfg (dict): Config dict for normalization layer. Default: None. + act_cfg (dict): Config dict for activation layer. + Default: dict(type='ReLU'). + inplace (bool): Whether to use inplace mode for activation. + Default: True. + with_spectral_norm (bool): Whether use spectral norm in conv module. + Default: False. + padding_mode (str): If the `padding_mode` has not been supported by + current `Conv2d` in PyTorch, we will use our own padding layer + instead. Currently, we support ['zeros', 'circular'] with official + implementation and ['reflect'] with our own implementation. + Default: 'zeros'. + order (tuple[str]): The order of conv/norm/activation layers. It is a + sequence of "conv", "norm" and "act". Common examples are + ("conv", "norm", "act") and ("act", "conv", "norm"). + Default: ('conv', 'norm', 'act'). + """ + + _abbr_ = 'conv_block' + + def __init__(self, + in_channels, + out_channels, + kernel_size, + stride=1, + padding=0, + dilation=1, + groups=1, + bias='auto', + conv_cfg=None, + norm_cfg=None, + act_cfg=dict(type='ReLU'), + inplace=True, + with_spectral_norm=False, + padding_mode='zeros', + order=('conv', 'norm', 'act')): + super(ConvModule, self).__init__() + assert conv_cfg is None or isinstance(conv_cfg, dict) + assert norm_cfg is None or isinstance(norm_cfg, dict) + assert act_cfg is None or isinstance(act_cfg, dict) + official_padding_mode = ['zeros', 'circular'] + self.conv_cfg = conv_cfg + self.norm_cfg = norm_cfg + self.act_cfg = act_cfg + self.inplace = inplace + self.with_spectral_norm = with_spectral_norm + self.with_explicit_padding = padding_mode not in official_padding_mode + self.order = order + assert isinstance(self.order, tuple) and len(self.order) == 3 + assert set(order) == set(['conv', 'norm', 'act']) + + self.with_norm = norm_cfg is not None + self.with_activation = act_cfg is not None + # if the conv layer is before a norm layer, bias is unnecessary. + if bias == 'auto': + bias = not self.with_norm + self.with_bias = bias + + if self.with_explicit_padding: + pad_cfg = dict(type=padding_mode) + self.padding_layer = build_padding_layer(pad_cfg, padding) + + # reset padding to 0 for conv module + conv_padding = 0 if self.with_explicit_padding else padding + # build convolution layer + self.conv = build_conv_layer( + conv_cfg, + in_channels, + out_channels, + kernel_size, + stride=stride, + padding=conv_padding, + dilation=dilation, + groups=groups, + bias=bias) + # export the attributes of self.conv to a higher level for convenience + self.in_channels = self.conv.in_channels + self.out_channels = self.conv.out_channels + self.kernel_size = self.conv.kernel_size + self.stride = self.conv.stride + self.padding = padding + self.dilation = self.conv.dilation + self.transposed = self.conv.transposed + self.output_padding = self.conv.output_padding + self.groups = self.conv.groups + + if self.with_spectral_norm: + self.conv = nn.utils.spectral_norm(self.conv) + + # build normalization layers + if self.with_norm: + # norm layer is after conv layer + if order.index('norm') > order.index('conv'): + norm_channels = out_channels + else: + norm_channels = in_channels + self.norm_name, norm = build_norm_layer(norm_cfg, norm_channels) + self.add_module(self.norm_name, norm) + if self.with_bias: + if isinstance(norm, (_BatchNorm, _InstanceNorm)): + warnings.warn( + 'Unnecessary conv bias before batch/instance norm') + else: + self.norm_name = None + + # build activation layer + if self.with_activation: + act_cfg_ = act_cfg.copy() + # nn.Tanh has no 'inplace' argument + if act_cfg_['type'] not in [ + 'Tanh', 'PReLU', 'Sigmoid', 'HSigmoid', 'Swish' + ]: + act_cfg_.setdefault('inplace', inplace) + self.activate = build_activation_layer(act_cfg_) + + @property + def norm(self): + if self.norm_name: + return getattr(self, self.norm_name) + else: + return None + + def forward(self, x, activate=True, norm=True): + for layer in self.order: + if layer == 'conv': + if self.with_explicit_padding: + x = self.padding_layer(x) + x = self.conv(x) + elif layer == 'norm' and norm and self.with_norm: + x = self.norm(x) + elif layer == 'act' and activate and self.with_activation: + x = self.activate(x) + return x \ No newline at end of file diff --git a/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtr/sdsvtr/converter.py b/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtr/sdsvtr/converter.py new file mode 100644 index 0000000..4d9bf82 --- /dev/null +++ b/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtr/sdsvtr/converter.py @@ -0,0 +1,152 @@ +import torch +import numpy as np + +class BaseConvertor: + """Convert between text, index and tensor for text recognize pipeline. + + Args: + dict_type (str): Type of dict, options are 'DICT36', 'DICT37', 'DICT90' + and 'DICT91'. + dict_file (None|str): Character dict file path. If not none, + the dict_file is of higher priority than dict_type. + dict_list (None|list[str]): Character list. If not none, the list + is of higher priority than dict_type, but lower than dict_file. + """ + start_idx = end_idx = padding_idx = 0 + unknown_idx = None + lower = False + + DICT36 = tuple('0123456789abcdefghijklmnopqrstuvwxyz') + DICT63 = tuple('0123456789abcdefghijklmnopqrstuvwxyz' + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ') + DICT90 = tuple('0123456789abcdefghijklmnopqrstuvwxyz' + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'()' + '*+,-./:;<=>?@[\\]_`~') + DICT131 = tuple('0123456789abcdefghijklmnopqrstuvwxyz' + '!"#$%&\'()' + '*+,-./:;<=>?@[\\]_`~' + 'ạảãàáâậầấẩẫăắằặẳẵóòọõỏôộổỗồốơờớợởỡéèẻẹẽêếềệểễúùụủũưựữửừứíìịỉĩýỳỷỵỹđ') + DICT224 = tuple('0123456789abcdefghijklmnopqrstuvwxyz' + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'()' + '*+,-./:;<=>?@[\\]_`~{}|^ ̂' + 'ạảãàáâậầấẩẫăắằặẳẵóòọõỏôộổỗồốơờớợởỡéèẻẹẽêếềệểễúùụủũưựữửừứíìịỉĩýỳỷỵỹđ' + 'ẠẢÃÀÁÂẬẦẤẨẪĂẮẰẶẲẴÓÒỌÕỎÔỘỔỖỒỐƠỜỚỢỞỠÉÈẺẸẼÊẾỀỆỂỄÚÙỤỦŨƯỰỮỬỪỨÍÌỊỈĨÝỲỶỴỸĐ✪') + + def __init__(self, dict_type='DICT90'): + assert dict_type in ('DICT36', 'DICT63', 'DICT90', 'DICT131', 'DICT224') + self.idx2char = [] + + if dict_type == 'DICT36': + self.idx2char = list(self.DICT36) + elif dict_type == 'DICT63': + self.idx2char = list(self.DICT63) + elif dict_type == 'DICT90': + self.idx2char = list(self.DICT90) + elif dict_type == 'DICT131': + self.idx2char = list(self.DICT131) + elif dict_type == 'DICT224': + self.idx2char = list(self.DICT224) + else: + raise ('Dictonary not implemented') + + assert len(set(self.idx2char)) == len(self.idx2char), \ + 'Invalid dictionary: Has duplicated characters.' + + self.char2idx = {char: idx for idx, char in enumerate(self.idx2char)} + + def num_classes(self): + """Number of output classes.""" + return len(self.idx2char) + + +class AttnConvertor(BaseConvertor): + """Convert between text, index and tensor for encoder-decoder based + pipeline. + + Args: + dict_type (str): Type of dict, should be one of {'DICT36', 'DICT90'}. + dict_file (None|str): Character dict file path. If not none, + higher priority than dict_type. + dict_list (None|list[str]): Character list. If not none, higher + priority than dict_type, but lower than dict_file. + with_unknown (bool): If True, add `UKN` token to class. + max_seq_len (int): Maximum sequence length of label. + lower (bool): If True, convert original string to lower case. + start_end_same (bool): Whether use the same index for + start and end token or not. Default: True. + """ + + def __init__(self, + dict_type='DICT90', + with_unknown=True, + max_seq_len=40, + lower=False, + start_end_same=True, + return_confident=False, + **kwargs): + super().__init__(dict_type) + assert isinstance(with_unknown, bool) + assert isinstance(max_seq_len, int) + assert isinstance(lower, bool) + + self.with_unknown = with_unknown + self.max_seq_len = max_seq_len + self.lower = lower + self.start_end_same = start_end_same + self.return_confident = return_confident + + self.update_dict() + + def update_dict(self): + start_end_token = '' + unknown_token = '' + padding_token = '' + + # unknown + self.unknown_idx = None + if self.with_unknown: + self.idx2char.append(unknown_token) + self.unknown_idx = len(self.idx2char) - 1 + + # BOS/EOS + self.idx2char.append(start_end_token) + self.start_idx = len(self.idx2char) - 1 + if not self.start_end_same: + self.idx2char.append(start_end_token) + self.end_idx = len(self.idx2char) - 1 + + # padding + self.idx2char.append(padding_token) + self.padding_idx = len(self.idx2char) - 1 + + # update char2idx + self.char2idx = {} + for idx, char in enumerate(self.idx2char): + self.char2idx[char] = idx + + def __call__(self, indexes): + strings = [] + confidents = [] + if self.return_confident: + b,sq,_ = indexes.shape + for idx in range(b): + index = indexes[idx, :, :] + chars = index.argmax(-1) + confident = index.max(-1) + i = 0 + while i < sq and chars[i] != self.end_idx and chars[i] != self.padding_idx: i += 1 + chars = chars[:i] + confident = confident[:i].min() + string = [self.idx2char[i] for i in chars] + strings.append(''.join(string)) + confidents.append(confident) + + return strings, confidents + else: + for index in indexes: + i, l = 0, len(index) + while i < l and index[i] != self.end_idx and index[i] != self.padding_idx: i += 1 + index = index[:i] + string = [self.idx2char[i] for i in index] + strings.append(''.join(string)) + return strings \ No newline at end of file diff --git a/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtr/sdsvtr/decoder.py b/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtr/sdsvtr/decoder.py new file mode 100644 index 0000000..b4ec51a --- /dev/null +++ b/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtr/sdsvtr/decoder.py @@ -0,0 +1,278 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F +import math +import numpy as np +from .encoder import MultiHeadAttention + + +class PositionwiseFeedForward(nn.Module): + """Two-layer feed-forward module. + + Args: + d_in (int): The dimension of the input for feedforward + network model. + d_hid (int): The dimension of the feedforward + network model. + dropout (float): Dropout layer on feedforward output. + act_cfg (dict): Activation cfg for feedforward module. + """ + + def __init__(self, d_in, d_hid, dropout=0.1): + super().__init__() + self.w_1 = nn.Linear(d_in, d_hid) + self.w_2 = nn.Linear(d_hid, d_in) + self.act = nn.GELU() + self.dropout = nn.Dropout(dropout) + + def forward(self, x): + x = self.w_1(x) + x = self.act(x) + x = self.w_2(x) + x = self.dropout(x) + + return x + + +class PositionalEncoding(nn.Module): + """Fixed positional encoding with sine and cosine functions.""" + + def __init__(self, d_hid=512, n_position=200): + super().__init__() + + # Not a parameter + # Position table of shape (1, n_position, d_hid) + self.register_buffer( + 'position_table', + self._get_sinusoid_encoding_table(n_position, d_hid)) + + def _get_sinusoid_encoding_table(self, n_position, d_hid): + """Sinusoid position encoding table.""" + denominator = torch.Tensor([ + 1.0 / np.power(10000, 2 * (hid_j // 2) / d_hid) + for hid_j in range(d_hid) + ]) + denominator = denominator.view(1, -1) + pos_tensor = torch.arange(n_position).unsqueeze(-1).float() + sinusoid_table = pos_tensor * denominator + sinusoid_table[:, 0::2] = torch.sin(sinusoid_table[:, 0::2]) + sinusoid_table[:, 1::2] = torch.cos(sinusoid_table[:, 1::2]) + + return sinusoid_table.unsqueeze(0) + + def forward(self, x): + """ + Args: + x (Tensor): Tensor of shape (batch_size, pos_len, d_hid, ...) + """ + self.device = x.device + x = x + self.position_table[:, :x.size(1)].clone().detach() + return x + + + +class TFDecoderLayer(nn.Module): + """Transformer Decoder Layer. + + Args: + d_model (int): The number of expected features + in the decoder inputs (default=512). + d_inner (int): The dimension of the feedforward + network model (default=256). + n_head (int): The number of heads in the + multiheadattention models (default=8). + d_k (int): Total number of features in key. + d_v (int): Total number of features in value. + dropout (float): Dropout layer on attn_output_weights. + qkv_bias (bool): Add bias in projection layer. Default: False. + act_cfg (dict): Activation cfg for feedforward module. + operation_order (tuple[str]): The execution order of operation + in transformer. Such as ('self_attn', 'norm', 'enc_dec_attn', + 'norm', 'ffn', 'norm') or ('norm', 'self_attn', 'norm', + 'enc_dec_attn', 'norm', 'ffn'). + Default:None. + """ + + def __init__(self, + d_model=512, + d_inner=256, + n_head=8, + d_k=64, + d_v=64, + dropout=0.1, + qkv_bias=False): + super().__init__() + + self.norm1 = nn.LayerNorm(d_model) + self.norm2 = nn.LayerNorm(d_model) + self.norm3 = nn.LayerNorm(d_model) + + self.self_attn = MultiHeadAttention( + n_head, d_model, d_k, d_v, dropout=dropout, qkv_bias=qkv_bias) + + self.enc_attn = MultiHeadAttention( + n_head, d_model, d_k, d_v, dropout=dropout, qkv_bias=qkv_bias) + + self.mlp = PositionwiseFeedForward( + d_model, d_inner, dropout=dropout) + + def forward(self, + dec_input, + enc_output, + self_attn_mask=None, + dec_enc_attn_mask=None): + dec_input_norm = self.norm1(dec_input) + dec_attn_out = self.self_attn(dec_input_norm, dec_input_norm, + dec_input_norm, self_attn_mask) + dec_attn_out += dec_input + + enc_dec_attn_in = self.norm2(dec_attn_out) + enc_dec_attn_out = self.enc_attn(enc_dec_attn_in, enc_output, + enc_output, dec_enc_attn_mask) + enc_dec_attn_out += dec_attn_out + + mlp_out = self.mlp(self.norm3(enc_dec_attn_out)) + mlp_out += enc_dec_attn_out + + return mlp_out + +class NRTRDecoder(nn.Module): + """Transformer Decoder block with self attention mechanism. + + Args: + n_layers (int): Number of attention layers. + d_embedding (int): Language embedding dimension. + n_head (int): Number of parallel attention heads. + d_k (int): Dimension of the key vector. + d_v (int): Dimension of the value vector. + d_model (int): Dimension :math:`D_m` of the input from previous model. + d_inner (int): Hidden dimension of feedforward layers. + n_position (int): Length of the positional encoding vector. Must be + greater than ``max_seq_len``. + dropout (float): Dropout rate. + num_classes (int): Number of output classes :math:`C`. + max_seq_len (int): Maximum output sequence length :math:`T`. + start_idx (int): The index of ``. + padding_idx (int): The index of ``. + init_cfg (dict or list[dict], optional): Initialization configs. + + Warning: + This decoder will not predict the final class which is assumed to be + ``. Therefore, its output size is always :math:`C - 1`. `` + is also ignored by loss as specified in + :obj:`mmocr.models.textrecog.recognizer.EncodeDecodeRecognizer`. + """ + + def __init__(self, + n_layers=6, + d_embedding=512, + n_head=8, + d_k=64, + d_v=64, + d_model=512, + d_inner=256, + n_position=200, + dropout=0.1, + num_classes=93, + max_seq_len=40, + start_idx=1, + padding_idx=92, + return_confident=False, + end_idx=None, + **kwargs): + super().__init__() + + self.padding_idx = padding_idx + self.start_idx = start_idx + self.max_seq_len = max_seq_len + + self.trg_word_emb = nn.Embedding( + num_classes, d_embedding, padding_idx=padding_idx) + + self.position_enc = PositionalEncoding( + d_embedding, n_position=n_position) + + self.layer_stack = nn.ModuleList([ + TFDecoderLayer( + d_model, d_inner, n_head, d_k, d_v, dropout=dropout, **kwargs) + for _ in range(n_layers) + ]) + self.layer_norm = nn.LayerNorm(d_model, eps=1e-6) + + pred_num_class = num_classes - 1 # ignore padding_idx + self.classifier = nn.Linear(d_model, pred_num_class) + + self.return_confident = return_confident + self.end_idx = end_idx + + @staticmethod + def get_pad_mask(seq, pad_idx): + + return (seq != pad_idx).unsqueeze(-2) + + @staticmethod + def get_subsequent_mask(seq): + """For masking out the subsequent info.""" + len_s = seq.size(1) + subsequent_mask = 1 - torch.triu( + torch.ones((len_s, len_s), device=seq.device), diagonal=1) + subsequent_mask = subsequent_mask.unsqueeze(0).bool() + + return subsequent_mask + + def _attention(self, trg_seq, src, src_mask=None): + trg_embedding = self.trg_word_emb(trg_seq) + trg_pos_encoded = self.position_enc(trg_embedding) + trg_mask = self.get_pad_mask( + trg_seq, + pad_idx=self.padding_idx) & self.get_subsequent_mask(trg_seq) + output = trg_pos_encoded + for dec_layer in self.layer_stack: + output = dec_layer( + output, + src, + self_attn_mask=trg_mask, + dec_enc_attn_mask=src_mask) + output = self.layer_norm(output) + + return output + + def _get_mask(self, logit): + N, T, _ = logit.size() + mask = logit.new_ones((N, T)) + + return mask + + def forward(self, out_enc): + src_mask = self._get_mask(out_enc) + N = out_enc.size(0) + init_target_seq = torch.full((N, self.max_seq_len + 1), + self.padding_idx, + device=out_enc.device, + dtype=torch.long) + # bsz * seq_len + init_target_seq[:, 0] = self.start_idx + + outputs = [] + for step in range(0, self.max_seq_len): + decoder_output = self._attention( + trg_seq=init_target_seq, + src=out_enc, + src_mask=src_mask) + if self.return_confident: + step_result = torch.softmax(self.classifier(decoder_output[:, step, :]), -1) + next_step_init = step_result.argmax(-1) + init_target_seq[:, step + 1] = next_step_init + if next_step_init.min() >= self.end_idx: + break + else: + step_result = self.classifier(decoder_output[:, step, :]).argmax(-1) + init_target_seq[:, step + 1] = step_result + if step_result.min() >= self.end_idx: + break + + outputs.append(step_result) + + outputs = torch.stack(outputs, dim=1) + + return outputs \ No newline at end of file diff --git a/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtr/sdsvtr/encoder.py b/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtr/sdsvtr/encoder.py new file mode 100644 index 0000000..6ccb612 --- /dev/null +++ b/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtr/sdsvtr/encoder.py @@ -0,0 +1,317 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F +import numpy as np +import math +from .conv import ConvModule + + +class LocalityAwareFeedforward(nn.Module): + """Locality-aware feedforward layer in SATRN, see `SATRN. + + `_ + """ + + def __init__(self, + d_in, + d_hid, + dropout=0.1): + super().__init__() + self.conv1 = ConvModule( + d_in, + d_hid, + kernel_size=1, + padding=0, + bias=False, + norm_cfg=dict(type='BN'), + act_cfg=dict(type='ReLU')) + + self.depthwise_conv = ConvModule( + d_hid, + d_hid, + kernel_size=3, + padding=1, + bias=False, + groups=d_hid, + norm_cfg=dict(type='BN'), + act_cfg=dict(type='ReLU')) + + self.conv2 = ConvModule( + d_hid, + d_in, + kernel_size=1, + padding=0, + bias=False, + norm_cfg=dict(type='BN'), + act_cfg=dict(type='ReLU')) + + def forward(self, x): + x = self.conv1(x) + x = self.depthwise_conv(x) + x = self.conv2(x) + + return x + + +class ScaledDotProductAttention(nn.Module): + """Scaled Dot-Product Attention Module. This code is adopted from + https://github.com/jadore801120/attention-is-all-you-need-pytorch. + + Args: + temperature (float): The scale factor for softmax input. + attn_dropout (float): Dropout layer on attn_output_weights. + """ + + def __init__(self, temperature, attn_dropout=0.1): + super().__init__() + self.temperature = temperature + self.dropout = nn.Dropout(attn_dropout) + + def forward(self, q, k, v, mask=None): + + attn = torch.matmul(q / self.temperature, k.transpose(2, 3)) + + if mask is not None: + attn = attn.masked_fill(mask == 0, float('-inf')) + + attn = self.dropout(F.softmax(attn, dim=-1)) + output = torch.matmul(attn, v) + + return output, attn + + +class MultiHeadAttention(nn.Module): + """Multi-Head Attention module. + + Args: + n_head (int): The number of heads in the + multiheadattention models (default=8). + d_model (int): The number of expected features + in the decoder inputs (default=512). + d_k (int): Total number of features in key. + d_v (int): Total number of features in value. + dropout (float): Dropout layer on attn_output_weights. + qkv_bias (bool): Add bias in projection layer. Default: False. + """ + + def __init__(self, + n_head=8, + d_model=512, + d_k=64, + d_v=64, + dropout=0.1, + qkv_bias=False): + super().__init__() + self.n_head = n_head + self.d_k = d_k + self.d_v = d_v + + self.dim_k = n_head * d_k + self.dim_v = n_head * d_v + + self.linear_q = nn.Linear(self.dim_k, self.dim_k, bias=qkv_bias) + self.linear_k = nn.Linear(self.dim_k, self.dim_k, bias=qkv_bias) + self.linear_v = nn.Linear(self.dim_v, self.dim_v, bias=qkv_bias) + + self.attention = ScaledDotProductAttention(d_k**0.5, dropout) + + self.fc = nn.Linear(self.dim_v, d_model, bias=qkv_bias) + self.proj_drop = nn.Dropout(dropout) + + def forward(self, q, k, v, mask=None): + batch_size, len_q, _ = q.size() + _, len_k, _ = k.size() + + q = self.linear_q(q).view(batch_size, len_q, self.n_head, self.d_k) + k = self.linear_k(k).view(batch_size, len_k, self.n_head, self.d_k) + v = self.linear_v(v).view(batch_size, len_k, self.n_head, self.d_v) + + q, k, v = q.transpose(1, 2), k.transpose(1, 2), v.transpose(1, 2) + + if mask is not None: + if mask.dim() == 3: + mask = mask.unsqueeze(1) + elif mask.dim() == 2: + mask = mask.unsqueeze(1).unsqueeze(1) + + attn_out, _ = self.attention(q, k, v, mask=mask) + + attn_out = attn_out.transpose(1, 2).contiguous().view( + batch_size, len_q, self.dim_v) + + attn_out = self.fc(attn_out) + attn_out = self.proj_drop(attn_out) + + return attn_out + + +class SatrnEncoderLayer(nn.Module): + """""" + + def __init__(self, + d_model=512, + d_inner=512, + n_head=8, + d_k=64, + d_v=64, + dropout=0.1, + qkv_bias=False): + super().__init__() + self.norm1 = nn.LayerNorm(d_model) + self.attn = MultiHeadAttention( + n_head, d_model, d_k, d_v, qkv_bias=qkv_bias, dropout=dropout) + self.norm2 = nn.LayerNorm(d_model) + self.feed_forward = LocalityAwareFeedforward( + d_model, d_inner, dropout=dropout) + + def forward(self, x, h, w, mask=None): + n, hw, c = x.size() + residual = x + x = self.norm1(x) + x = residual + self.attn(x, x, x, mask) + residual = x + x = self.norm2(x) + x = x.transpose(1, 2).contiguous().view(n, c, h, w) + x = self.feed_forward(x) + x = x.view(n, c, hw).transpose(1, 2) + x = residual + x + return x + + +class Adaptive2DPositionalEncoding(nn.Module): + """Implement Adaptive 2D positional encoder for SATRN, see + `SATRN `_ + Modified from https://github.com/Media-Smart/vedastr + Licensed under the Apache License, Version 2.0 (the "License"); + Args: + d_hid (int): Dimensions of hidden layer. + n_height (int): Max height of the 2D feature output. + n_width (int): Max width of the 2D feature output. + dropout (int): Size of hidden layers of the model. + """ + + def __init__(self, + d_hid=512, + n_height=100, + n_width=100, + dropout=0.1): + super().__init__() + + h_position_encoder = self._get_sinusoid_encoding_table(n_height, d_hid) + h_position_encoder = h_position_encoder.transpose(0, 1) + h_position_encoder = h_position_encoder.view(1, d_hid, n_height, 1) + + w_position_encoder = self._get_sinusoid_encoding_table(n_width, d_hid) + w_position_encoder = w_position_encoder.transpose(0, 1) + w_position_encoder = w_position_encoder.view(1, d_hid, 1, n_width) + + self.register_buffer('h_position_encoder', h_position_encoder) + self.register_buffer('w_position_encoder', w_position_encoder) + + self.h_scale = self.scale_factor_generate(d_hid) + self.w_scale = self.scale_factor_generate(d_hid) + self.pool = nn.AdaptiveAvgPool2d(1) + self.dropout = nn.Dropout(p=dropout) + + def _get_sinusoid_encoding_table(self, n_position, d_hid): + """Sinusoid position encoding table.""" + denominator = torch.Tensor([ + 1.0 / np.power(10000, 2 * (hid_j // 2) / d_hid) + for hid_j in range(d_hid) + ]) + denominator = denominator.view(1, -1) + pos_tensor = torch.arange(n_position).unsqueeze(-1).float() + sinusoid_table = pos_tensor * denominator + sinusoid_table[:, 0::2] = torch.sin(sinusoid_table[:, 0::2]) + sinusoid_table[:, 1::2] = torch.cos(sinusoid_table[:, 1::2]) + + return sinusoid_table + + def scale_factor_generate(self, d_hid): + scale_factor = nn.Sequential( + nn.Conv2d(d_hid, d_hid, kernel_size=1), nn.ReLU(inplace=True), + nn.Conv2d(d_hid, d_hid, kernel_size=1), nn.Sigmoid()) + + return scale_factor + + def forward(self, x): + b, c, h, w = x.size() + + avg_pool = self.pool(x) + + h_pos_encoding = \ + self.h_scale(avg_pool) * self.h_position_encoder[:, :, :h, :] + w_pos_encoding = \ + self.w_scale(avg_pool) * self.w_position_encoder[:, :, :, :w] + + out = x + h_pos_encoding + w_pos_encoding + + out = self.dropout(out) + + return out + + +class SatrnEncoder(nn.Module): + """Implement encoder for SATRN, see `SATRN. + + `_. + + Args: + n_layers (int): Number of attention layers. + n_head (int): Number of parallel attention heads. + d_k (int): Dimension of the key vector. + d_v (int): Dimension of the value vector. + d_model (int): Dimension :math:`D_m` of the input from previous model. + n_position (int): Length of the positional encoding vector. Must be + greater than ``max_seq_len``. + d_inner (int): Hidden dimension of feedforward layers. + dropout (float): Dropout rate. + init_cfg (dict or list[dict], optional): Initialization configs. + """ + + def __init__(self, + n_layers=12, + n_head=8, + d_k=64, + d_v=64, + d_model=512, + n_position=100, + d_inner=256, + dropout=0.1, + **kwargs): + super().__init__() + self.d_model = d_model + self.position_enc = Adaptive2DPositionalEncoding( + d_hid=d_model, + n_height=n_position, + n_width=n_position, + dropout=dropout) + self.layer_stack = nn.ModuleList([ + SatrnEncoderLayer( + d_model, d_inner, n_head, d_k, d_v, dropout=dropout) + for _ in range(n_layers) + ]) + self.layer_norm = nn.LayerNorm(d_model) + + def forward(self, feat): + """ + Args: + feat (Tensor): Feature tensor of shape :math:`(N, D_m, H, W)`. + + Returns: + Tensor: A tensor of shape :math:`(N, T, D_m)`. + """ + feat = feat + self.position_enc(feat) + n, c, h, w = feat.size() + mask = feat.new_zeros((n, h, w)) + mask[:,:,:w] = 1 + + mask = mask.view(n, h * w) + feat = feat.view(n, c, h * w) + + output = feat.permute(0, 2, 1).contiguous() + for enc_layer in self.layer_stack: + output = enc_layer(output, h, w, mask) + output = self.layer_norm(output) + + return output \ No newline at end of file diff --git a/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtr/sdsvtr/factory.py b/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtr/sdsvtr/factory.py new file mode 100644 index 0000000..773d5a0 --- /dev/null +++ b/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtr/sdsvtr/factory.py @@ -0,0 +1,57 @@ +import os +import shutil +import colorama +import hashlib + +def sha256sum(filename): + h = hashlib.sha256() + b = bytearray(128*1024) + mv = memoryview(b) + with open(filename, 'rb', buffering=0) as f: + for n in iter(lambda : f.readinto(mv), 0): + h.update(mv[:n]) + return h.hexdigest() + + +online_model_factory = { + 'satrn-lite-general-pretrain-20230106': { + 'url': 'https://github.com/moewiee/satrn-model-factory/raw/main/jxqhbem4to.pth', + 'hash': 'b0069a72bf6fc080ad5d431d5ce650c3bfbab535141adef1631fce331cb1471c'}, + 'satrn-lite-captcha-finetune-20230108': { + 'url': 'https://github.com/moewiee/satrn-model-factory/raw/main/l27vitogmc.pth', + 'hash': 'efcbcf2955b6b21125b073f83828d2719e908c7303b0d9901e94be5a8efba916'}, + 'satrn-lite-handwritten-finetune-20230108': { + 'url': 'https://github.com/moewiee/satrn-model-factory/raw/main/lj9gkwelns.pth', + 'hash': 'bccd8e985b131fcd4701114af5ceaef098f2eac50654bbb1d828e7f829e711dd'}, +} + +__hub_available_versions__ = online_model_factory.keys() + +def _get(version): + use_online = version in __hub_available_versions__ + + if not use_online and not os.path.exists(version): + raise ValueError(f'Model version {version} not found online and not found local.') + + hub_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'hub') + if not os.path.exists(hub_path): + os.makedirs(hub_path) + if use_online: + version_url = online_model_factory[version]['url'] + file_path = os.path.join(hub_path, os.path.basename(version_url)) + else: + file_path = os.path.join(hub_path, os.path.basename(version)) + + if not os.path.exists(file_path): + if use_online: + os.system(f'wget -O {file_path} {version_url}') + assert os.path.exists(file_path), \ + colorama.Fore.RED + 'wget failed while trying to retrieve from hub.' + colorama.Style.RESET_ALL + downloaded_hash = sha256sum(file_path) + if downloaded_hash != online_model_factory[version]['hash']: + os.remove(file_path) + raise ValueError(colorama.Fore.RED + 'sha256 hash doesnt match for version retrieved from hub.' + colorama.Style.RESET_ALL) + else: + shutil.copy2(version, file_path) + + return file_path \ No newline at end of file diff --git a/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtr/sdsvtr/fp16_utils.py b/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtr/sdsvtr/fp16_utils.py new file mode 100644 index 0000000..126ff02 --- /dev/null +++ b/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtr/sdsvtr/fp16_utils.py @@ -0,0 +1,78 @@ +import torch +import torch.nn as nn +import numpy as np +from collections import abc + + +def cast_tensor_type(inputs, src_type, dst_type): + """Recursively convert Tensor in inputs from src_type to dst_type. + + Args: + inputs: Inputs that to be casted. + src_type (torch.dtype): Source type.. + dst_type (torch.dtype): Destination type. + + Returns: + The same type with inputs, but all contained Tensors have been cast. + """ + if isinstance(inputs, nn.Module): + return inputs + elif isinstance(inputs, torch.Tensor): + return inputs.to(dst_type) + elif isinstance(inputs, str): + return inputs + elif isinstance(inputs, np.ndarray): + return inputs + elif isinstance(inputs, abc.Mapping): + return type(inputs)({ + k: cast_tensor_type(v, src_type, dst_type) + for k, v in inputs.items() + }) + elif isinstance(inputs, abc.Iterable): + return type(inputs)( + cast_tensor_type(item, src_type, dst_type) for item in inputs) + else: + return inputs + + +def patch_forward_method(func, src_type, dst_type, convert_output=True): + """Patch the forward method of a module. + + Args: + func (callable): The original forward method. + src_type (torch.dtype): Type of input arguments to be converted from. + dst_type (torch.dtype): Type of input arguments to be converted to. + convert_output (bool): Whether to convert the output back to src_type. + + Returns: + callable: The patched forward method. + """ + + def new_forward(*args, **kwargs): + output = func(*cast_tensor_type(args, src_type, dst_type), + **cast_tensor_type(kwargs, src_type, dst_type)) + if convert_output: + output = cast_tensor_type(output, dst_type, src_type) + return output + + return new_forward + + +def patch_norm_fp32(module): + """Recursively convert normalization layers from FP16 to FP32. + + Args: + module (nn.Module): The modules to be converted in FP16. + + Returns: + nn.Module: The converted module, the normalization layers have been + converted to FP32. + """ + if isinstance(module, (nn.modules.batchnorm._BatchNorm, nn.GroupNorm)): + module.float() + if isinstance(module, nn.GroupNorm) or torch.__version__ < '1.3': + module.forward = patch_forward_method(module.forward, torch.half, + torch.float) + for child in module.children(): + patch_norm_fp32(child) + return module \ No newline at end of file diff --git a/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtr/sdsvtr/transform.py b/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtr/sdsvtr/transform.py new file mode 100644 index 0000000..e366a4c --- /dev/null +++ b/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtr/sdsvtr/transform.py @@ -0,0 +1,33 @@ +import torchvision.transforms.functional as TF +import cv2 +import torch + +class DataPipelineSATRN: + def __init__(self, + resize_height, + resize_width, + norm_mean, + norm_std, + device='cpu'): + self.resize_height = resize_height + self.resize_width = resize_width + self.norm_mean = norm_mean + self.norm_std = norm_std + self.device = device + + def __call__(self, imgs): + if not isinstance(imgs, list): + imgs = [imgs] + datas = [] + for img in imgs: + if isinstance(img, str): + img = cv2.imread(img) + data = torch.from_numpy(cv2.resize(img, (self.resize_width, self.resize_height), interpolation=cv2.INTER_LINEAR)) + datas.append(data) + + data = torch.stack(datas, dim=0) + data = data.to(self.device) + data = data.float().div_(255.).permute((0,3,1,2)) + TF.normalize(data, mean=self.norm_mean, std=self.norm_std, inplace=True) + + return data.half() if self.device != 'cpu' else data \ No newline at end of file diff --git a/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtr/sdsvtr/version.py b/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtr/sdsvtr/version.py new file mode 100644 index 0000000..a55ccd2 --- /dev/null +++ b/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtr/sdsvtr/version.py @@ -0,0 +1 @@ +__version__ = '0.0.5' \ No newline at end of file diff --git a/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtr/setup.py b/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtr/setup.py new file mode 100644 index 0000000..4df1557 --- /dev/null +++ b/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtr/setup.py @@ -0,0 +1,187 @@ +import os +import os.path as osp +import shutil +import sys +import warnings +from setuptools import find_packages, setup + + +def readme(): + with open('README.md', encoding='utf-8') as f: + content = f.read() + return content + + +version_file = 'sdsvtr/version.py' +is_windows = sys.platform == 'win32' + + +def add_mim_extention(): + """Add extra files that are required to support MIM into the package. + + These files will be added by creating a symlink to the originals if the + package is installed in `editable` mode (e.g. pip install -e .), or by + copying from the originals otherwise. + """ + + # parse installment mode + if 'develop' in sys.argv: + # installed by `pip install -e .` + mode = 'symlink' + elif 'sdist' in sys.argv or 'bdist_wheel' in sys.argv: + # installed by `pip install .` + # or create source distribution by `python setup.py sdist` + mode = 'copy' + else: + return + + filenames = ['tools', 'configs', 'model-index.yml'] + repo_path = osp.dirname(__file__) + mim_path = osp.join(repo_path, 'mmocr', '.mim') + os.makedirs(mim_path, exist_ok=True) + + for filename in filenames: + if osp.exists(filename): + src_path = osp.join(repo_path, filename) + tar_path = osp.join(mim_path, filename) + + if osp.isfile(tar_path) or osp.islink(tar_path): + os.remove(tar_path) + elif osp.isdir(tar_path): + shutil.rmtree(tar_path) + + if mode == 'symlink': + src_relpath = osp.relpath(src_path, osp.dirname(tar_path)) + try: + os.symlink(src_relpath, tar_path) + except OSError: + # Creating a symbolic link on windows may raise an + # `OSError: [WinError 1314]` due to privilege. If + # the error happens, the src file will be copied + mode = 'copy' + warnings.warn( + f'Failed to create a symbolic link for {src_relpath}, ' + f'and it will be copied to {tar_path}') + else: + continue + + if mode == 'copy': + if osp.isfile(src_path): + shutil.copyfile(src_path, tar_path) + elif osp.isdir(src_path): + shutil.copytree(src_path, tar_path) + else: + warnings.warn(f'Cannot copy file {src_path}.') + else: + raise ValueError(f'Invalid mode {mode}') + + +def get_version(): + with open(version_file, 'r') as f: + exec(compile(f.read(), version_file, 'exec')) + import sys + + # return short version for sdist + if 'sdist' in sys.argv or 'bdist_wheel' in sys.argv: + return locals()['short_version'] + else: + return locals()['__version__'] + + +def parse_requirements(fname='requirements.txt', with_version=True): + """Parse the package dependencies listed in a requirements file but strip + specific version information. + + Args: + fname (str): Path to requirements file. + with_version (bool, default=False): If True, include version specs. + Returns: + info (list[str]): List of requirements items. + CommandLine: + python -c "import setup; print(setup.parse_requirements())" + """ + import re + import sys + from os.path import exists + require_fpath = fname + + def parse_line(line): + """Parse information from a line in a requirements text file.""" + if line.startswith('-r '): + # Allow specifying requirements in other files + target = line.split(' ')[1] + for info in parse_require_file(target): + yield info + else: + info = {'line': line} + if line.startswith('-e '): + info['package'] = line.split('#egg=')[1] + else: + # Remove versioning from the package + pat = '(' + '|'.join(['>=', '==', '>']) + ')' + parts = re.split(pat, line, maxsplit=1) + parts = [p.strip() for p in parts] + + info['package'] = parts[0] + if len(parts) > 1: + op, rest = parts[1:] + if ';' in rest: + # Handle platform specific dependencies + # http://setuptools.readthedocs.io/en/latest/setuptools.html#declaring-platform-specific-dependencies + version, platform_deps = map(str.strip, + rest.split(';')) + info['platform_deps'] = platform_deps + else: + version = rest # NOQA + info['version'] = (op, version) + yield info + + def parse_require_file(fpath): + with open(fpath, 'r') as f: + for line in f.readlines(): + line = line.strip() + if line and not line.startswith('#'): + for info in parse_line(line): + yield info + + def gen_packages_items(): + if exists(require_fpath): + for info in parse_require_file(require_fpath): + parts = [info['package']] + if with_version and 'version' in info: + parts.extend(info['version']) + if not sys.version.startswith('3.4'): + # apparently package_deps are broken in 3.4 + platform_deps = info.get('platform_deps') + if platform_deps is not None: + parts.append(';' + platform_deps) + item = ''.join(parts) + yield item + + packages = list(gen_packages_items()) + return packages + + +if __name__ == '__main__': + setup( + name='sdsvtr', + version=get_version(), + description='SDSV OCR Team Text Recognizer', + long_description=readme(), + long_description_content_type='text/markdown', + packages=find_packages(exclude=('configs', 'tools', 'demo')), + include_package_data=True, + url='https://github.com/open-mmlab/mmocr', + classifiers=[ + 'Development Status :: 4 - Beta', + 'License :: OSI Approved :: Apache Software License', + 'Operating System :: OS Independent', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', + 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', + ], + license='Apache License 2.0', + install_requires=parse_requirements('requirements.txt'), + zip_safe=False) diff --git a/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtr/test.py b/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtr/test.py new file mode 100644 index 0000000..b929e7e --- /dev/null +++ b/cope2n-ai-fi/modules/ocr_engine/externals/sdsvtr/test.py @@ -0,0 +1,12 @@ +import numpy as np +from sdsvtr import StandaloneSATRNRunner +runner = StandaloneSATRNRunner(version='satrn-lite-general-pretrain-20230106', return_confident=False, device='cuda:1') + +dummy_list = [np.ndarray((32,128,3)) for _ in range(100)] +bs = 32 + +all_results = [] +while len(dummy_list) > 0: + dummy_batch = dummy_list[:bs] + dummy_list = dummy_list[bs:] + all_results += runner(dummy_batch) \ No newline at end of file From 2cd04d829696f9e7638c8a1c4d90f514ea4677b7 Mon Sep 17 00:00:00 2001 From: dx-tan Date: Tue, 12 Dec 2023 12:16:08 +0700 Subject: [PATCH 2/2] Add: Migration --- .gitignore | 2 +- cope2n-api/fwd_api/migrations/0001_initial.py | 118 ++++++++++++++++++ ...estfile_code_userprofile_email_and_more.py | 28 +++++ ...0003_alter_subscriptionrequestfile_code.py | 18 +++ ...0004_alter_subscriptionrequestfile_code.py | 18 +++ ...0005_alter_subscriptionrequestfile_code.py | 18 +++ ...0006_alter_subscriptionrequestfile_code.py | 18 +++ ...0007_alter_subscriptionrequestfile_code.py | 18 +++ ...0008_alter_subscriptionrequestfile_code.py | 18 +++ ...0009_alter_subscriptionrequestfile_code.py | 18 +++ ...0010_alter_subscriptionrequestfile_code.py | 18 +++ ...0011_alter_subscriptionrequestfile_code.py | 18 +++ ...0012_alter_subscriptionrequestfile_code.py | 18 +++ ...0013_alter_subscriptionrequestfile_code.py | 18 +++ ...0014_alter_subscriptionrequestfile_code.py | 18 +++ ...0015_alter_subscriptionrequestfile_code.py | 18 +++ ...0016_alter_subscriptionrequestfile_code.py | 18 +++ ...0017_alter_subscriptionrequestfile_code.py | 18 +++ ...0018_alter_subscriptionrequestfile_code.py | 18 +++ ...0019_alter_subscriptionrequestfile_code.py | 18 +++ ...0020_alter_subscriptionrequestfile_code.py | 18 +++ ...0021_alter_subscriptionrequestfile_code.py | 18 +++ ...0022_alter_subscriptionrequestfile_code.py | 18 +++ ...0023_alter_subscriptionrequestfile_code.py | 18 +++ ...0024_alter_subscriptionrequestfile_code.py | 18 +++ ...0025_alter_subscriptionrequestfile_code.py | 18 +++ ...0026_alter_subscriptionrequestfile_code.py | 18 +++ ...0027_alter_subscriptionrequestfile_code.py | 18 +++ ...0028_alter_subscriptionrequestfile_code.py | 18 +++ ...0029_alter_subscriptionrequestfile_code.py | 18 +++ ...0030_alter_subscriptionrequestfile_code.py | 18 +++ ...0031_alter_subscriptionrequestfile_code.py | 18 +++ ...0032_alter_subscriptionrequestfile_code.py | 18 +++ ...0033_alter_subscriptionrequestfile_code.py | 18 +++ ...0034_alter_subscriptionrequestfile_code.py | 18 +++ ...0035_alter_subscriptionrequestfile_code.py | 18 +++ ...0036_alter_subscriptionrequestfile_code.py | 18 +++ ...0037_alter_subscriptionrequestfile_code.py | 18 +++ ...0038_alter_subscriptionrequestfile_code.py | 18 +++ ...0039_alter_subscriptionrequestfile_code.py | 18 +++ ...0040_alter_subscriptionrequestfile_code.py | 18 +++ ...0041_alter_subscriptionrequestfile_code.py | 18 +++ ...0042_alter_subscriptionrequestfile_code.py | 18 +++ ...0043_alter_subscriptionrequestfile_code.py | 18 +++ ...0044_alter_subscriptionrequestfile_code.py | 18 +++ ...0045_alter_subscriptionrequestfile_code.py | 18 +++ ...0046_alter_subscriptionrequestfile_code.py | 18 +++ ...0047_alter_subscriptionrequestfile_code.py | 18 +++ ...0048_alter_subscriptionrequestfile_code.py | 18 +++ ...0049_alter_subscriptionrequestfile_code.py | 18 +++ ...0050_alter_subscriptionrequestfile_code.py | 18 +++ ...0051_alter_subscriptionrequestfile_code.py | 18 +++ ...0052_alter_subscriptionrequestfile_code.py | 18 +++ ...0053_alter_subscriptionrequestfile_code.py | 18 +++ ...0054_alter_subscriptionrequestfile_code.py | 18 +++ ...0055_alter_subscriptionrequestfile_code.py | 18 +++ ...0056_alter_subscriptionrequestfile_code.py | 18 +++ ...0057_alter_subscriptionrequestfile_code.py | 18 +++ ...0058_alter_subscriptionrequestfile_code.py | 18 +++ ...0059_alter_subscriptionrequestfile_code.py | 18 +++ ...0060_alter_subscriptionrequestfile_code.py | 18 +++ ...0061_alter_subscriptionrequestfile_code.py | 18 +++ ...0062_alter_subscriptionrequestfile_code.py | 18 +++ ...0063_alter_subscriptionrequestfile_code.py | 18 +++ ...0064_alter_subscriptionrequestfile_code.py | 18 +++ ...0065_alter_subscriptionrequestfile_code.py | 18 +++ ...0066_alter_subscriptionrequestfile_code.py | 18 +++ ...0067_alter_subscriptionrequestfile_code.py | 18 +++ ...0068_alter_subscriptionrequestfile_code.py | 18 +++ ...0069_alter_subscriptionrequestfile_code.py | 18 +++ ...0070_alter_subscriptionrequestfile_code.py | 18 +++ ...0071_alter_subscriptionrequestfile_code.py | 18 +++ ...0072_alter_subscriptionrequestfile_code.py | 18 +++ ...0073_alter_subscriptionrequestfile_code.py | 18 +++ ...0074_alter_subscriptionrequestfile_code.py | 18 +++ ...0075_alter_subscriptionrequestfile_code.py | 18 +++ ...0076_alter_subscriptionrequestfile_code.py | 18 +++ ...0077_alter_subscriptionrequestfile_code.py | 18 +++ ...0078_alter_subscriptionrequestfile_code.py | 18 +++ ...0079_alter_subscriptionrequestfile_code.py | 18 +++ ...0080_alter_subscriptionrequestfile_code.py | 18 +++ ...0081_alter_subscriptionrequestfile_code.py | 18 +++ ...0082_alter_subscriptionrequestfile_code.py | 18 +++ ...0083_alter_subscriptionrequestfile_code.py | 18 +++ ...0084_alter_subscriptionrequestfile_code.py | 18 +++ ...0085_alter_subscriptionrequestfile_code.py | 18 +++ ...0086_alter_subscriptionrequestfile_code.py | 18 +++ ...0087_alter_subscriptionrequestfile_code.py | 18 +++ ...0088_alter_subscriptionrequestfile_code.py | 18 +++ ...0089_alter_subscriptionrequestfile_code.py | 18 +++ ...0090_alter_subscriptionrequestfile_code.py | 18 +++ ...0091_alter_subscriptionrequestfile_code.py | 18 +++ ...0092_alter_subscriptionrequestfile_code.py | 18 +++ ...0093_alter_subscriptionrequestfile_code.py | 18 +++ ...0094_alter_subscriptionrequestfile_code.py | 18 +++ ...0095_alter_subscriptionrequestfile_code.py | 18 +++ ...0096_alter_subscriptionrequestfile_code.py | 18 +++ ...0097_alter_subscriptionrequestfile_code.py | 18 +++ ...0098_alter_subscriptionrequestfile_code.py | 18 +++ ...0099_alter_subscriptionrequestfile_code.py | 18 +++ ...0100_alter_subscriptionrequestfile_code.py | 18 +++ ...0101_alter_subscriptionrequestfile_code.py | 18 +++ ...0102_alter_subscriptionrequestfile_code.py | 18 +++ ...0103_alter_subscriptionrequestfile_code.py | 18 +++ ...0104_alter_subscriptionrequestfile_code.py | 18 +++ ...0105_alter_subscriptionrequestfile_code.py | 18 +++ ...0106_alter_subscriptionrequestfile_code.py | 18 +++ ...0107_alter_subscriptionrequestfile_code.py | 18 +++ ...password_userprofile_user_name_and_more.py | 38 ++++++ ...0109_alter_subscriptionrequestfile_code.py | 18 +++ ...0110_alter_subscriptionrequestfile_code.py | 18 +++ ...0111_alter_subscriptionrequestfile_code.py | 18 +++ ...0112_alter_subscriptionrequestfile_code.py | 18 +++ ...0113_alter_subscriptionrequestfile_code.py | 18 +++ ...0114_alter_subscriptionrequestfile_code.py | 18 +++ ...0115_alter_subscriptionrequestfile_code.py | 18 +++ ...0116_alter_subscriptionrequestfile_code.py | 18 +++ ...0117_alter_subscriptionrequestfile_code.py | 18 +++ ...0118_alter_subscriptionrequestfile_code.py | 18 +++ ...0119_alter_subscriptionrequestfile_code.py | 18 +++ ...0120_alter_subscriptionrequestfile_code.py | 18 +++ ...0121_alter_subscriptionrequestfile_code.py | 18 +++ ...0122_alter_subscriptionrequestfile_code.py | 18 +++ ...0123_alter_subscriptionrequestfile_code.py | 18 +++ ...0124_alter_subscriptionrequestfile_code.py | 18 +++ ...0125_alter_subscriptionrequestfile_code.py | 18 +++ ...0126_alter_subscriptionrequestfile_code.py | 18 +++ ...0127_alter_subscriptionrequestfile_code.py | 18 +++ ...0128_alter_subscriptionrequestfile_code.py | 18 +++ ...0129_alter_subscriptionrequestfile_code.py | 18 +++ ...0130_alter_subscriptionrequestfile_code.py | 18 +++ ...0131_alter_subscriptionrequestfile_code.py | 18 +++ ...0132_alter_subscriptionrequestfile_code.py | 18 +++ ...0133_alter_subscriptionrequestfile_code.py | 18 +++ ...0134_alter_subscriptionrequestfile_code.py | 18 +++ ...0135_alter_subscriptionrequestfile_code.py | 18 +++ ...0136_alter_subscriptionrequestfile_code.py | 18 +++ ...0137_alter_subscriptionrequestfile_code.py | 18 +++ ...0138_alter_subscriptionrequestfile_code.py | 18 +++ ...0139_alter_subscriptionrequestfile_code.py | 18 +++ ...0140_alter_subscriptionrequestfile_code.py | 18 +++ ...0141_alter_subscriptionrequestfile_code.py | 18 +++ ...0142_alter_subscriptionrequestfile_code.py | 18 +++ ...0143_alter_subscriptionrequestfile_code.py | 18 +++ ...0144_alter_subscriptionrequestfile_code.py | 18 +++ ...0145_alter_subscriptionrequestfile_code.py | 18 +++ ...subscriptionrequest_pages_left_and_more.py | 23 ++++ ...0147_alter_subscriptionrequestfile_code.py | 18 +++ ...0148_alter_subscriptionrequestfile_code.py | 18 +++ ...0149_alter_subscriptionrequestfile_code.py | 18 +++ ...riptionrequest_feedback_result_and_more.py | 23 ++++ ...0151_alter_subscriptionrequestfile_code.py | 18 +++ ...0152_alter_subscriptionrequestfile_code.py | 18 +++ ...0153_alter_subscriptionrequestfile_code.py | 18 +++ ...0154_alter_subscriptionrequestfile_code.py | 18 +++ ...0155_alter_subscriptionrequestfile_code.py | 18 +++ cope2n-api/fwd_api/migrations/__init__.py | 0 157 files changed, 2931 insertions(+), 1 deletion(-) create mode 100755 cope2n-api/fwd_api/migrations/0001_initial.py create mode 100755 cope2n-api/fwd_api/migrations/0002_subscriptionrequestfile_code_userprofile_email_and_more.py create mode 100755 cope2n-api/fwd_api/migrations/0003_alter_subscriptionrequestfile_code.py create mode 100755 cope2n-api/fwd_api/migrations/0004_alter_subscriptionrequestfile_code.py create mode 100755 cope2n-api/fwd_api/migrations/0005_alter_subscriptionrequestfile_code.py create mode 100755 cope2n-api/fwd_api/migrations/0006_alter_subscriptionrequestfile_code.py create mode 100755 cope2n-api/fwd_api/migrations/0007_alter_subscriptionrequestfile_code.py create mode 100755 cope2n-api/fwd_api/migrations/0008_alter_subscriptionrequestfile_code.py create mode 100755 cope2n-api/fwd_api/migrations/0009_alter_subscriptionrequestfile_code.py create mode 100755 cope2n-api/fwd_api/migrations/0010_alter_subscriptionrequestfile_code.py create mode 100755 cope2n-api/fwd_api/migrations/0011_alter_subscriptionrequestfile_code.py create mode 100755 cope2n-api/fwd_api/migrations/0012_alter_subscriptionrequestfile_code.py create mode 100755 cope2n-api/fwd_api/migrations/0013_alter_subscriptionrequestfile_code.py create mode 100755 cope2n-api/fwd_api/migrations/0014_alter_subscriptionrequestfile_code.py create mode 100755 cope2n-api/fwd_api/migrations/0015_alter_subscriptionrequestfile_code.py create mode 100755 cope2n-api/fwd_api/migrations/0016_alter_subscriptionrequestfile_code.py create mode 100755 cope2n-api/fwd_api/migrations/0017_alter_subscriptionrequestfile_code.py create mode 100755 cope2n-api/fwd_api/migrations/0018_alter_subscriptionrequestfile_code.py create mode 100755 cope2n-api/fwd_api/migrations/0019_alter_subscriptionrequestfile_code.py create mode 100755 cope2n-api/fwd_api/migrations/0020_alter_subscriptionrequestfile_code.py create mode 100755 cope2n-api/fwd_api/migrations/0021_alter_subscriptionrequestfile_code.py create mode 100755 cope2n-api/fwd_api/migrations/0022_alter_subscriptionrequestfile_code.py create mode 100755 cope2n-api/fwd_api/migrations/0023_alter_subscriptionrequestfile_code.py create mode 100755 cope2n-api/fwd_api/migrations/0024_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0025_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0026_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0027_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0028_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0029_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0030_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0031_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0032_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0033_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0034_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0035_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0036_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0037_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0038_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0039_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0040_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0041_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0042_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0043_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0044_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0045_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0046_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0047_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0048_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0049_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0050_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0051_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0052_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0053_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0054_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0055_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0056_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0057_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0058_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0059_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0060_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0061_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0062_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0063_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0064_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0065_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0066_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0067_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0068_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0069_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0070_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0071_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0072_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0073_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0074_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0075_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0076_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0077_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0078_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0079_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0080_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0081_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0082_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0083_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0084_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0085_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0086_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0087_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0088_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0089_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0090_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0091_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0092_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0093_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0094_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0095_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0096_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0097_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0098_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0099_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0100_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0101_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0102_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0103_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0104_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0105_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0106_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0107_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0108_userprofile_password_userprofile_user_name_and_more.py create mode 100644 cope2n-api/fwd_api/migrations/0109_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0110_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0111_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0112_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0113_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0114_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0115_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0116_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0117_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0118_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0119_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0120_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0121_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0122_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0123_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0124_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0125_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0126_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0127_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0128_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0129_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0130_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0131_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0132_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0133_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0134_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0135_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0136_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0137_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0138_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0139_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0140_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0141_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0142_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0143_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0144_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0145_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0146_subscriptionrequest_pages_left_and_more.py create mode 100644 cope2n-api/fwd_api/migrations/0147_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0148_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0149_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0150_subscriptionrequest_feedback_result_and_more.py create mode 100644 cope2n-api/fwd_api/migrations/0151_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0152_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0153_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0154_alter_subscriptionrequestfile_code.py create mode 100644 cope2n-api/fwd_api/migrations/0155_alter_subscriptionrequestfile_code.py create mode 100755 cope2n-api/fwd_api/migrations/__init__.py diff --git a/.gitignore b/.gitignore index b86e5ac..5632a31 100644 --- a/.gitignore +++ b/.gitignore @@ -11,7 +11,7 @@ backup/ *.sqlite3 *.log __pycache__ -migrations/ +# migrations/ test/ ._git/ sdsvkvu_/ diff --git a/cope2n-api/fwd_api/migrations/0001_initial.py b/cope2n-api/fwd_api/migrations/0001_initial.py new file mode 100755 index 0000000..ffc06ac --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0001_initial.py @@ -0,0 +1,118 @@ +# Generated by Django 4.1.3 on 2023-04-05 07:19 + +from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone +import fwd_api.models.fields.EncryptedCharField + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='OcrTemplate', + fields=[ + ('id', models.AutoField(primary_key=True, serialize=False)), + ('name', models.CharField(max_length=300)), + ('status', models.IntegerField()), + ('file_path', fwd_api.models.fields.EncryptedCharField.EncryptedCharField(max_length=500, null=True)), + ('file_name', fwd_api.models.fields.EncryptedCharField.EncryptedCharField(max_length=500, null=True)), + ('created_at', models.DateTimeField(default=django.utils.timezone.now)), + ('updated_at', models.DateTimeField(auto_now=True)), + ], + ), + migrations.CreateModel( + name='PricingPlan', + fields=[ + ('id', models.AutoField(primary_key=True, serialize=False)), + ('code', models.CharField(max_length=300)), + ('token_limitations', models.IntegerField(default=0)), + ('duration', models.IntegerField(default=0)), + ('created_at', models.DateTimeField(default=django.utils.timezone.now)), + ('updated_at', models.DateTimeField(auto_now=True)), + ], + ), + migrations.CreateModel( + name='Subscription', + fields=[ + ('id', models.AutoField(primary_key=True, serialize=False)), + ('current_token', models.IntegerField(default=0)), + ('limit_token', models.IntegerField(default=0)), + ('status', models.IntegerField(default=0)), + ('start_at', models.DateTimeField(default=django.utils.timezone.now)), + ('expired_at', models.DateTimeField(default=django.utils.timezone.now)), + ('created_at', models.DateTimeField(default=django.utils.timezone.now)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('pricing_plan', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='fwd_api.pricingplan')), + ], + ), + migrations.CreateModel( + name='SubscriptionRequest', + fields=[ + ('id', models.AutoField(primary_key=True, serialize=False)), + ('pages', models.IntegerField()), + ('doc_type', models.CharField(max_length=100)), + ('request_id', models.CharField(max_length=200)), + ('process_type', models.CharField(max_length=200)), + ('provider_code', models.CharField(default='Guest', max_length=200)), + ('predict_result', models.JSONField(null=True)), + ('status', models.IntegerField()), + ('created_at', models.DateTimeField(default=django.utils.timezone.now)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('subscription', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='fwd_api.subscription')), + ], + ), + migrations.CreateModel( + name='UserProfile', + fields=[ + ('id', models.AutoField(primary_key=True, serialize=False)), + ('full_name', models.CharField(max_length=100)), + ('sync_id', models.CharField(max_length=100)), + ('provider_id', models.CharField(default='Ctel', max_length=100)), + ('current_total_pages', models.IntegerField(default=0)), + ('limit_total_pages', models.IntegerField(default=0)), + ('status', models.IntegerField(default=0)), + ('created_at', models.DateTimeField(default=django.utils.timezone.now)), + ('updated_at', models.DateTimeField(auto_now=True)), + ], + ), + migrations.CreateModel( + name='SubscriptionRequestFile', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('file_name', models.CharField(default=None, max_length=300)), + ('file_path', fwd_api.models.fields.EncryptedCharField.EncryptedCharField(default=None, max_length=500)), + ('file_category', models.CharField(default='Origin', max_length=200)), + ('created_at', models.DateTimeField(default=django.utils.timezone.now)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('request', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='files', to='fwd_api.subscriptionrequest')), + ], + ), + migrations.AddField( + model_name='subscription', + name='user', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='fwd_api.userprofile'), + ), + migrations.CreateModel( + name='OcrTemplateBox', + fields=[ + ('id', models.AutoField(primary_key=True, serialize=False)), + ('name', models.CharField(max_length=300, null=True)), + ('type', models.CharField(max_length=100)), + ('coordinates', models.CharField(max_length=200)), + ('created_at', models.DateTimeField(default=django.utils.timezone.now)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('template', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='fwd_api.ocrtemplate')), + ], + ), + migrations.AddField( + model_name='ocrtemplate', + name='subscription', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='fwd_api.subscription'), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0002_subscriptionrequestfile_code_userprofile_email_and_more.py b/cope2n-api/fwd_api/migrations/0002_subscriptionrequestfile_code_userprofile_email_and_more.py new file mode 100755 index 0000000..dbcc866 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0002_subscriptionrequestfile_code_userprofile_email_and_more.py @@ -0,0 +1,28 @@ +# Generated by Django 4.1.3 on 2023-10-13 08:10 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL6ad3c98077bf4f9d80514d73219f24d1', max_length=300), + ), + migrations.AddField( + model_name='userprofile', + name='email', + field=models.CharField(max_length=200, null=True), + ), + migrations.AlterField( + model_name='userprofile', + name='full_name', + field=models.CharField(max_length=200), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0003_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0003_alter_subscriptionrequestfile_code.py new file mode 100755 index 0000000..d82b099 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0003_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-10-13 08:16 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0002_subscriptionrequestfile_code_userprofile_email_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL6cdfa631c89d41adb8263d8520732ea6', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0004_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0004_alter_subscriptionrequestfile_code.py new file mode 100755 index 0000000..1b0cd90 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0004_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-10-13 08:17 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0003_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FILa095ae5ffa3f490bab474c4f2e66a1ba', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0005_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0005_alter_subscriptionrequestfile_code.py new file mode 100755 index 0000000..b101190 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0005_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-10-13 08:26 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0004_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL80569683e66148cd8aaa53a5ff622615', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0006_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0006_alter_subscriptionrequestfile_code.py new file mode 100755 index 0000000..e423d75 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0006_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-10-13 08:27 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0005_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL4a84b7636cfe4db39cd10fbd5a77c085', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0007_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0007_alter_subscriptionrequestfile_code.py new file mode 100755 index 0000000..b390d99 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0007_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-10-13 08:28 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0006_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL45b8e408ff1c4e9e8794b77e78437699', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0008_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0008_alter_subscriptionrequestfile_code.py new file mode 100755 index 0000000..7e98cd2 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0008_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-10-13 08:30 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0007_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL7a628e80e45e4c3ea09c5b90054045aa', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0009_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0009_alter_subscriptionrequestfile_code.py new file mode 100755 index 0000000..56b1a6a --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0009_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-10-13 08:34 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0008_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FILa7745c2091c84eb29b57e5344bf6cb31', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0010_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0010_alter_subscriptionrequestfile_code.py new file mode 100755 index 0000000..161cd4a --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0010_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-10-13 08:44 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0009_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FILaff0fce70fb04779825ba49b86a65ed3', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0011_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0011_alter_subscriptionrequestfile_code.py new file mode 100755 index 0000000..1ef760a --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0011_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-10-13 08:49 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0010_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL945a1575172d45f0a680ddc178798575', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0012_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0012_alter_subscriptionrequestfile_code.py new file mode 100755 index 0000000..83bf016 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0012_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-10-13 09:03 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0011_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FILf7d18096cb3746dda5e943f06130591a', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0013_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0013_alter_subscriptionrequestfile_code.py new file mode 100755 index 0000000..aaa4c49 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0013_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-10-13 09:05 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0012_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FILa1b36d470eb74a0cb49abc006b7a45d4', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0014_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0014_alter_subscriptionrequestfile_code.py new file mode 100755 index 0000000..323ac03 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0014_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-10-13 09:09 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0013_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FILd7e2686ad2294812b8e39028dbad95d0', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0015_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0015_alter_subscriptionrequestfile_code.py new file mode 100755 index 0000000..2c50fab --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0015_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-10-13 09:54 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0014_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FILc8d66f9a9820478dbeff39a7f1bdaae7', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0016_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0016_alter_subscriptionrequestfile_code.py new file mode 100755 index 0000000..d8145a6 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0016_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-10-13 10:12 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0015_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FILfe1b5576bb7f4b1ebbc9eff4444048f3', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0017_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0017_alter_subscriptionrequestfile_code.py new file mode 100755 index 0000000..26fc89e --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0017_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-10-13 12:30 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0016_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FILca899ac19c814b5e8abb6fd739950b48', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0018_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0018_alter_subscriptionrequestfile_code.py new file mode 100755 index 0000000..2355e6b --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0018_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-10-16 06:01 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0017_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL679f7b306fa041518d362290db1109ad', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0019_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0019_alter_subscriptionrequestfile_code.py new file mode 100755 index 0000000..8133e53 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0019_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-10-16 07:26 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0018_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL9125f3f02a994758b5819d635cf354ed', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0020_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0020_alter_subscriptionrequestfile_code.py new file mode 100755 index 0000000..492c25c --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0020_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-10-16 07:26 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0019_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL0ce5f73923cc4eab9a66adadf874354c', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0021_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0021_alter_subscriptionrequestfile_code.py new file mode 100755 index 0000000..feeba28 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0021_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-10-16 07:55 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0020_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FILcb3b1cfd6a174caea4a45395435e8264', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0022_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0022_alter_subscriptionrequestfile_code.py new file mode 100755 index 0000000..1a2554d --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0022_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-10-16 08:48 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0021_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL4c38a62d96994bf09e5a1730ecfaf10e', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0023_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0023_alter_subscriptionrequestfile_code.py new file mode 100755 index 0000000..d8cb904 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0023_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-10-18 06:23 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0022_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL8d7d194cce344b7da23466f277c68184', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0024_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0024_alter_subscriptionrequestfile_code.py new file mode 100755 index 0000000..ba2ca2f --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0024_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-10-27 03:22 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0023_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FILbdffc84dde6b497c9c450c78b0640a0f', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0025_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0025_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..27d39f0 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0025_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-11-27 10:59 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0024_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL5b6b2a5176e749edae3be7cac245ea3e', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0026_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0026_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..58acef8 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0026_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-11-27 11:03 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0025_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL7d56336dcec347c79da7feec7d802687', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0027_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0027_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..ccc8ec1 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0027_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-11-27 12:22 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0026_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FILc2a2a162611142f9888fe60df3930fb4', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0028_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0028_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..b10418e --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0028_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-11-27 12:26 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0027_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL7a6dc0368a9d42cc872dc86a115ce956', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0029_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0029_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..bd76a0b --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0029_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-11-27 12:27 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0028_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL48b3c5102d7e4d109963edd70293524b', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0030_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0030_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..6102616 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0030_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-11-27 12:29 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0029_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FILbf88633ff774438cb6c75663b578851f', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0031_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0031_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..ccc64ec --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0031_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-11-27 12:34 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0030_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL31b8cc93916948b589117c19fa2c62f1', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0032_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0032_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..e4b91f8 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0032_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-11-27 12:36 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0031_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FILa8037c1a968f4922ae5ddd5904989745', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0033_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0033_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..acf61d0 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0033_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-11-27 12:41 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0032_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL99554e8c9ac04e4cb710b0d3f5ca7962', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0034_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0034_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..21d0559 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0034_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-11-27 12:45 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0033_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FILa03caec1116644b8ac3363c4ff86ae84', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0035_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0035_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..3bb276a --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0035_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-11-27 12:47 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0034_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL95116a6c7072422f8b85d6e627bb25b6', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0036_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0036_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..e2d7ead --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0036_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-11-27 12:47 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0035_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL3cd55c695d634d8c8b0f9b174c5aa5c0', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0037_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0037_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..bc2767c --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0037_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-11-27 12:48 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0036_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL48af5750e75c44aba1c37b7db81c301d', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0038_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0038_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..4b92446 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0038_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-11-27 12:52 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0037_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FILb91182363733468fb097a90e858d8fd4', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0039_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0039_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..777ef61 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0039_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-11-27 13:09 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0038_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FILed00caacc0594739a7303d0017940d3f', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0040_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0040_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..3e12aa3 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0040_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-11-27 13:10 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0039_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FILa4a846ce46c744bb9a20a35d98cc98c7', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0041_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0041_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..e2fd718 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0041_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-11-27 13:25 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0040_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL614361b87041476aa7983dded361341a', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0042_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0042_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..e8ef09f --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0042_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-11-28 03:49 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0041_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FILd6755b95d03c499792041b55a64d5a9f', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0043_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0043_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..3e8cc92 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0043_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-11-28 08:52 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0042_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL2ff8a87566434d23b50baa82d0993483', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0044_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0044_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..0dd5630 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0044_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-11-28 09:24 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0043_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL457d126686c34c4bb200cb576c5fd31c', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0045_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0045_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..7352a28 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0045_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-11-28 09:35 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0044_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL990106372b0b456e9d936e3bc170cfb4', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0046_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0046_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..f75b8ec --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0046_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-11-28 09:37 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0045_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL8df31dbe1bfd402eb976a67919244f51', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0047_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0047_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..f464f45 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0047_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-11-28 09:38 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0046_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL6bb95d8fb2f14757a4365058e7aab84c', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0048_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0048_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..70548c2 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0048_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-11-28 09:42 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0047_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL6910cd1cff1849ee91109298cfee2fb0', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0049_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0049_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..f25b20c --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0049_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-11-28 09:42 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0048_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FILd6b0d80a5bf94f87aeea803cf77a1d81', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0050_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0050_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..2ef70fc --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0050_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-11-28 09:53 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0049_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL359fb138f4434fa1860f6927badb4a3c', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0051_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0051_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..0ede129 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0051_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-11-28 09:57 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0050_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FILee6ab5a3296345ca8d42bde2f523e852', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0052_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0052_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..712cbb3 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0052_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-11-28 10:02 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0051_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL622353d9d8d1492d8bd77f150e02aabf', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0053_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0053_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..1892c2b --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0053_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-11-28 10:03 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0052_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL20bddf9dd2694e56adb2f4160d9254ee', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0054_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0054_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..07e67f6 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0054_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-11-28 10:03 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0053_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FILbba8d19152024d01bb26063ca26f57ef', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0055_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0055_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..b5aa1d0 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0055_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-11-28 10:05 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0054_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL619b04fdcd9a44ed987a72a282cc4ca3', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0056_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0056_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..a12983c --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0056_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-11-28 10:08 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0055_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FILa86df077a1734c289e04b2c56afa33fe', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0057_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0057_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..6ce2b02 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0057_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-11-28 12:21 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0056_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL996c470fedc64ad4825798642d687092', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0058_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0058_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..4110991 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0058_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-11-28 12:28 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0057_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL3eb614edc9284d7892c890ee5ebffce5', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0059_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0059_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..b439363 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0059_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-11-28 12:29 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0058_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL51bbc6937ddf4dea93a8ab57d3e04411', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0060_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0060_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..c1191d1 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0060_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-11-28 12:30 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0059_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FILe8ad9caeca4a4f86a23673cc8d00ee65', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0061_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0061_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..1de7453 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0061_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-11-28 12:33 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0060_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL63c7091d586d4acea449985045a5bba9', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0062_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0062_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..3c780e9 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0062_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-11-28 12:34 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0061_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL95df4ac68d194c86ba7aed53940f083a', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0063_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0063_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..c582235 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0063_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-11-28 12:35 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0062_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FILf41f2b04385845258b40ba4296aebafc', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0064_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0064_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..a21fe4f --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0064_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-11-28 12:37 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0063_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL8e126a8613ab4346acb968121ba10465', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0065_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0065_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..52952e8 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0065_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-11-29 07:11 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0064_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL14de2e7b97194afa97a7825143af8aee', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0066_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0066_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..8989972 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0066_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-11-29 07:56 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0065_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FILa34ea0946b9f45ac81c9a27baeeb0dec', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0067_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0067_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..ee2b01c --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0067_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-11-29 07:57 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0066_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL2ced0a615954429ebcaeae17911523ae', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0068_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0068_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..54b3923 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0068_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-11-29 08:53 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0067_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL03d3ec8941754434a0fce2506b2a5097', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0069_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0069_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..08abce1 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0069_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-11-29 08:55 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0068_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL261f6c33dc94443b9f2f7797ab755c1b', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0070_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0070_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..5348c8a --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0070_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-11-29 10:23 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0069_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FILc09522b1b1fb48bbb0ff09a626edb460', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0071_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0071_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..3afd37c --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0071_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-11-29 10:46 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0070_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL5c818cfff0c34ebb80c8f1f4f109f6d4', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0072_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0072_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..a74bc7c --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0072_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-11-29 10:49 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0071_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL481bbc026dc2478bad9aef691170be7f', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0073_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0073_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..6bc7e44 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0073_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-11-29 11:33 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0072_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FILd25879a8398b4c2a91957b7591e5293f', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0074_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0074_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..696846c --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0074_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-11-29 12:07 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0073_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL70de352c3c444e2cb59549332a80804c', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0075_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0075_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..e3e1935 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0075_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-11-29 12:09 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0074_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL5e75dfbb5408410d84a8a2ecc7075e76', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0076_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0076_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..d5c297e --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0076_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-11-29 12:11 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0075_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL6723b091b4ef458381a0776f01dac2ed', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0077_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0077_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..1cd6dc5 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0077_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-11-29 12:18 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0076_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL9374d86d354c40ef9e092c8de167dee9', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0078_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0078_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..c5f7f84 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0078_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-11-29 12:20 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0077_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FILad784dc904fc4887bf3faafc5776efce', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0079_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0079_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..2e591fe --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0079_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-11-30 03:36 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0078_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FILaf78241d30e14c82a0bfbe3942fb7a94', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0080_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0080_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..f782c98 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0080_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-11-30 10:18 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0079_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL2d6ff88bb7b84bfdb5f58a09784b3456', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0081_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0081_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..1f1f471 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0081_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-12-04 05:52 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0080_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FILe5fdb986f1d94881bcc6e7a1db9941ab', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0082_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0082_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..4d6a845 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0082_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-12-04 05:54 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0081_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL8103f9693bff43d49861f3a2936a9a99', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0083_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0083_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..a3f2dfe --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0083_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-12-04 06:09 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0082_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FILd8c5b8b919a34af39e695daa2de3066f', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0084_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0084_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..66d9970 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0084_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-12-04 06:10 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0083_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL1c830421f0e54ced8d15c57c3c173722', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0085_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0085_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..2b5328f --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0085_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-12-04 06:18 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0084_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FILa9efee200d3043c384a3afb21752c227', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0086_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0086_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..2f63523 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0086_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-12-04 06:25 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0085_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL336fdc9bf94845eab5b05a6f4b5b3e17', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0087_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0087_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..9caf63f --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0087_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-12-04 06:26 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0086_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL833cbc10c9244f76a0fe222df20ef9c5', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0088_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0088_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..989568b --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0088_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-12-04 06:53 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0087_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FILb4c7005e670d4a9b9224726a1a87db82', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0089_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0089_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..0c499f5 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0089_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-12-04 06:54 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0088_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FILbad444b587b34111a6f9e2e213de139c', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0090_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0090_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..7c61fc9 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0090_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-12-04 06:55 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0089_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FILf72053106c574c8788aee534a60b2b45', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0091_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0091_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..90f946f --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0091_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-12-04 06:57 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0090_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FILa824aca123bc4fe08d209fc212ef81b2', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0092_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0092_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..f3a7468 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0092_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-12-04 06:58 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0091_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL059f4a07f6434890a23bb62061bc70fc', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0093_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0093_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..ec96403 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0093_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-12-04 08:08 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0092_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL94831c61e579461989dc21cc8d9682e7', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0094_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0094_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..58eabfd --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0094_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-12-04 08:11 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0093_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FILaad5748718204676bbf12642bd7d0c69', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0095_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0095_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..c1cb9b8 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0095_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-12-04 08:27 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0094_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL4d40f42a977c4ef7a525d3441eff0efa', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0096_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0096_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..93e7aa1 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0096_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-12-04 08:37 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0095_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FILa0bb817e1e5e499da1ae400065843625', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0097_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0097_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..d04a15d --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0097_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-12-04 08:43 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0096_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL6ed80d0cb71b4e34932643c643bb7c1b', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0098_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0098_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..f6b1698 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0098_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-12-04 08:49 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0097_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FILeb6c27424e1d4b768e182c0de4726df8', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0099_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0099_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..7287a02 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0099_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-12-04 08:50 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0098_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL102ff313bc4c4363a3968eea77380ffc', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0100_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0100_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..0a5957e --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0100_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-12-04 09:12 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0099_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FILf0a6c8527f804b4980187e1b41930cb9', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0101_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0101_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..cc30b3c --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0101_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-12-04 09:14 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0100_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FILd1e0a2e6bd534faa9599da7e11940c18', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0102_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0102_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..5058e01 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0102_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-12-04 09:16 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0101_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL76cdcbd81fa5455f922b8ff914bc832a', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0103_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0103_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..d074655 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0103_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-12-04 09:18 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0102_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL3d7e3048e5d34a828363e18b6e81ad01', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0104_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0104_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..44a0d05 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0104_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-12-04 09:19 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0103_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL9d0ac10494ba455d8a8dfea01b1901f9', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0105_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0105_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..6c4e91a --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0105_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-12-04 09:22 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0104_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FILb2c7936194c644f4b578f6a3469c5e1b', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0106_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0106_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..93a6f91 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0106_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-12-04 09:24 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0105_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL5364aedba5414d0f958c16a541996f9c', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0107_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0107_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..e9d8fcb --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0107_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-12-04 09:30 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0106_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FILe43bc4daab4a4a3583416e1e09515221', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0108_userprofile_password_userprofile_user_name_and_more.py b/cope2n-api/fwd_api/migrations/0108_userprofile_password_userprofile_user_name_and_more.py new file mode 100644 index 0000000..aecd3f8 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0108_userprofile_password_userprofile_user_name_and_more.py @@ -0,0 +1,38 @@ +# Generated by Django 4.1.3 on 2023-12-04 11:36 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0107_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AddField( + model_name='userprofile', + name='password', + field=models.CharField(max_length=200, null=True), + ), + migrations.AddField( + model_name='userprofile', + name='user_name', + field=models.CharField(max_length=200, null=True), + ), + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FILacd4a42a9ddf4b0b9da267d5de823b09', max_length=300), + ), + migrations.AlterField( + model_name='userprofile', + name='full_name', + field=models.CharField(max_length=200, null=True), + ), + migrations.AlterField( + model_name='userprofile', + name='sync_id', + field=models.CharField(max_length=100, null=True), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0109_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0109_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..d9530f0 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0109_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-12-04 11:46 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0108_userprofile_password_userprofile_user_name_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FILc5bb241752a84128a3d573781d584d2d', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0110_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0110_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..f6a6183 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0110_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-12-04 11:56 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0109_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FILa9bae6f79bcc4c6f984a15323e13c1c3', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0111_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0111_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..6ee7003 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0111_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-12-05 03:08 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0110_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL10ffd254c3ac4de9ba189be326313e65', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0112_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0112_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..e591fb7 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0112_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-12-05 03:11 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0111_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FILfca8862c8a8148bda05b7739935920a8', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0113_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0113_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..9847924 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0113_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-12-05 03:15 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0112_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL2c5b2fd07712436eb3668293cbff1583', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0114_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0114_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..08bec79 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0114_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-12-05 03:24 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0113_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FILd1eb8304388243c38103f5613452df8a', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0115_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0115_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..e098736 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0115_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-12-05 03:29 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0114_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL14a547911b8b412e8a7b83c21a8f4dae', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0116_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0116_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..43893c8 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0116_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-12-05 03:40 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0115_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL4ba3d7a39b334298a348a61c1d6df980', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0117_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0117_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..642d751 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0117_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-12-05 03:45 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0116_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL3627683fbb8d4732a2b61e98b7a6fd61', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0118_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0118_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..98cc3e9 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0118_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-12-05 03:47 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0117_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL3a58c310ee1a46dcad2fe0fbd6084d98', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0119_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0119_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..c8e41d9 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0119_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-12-05 04:16 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0118_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FILa3868fabcb8e4f2c82571a7d0f0b8d16', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0120_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0120_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..3ca0322 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0120_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-12-05 05:11 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0119_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL51455855d52149efb459a7e948557129', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0121_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0121_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..e93c57a --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0121_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-12-05 05:34 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0120_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL4de16271ab104523bbe14caad1c1b37f', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0122_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0122_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..5f2f3cd --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0122_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-12-05 12:15 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0121_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL6ff8bc0cad1847b284c03ff8acda6154', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0123_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0123_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..1379dc5 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0123_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-12-07 05:46 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0122_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL13bfe6f79cb1451ba65feec2919ec473', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0124_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0124_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..e6f34fc --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0124_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-12-07 05:48 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0123_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL7f6beb6d3db74fe49a4d188a7cf0f16e', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0125_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0125_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..a6ecde4 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0125_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-12-07 05:52 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0124_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL42ba522f1be948efa4a4fda4cd7dbf2c', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0126_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0126_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..175b488 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0126_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-12-07 05:57 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0125_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FILcfd3837952bf41e5a300accb0e54d07c', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0127_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0127_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..4d35d3f --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0127_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-12-07 05:58 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0126_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FILc447caa0bfe74e4bb9bbe32a0a163393', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0128_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0128_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..73003e9 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0128_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-12-07 06:04 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0127_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL4313460699464759914b4847642aa241', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0129_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0129_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..c0c805f --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0129_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-12-07 06:05 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0128_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL2e3a749c78974bb3aac478429048d1ac', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0130_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0130_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..870f87f --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0130_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-12-07 06:22 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0129_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL149a2de6a9364914af05e85c2942669c', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0131_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0131_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..4cd8bfb --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0131_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-12-07 09:37 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0130_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL508ff2f50e1f4fd791114465fda6be52', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0132_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0132_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..7bc8f07 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0132_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-12-07 09:38 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0131_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FILf89eb9c3d0df4bc5b032ce777fc68223', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0133_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0133_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..cf1cd11 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0133_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-12-07 09:39 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0132_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL0fa7cc9b99524f5eb472b725e54f1c8c', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0134_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0134_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..8496ce5 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0134_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-12-07 09:43 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0133_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL16aadab8f3fb4084bc75c8088dfc5058', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0135_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0135_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..a3c28ed --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0135_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-12-07 09:47 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0134_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FILe409f85cd12f4164b205072aba79e973', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0136_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0136_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..aa18a5f --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0136_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-12-07 09:50 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0135_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FILaa59d524a0b84e65a97083eccf043ec3', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0137_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0137_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..2aad329 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0137_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-12-07 09:52 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0136_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FILaa25de029c3846188b970ecb341d0306', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0138_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0138_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..779de6d --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0138_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-12-07 09:54 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0137_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FILac4550af1d6d43758cf9fa552e63fb2b', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0139_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0139_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..3c43e88 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0139_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-12-07 09:57 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0138_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL191691d969dd48c8acea26fce4962b95', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0140_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0140_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..2d83b1c --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0140_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-12-07 09:58 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0139_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FILa1385b265fc845708cba27e132c44fcf', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0141_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0141_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..180e651 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0141_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-12-07 09:59 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0140_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FILed8c243d247a48f19b1274140c9d43c0', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0142_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0142_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..6c29cce --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0142_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-12-07 10:01 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0141_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FILb5221965407840d1bb652ca93f97a52c', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0143_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0143_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..25f1d68 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0143_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-12-07 12:46 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0142_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL5822470e545549b88d1f84833d64c375', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0144_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0144_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..ccd3e9e --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0144_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-12-07 12:48 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0143_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL5543bb4ad0b94060a917b6915a1beae9', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0145_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0145_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..8c0c93c --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0145_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-12-07 12:49 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0144_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FILd2a14464de0441f88e4525e4b361b5f8', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0146_subscriptionrequest_pages_left_and_more.py b/cope2n-api/fwd_api/migrations/0146_subscriptionrequest_pages_left_and_more.py new file mode 100644 index 0000000..1386184 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0146_subscriptionrequest_pages_left_and_more.py @@ -0,0 +1,23 @@ +# Generated by Django 4.1.3 on 2023-12-08 07:20 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0145_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AddField( + model_name='subscriptionrequest', + name='pages_left', + field=models.IntegerField(default=1), + ), + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL2d69e701afdc494cacbb44e63ec6c2a8', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0147_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0147_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..2266fbe --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0147_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-12-08 08:25 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0146_subscriptionrequest_pages_left_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL734eac71a7e44a7496583a75d04feb72', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0148_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0148_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..fc7d282 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0148_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-12-08 08:33 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0147_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FILd04941fdbc884fedaab2eb9f10e65131', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0149_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0149_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..695a63a --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0149_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-12-08 09:56 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0148_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FILb2b85f51d557426cb85746513966cb97', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0150_subscriptionrequest_feedback_result_and_more.py b/cope2n-api/fwd_api/migrations/0150_subscriptionrequest_feedback_result_and_more.py new file mode 100644 index 0000000..50df8be --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0150_subscriptionrequest_feedback_result_and_more.py @@ -0,0 +1,23 @@ +# Generated by Django 4.1.3 on 2023-12-08 11:55 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0149_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AddField( + model_name='subscriptionrequest', + name='feedback_result', + field=models.JSONField(null=True), + ), + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL37f0b813ff16476f9037c700d0fff6a6', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0151_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0151_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..b8a565d --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0151_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-12-08 11:55 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0150_subscriptionrequest_feedback_result_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL22a1f263cacd40aba403cfc60e62f4ae', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0152_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0152_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..aeb260f --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0152_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-12-08 11:56 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0151_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FILb512c6f863814a14ab6d45c724792564', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0153_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0153_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..79c2133 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0153_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-12-08 12:01 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0152_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FILc5b3fe0f27534d5fa1ddac3cf961f8de', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0154_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0154_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..257a2ba --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0154_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-12-08 12:03 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0153_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL422bc3c29643482982a42db76f4bc30e', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/0155_alter_subscriptionrequestfile_code.py b/cope2n-api/fwd_api/migrations/0155_alter_subscriptionrequestfile_code.py new file mode 100644 index 0000000..d0bea20 --- /dev/null +++ b/cope2n-api/fwd_api/migrations/0155_alter_subscriptionrequestfile_code.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.3 on 2023-12-08 12:46 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fwd_api', '0154_alter_subscriptionrequestfile_code'), + ] + + operations = [ + migrations.AlterField( + model_name='subscriptionrequestfile', + name='code', + field=models.CharField(default='FIL6ec7f0e84f864eab818c7ff715c4b920', max_length=300), + ), + ] diff --git a/cope2n-api/fwd_api/migrations/__init__.py b/cope2n-api/fwd_api/migrations/__init__.py new file mode 100755 index 0000000..e69de29