From 02f9d04bf065d5fbb9d397606f2fc8181c6c5b23 Mon Sep 17 00:00:00 2001 From: Viet-Anh Nguyen Date: Tue, 1 Oct 2024 23:49:24 +0700 Subject: [PATCH] Experimental build for macOS --- LICENSE | 695 +++++++++++++++++++++++++- LlamaAssistant.desktop | 8 + LlamaAssistant.spec | 65 +++ README.md | 5 +- build.sh | 1 + icon.png | Bin 0 -> 23222 bytes llama_assistant/llama_assistant.py | 14 +- llama_assistant/main.py | 3 + llama_assistant/model_handler.py | 14 - llama_assistant/resources/icon.icns | Bin 0 -> 42215 bytes llama_assistant/utils.py | 39 ++ llama_assistant/wake_word_detector.py | 32 +- requirements.txt | 1 + 13 files changed, 804 insertions(+), 73 deletions(-) create mode 100644 LlamaAssistant.desktop create mode 100644 LlamaAssistant.spec create mode 100644 build.sh create mode 100644 icon.png create mode 100644 llama_assistant/resources/icon.icns diff --git a/LICENSE b/LICENSE index e34fcb0..577e731 100644 --- a/LICENSE +++ b/LICENSE @@ -1,21 +1,674 @@ -# MIT License - -Copyright (c) 2024 Viet Anh Nguyen - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file + 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) 2024 Viet-Anh Nguyen + + 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: + + LlamaAssistant Copyright (C) 2024 Viet-Anh Nguyen + 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/LlamaAssistant.desktop b/LlamaAssistant.desktop new file mode 100644 index 0000000..ceff179 --- /dev/null +++ b/LlamaAssistant.desktop @@ -0,0 +1,8 @@ +[Desktop Entry] +Name=LlamaAssistant +Comment=Your Local AI Assistant with Llama Models +Exec=LlamaAssistant +Icon=llama_assistant/resources/logo.png +Terminal=false +Type=Application +Categories=Graphics;RasterGraphics;MachineLearning diff --git a/LlamaAssistant.spec b/LlamaAssistant.spec new file mode 100644 index 0000000..c580815 --- /dev/null +++ b/LlamaAssistant.spec @@ -0,0 +1,65 @@ +# -*- mode: python -*- +# vim: ft=python + +from PyInstaller.utils.hooks import collect_data_files, get_package_paths +import os, sys + +sys.setrecursionlimit(5000) # required on Windows + +# Get the package path +package_path = get_package_paths('llama_cpp')[0] + +# Collect data files +datas = collect_data_files('llama_cpp') + +# Append the additional .dll or .so file +if os.name == 'nt': # Windows + for l in ["ggml", "llama", "llava"]: + dll_path = os.path.join(package_path, 'llama_cpp', 'lib', f'{l}.dll') + datas.append((dll_path, 'llama_cpp/lib')) +elif sys.platform == 'darwin': # Mac + for l in ["ggml", "llama", "llava"]: + dylib_path = os.path.join(package_path, 'llama_cpp', 'lib', f'lib{l}.dylib') + datas.append((dylib_path, 'llama_cpp/lib')) +elif os.name == 'posix': # Linux + for l in ["ggml", "llama", "llava"]: + so_path = os.path.join(package_path, 'llama_cpp', 'lib', f'lib{l}.so') + datas.append((so_path, 'llama_cpp/lib')) + +datas += [ + ('llama_assistant/resources/*.onnx', 'llama_assistant/resources'), + ('llama_assistant/resources/*.png', 'llama_assistant/resources'), +] + +a = Analysis( + ['llama_assistant/main.py'], + pathex=['llama_assistant'], + binaries=[], + datas=datas, + hiddenimports=[], + hookspath=[], + runtime_hooks=[], + excludes=[], +) +pyz = PYZ(a.pure, a.zipped_data) +exe = EXE( + pyz, + a.scripts, + a.binaries, + a.zipfiles, + a.datas, + name='LlamaAssistant', + debug=True, + strip=False, + upx=False, + runtime_tmpdir=None, + console=True, + icon='llama_assistant/resources/icon.icns', +) +app = BUNDLE( + exe, + name='LlamaAssistant.app', + icon='llama_assistant/resources/icon.icns', + bundle_identifier=None, + info_plist={'NSHighResolutionCapable': 'True'}, +) diff --git a/README.md b/README.md index 3b4743e..63169be 100644 --- a/README.md +++ b/README.md @@ -159,7 +159,8 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file ## Acknowledgements -- [Llama 3.2](https://github.com/facebookresearch/llama) by Meta AI Research +- The default model is [Llama 3.2](https://github.com/facebookresearch/llama) by Meta AI Research. +- This project uses [LlamaCPP](https://github.com/ggerganov/llama.cpp) by Georgi Gerganov and contributors. ## Star History @@ -168,4 +169,4 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file ## Contact - Viet-Anh Nguyen - [vietanhdev](https://github.com/vietanhdev), [contact form](https://www.vietanh.dev/contact). -- Project Link: [https://github.com/vietanhdev/llama-assistant](https://github.com/vietanhdev/llama-assistant) +- Project Link: [https://github.com/vietanhdev/llama-assistant](https://github.com/vietanhdev/llama-assistant), [https://llama-assistant.nrl.ai/](https://llama-assistant.nrl.ai/). diff --git a/build.sh b/build.sh new file mode 100644 index 0000000..c641caf --- /dev/null +++ b/build.sh @@ -0,0 +1 @@ +pyinstaller --noconfirm LlamaAssistant.spec diff --git a/icon.png b/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..d1508da41f4ed735297a0b408ed5a1b6641687b8 GIT binary patch literal 23222 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

x^pUt#y7Lr6Eo4m2R;y2^C0rQlNL7Z9*E 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 literal 0 HcmV?d00001 diff --git a/llama_assistant/utils.py b/llama_assistant/utils.py index 6e28dba..48d9326 100644 --- a/llama_assistant/utils.py +++ b/llama_assistant/utils.py @@ -1,7 +1,46 @@ import base64 +import os +import sys +from importlib import resources + +from PyQt6.QtGui import QPixmap +from PyQt6.QtCore import Qt def image_to_base64_data_uri(file_path): with open(file_path, "rb") as img_file: base64_data = base64.b64encode(img_file.read()).decode("utf-8") return f"data:image/png;base64,{base64_data}" + + +def get_resource_path(relative_path): + """Get the path to a resource, works for dev and for PyInstaller""" + if getattr(sys, "frozen", False): + # Running in a bundle (PyInstaller) + base_path = sys._MEIPASS + else: + # Running in normal Python environment + base_path = os.path.dirname(os.path.abspath(__file__)) + + path = os.path.join(base_path, relative_path) + if not os.path.exists(path): + # Fallback to reading from the package + file_name = os.path.basename(path) + package_name = os.path.dirname(relative_path).replace("/", ".") + with resources.path(package_name, file_name) as p: + path = str(p) + + return path + + +def load_image(relative_path, size=None): + """Load an image from a relative path and optionally resize it""" + full_path = get_resource_path(relative_path) + if os.path.exists(full_path): + pixmap = QPixmap(full_path) + if size: + pixmap = pixmap.scaled(size[0], size[1], Qt.AspectRatioMode.KeepAspectRatio) + return pixmap + else: + print(f"Image not found at: {full_path}") + return QPixmap() diff --git a/llama_assistant/wake_word_detector.py b/llama_assistant/wake_word_detector.py index b5e9ba7..c34f54a 100644 --- a/llama_assistant/wake_word_detector.py +++ b/llama_assistant/wake_word_detector.py @@ -6,6 +6,8 @@ from PyQt6.QtCore import QThread, pyqtSignal import time +from llama_assistant.utils import get_resource_path + class WakeWordDetector(QThread): wakeword_detected = pyqtSignal(str) @@ -33,11 +35,11 @@ def __init__(self, chunk_size=1280, inference_framework="onnx"): self.n_models = 0 def load_model(self): - with resources.path("llama_assistant.resources", "wk_hey_llama.onnx") as path: - self.owwModel = Model( - wakeword_models=[str(path)], - inference_framework=self.inference_framework, - ) + path = get_resource_path("llama_assistant/resources/wk_hey_llama.onnx") + self.owwModel = Model( + wakeword_models=[path], + inference_framework=self.inference_framework, + ) self.n_models = len(self.owwModel.models.keys()) def unload_model(self): @@ -88,23 +90,3 @@ def print_results(self): print("\033[F" * (4 * self.n_models + 1)) print(output_string_header, " ", end="\r") - - -if __name__ == "__main__": - from PyQt6.QtWidgets import QApplication - import sys - - app = QApplication(sys.argv) - - detector = WakeWordDetector() - detector.wakeword_detected.connect(lambda mdl: print(f"Main thread: Wakeword detected - {mdl}")) - - print("\n\n") - print("#" * 100) - print("Listening for wakewords...") - print("#" * 100) - print("\n" * (detector.n_models * 3)) - - detector.start() - - sys.exit(app.exec()) diff --git a/requirements.txt b/requirements.txt index 362d5f8..4e9e4e9 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,3 +5,4 @@ pynput==1.7.7 llama-cpp-python huggingface_hub==0.25.1 openwakeword==0.6.0 +pyinstaller==6.10.0