Evrmind commited on
Commit
1669554
·
verified ·
1 Parent(s): 971c483

Upload folder using huggingface_hub

Browse files
.gitattributes CHANGED
@@ -1,35 +1,7 @@
1
- *.7z filter=lfs diff=lfs merge=lfs -text
2
- *.arrow filter=lfs diff=lfs merge=lfs -text
3
- *.bin filter=lfs diff=lfs merge=lfs -text
4
- *.bz2 filter=lfs diff=lfs merge=lfs -text
5
- *.ckpt filter=lfs diff=lfs merge=lfs -text
6
- *.ftz filter=lfs diff=lfs merge=lfs -text
7
- *.gz filter=lfs diff=lfs merge=lfs -text
8
- *.h5 filter=lfs diff=lfs merge=lfs -text
9
- *.joblib filter=lfs diff=lfs merge=lfs -text
10
- *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
- *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
- *.model filter=lfs diff=lfs merge=lfs -text
13
- *.msgpack filter=lfs diff=lfs merge=lfs -text
14
- *.npy filter=lfs diff=lfs merge=lfs -text
15
- *.npz filter=lfs diff=lfs merge=lfs -text
16
- *.onnx filter=lfs diff=lfs merge=lfs -text
17
- *.ot filter=lfs diff=lfs merge=lfs -text
18
- *.parquet filter=lfs diff=lfs merge=lfs -text
19
- *.pb filter=lfs diff=lfs merge=lfs -text
20
- *.pickle filter=lfs diff=lfs merge=lfs -text
21
- *.pkl filter=lfs diff=lfs merge=lfs -text
22
- *.pt filter=lfs diff=lfs merge=lfs -text
23
- *.pth filter=lfs diff=lfs merge=lfs -text
24
- *.rar filter=lfs diff=lfs merge=lfs -text
25
- *.safetensors filter=lfs diff=lfs merge=lfs -text
26
- saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
- *.tar.* filter=lfs diff=lfs merge=lfs -text
28
- *.tar filter=lfs diff=lfs merge=lfs -text
29
- *.tflite filter=lfs diff=lfs merge=lfs -text
30
- *.tgz filter=lfs diff=lfs merge=lfs -text
31
- *.wasm filter=lfs diff=lfs merge=lfs -text
32
- *.xz filter=lfs diff=lfs merge=lfs -text
33
- *.zip filter=lfs diff=lfs merge=lfs -text
34
- *.zst filter=lfs diff=lfs merge=lfs -text
35
- *tfevents* filter=lfs diff=lfs merge=lfs -text
 
1
+ *.gguf filter=lfs diff=lfs merge=lfs -text
2
+ evrmind-android-vulkan.tar.gz filter=lfs diff=lfs merge=lfs -text
3
+ evrmind-linux-cuda.tar.gz filter=lfs diff=lfs merge=lfs -text
4
+ evrmind-linux-vulkan.tar.gz filter=lfs diff=lfs merge=lfs -text
5
+ evrmind-macos-metal.tar.gz filter=lfs diff=lfs merge=lfs -text
6
+ evrmind-windows-cuda.zip filter=lfs diff=lfs merge=lfs -text
7
+ evrmind-windows-vulkan.zip filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
BENCHMARK_RESULTS.md ADDED
@@ -0,0 +1,161 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # EVR-1 Maano-8b-Instruct: Benchmark Results
2
+
3
+ **Date:** 2026-03-09
4
+ **Model:** Meta Llama 3.1 8B Instruct, EVR-1 quantized
5
+ **Hardware:** RTX 6000 Ada (GPU offload, -ngl 99)
6
+
7
+ ## Model Tested
8
+
9
+ | Model | File | Size | Notes |
10
+ |-------|------|------|-------|
11
+ | EVR-1 Instruct | evr-llama-3.1-8b-instruct.gguf | 3.93 GiB | EVR-1 3-bit compression |
12
+
13
+ ## Test 1: Coherence (5 continuation-style prompts, 500 + 1000 tokens)
14
+
15
+ **Setup:** 5 continuation-style prompts, generated at both 500 and 1000 tokens. Temperature 0, no repeat penalty, `--ignore-eos`. Repetition measured by 4-gram repetition rate (rep4). Lower is better.
16
+
17
+ ### Summary Table
18
+
19
+ | Model | Size | rep4 @ 500 | rep4 @ 1000 |
20
+ |-------|------|-----------|-------------|
21
+ | **EVR-1 Instruct** | **3.93 GiB** | **2.77%** | **9.66%** |
22
+
23
+ ### Per-Prompt Results (EVR-1 Instruct)
24
+
25
+ | Prompt | rep4 @ 500 | rep4 @ 1000 |
26
+ |--------|-----------|-------------|
27
+ | Nuclear fusion in stars | 1.17% | 9.44% |
28
+ | Global financial crisis of 2008 | 5.08% | 12.14% |
29
+ | General relativity | 0.49% | 0.75% |
30
+ | Human immune system | 0.80% | 6.89% |
31
+ | Quantum computing | 6.30% | 19.09% |
32
+
33
+ ### Perplexity
34
+
35
+ | Model | Size | Perplexity (wikitext-2, ctx=512) |
36
+ |-------|------|--------------------------------|
37
+ | **EVR-1 Instruct** | **3.93 GiB** | **7.37 ± 0.05** |
38
+
39
+ ### Sample Outputs (Coherence Tests)
40
+
41
+ #### "Albert Einstein's theory of general relativity describes" (500 tokens, 0.49% rep4)
42
+ ```
43
+ Albert Einstein's theory of general relativity describes gravity as the curvature of
44
+ spacetime caused by the presence of mass and energy. According to this theory, the
45
+ curvature of space and time around a massive object such as the Earth causes objects
46
+ to fall towards it, which we experience on our planet.
47
+
48
+ The curvature caused by a massive object is not limited to its surface. The curvature
49
+ extends into space and time, creating a region around it known as its gravitational
50
+ field. The strength and direction of this field depend on how much mass is present
51
+ in that region.
52
+
53
+ The gravitational field is not just limited to objects with mass; it also affects light.
54
+ According to general relativity, light follows curved paths in spacetime around massive
55
+ objects.
56
+ ```
57
+ *(continues coherently for full 500 tokens - discusses gravitational lensing, Einstein rings, arcs, multiple images)*
58
+
59
+ #### "The process of nuclear fusion in stars begins when" (500 tokens, 1.17% rep4)
60
+ ```
61
+ The process of nuclear fusion in stars begins when hydrogen atoms in the core of the
62
+ star are heated to extremely high temperatures. At these temperatures, the protons in
63
+ the hydrogen nuclei are stripped of their electrons, leaving only protons. These protons
64
+ then begin to fuse together to form helium nuclei. This process releases a tremendous
65
+ amount of energy, which is what powers a star.
66
+
67
+ The process begins when hydrogen nuclei are heated to a temperature at which they can
68
+ overcome their mutual repulsion and fuse together. This temperature is known as the
69
+ "fusion temperature." Once this temperature is reached, nuclear fusion can begin.
70
+ ```
71
+ *(continues for full 500 tokens - transitions to discussing nuclear fission, which is a topic drift but not repetitive)*
72
+
73
+ ---
74
+
75
+ ## Test 2: Chat Quality Samples
76
+
77
+ ### Prompt: "hello, are you there?"
78
+ ```
79
+ Hello! Yes, I'm here. How can I assist you today?
80
+ ```
81
+
82
+ ### Prompt: "What are the main causes of the French Revolution?"
83
+ ```
84
+ The French Revolution, which lasted from 1789 to 1792 and 1799 to 1804, was a complex
85
+ event with multiple causes. However, some of the main contributing factors include:
86
+
87
+ 1. Financial Crisis: France was deeply in debt from its involvement in American
88
+ Revolutionary War and other wars. The burden of taxation fell on the common people,
89
+ who were already facing economic hardship. The financial crisis exacerbated social
90
+ and economic issues.
91
+
92
+ 2. Social Inequality: The French nobility held a significant amount of power over
93
+ commoners through their control over land and government positions. This created a
94
+ sense of discontent among the lower classes who felt they were being oppressed.
95
+
96
+ 3. Enlightenment Ideas: The ideas presented by Enlightenment thinkers such as
97
+ Rousseau, Voltaire, Diderot encouraged people to think critically about their
98
+ government and seek change.
99
+
100
+ 4. Food Shortages: A series of poor harvests led to widespread hunger and starvation.
101
+ This further exacerbated social unrest, as people began to blame the government for
102
+ the shortages.
103
+
104
+ 5. Absolute Monarchy: The rule of King Louis XVI was seen as tyrannical by many.
105
+ His attempts to reform the tax system and other aspects of government were met with
106
+ resistance from those who saw his efforts as an attempt to tighten his control rather
107
+ than alleviate their suffering.
108
+
109
+ 6. The American Revolution's Influence: The American Revolution inspired the French
110
+ people with its ideas of liberty, equality, and fraternity.
111
+ ```
112
+
113
+ ### Prompt: "Explain quantum computing in detail"
114
+ ```
115
+ Quantum computing is a type of computing that uses the principles of quantum mechanics
116
+ to perform calculations on data. It's a new paradigm for computation that's fundamentally
117
+ different from classical computers.
118
+
119
+ Qubits: A qubit is a two-state quantum system that represents information in the form
120
+ of a quantum bit. Qubits can exist in states like 0, 1, or both simultaneously, thanks
121
+ to superposition.
122
+
123
+ Superposition: In quantum mechanics and computing superposition means that a qubit
124
+ exists at both states simultaneously (0 and/or 1) until it's observed or measured.
125
+
126
+ Entanglement: Entanglement is when two qubits become connected in such a way they can't
127
+ exist independently. When something happens to one entangled particle, the other particle
128
+ instantly responds, no matter how far apart they are.
129
+
130
+ Quantum Gates: Quantum gates are the quantum equivalent of logic gates in digital
131
+ computing. Types include: Hadamard Gate, Pauli X and Z Gates, CNOT Gate, Swap Gates.
132
+
133
+ Current Challenges: Quantum Noise, Scalability, Quantum Error Correction, Quantifying
134
+ Quantum Advantage.
135
+ ```
136
+ *(Chat-formatted prompt, 1000 tokens. Note: The coherence test above used a different methodology - continuation-style prompts with `--ignore-eos` - which produces different repetition rates.)*
137
+
138
+ ---
139
+
140
+ ## Performance
141
+
142
+ | Metric | Value |
143
+ |--------|-------|
144
+ | Prompt eval | ~37 tokens/sec |
145
+ | Generation | ~34 tokens/sec |
146
+ | Model load | ~7-16 sec |
147
+ | VRAM usage | ~3.7 GiB (model) + KV cache |
148
+
149
+ *RTX 6000 Ada, CUDA 12, -ngl 99*
150
+
151
+ ### Apple Silicon (Mac Mini M4, Metal)
152
+
153
+ | Metric | Value |
154
+ |--------|-------|
155
+ | Prompt eval | ~9 tokens/sec |
156
+ | Generation | ~8 tokens/sec |
157
+ | Model load | ~6 sec |
158
+ | Memory usage | ~4.0 GiB (fits in 16 GB unified memory) |
159
+
160
+ *Apple M4, Metal backend, ARM64 static binary with LTO*
161
+
LICENSE.md ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Evrmind EVR-1 Maano-8b-Instruct License Agreement
2
+
3
+ Version 1.0, March 2026
4
+
5
+ Copyright (c) 2026 Evrmind. All rights reserved.
6
+
7
+ ## Terms of Use
8
+
9
+ ### 1. Permitted Use
10
+ You are granted a non-exclusive, worldwide, royalty-free license to:
11
+ - Download, use, copy, and distribute the Model and binaries for any purpose, including commercial use
12
+ - Create derivative works (fine-tuning, modifications, adaptations) for any purpose
13
+ - Use the Model in products, services, and applications
14
+
15
+ ### 2. Attribution
16
+ If you use this Model, or create any derivative work based on it (including but not limited to fine-tuned models, quantized variants, distilled models, or models trained using outputs of this Model), you must:
17
+ - Prominently credit **"EVR-1 Maano"** in the model name, model card, documentation, and any related publications or materials
18
+ - Include a copy of this license with any distributed derivative work
19
+
20
+ ### 3. Restrictions
21
+ You may NOT:
22
+ - Reverse engineer, decompile, or disassemble the provided binaries
23
+ - Remove or alter any proprietary notices or labels on the Model or binaries
24
+ - Represent the Model or derivative works as entirely your own creation without attribution
25
+
26
+ ### 4. Meta Llama 3.1 License
27
+ This model is a derivative of Meta's Llama 3.1 8B Instruct. All use is additionally subject to the Meta Llama 3.1 Community License Agreement (see META_LLAMA_LICENSE.md).
28
+
29
+ ### 5. No Warranty
30
+ THE MODEL AND BINARIES ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED. EVRMIND DISCLAIMS ALL WARRANTIES INCLUDING MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
31
+
32
+ ### 6. Limitation of Liability
33
+ IN NO EVENT SHALL EVRMIND BE LIABLE FOR ANY DAMAGES ARISING FROM THE USE OF THE MODEL OR BINARIES.
META_LLAMA_LICENSE.md ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ LLAMA 3.1 COMMUNITY LICENSE AGREEMENT
2
+
3
+ Llama 3.1 Version Release Date: July 23, 2024
4
+
5
+ “Agreement” means the terms and conditions for use, reproduction, distribution and modification of the Llama Materials set forth herein.
6
+
7
+ “Documentation” means the specifications, manuals and documentation accompanying Llama 3.1 distributed by Meta at https://llama.meta.com/doc/overview.
8
+
9
+ “Licensee” or “you” means you, or your employer or any other person or entity (if you are entering into this Agreement on such person or entity’s behalf), of the age required under applicable laws, rules or regulations to provide legal consent and that has legal authority to bind your employer or such other person or entity if you are entering in this Agreement on their behalf.
10
+
11
+ “Llama 3.1” means the foundational large language models and software and algorithms, including machine-learning model code, trained model weights, inference-enabling code, training-enabling code, fine-tuning enabling code and other elements of the foregoing distributed by Meta at https://llama.meta.com/llama-downloads.
12
+
13
+ “Llama Materials” means, collectively, Meta’s proprietary Llama 3.1 and Documentation (and any portion thereof) made available under this Agreement.
14
+
15
+ “Meta” or “we” means Meta Platforms Ireland Limited (if you are located in or, if you are an entity, your principal place of business is in the EEA or Switzerland) and Meta Platforms, Inc. (if you are located outside of the EEA or Switzerland). 
16
+
17
+ By clicking “I Accept” below or by using or distributing any portion or element of the Llama Materials, you agree to be bound by this Agreement.
18
+
19
+ 1. License Rights and Redistribution.

20
+ a. Grant of Rights. You are granted a non-exclusive, worldwide, non-transferable and royalty-free limited license under Meta’s intellectual property or other rights owned by Meta embodied in the Llama Materials to use, reproduce, distribute, copy, create derivative works of, and make modifications to the Llama Materials.  
21
+
22
+ b. Redistribution and Use.  
23
+
24
+ i. If you distribute or make available the Llama Materials (or any derivative works thereof), or a product or service (including another AI model) that contains any of them, you shall (A) provide a copy of this Agreement with any such Llama Materials; and (B) prominently display “Built with Llama” on a related website, user interface, blogpost, about page, or product documentation. If you use the Llama Materials or any outputs or results of the Llama Materials to create, train, fine tune, or otherwise improve an AI model, which is distributed or made available, you shall also include “Llama” at the beginning of any such AI model name.
25
+
26
+ ii. If you receive Llama Materials, or any derivative works thereof, from a Licensee as part of an integrated end user product, then Section 2 of this Agreement will not apply to you. 
27
+
28
+ iii. You must retain in all copies of the Llama Materials that you distribute the following attribution notice within a “Notice” text file distributed as a part of such copies: “Llama 3.1 is licensed under the Llama 3.1 Community License, Copyright © Meta Platforms, Inc. All Rights Reserved.”
29
+
30
+ iv. Your use of the Llama Materials must comply with applicable laws and regulations (including trade compliance laws and regulations) and adhere to the Acceptable Use Policy for the Llama Materials (available at https://llama.meta.com/llama3_1/use-policy), which is hereby incorporated by reference into this Agreement.
31
+   
32
+ 2. Additional Commercial Terms. If, on the Llama 3.1 version release date, the monthly active users of the products or services made available by or for Licensee, or Licensee’s affiliates, is greater than 700 million monthly active users in the preceding calendar month, you must request a license from Meta, which Meta may grant to you in its sole discretion, and you are not authorized to exercise any of the rights under this Agreement unless or until Meta otherwise expressly grants you such rights.
33
+
34
+ 3. Disclaimer of Warranty. UNLESS REQUIRED BY APPLICABLE LAW, THE LLAMA MATERIALS AND ANY OUTPUT AND RESULTS THEREFROM ARE PROVIDED ON AN “AS IS” BASIS, WITHOUT WARRANTIES OF ANY KIND, AND META DISCLAIMS ALL WARRANTIES OF ANY KIND, BOTH EXPRESS AND IMPLIED, INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. YOU ARE SOLELY RESPONSIBLE FOR DETERMINING THE APPROPRIATENESS OF USING OR REDISTRIBUTING THE LLAMA MATERIALS AND ASSUME ANY RISKS ASSOCIATED WITH YOUR USE OF THE LLAMA MATERIALS AND ANY OUTPUT AND RESULTS.
35
+
36
+ 4. Limitation of Liability. IN NO EVENT WILL META OR ITS AFFILIATES BE LIABLE UNDER ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, TORT, NEGLIGENCE, PRODUCTS LIABILITY, OR OTHERWISE, ARISING OUT OF THIS AGREEMENT, FOR ANY LOST PROFITS OR ANY INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL, EXEMPLARY OR PUNITIVE DAMAGES, EVEN IF META OR ITS AFFILIATES HAVE BEEN ADVISED OF THE POSSIBILITY OF ANY OF THE FOREGOING.
37
+  
38
+ 5. Intellectual Property.
39
+
40
+ a. No trademark licenses are granted under this Agreement, and in connection with the Llama Materials, neither Meta nor Licensee may use any name or mark owned by or associated with the other or any of its affiliates, except as required for reasonable and customary use in describing and redistributing the Llama Materials or as set forth in this Section 5(a). Meta hereby grants you a license to use “Llama” (the “Mark”) solely as required to comply with the last sentence of Section 1.b.i. You will comply with Meta’s brand guidelines (currently accessible at https://about.meta.com/brand/resources/meta/company-brand/). All goodwill arising out of your use of the Mark will inure to the benefit of Meta.
41
+
42
+ b. Subject to Meta’s ownership of Llama Materials and derivatives made by or for Meta, with respect to any derivative works and modifications of the Llama Materials that are made by you, as between you and Meta, you are and will be the owner of such derivative works and modifications.
43
+
44
+ c. If you institute litigation or other proceedings against Meta or any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Llama Materials or Llama 3.1 outputs or results, or any portion of any of the foregoing, constitutes infringement of intellectual property or other rights owned or licensable by you, then any licenses granted to you under this Agreement shall terminate as of the date such litigation or claim is filed or instituted. You will indemnify and hold harmless Meta from and against any claim by any third party arising out of or related to your use or distribution of the Llama Materials.
45
+
46
+ 6. Term and Termination. The term of this Agreement will commence upon your acceptance of this Agreement or access to the Llama Materials and will continue in full force and effect until terminated in accordance with the terms and conditions herein. Meta may terminate this Agreement if you are in breach of any term or condition of this Agreement. Upon termination of this Agreement, you shall delete and cease use of the Llama Materials. Sections 3, 4 and 7 shall survive the termination of this Agreement. 
47
+
48
+ 7. Governing Law and Jurisdiction. This Agreement will be governed and construed under the laws of the State of California without regard to choice of law principles, and the UN Convention on Contracts for the International Sale of Goods does not apply to this Agreement. The courts of California shall have exclusive jurisdiction of any dispute arising out of this Agreement. 
MODEL_CARD.md ADDED
@@ -0,0 +1,189 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: other
3
+ license_name: evrmind-free-1.0
4
+ license_link: LICENSE.md
5
+ language:
6
+ - en
7
+ library_name: llama.cpp
8
+ tags:
9
+ - llama
10
+ - llama-3.1
11
+ - gguf
12
+ - 3-bit
13
+ - quantization
14
+ - evr
15
+ - evrmind
16
+ - text-generation
17
+ - instruct
18
+ - chat
19
+ - on-device
20
+ - maano
21
+ pipeline_tag: text-generation
22
+ model-index:
23
+ - name: Evrmind EVR-1 Maano-8b-Instruct
24
+ results:
25
+ - task:
26
+ type: text-generation
27
+ metrics:
28
+ - name: Perplexity (wikitext-2, ctx=512)
29
+ type: perplexity
30
+ value: 7.37
31
+ - name: Coherence (rep4 @ 500 tokens)
32
+ type: repetition-rate
33
+ value: 2.77
34
+ - name: Coherence (rep4 @ 1000 tokens)
35
+ type: repetition-rate
36
+ value: 9.66
37
+ ---
38
+
39
+ # Evrmind EVR-1 Maano-8b-Instruct (3.93 GiB)
40
+
41
+ A custom 3-bit compression of Meta's Llama 3.1 8B Instruct that fits in **under 4 GiB** while maintaining coherent instruction-following at 1000+ tokens.
42
+
43
+ EVR-1 is not a standard quantization (not Q2, Q3, Q4, etc). It is a custom compression method developed by Evrmind. The compressed weights average approximately 3 bits per parameter; the total GGUF file (3.93 GiB) includes additional metadata and structure overhead.
44
+
45
+ ## Key Results
46
+
47
+ | Metric | EVR-1 Instruct (3.93 GiB) |
48
+ |--------|--------------------------|
49
+ | Coherence @ 500 tokens | **2.77% repetition** |
50
+ | Coherence @ 1000 tokens | **9.66% repetition** |
51
+ | Perplexity (wikitext-2, ctx=512) | **7.37** |
52
+
53
+ ## Chat Example
54
+
55
+ **User:** What are the main causes of the French Revolution?
56
+
57
+ **EVR-1 Maano-8b-Instruct:**
58
+
59
+ > The French Revolution, which lasted from 1789 to 1799, was a complex event with multiple causes. However, some of the main contributing factors include:
60
+ >
61
+ > 1. **Financial Crisis**: France was deeply in debt from its involvement in the American Revolutionary War and other wars. The burden of taxation fell on the common people, who were already facing economic hardship.
62
+ >
63
+ > 2. **Social Inequality**: The French nobility held a significant amount of power over commoners through their control over land and government positions.
64
+ >
65
+ > 3. **Enlightenment Ideas**: The ideas presented by Enlightenment thinkers such as Rousseau, Voltaire, Diderot encouraged people to think critically about their government and seek change.
66
+ >
67
+ > 4. **Food Shortages**: A series of poor harvests led to widespread hunger and starvation.
68
+ >
69
+ > 5. **Absolute Monarchy**: The rule of King Louis XVI was seen as tyrannical by many.
70
+ >
71
+ > 6. **The American Revolution's Influence**: The American Revolution inspired the French people with its ideas of liberty, equality, and fraternity.
72
+
73
+ ## How to Run
74
+
75
+ Download the model file and the binary for your platform, then:
76
+
77
+ ```bash
78
+ # Extract the binary
79
+ mkdir -p linux-cuda && tar xzf evrmind-linux-cuda.tar.gz -C linux-cuda
80
+
81
+ # Run (interactive chat)
82
+ cd linux-cuda
83
+ LD_LIBRARY_PATH=. ./llama-cli -m ../evr-llama-3.1-8b-instruct.gguf -ngl 99
84
+
85
+ # Run (single completion)
86
+ LD_LIBRARY_PATH=. ./llama-completion -m ../evr-llama-3.1-8b-instruct.gguf -p "Your prompt here" -n 500 -ngl 99
87
+ ```
88
+
89
+ ### Platform Binaries
90
+
91
+ | Platform | File | GPU Required |
92
+ |----------|------|-------------|
93
+ | Linux + NVIDIA | `evrmind-linux-cuda.tar.gz` | NVIDIA GPU (CUDA 12) |
94
+ | Linux + Any GPU | `evrmind-linux-vulkan.tar.gz` | Any Vulkan-capable GPU |
95
+ | Windows + NVIDIA | `evrmind-windows-cuda.zip` | NVIDIA GPU (CUDA 12) |
96
+ | Windows + Any GPU | `evrmind-windows-vulkan.zip` | Any Vulkan-capable GPU |
97
+ | macOS (Apple Silicon) | `evrmind-macos-metal.tar.gz` | M1/M2/M3/M4 |
98
+ | Android (Termux) | `evrmind-android-vulkan.tar.gz` | Vulkan |
99
+
100
+ > **Note:** The binaries are the same for all EVR-1 models. You only need to download them once. Just point them at whichever GGUF you want to run.
101
+
102
+ ### Flags
103
+
104
+ | Flag | Description |
105
+ |------|------------|
106
+ | `-ngl 99` | Offload all layers to GPU (recommended) |
107
+ | `-n 500` | Generate 500 tokens |
108
+ | `-p "..."` | Your prompt |
109
+ | `-t 8` | Number of CPU threads (for CPU layers) |
110
+
111
+ ## Model Details
112
+
113
+ - **Name:** Evrmind EVR-1 Maano-8b-Instruct
114
+ - **Base model:** Meta Llama 3.1 8B Instruct
115
+ - **Size:** 3.93 GiB (GGUF)
116
+ - **Method:** EVR-1 (Evrmind Reconstruction), a custom 3-bit compression method
117
+ - **Backends:** CUDA, Vulkan, Metal, CPU
118
+ - **Context:** Tested up to 2048 tokens; longer contexts have not been validated at 3-bit compression
119
+ - **Chat template:** Llama 3.1 instruct format (built-in)
120
+
121
+ ## Benchmarks
122
+
123
+ ### Coherence (5 continuation-style prompts, 500 and 1000 tokens each)
124
+
125
+ Average 4-gram repetition rate (lower = better):
126
+
127
+ | Model | Size | rep4 @ 500 | rep4 @ 1000 |
128
+ |-------|------|-----------|-------------|
129
+ | **EVR-1 Instruct** | **3.93 GiB** | **2.77%** | **9.66%** |
130
+
131
+ ## Also Available
132
+
133
+ - **[EVR-1 Maano-8b](https://huggingface.co/evrmind/evr-1-maano-8b)**, base model (not instruction-tuned), for text completion and creative writing
134
+ - **[EVR-1 Bafethu-8b-Reasoning](https://huggingface.co/evrmind/evr-1-bafethu-8b-reasoning)**, reasoning model (DeepSeek R1)
135
+
136
+ ## Intended Use
137
+
138
+ This model is intended for on-device chat and instruction-following on laptops, desktops, and edge devices where memory is constrained. An Android (Termux) build is also available. There is no iOS build.
139
+
140
+ ## Limitations
141
+
142
+ - Math reasoning is limited, consistent with the base Llama 3.1 8B Instruct at this compression level.
143
+ - Occasional minor character-level artefacts (e.g., dropped letters) due to 3-bit compression.
144
+ - Generation quality degrades somewhat beyond 1000 tokens.
145
+ - As with all heavily quantized models, generated text may contain factual inaccuracies (e.g., incorrect numbers, dates, or scientific details). Always verify factual claims independently.
146
+
147
+ ## System Requirements
148
+
149
+ - **Storage:** ~4 GiB for model weights + ~50 MB for binaries
150
+ - **RAM:** 6 GiB minimum (8 GiB recommended)
151
+ - **GPU (recommended):** NVIDIA GPU with CUDA 12, Apple Silicon (M1/M2/M3/M4), or any Vulkan-capable GPU
152
+ - **CPU-only:** Supported but significantly slower
153
+ - **OS:** Linux (x86_64), macOS (Apple Silicon), Windows (x86_64), Android (Termux, ARM64)
154
+ - **Not supported:** iOS, 32-bit systems
155
+
156
+ ## Safety and Responsible Use
157
+
158
+ This model inherits the capabilities and limitations of its base model (Meta Llama 3.1 8B Instruct). Like all language models, it can generate incorrect, biased, or harmful content. Users should:
159
+
160
+ - Not rely on this model for factual accuracy without verification
161
+ - Not use this model to generate content that could cause harm
162
+ - Apply appropriate content filtering for any user-facing applications
163
+ - Be aware that 3-bit compression may amplify certain failure modes of the base model
164
+
165
+ ## Derivative Works
166
+
167
+ If you create derivative works, credit **"EVR-1 Maano"** in your model name and documentation. Commercial use is permitted subject to the Llama 3.1 Community License Agreement.
168
+
169
+ ## License
170
+
171
+ Available for personal, research, and commercial use with attribution, subject to upstream license terms. See LICENSE.md for full terms.
172
+
173
+ Built with Llama. This model is a derivative of Meta's Llama 3.1 8B Instruct and is subject to the [Llama 3.1 Community License Agreement](https://www.llama.com/llama3_1/license/) in addition to the Evrmind license.
174
+
175
+ ## Citation
176
+
177
+ ```
178
+ @misc{evrmind2026evr1maano8binstruct,
179
+ title={Evrmind EVR-1 Maano-8b-Instruct: A Custom 3-Bit Compression Method for Coherent On-Device Instruction-Following},
180
+ author={Evrmind},
181
+ year={2026},
182
+ url={https://huggingface.co/evrmind/evr-1-maano-8b-instruct}
183
+ }
184
+ ```
185
+
186
+ ## Contact
187
+
188
+ - Email: hello@evrmind.io
189
+ - Issues: [GitHub](https://github.com/evrmind-uk/evr-llama/issues)
NOTICE.md ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ Llama 3.1 is licensed under the Llama 3.1 Community License, Copyright (c) Meta Platforms, Inc. All Rights Reserved.
2
+
3
+ This software includes binaries built from llama.cpp (https://github.com/ggerganov/llama.cpp), licensed under the MIT License, Copyright (c) 2023-2025 The ggml authors.
README.md ADDED
@@ -0,0 +1,256 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ language:
3
+ - en
4
+ license: other
5
+ license_name: evrmind-free-1.0
6
+ license_link: LICENSE.md
7
+ library_name: llama.cpp
8
+ tags:
9
+ - llama
10
+ - llama-3.1
11
+ - gguf
12
+ - 3-bit
13
+ - quantization
14
+ - evr
15
+ - evrmind
16
+ - text-generation
17
+ - instruct
18
+ - chat
19
+ - on-device
20
+ - maano
21
+ model_name: EVR-1 Maano-8b-Instruct
22
+ base_model: meta-llama/Llama-3.1-8B-Instruct
23
+ pipeline_tag: text-generation
24
+ model_type: llama
25
+ quantized_by: evrmind
26
+ num_parameters: 8030000000
27
+ ---
28
+
29
+ # Evrmind EVR-1 Maano-8b-Instruct
30
+
31
+ Llama 3.1 8B Instruct compressed using EVR-1 (Evrmind Reconstruction), a novel compression method developed independently by Evrmind. The compressed weights average approximately 3 bits per parameter; the total GGUF file (3.93 GiB) includes additional metadata and structure overhead.
32
+
33
+ In our coherence tests (5 continuation-style prompts), EVR-1 Instruct averaged 2.77% repetition (rep4) at 500 tokens and 9.66% at 1000 tokens.
34
+
35
+ **3.93 GiB | Llama 3.1 8B Instruct | Runs on laptops, desktops, and Android (Termux)**
36
+
37
+ HuggingFace may display an incorrect parameter count in the sidebar due to the custom compression format. EVR-1 is not a standard quantization (not Q2, Q3, Q4, etc).
38
+
39
+ ## Setup
40
+
41
+ You need two things: the **model files** (from this HuggingFace repo) and a **platform binary** (from GitHub).
42
+
43
+ **Step 1:** Clone this repo or download the files:
44
+
45
+ ```bash
46
+ # Option A: Clone everything (~4.2 GB, requires git-lfs)
47
+ git lfs install
48
+ git clone https://huggingface.co/evrmind/evr-1-maano-8b-instruct
49
+ cd evr-1-maano-8b-instruct
50
+
51
+ # Option B: Or download individual files from the "Files" tab above
52
+ ```
53
+
54
+ **Step 2:** Download the binary for your platform from the [Downloads](#downloads) table. Save the archive into the `evr-1-maano-8b-instruct` directory, then extract it:
55
+
56
+ ```bash
57
+ # Linux + NVIDIA
58
+ mkdir -p linux-cuda && tar xzf evrmind-linux-cuda.tar.gz -C linux-cuda
59
+
60
+ # Linux + Vulkan
61
+ mkdir -p linux-vulkan && tar xzf evrmind-linux-vulkan.tar.gz -C linux-vulkan
62
+
63
+ # macOS (Apple Silicon)
64
+ mkdir -p metal && tar xzf evrmind-macos-metal.tar.gz -C metal
65
+
66
+ # Android (Termux)
67
+ mkdir -p android-vulkan && tar xzf evrmind-android-vulkan.tar.gz -C android-vulkan
68
+ ```
69
+
70
+ For Windows, extract the `.zip` into a folder with the matching name (e.g., extract `evrmind-windows-cuda.zip` into a folder called `windows-cuda`).
71
+
72
+ After completing both steps, your directory should look like this:
73
+
74
+ ```
75
+ evr-1-maano-8b-instruct/
76
+ evr-llama-3.1-8b-instruct.gguf <-- model weights
77
+ start-server.sh <-- Linux/macOS/Android launcher
78
+ start-server.bat <-- Windows launcher
79
+ webui/ <-- browser interface
80
+ linux-cuda/ <-- extracted platform binary (example)
81
+ llama-server
82
+ llama-cli
83
+ llama-completion
84
+ ...
85
+ ```
86
+
87
+ ## Web UI
88
+
89
+ **Linux, macOS, Android (Termux):**
90
+
91
+ ```bash
92
+ ./start-server.sh
93
+ # Open http://localhost:8080
94
+ ```
95
+
96
+ **Windows:**
97
+
98
+ Double-click `start-server.bat`, or from Command Prompt:
99
+
100
+ ```
101
+ start-server.bat
102
+ ```
103
+
104
+ Then open http://localhost:8080 in your browser.
105
+
106
+ **Network access (phone, tablet, other devices on the same WiFi):**
107
+
108
+ ```bash
109
+ ./start-server.sh --network
110
+ ```
111
+
112
+ The script will print the URL to open on other devices. The model runs on your computer; other devices just connect to the web UI. The `--network` and `--cpu` flags are only available in `start-server.sh` (Linux/macOS/Android).
113
+
114
+ See [WEB_UI.md](WEB_UI.md) for more options and troubleshooting.
115
+
116
+ ## Quick Start (CLI)
117
+
118
+ These examples assume you have completed [Setup](#setup) and are in the repo directory.
119
+
120
+ **Linux + NVIDIA GPU:**
121
+
122
+ ```bash
123
+ cd linux-cuda
124
+ LD_LIBRARY_PATH=. ./llama-cli -m ../evr-llama-3.1-8b-instruct.gguf -ngl 99
125
+ ```
126
+
127
+ **macOS (Apple Silicon):**
128
+
129
+ ```bash
130
+ cd metal
131
+ ./llama-cli -m ../evr-llama-3.1-8b-instruct.gguf -ngl 99
132
+ ```
133
+
134
+ **Linux + Vulkan:**
135
+
136
+ ```bash
137
+ cd linux-vulkan
138
+ LD_LIBRARY_PATH=. ./llama-cli -m ../evr-llama-3.1-8b-instruct.gguf -ngl 99
139
+ ```
140
+
141
+ **Android (Termux):**
142
+
143
+ ```bash
144
+ cd android-vulkan
145
+ LD_LIBRARY_PATH=. ./llama-cli -m ../evr-llama-3.1-8b-instruct.gguf -ngl 99
146
+ ```
147
+
148
+ **Windows + NVIDIA (Command Prompt):**
149
+
150
+ ```cmd
151
+ cd windows-cuda
152
+ llama-cli.exe -m ..\evr-llama-3.1-8b-instruct.gguf -ngl 99
153
+ ```
154
+
155
+ **Windows + Vulkan (Command Prompt):**
156
+
157
+ ```cmd
158
+ cd windows-vulkan
159
+ llama-cli.exe -m ..\evr-llama-3.1-8b-instruct.gguf -ngl 99
160
+ ```
161
+
162
+ **CPU-only (no GPU):**
163
+
164
+ Use `-ngl 0` instead of `-ngl 99` on any platform. Roughly 5-10x slower but works on any machine.
165
+
166
+ ## Downloads
167
+
168
+ | Platform | Download | GPU |
169
+ |----------|----------|-----|
170
+ | Linux + NVIDIA | [evrmind-linux-cuda.tar.gz](https://github.com/evrmind-uk/evr-llama/releases/download/v1.0.0/evrmind-linux-cuda.tar.gz) | CUDA 12 |
171
+ | Linux + Any GPU | [evrmind-linux-vulkan.tar.gz](https://github.com/evrmind-uk/evr-llama/releases/download/v1.0.0/evrmind-linux-vulkan.tar.gz) | Vulkan |
172
+ | Windows + NVIDIA | [evrmind-windows-cuda.zip](https://github.com/evrmind-uk/evr-llama/releases/download/v1.0.0/evrmind-windows-cuda.zip) | CUDA 12 |
173
+ | Windows + Any GPU | [evrmind-windows-vulkan.zip](https://github.com/evrmind-uk/evr-llama/releases/download/v1.0.0/evrmind-windows-vulkan.zip) | Vulkan |
174
+ | macOS (Apple Silicon) | [evrmind-macos-metal.tar.gz](https://github.com/evrmind-uk/evr-llama/releases/download/v1.0.0/evrmind-macos-metal.tar.gz) | Apple Silicon |
175
+ | Android (Termux) | [evrmind-android-vulkan.tar.gz](https://github.com/evrmind-uk/evr-llama/releases/download/v1.0.0/evrmind-android-vulkan.tar.gz) | Vulkan |
176
+
177
+ The model weights (`evr-llama-3.1-8b-instruct.gguf`, ~4.2 GB) are available from the **Files** tab on this HuggingFace page. Platform binaries are hosted on [GitHub Releases](https://github.com/evrmind-uk/evr-llama/releases/tag/v1.0.0). You can verify downloads with [SHA256SUMS.txt](SHA256SUMS.txt).
178
+
179
+ > **Note:** The binaries are the same for all EVR-1 models. You only need to download them once. Just point them at whichever GGUF you want to run.
180
+
181
+ ## Why EVR-1 Maano-8b-Instruct?
182
+
183
+ Standard quantizations at 3-4 GiB can produce repetition during extended generation. In our tests (5 continuation-style prompts), EVR-1 Maano-8b-Instruct maintained coherent output with an average repetition rate of 2.77% (rep4) at 500 tokens and 9.66% at 1000 tokens.
184
+
185
+ **EVR-1 Maano-8b-Instruct (3.93 GiB):**
186
+ > User: "What are the main causes of the French Revolution?"
187
+ >
188
+ > "The French Revolution, which lasted from 1789 to 1799, was a complex event with multiple causes. However, some of the main contributing factors include: 1. Financial Crisis: France was deeply in debt from its involvement in the American Revolutionary War... 2. Social Inequality: The French nobility held a significant amount of power... 3. Enlightenment Ideas: The ideas presented by Enlightenment thinkers such as Rousseau, Voltaire..." *(continues coherently for 500+ words)*
189
+
190
+ ## Benchmarks
191
+
192
+ ### Coherence (lower is better)
193
+
194
+ Average 4-gram repetition rate (lower = better), 5 continuation-style prompts:
195
+
196
+ | Model | Size | rep4 @ 500 | rep4 @ 1000 |
197
+ |-------|------|-----------|-------------|
198
+ | **EVR-1 Instruct** | **3.93 GiB** | **2.77%** | **9.66%** |
199
+
200
+ ### Perplexity
201
+
202
+ | Model | Size | Perplexity (wikitext-2, ctx=512) |
203
+ |-------|------|--------------------------------|
204
+ | **EVR-1 Instruct** | **3.93 GiB** | **7.37** |
205
+
206
+ ### Accuracy (EVR-1 base model reference numbers)
207
+
208
+ | Benchmark | EVR-1 Base (3.93 GiB) | Q3_K_M (3.83 GiB) | Q4_K_M (4.69 GiB) |
209
+ |-----------|----------------------|--------------------|-------|
210
+ | ARC-Challenge (25-shot, 1172q) | 59.8% | 60.8% | 61.3% |
211
+ | Perplexity (wikitext-2, ctx=512) | 6.70 | 7.02 | 6.58 |
212
+
213
+ *Coherence tested with 5 continuation-style prompts at 500 and 1000 tokens each, temperature 0, no repeat penalty. Accuracy numbers above are from the [EVR-1 base model](https://huggingface.co/evrmind/evr-1-maano-8b), shown here for reference. See [BENCHMARK_RESULTS.md](BENCHMARK_RESULTS.md) for full coherence results and sample outputs.*
214
+
215
+ ## Limitations
216
+
217
+ - Context window has been tested up to 2048 tokens. Longer contexts may work but have not been validated at 3-bit compression.
218
+ - Occasional minor character-level artefacts due to 3-bit compression.
219
+ - Math reasoning is limited at this compression level.
220
+ - As with all heavily quantized models, generated text may contain factual inaccuracies (e.g., incorrect numbers, dates, or scientific details). Always verify factual claims independently.
221
+
222
+ ## System Requirements
223
+
224
+ - **Storage:** ~4 GiB for model weights + ~50 MB for binaries
225
+ - **RAM:** 6 GiB minimum (8 GiB recommended)
226
+ - **GPU (recommended):** NVIDIA (CUDA 12), Apple Silicon, or any Vulkan GPU
227
+ - **CPU-only:** Supported but slower (use `-ngl 0` or `--cpu` flag)
228
+ - **OS:** Linux, macOS (Apple Silicon), Windows, Android (Termux)
229
+ - **Not supported:** iOS, 32-bit systems
230
+
231
+ ## Safety and Responsible Use
232
+
233
+ This model can generate incorrect, biased, or harmful content. Users should apply appropriate content filtering for user-facing applications. See [MODEL_CARD.md](MODEL_CARD.md) for details.
234
+
235
+ ## Derivative Works
236
+
237
+ If you create derivative works, credit **"EVR-1 Maano"** in your model name and documentation. Commercial use is permitted subject to the Llama 3.1 Community License Agreement.
238
+
239
+ ## License
240
+
241
+ This model is dual-licensed:
242
+
243
+ 1. **[Evrmind Free License 1.0](LICENSE.md)**: Covers the EVR-1 compression and distribution. Permits personal, research, and commercial use with attribution.
244
+ 2. **[Llama 3.1 Community License](META_LLAMA_LICENSE.md)**: Covers the underlying Llama 3.1 weights. Permits commercial use for entities with fewer than 700 million monthly active users.
245
+
246
+ Both licenses apply. See [LICENSE.md](LICENSE.md) and [META_LLAMA_LICENSE.md](META_LLAMA_LICENSE.md) for full terms.
247
+
248
+ ## Also Available
249
+
250
+ - **[EVR-1 Maano-8b](https://huggingface.co/evrmind/evr-1-maano-8b)**, base model for text completion
251
+ - **[EVR-1 Bafethu-8b-Reasoning](https://huggingface.co/evrmind/evr-1-bafethu-8b-reasoning)**, reasoning model (DeepSeek R1)
252
+
253
+ ## Contact
254
+
255
+ - Email: hello@evrmind.io
256
+ - Issues: [GitHub](https://github.com/evrmind-uk/evr-llama/issues)
SHA256SUMS.txt ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ 2b7c0199480b317ac83056f1a43182e2f11c40bef3dc55a6d33fc1058466d487 evr-llama-3.1-8b-instruct.gguf
2
+ a5eb826bd63079130342c1489c19da6376d3ce556a56ab198048d142c556d515 evrmind-linux-cuda.tar.gz
3
+ ec18cedaee09f9892b2bd81bdf5d886ac48bdc2be5ddae9c5eb9e99b0dfee13d evrmind-linux-vulkan.tar.gz
4
+ 56ac979b87d59d6a62861417ee5734568ebc3f85760c6259b6724218b23ad69a evrmind-macos-metal.tar.gz
5
+ 05550016b1e56e04df7b10ef3f509b7657b06381e2cb8e500772a5139ca45af0 evrmind-windows-cuda.zip
6
+ cdfd5f4d0b071a77cdd3a3862cb2ac01611fa34964a570e55b2a9ed5975ef8b3 evrmind-windows-vulkan.zip
7
+ 0f6961c18e018cc2af7088566ccb9b874ca06057a51110e07541388ebf8a7c1e evrmind-android-vulkan.tar.gz
WEB_UI.md ADDED
@@ -0,0 +1,92 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Web UI
2
+
3
+ ## Start
4
+
5
+ ```bash
6
+ ./start-server.sh
7
+ ```
8
+
9
+ Opens the web interface at **http://localhost:8080**.
10
+
11
+ ## Network Mode
12
+
13
+ Access the web UI from your phone's browser or any device on the same WiFi (the model runs on your computer, your phone is just the display):
14
+
15
+ ```bash
16
+ ./start-server.sh --network
17
+ ```
18
+
19
+ The script will print the URL to open on other devices.
20
+
21
+ ## Options
22
+
23
+ These flags work with `start-server.sh` (Linux, macOS, Android):
24
+
25
+ | Flag | Description |
26
+ |------|------------|
27
+ | `--network` | Bind to all interfaces (allows LAN access) |
28
+ | `--port=N` | Use a different port (default: 8080) |
29
+ | `--cpu` | CPU-only mode (no GPU offload) |
30
+
31
+ ## Windows
32
+
33
+ Double-click `start-server.bat` or run from Command Prompt:
34
+
35
+ ```
36
+ start-server.bat
37
+ ```
38
+
39
+ Uses the CUDA build if available, otherwise falls back to Vulkan. The `.bat` script uses the default settings (localhost, port 8080, GPU enabled). To change these, use the Manual Start section below.
40
+
41
+ ## Manual Start
42
+
43
+ If you prefer to start the server directly:
44
+
45
+ ```bash
46
+ # Linux (CUDA)
47
+ cd linux-cuda
48
+ LD_LIBRARY_PATH=. ./llama-server -m ../evr-llama-3.1-8b-instruct.gguf -ngl 99 --port 8080 --path ../webui
49
+
50
+ # Linux (Vulkan)
51
+ cd linux-vulkan
52
+ LD_LIBRARY_PATH=. ./llama-server -m ../evr-llama-3.1-8b-instruct.gguf -ngl 99 --port 8080 --path ../webui
53
+
54
+ # macOS (Apple Silicon)
55
+ cd metal
56
+ ./llama-server -m ../evr-llama-3.1-8b-instruct.gguf -ngl 99 --port 8080 --path ../webui
57
+
58
+ # Windows (CUDA)
59
+ cd windows-cuda
60
+ llama-server.exe -m ..\evr-llama-3.1-8b-instruct.gguf -ngl 99 --port 8080 --path ..\webui
61
+
62
+ # Windows (Vulkan)
63
+ cd windows-vulkan
64
+ llama-server.exe -m ..\evr-llama-3.1-8b-instruct.gguf -ngl 99 --port 8080 --path ..\webui
65
+ ```
66
+
67
+ ## API
68
+
69
+ The server exposes an OpenAI-compatible API:
70
+
71
+ ```bash
72
+ # Chat completion
73
+ curl http://localhost:8080/v1/chat/completions \
74
+ -H "Content-Type: application/json" \
75
+ -d '{"messages":[{"role":"user","content":"Hello"}],"stream":false}'
76
+
77
+ # Text completion
78
+ curl http://localhost:8080/v1/completions \
79
+ -H "Content-Type: application/json" \
80
+ -d '{"prompt":"The main causes of","max_tokens":200,"stream":false}'
81
+
82
+ # Health check
83
+ curl http://localhost:8080/health
84
+ ```
85
+
86
+ ## Troubleshooting
87
+
88
+ **Server won't start:** Make sure no other process is using port 8080. Try `--port=8081`.
89
+
90
+ **Slow generation:** Ensure GPU offload is working (`-ngl 99`). Check that CUDA/Vulkan drivers are installed.
91
+
92
+ **Can't access from phone:** Use `--network` flag. Make sure both devices are on the same WiFi network. Check firewall settings.
evr-llama-3.1-8b-instruct.gguf ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:2b7c0199480b317ac83056f1a43182e2f11c40bef3dc55a6d33fc1058466d487
3
+ size 4218958528
evrmind-android-vulkan.tar.gz ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:0f6961c18e018cc2af7088566ccb9b874ca06057a51110e07541388ebf8a7c1e
3
+ size 70494847
evrmind-linux-cuda.tar.gz ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:a5eb826bd63079130342c1489c19da6376d3ce556a56ab198048d142c556d515
3
+ size 78250511
evrmind-linux-vulkan.tar.gz ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:ec18cedaee09f9892b2bd81bdf5d886ac48bdc2be5ddae9c5eb9e99b0dfee13d
3
+ size 52432127
evrmind-macos-metal.tar.gz ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:56ac979b87d59d6a62861417ee5734568ebc3f85760c6259b6724218b23ad69a
3
+ size 11445308
evrmind-windows-cuda.zip ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:05550016b1e56e04df7b10ef3f509b7657b06381e2cb8e500772a5139ca45af0
3
+ size 160354995
evrmind-windows-vulkan.zip ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:cdfd5f4d0b071a77cdd3a3862cb2ac01611fa34964a570e55b2a9ed5975ef8b3
3
+ size 19237385
start-server.bat ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ @echo off
2
+ setlocal enabledelayedexpansion
3
+ title Evrmind
4
+
5
+ :: Find model file
6
+ set "MODEL="
7
+ for %%f in ("%~dp0*.gguf") do (
8
+ set "MODEL=%%f"
9
+ goto :found_model
10
+ )
11
+ echo Error: No .gguf model file found in %~dp0
12
+ echo Place your model file (e.g. evr-llama-3.1-8b-instruct.gguf) in this directory.
13
+ pause
14
+ exit /b 1
15
+
16
+ :found_model
17
+
18
+ :: Find server binary (prefer CUDA, fallback to Vulkan)
19
+ set "BIN_DIR="
20
+ if exist "%~dp0windows-cuda\llama-server.exe" (
21
+ set "BIN_DIR=%~dp0windows-cuda"
22
+ ) else if exist "%~dp0windows-vulkan\llama-server.exe" (
23
+ set "BIN_DIR=%~dp0windows-vulkan"
24
+ ) else (
25
+ echo Error: No llama-server.exe found.
26
+ echo Expected in: windows-cuda\ or windows-vulkan\
27
+ echo.
28
+ echo Download from: https://github.com/evrmind-uk/evr-llama/releases/tag/v1.0.0
29
+ echo Then extract into the matching folder name, e.g.:
30
+ echo Extract evrmind-windows-cuda.zip into a folder called windows-cuda
31
+ pause
32
+ exit /b 1
33
+ )
34
+
35
+ set "PATH=%BIN_DIR%;%PATH%"
36
+
37
+ echo.
38
+ echo ========================================
39
+ echo E V R M I N D
40
+ echo ========================================
41
+ echo.
42
+ echo Model: %MODEL%
43
+ echo Server: http://localhost:8080
44
+ echo.
45
+ echo Starting server...
46
+
47
+ start /b "" "%BIN_DIR%\llama-server" -m "%MODEL%" -ngl 99 --host 127.0.0.1 --port 8080 --path "%~dp0webui"
48
+
49
+ :: Wait for server (timeout after 60 seconds)
50
+ set "WAIT_COUNT=0"
51
+ :wait_loop
52
+ timeout /t 1 /nobreak >nul
53
+ curl -sf http://127.0.0.1:8080/health >nul 2>&1
54
+ if %errorlevel% equ 0 goto :server_ready
55
+ set /a WAIT_COUNT+=1
56
+ if %WAIT_COUNT% geq 60 (
57
+ echo Error: Server did not start within 60 seconds.
58
+ echo Check that your GPU is supported and drivers are up to date.
59
+ taskkill /f /im llama-server.exe >nul 2>&1
60
+ pause
61
+ exit /b 1
62
+ )
63
+ goto :wait_loop
64
+
65
+ :server_ready
66
+ echo Server ready!
67
+ echo.
68
+ echo Open in your browser:
69
+ echo http://localhost:8080
70
+ echo.
71
+ echo Press any key to stop the server...
72
+ pause >nul
73
+
74
+ :: Kill server
75
+ taskkill /f /im llama-server.exe >nul 2>&1
start-server.sh ADDED
@@ -0,0 +1,128 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env bash
2
+ # Evrmind: Start the local AI server with web UI
3
+ set -e
4
+
5
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
6
+ PORT=8080
7
+ HOST="127.0.0.1"
8
+ NGL=99
9
+
10
+ # Parse flags
11
+ for arg in "$@"; do
12
+ case "$arg" in
13
+ --network) HOST="0.0.0.0" ;;
14
+ --port=*) PORT="${arg#*=}" ;;
15
+ --cpu) NGL=0 ;;
16
+ *) ;;
17
+ esac
18
+ done
19
+
20
+ # Find model file
21
+ MODEL=""
22
+ for f in "$SCRIPT_DIR"/*.gguf; do
23
+ [ -f "$f" ] && MODEL="$f" && break
24
+ done
25
+
26
+ if [ -z "$MODEL" ]; then
27
+ echo "Error: No .gguf model file found in $SCRIPT_DIR"
28
+ echo "Place your model file (e.g. evr-llama-3.1-8b-instruct.gguf) in this directory."
29
+ exit 1
30
+ fi
31
+
32
+ # Detect platform
33
+ BIN_DIR=""
34
+ if [ -d "$SCRIPT_DIR/linux-cuda" ] && [ -f "$SCRIPT_DIR/linux-cuda/llama-server" ]; then
35
+ BIN_DIR="$SCRIPT_DIR/linux-cuda"
36
+ elif [ -d "$SCRIPT_DIR/linux-vulkan" ] && [ -f "$SCRIPT_DIR/linux-vulkan/llama-server" ]; then
37
+ BIN_DIR="$SCRIPT_DIR/linux-vulkan"
38
+ elif [ -d "$SCRIPT_DIR/metal" ] && [ -f "$SCRIPT_DIR/metal/llama-server" ]; then
39
+ BIN_DIR="$SCRIPT_DIR/metal"
40
+ elif [ -d "$SCRIPT_DIR/android-vulkan" ] && [ -f "$SCRIPT_DIR/android-vulkan/llama-server" ]; then
41
+ BIN_DIR="$SCRIPT_DIR/android-vulkan"
42
+ else
43
+ echo "Error: No llama-server binary found."
44
+ echo "Expected in one of: linux-cuda/, linux-vulkan/, metal/, android-vulkan/"
45
+ echo ""
46
+ echo "Download a platform binary from:"
47
+ echo " https://github.com/evrmind-uk/evr-llama/releases/tag/v1.0.0"
48
+ echo ""
49
+ echo "Then extract it into the matching directory name, e.g.:"
50
+ echo " mkdir -p linux-cuda && tar xzf evrmind-linux-cuda.tar.gz -C linux-cuda"
51
+ exit 1
52
+ fi
53
+
54
+ SERVER="$BIN_DIR/llama-server"
55
+
56
+ # Set library path
57
+ if [[ "$OSTYPE" == "darwin"* ]]; then
58
+ export DYLD_LIBRARY_PATH="$BIN_DIR:${DYLD_LIBRARY_PATH:-}"
59
+ else
60
+ export LD_LIBRARY_PATH="$BIN_DIR:${LD_LIBRARY_PATH:-}"
61
+ fi
62
+
63
+ # Clean shutdown
64
+ cleanup() {
65
+ echo ""
66
+ echo "Shutting down..."
67
+ kill "$SERVER_PID" 2>/dev/null
68
+ wait "$SERVER_PID" 2>/dev/null
69
+ exit 0
70
+ }
71
+ trap cleanup INT TERM
72
+
73
+ # Start server
74
+ echo ""
75
+ echo " ╔═══════════════════════════════════════╗"
76
+ echo " ║ E V R M I N D ║"
77
+ echo " ╚═══════════════════════════════════════╝"
78
+ echo ""
79
+ echo " Model: $(basename "$MODEL")"
80
+ echo " Server: $HOST:$PORT"
81
+ echo " GPU: $( [ "$NGL" -gt 0 ] && echo "Yes (-ngl $NGL)" || echo "CPU only" )"
82
+ echo ""
83
+
84
+ "$SERVER" \
85
+ -m "$MODEL" \
86
+ -ngl "$NGL" \
87
+ --host "$HOST" \
88
+ --port "$PORT" \
89
+ --path "$SCRIPT_DIR/webui" \
90
+ 2>&1 &
91
+
92
+ SERVER_PID=$!
93
+
94
+ # Wait for server to be ready
95
+ echo -n " Starting server..."
96
+ for i in $(seq 1 120); do
97
+ if ! kill -0 "$SERVER_PID" 2>/dev/null; then
98
+ echo " FAILED (server exited)"
99
+ exit 1
100
+ fi
101
+ if curl -sf "http://127.0.0.1:$PORT/health" > /dev/null 2>&1; then
102
+ echo " ready!"
103
+ echo ""
104
+ if [ "$HOST" = "0.0.0.0" ]; then
105
+ LOCAL_IP=$(hostname -I 2>/dev/null | awk '{print $1}')
106
+ echo " Open in your browser:"
107
+ echo " Local: http://localhost:$PORT"
108
+ echo " Network: http://$LOCAL_IP:$PORT"
109
+ echo ""
110
+ echo " Access from your phone on the same WiFi:"
111
+ echo " http://$LOCAL_IP:$PORT"
112
+ else
113
+ echo " Open in your browser:"
114
+ echo " http://localhost:$PORT"
115
+ fi
116
+ echo ""
117
+ echo " Press Ctrl+C to stop."
118
+ echo ""
119
+ wait "$SERVER_PID"
120
+ exit 0
121
+ fi
122
+ sleep 1
123
+ [ $((i % 10)) -eq 0 ] && echo -n "."
124
+ done
125
+
126
+ echo " TIMEOUT (server did not start in 120s)"
127
+ kill "$SERVER_PID" 2>/dev/null
128
+ exit 1
webui/index.html ADDED
@@ -0,0 +1,1147 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Evrmind</title>
7
+ <style>
8
+ *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
9
+
10
+ :root {
11
+ --bg: #0b0b10;
12
+ --surface: #131318;
13
+ --surface-2: #1a1a22;
14
+ --border: #252530;
15
+ --text: #e8e8e8;
16
+ --text-muted: #777;
17
+ --accent: #4ade80;
18
+ --accent-dim: #22543d;
19
+ --user-bg: #1a2420;
20
+ --ai-bg: #131318;
21
+ --think-bg: #16161e;
22
+ --think-border: #2d2d3a;
23
+ }
24
+
25
+ html, body {
26
+ height: 100%;
27
+ background: var(--bg);
28
+ background-image:
29
+ radial-gradient(ellipse 60% 50% at 20% 50%, rgba(100, 60, 160, 0.18) 0%, transparent 70%),
30
+ radial-gradient(ellipse 50% 60% at 80% 60%, rgba(50, 160, 100, 0.14) 0%, transparent 70%);
31
+ color: var(--text);
32
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Inter', sans-serif;
33
+ font-size: 15px;
34
+ line-height: 1.6;
35
+ overflow: hidden;
36
+ }
37
+
38
+ #app {
39
+ display: flex;
40
+ flex-direction: column;
41
+ height: 100vh;
42
+ width: 100%;
43
+ }
44
+
45
+ /* Header */
46
+ .header-wrap {
47
+ border-bottom: 1px solid var(--border);
48
+ flex-shrink: 0;
49
+ }
50
+ header {
51
+ display: flex;
52
+ align-items: center;
53
+ justify-content: space-between;
54
+ padding: 14px 20px;
55
+ }
56
+
57
+ /* Full-width wrappers for borders */
58
+ .input-wrap {
59
+ border-top: 1px solid var(--border);
60
+ flex-shrink: 0;
61
+ }
62
+ .status-wrap {
63
+ border-top: 1px solid var(--border);
64
+ flex-shrink: 0;
65
+ }
66
+
67
+ .logo img {
68
+ height: 20px;
69
+ width: auto;
70
+ display: block;
71
+ }
72
+
73
+ .welcome-logo img {
74
+ height: 32px;
75
+ width: auto;
76
+ }
77
+
78
+ .header-right {
79
+ display: flex;
80
+ align-items: center;
81
+ gap: 12px;
82
+ }
83
+
84
+ #model-name {
85
+ font-size: 12px;
86
+ color: var(--text-muted);
87
+ font-weight: 400;
88
+ }
89
+
90
+ .settings-btn {
91
+ background: none;
92
+ border: 1px solid var(--border);
93
+ color: var(--text-muted);
94
+ width: 32px;
95
+ height: 32px;
96
+ border-radius: 6px;
97
+ cursor: pointer;
98
+ display: flex;
99
+ align-items: center;
100
+ justify-content: center;
101
+ font-size: 16px;
102
+ transition: border-color 0.2s;
103
+ }
104
+ .settings-btn:hover { border-color: var(--text-muted); }
105
+
106
+ /* Messages */
107
+ #messages {
108
+ flex: 1;
109
+ overflow-y: auto;
110
+ padding: 20px calc(50% - 430px);
111
+ display: flex;
112
+ flex-direction: column;
113
+ gap: 16px;
114
+ scrollbar-width: thin;
115
+ scrollbar-color: var(--border) transparent;
116
+ }
117
+
118
+ @media (max-width: 920px) {
119
+ #messages { padding: 20px 20px; }
120
+ #input-area { padding: 16px 20px; }
121
+ #status-bar { padding: 8px 20px; }
122
+ #file-preview { padding: 0 20px; }
123
+ }
124
+
125
+ #messages::-webkit-scrollbar { width: 6px; }
126
+ #messages::-webkit-scrollbar-track { background: transparent; }
127
+ #messages::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; }
128
+
129
+ .msg {
130
+ max-width: 85%;
131
+ padding: 12px 16px;
132
+ border-radius: 12px;
133
+ font-size: 14.5px;
134
+ line-height: 1.65;
135
+ word-wrap: break-word;
136
+ }
137
+
138
+ .msg-user {
139
+ align-self: flex-end;
140
+ background: var(--user-bg);
141
+ border: 1px solid #253a29;
142
+ color: var(--text);
143
+ }
144
+
145
+ .msg-ai {
146
+ align-self: flex-start;
147
+ background: var(--ai-bg);
148
+ border: 1px solid var(--border);
149
+ }
150
+
151
+ .msg-label {
152
+ font-size: 11px;
153
+ font-weight: 500;
154
+ letter-spacing: 0.5px;
155
+ margin-bottom: 4px;
156
+ text-transform: uppercase;
157
+ }
158
+
159
+ .msg-user .msg-label { color: var(--accent); }
160
+ .msg-ai .msg-label { color: var(--text-muted); }
161
+
162
+ .msg-body p { margin-bottom: 8px; }
163
+ .msg-body p:last-child { margin-bottom: 0; }
164
+ .msg-body strong { font-weight: 600; }
165
+ .msg-body em { font-style: italic; }
166
+
167
+ .msg-body code {
168
+ background: #1e1e26;
169
+ padding: 2px 5px;
170
+ border-radius: 4px;
171
+ font-family: 'SF Mono', 'Fira Code', 'Consolas', monospace;
172
+ font-size: 13px;
173
+ }
174
+
175
+ .msg-body pre {
176
+ background: #111118;
177
+ border: 1px solid var(--border);
178
+ border-radius: 8px;
179
+ padding: 12px;
180
+ overflow-x: auto;
181
+ margin: 8px 0;
182
+ }
183
+
184
+ .msg-body pre code {
185
+ background: none;
186
+ padding: 0;
187
+ font-size: 13px;
188
+ }
189
+
190
+ .msg-body ol, .msg-body ul {
191
+ margin: 6px 0;
192
+ padding-left: 20px;
193
+ }
194
+
195
+ .msg-body li { margin-bottom: 4px; }
196
+
197
+ .think-block {
198
+ background: var(--think-bg);
199
+ border-left: 2px solid var(--think-border);
200
+ margin: 6px 0;
201
+ border-radius: 0 6px 6px 0;
202
+ font-size: 13px;
203
+ color: var(--text-muted);
204
+ font-style: italic;
205
+ }
206
+
207
+ .think-toggle {
208
+ display: flex;
209
+ align-items: center;
210
+ gap: 6px;
211
+ padding: 8px 12px;
212
+ cursor: pointer;
213
+ user-select: none;
214
+ }
215
+
216
+ .think-toggle:hover { background: rgba(255,255,255,0.03); }
217
+
218
+ .think-arrow {
219
+ display: inline-block;
220
+ font-size: 10px;
221
+ transition: transform 0.2s;
222
+ color: #555;
223
+ }
224
+
225
+ .think-block.open .think-arrow { transform: rotate(90deg); }
226
+
227
+ .think-label {
228
+ font-size: 10px;
229
+ text-transform: uppercase;
230
+ letter-spacing: 1px;
231
+ color: #555;
232
+ }
233
+
234
+ .think-content {
235
+ display: none;
236
+ padding: 0 12px 8px 12px;
237
+ }
238
+
239
+ .think-block.open .think-content { display: block; }
240
+
241
+ .cursor {
242
+ display: inline-block;
243
+ width: 7px;
244
+ height: 16px;
245
+ background: var(--accent);
246
+ margin-left: 2px;
247
+ vertical-align: middle;
248
+ animation: blink 0.8s step-end infinite;
249
+ }
250
+
251
+ @keyframes blink { 50% { opacity: 0; } }
252
+
253
+ /* Input */
254
+ #input-area {
255
+ padding: 16px calc(50% - 430px);
256
+ }
257
+
258
+ #input-row {
259
+ display: flex;
260
+ gap: 10px;
261
+ align-items: flex-end;
262
+ }
263
+
264
+ #user-input {
265
+ flex: 1;
266
+ background: var(--surface-2);
267
+ border: 1px solid var(--border);
268
+ color: var(--text);
269
+ padding: 12px 16px;
270
+ border-radius: 10px;
271
+ font-size: 14.5px;
272
+ font-family: inherit;
273
+ line-height: 1.5;
274
+ resize: none;
275
+ min-height: 44px;
276
+ max-height: 160px;
277
+ outline: none;
278
+ transition: border-color 0.2s;
279
+ }
280
+
281
+ #user-input:focus { border-color: var(--accent-dim); }
282
+ #user-input::placeholder { color: #555; }
283
+
284
+ #send-btn {
285
+ background: var(--accent);
286
+ border: none;
287
+ color: #0a0a0f;
288
+ width: 44px;
289
+ height: 44px;
290
+ border-radius: 10px;
291
+ cursor: pointer;
292
+ display: flex;
293
+ align-items: center;
294
+ justify-content: center;
295
+ font-size: 18px;
296
+ font-weight: 700;
297
+ flex-shrink: 0;
298
+ transition: opacity 0.2s;
299
+ }
300
+
301
+ #send-btn:hover { opacity: 0.85; }
302
+ #send-btn:disabled { opacity: 0.3; cursor: not-allowed; }
303
+
304
+ /* Status bar */
305
+ #status-bar {
306
+ padding: 8px calc(50% - 430px);
307
+ display: flex;
308
+ justify-content: space-between;
309
+ font-size: 11px;
310
+ color: var(--text-muted);
311
+ }
312
+
313
+ #status-dot {
314
+ display: inline-block;
315
+ width: 6px;
316
+ height: 6px;
317
+ border-radius: 50%;
318
+ background: #555;
319
+ margin-right: 6px;
320
+ vertical-align: middle;
321
+ }
322
+
323
+ #status-dot.connected { background: var(--accent); }
324
+ #status-dot.error { background: #ef4444; }
325
+
326
+ /* Settings panel */
327
+ #settings-panel {
328
+ display: none;
329
+ position: fixed;
330
+ top: 0; right: 0; bottom: 0;
331
+ width: 320px;
332
+ background: var(--surface);
333
+ border-left: 1px solid var(--border);
334
+ padding: 20px;
335
+ z-index: 100;
336
+ overflow-y: auto;
337
+ }
338
+
339
+ #settings-panel.open { display: block; }
340
+
341
+ #settings-panel h3 {
342
+ font-size: 14px;
343
+ font-weight: 500;
344
+ letter-spacing: 1px;
345
+ margin-bottom: 20px;
346
+ text-transform: uppercase;
347
+ color: var(--text-muted);
348
+ }
349
+
350
+ .setting-group {
351
+ margin-bottom: 18px;
352
+ }
353
+
354
+ .setting-group label {
355
+ display: block;
356
+ font-size: 12px;
357
+ color: var(--text-muted);
358
+ margin-bottom: 6px;
359
+ }
360
+
361
+ .setting-group input, .setting-group textarea {
362
+ width: 100%;
363
+ background: var(--surface-2);
364
+ border: 1px solid var(--border);
365
+ color: var(--text);
366
+ padding: 8px 10px;
367
+ border-radius: 6px;
368
+ font-family: inherit;
369
+ font-size: 13px;
370
+ outline: none;
371
+ }
372
+
373
+ .setting-group textarea {
374
+ min-height: 80px;
375
+ resize: vertical;
376
+ }
377
+
378
+ .setting-group input[type="range"] {
379
+ padding: 0;
380
+ -webkit-appearance: none;
381
+ height: 4px;
382
+ border-radius: 2px;
383
+ background: var(--border);
384
+ border: none;
385
+ }
386
+
387
+ .setting-group input[type="range"]::-webkit-slider-thumb {
388
+ -webkit-appearance: none;
389
+ width: 14px;
390
+ height: 14px;
391
+ border-radius: 50%;
392
+ background: var(--accent);
393
+ cursor: pointer;
394
+ }
395
+
396
+ .setting-val {
397
+ font-size: 12px;
398
+ color: var(--accent);
399
+ float: right;
400
+ }
401
+
402
+ .presets {
403
+ display: flex;
404
+ gap: 6px;
405
+ margin-bottom: 18px;
406
+ }
407
+
408
+ .preset-btn {
409
+ flex: 1;
410
+ background: var(--surface-2);
411
+ border: 1px solid var(--border);
412
+ color: var(--text-muted);
413
+ padding: 6px 0;
414
+ border-radius: 6px;
415
+ font-size: 11px;
416
+ font-family: inherit;
417
+ cursor: pointer;
418
+ transition: all 0.2s;
419
+ }
420
+ .preset-btn:hover { border-color: var(--text-muted); color: var(--text); }
421
+ .preset-btn.active { border-color: var(--accent); color: var(--accent); }
422
+
423
+ .setting-group input[type="number"] {
424
+ width: 80px;
425
+ padding: 6px 8px;
426
+ -moz-appearance: textfield;
427
+ }
428
+ .setting-group input[type="number"]::-webkit-inner-spin-button { -webkit-appearance: none; }
429
+
430
+ .setting-divider {
431
+ border: none;
432
+ border-top: 1px solid var(--border);
433
+ margin: 20px 0;
434
+ }
435
+
436
+ #settings-overlay {
437
+ display: none;
438
+ position: fixed;
439
+ top: 0; left: 0; right: 0; bottom: 0;
440
+ background: rgba(0,0,0,0.5);
441
+ z-index: 99;
442
+ }
443
+
444
+ #settings-overlay.open { display: block; }
445
+
446
+ /* Welcome */
447
+ .welcome {
448
+ flex: 1;
449
+ display: flex;
450
+ align-items: center;
451
+ justify-content: center;
452
+ flex-direction: column;
453
+ gap: 12px;
454
+ color: var(--text-muted);
455
+ }
456
+
457
+ .welcome-sub {
458
+ font-size: 13px;
459
+ }
460
+
461
+ /* File attachment */
462
+ .attach-btn {
463
+ background: none;
464
+ border: 1px solid var(--border);
465
+ color: var(--text-muted);
466
+ width: 44px;
467
+ height: 44px;
468
+ border-radius: 10px;
469
+ cursor: pointer;
470
+ display: flex;
471
+ align-items: center;
472
+ justify-content: center;
473
+ font-size: 20px;
474
+ flex-shrink: 0;
475
+ transition: border-color 0.2s;
476
+ }
477
+ .attach-btn:hover { border-color: var(--text-muted); }
478
+
479
+ #file-preview {
480
+ display: none;
481
+ padding: 0 calc(50% - 430px);
482
+ }
483
+
484
+ .file-chip {
485
+ display: inline-flex;
486
+ align-items: center;
487
+ gap: 6px;
488
+ background: var(--surface-2);
489
+ border: 1px solid var(--border);
490
+ border-radius: 6px;
491
+ padding: 4px 10px;
492
+ font-size: 12px;
493
+ color: var(--text-muted);
494
+ }
495
+
496
+ .file-chip-icon { font-size: 14px; }
497
+
498
+ .file-chip-remove {
499
+ background: none;
500
+ border: none;
501
+ color: var(--text-muted);
502
+ cursor: pointer;
503
+ font-size: 14px;
504
+ padding: 0 0 0 4px;
505
+ line-height: 1;
506
+ }
507
+ .file-chip-remove:hover { color: #ef4444; }
508
+
509
+ .file-spinner {
510
+ display: inline-block;
511
+ width: 12px;
512
+ height: 12px;
513
+ border: 2px solid var(--border);
514
+ border-top-color: var(--accent);
515
+ border-radius: 50%;
516
+ animation: spin 0.6s linear infinite;
517
+ }
518
+ @keyframes spin { to { transform: rotate(360deg); } }
519
+
520
+ .file-chip.loading {
521
+ animation: pulse 1.2s ease-in-out infinite;
522
+ border-color: var(--accent-dim);
523
+ }
524
+ @keyframes pulse {
525
+ 0%, 100% { opacity: 0.5; }
526
+ 50% { opacity: 1; }
527
+ }
528
+
529
+ .file-loading-msg {
530
+ display: flex;
531
+ align-items: center;
532
+ gap: 10px;
533
+ font-size: 13px;
534
+ color: var(--text-muted);
535
+ animation: pulse 1.2s ease-in-out infinite;
536
+ padding: 4px 0;
537
+ }
538
+
539
+ .file-loading-msg .file-spinner {
540
+ width: 16px;
541
+ height: 16px;
542
+ flex-shrink: 0;
543
+ }
544
+
545
+ .msg-attachment {
546
+ background: var(--surface-2);
547
+ border: 1px solid var(--border);
548
+ border-radius: 6px;
549
+ padding: 4px 10px;
550
+ font-size: 11px;
551
+ color: var(--text-muted);
552
+ margin-bottom: 6px;
553
+ display: inline-block;
554
+ }
555
+
556
+ /* Responsive */
557
+ @media (max-width: 600px) {
558
+ .msg { max-width: 92%; }
559
+ header { padding: 12px 14px; }
560
+ #messages { padding: 14px; }
561
+ #input-area { padding: 12px 14px; }
562
+ #status-bar { padding: 8px 14px; }
563
+ #file-preview { padding: 0 14px; }
564
+ #settings-panel { width: 280px; }
565
+ }
566
+ </style>
567
+ </head>
568
+ <body>
569
+ <div id="app">
570
+ <div class="header-wrap">
571
+ <header>
572
+ <div class="logo"><img src="data:image/png;base64,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" alt="Evrmind"></div>
573
+ <div class="header-right">
574
+ <span id="model-name"></span>
575
+ <button class="settings-btn" onclick="toggleSettings()" title="Settings">&#9881;</button>
576
+ </div>
577
+ </header>
578
+ </div>
579
+
580
+ <div id="messages">
581
+ <div class="welcome" id="welcome">
582
+ <div class="welcome-logo"><img src="data:image/png;base64,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" alt="Evrmind"></div>
583
+ <div class="welcome-sub">Type a message to begin</div>
584
+ </div>
585
+ </div>
586
+
587
+ <div id="file-preview"></div>
588
+ <div class="input-wrap">
589
+ <div id="input-area">
590
+ <div id="input-row">
591
+ <button class="attach-btn" onclick="document.getElementById('file-input').click()" title="Attach file"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21.44 11.05l-9.19 9.19a6 6 0 01-8.49-8.49l9.19-9.19a4 4 0 015.66 5.66l-9.2 9.19a2 2 0 01-2.83-2.83l8.49-8.48"/></svg></button>
592
+ <input type="file" id="file-input" style="display:none" accept=".txt,.md,.csv,.json,.js,.ts,.py,.html,.css,.xml,.yaml,.yml,.toml,.ini,.cfg,.log,.sh,.bat,.c,.cpp,.h,.java,.rs,.go,.rb,.php,.sql,.pdf" onchange="handleFileAttach(this)">
593
+ <textarea id="user-input" rows="1" placeholder="Message Evrmind..." onkeydown="handleKey(event)" oninput="autoResize(this)"></textarea>
594
+ <button id="send-btn" onclick="sendMessage()" title="Send">&#9654;</button>
595
+ </div>
596
+ </div>
597
+ </div>
598
+
599
+ <div class="status-wrap">
600
+ <div id="status-bar">
601
+ <span><span id="status-dot"></span><span id="status-text">Connecting...</span></span>
602
+ <span id="speed-info"></span>
603
+ </div>
604
+ </div>
605
+ </div>
606
+
607
+ <div id="settings-overlay" onclick="toggleSettings()"></div>
608
+ <div id="settings-panel">
609
+ <h3>Settings</h3>
610
+ <div class="presets">
611
+ <button class="preset-btn" onclick="applyPreset('creative')">Creative</button>
612
+ <button class="preset-btn active" onclick="applyPreset('balanced')">Balanced</button>
613
+ <button class="preset-btn" onclick="applyPreset('precise')">Precise</button>
614
+ </div>
615
+ <div class="setting-group">
616
+ <label>Temperature <span class="setting-val" id="temp-val">0.7</span></label>
617
+ <input type="range" id="temp" min="0" max="2" step="0.1" value="0.7" oninput="onSettingChange('temp-val',this.value)">
618
+ </div>
619
+ <div class="setting-group">
620
+ <label>Top P <span class="setting-val" id="topp-val">0.90</span></label>
621
+ <input type="range" id="top-p" min="0" max="1" step="0.05" value="0.90" oninput="onSettingChange('topp-val',this.value)">
622
+ </div>
623
+ <div class="setting-group">
624
+ <label>Min P <span class="setting-val" id="minp-val">0.05</span></label>
625
+ <input type="range" id="min-p" min="0" max="0.5" step="0.01" value="0.05" oninput="onSettingChange('minp-val',this.value)">
626
+ </div>
627
+ <div class="setting-group">
628
+ <label>Repeat Penalty <span class="setting-val" id="repeat-val">1.10</span></label>
629
+ <input type="range" id="repeat-penalty" min="1" max="2" step="0.05" value="1.10" oninput="onSettingChange('repeat-val',this.value)">
630
+ </div>
631
+ <hr class="setting-divider">
632
+ <div class="setting-group">
633
+ <label>Max Tokens <span class="setting-val" id="maxtok-val">1024</span></label>
634
+ <input type="range" id="max-tokens" min="64" max="2048" step="64" value="1024" oninput="document.getElementById('maxtok-val').textContent=this.value">
635
+ </div>
636
+ <div class="setting-group">
637
+ <label>Seed <span class="setting-val" style="color:var(--text-muted)">-1 = random</span></label>
638
+ <input type="number" id="seed" value="-1" min="-1">
639
+ </div>
640
+ <hr class="setting-divider">
641
+ <div class="setting-group">
642
+ <label>System Prompt</label>
643
+ <textarea id="system-prompt" placeholder="Optional system prompt..."></textarea>
644
+ </div>
645
+ </div>
646
+
647
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.min.js"></script>
648
+ <script>
649
+ if (typeof pdfjsLib !== 'undefined') pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.worker.min.js';
650
+
651
+ const BASE = window.location.origin;
652
+ let modelId = '';
653
+ let modelType = 'chat'; // 'chat' or 'completion'
654
+ let chatHistory = [];
655
+ let isGenerating = false;
656
+ let abortCtrl = null;
657
+ let attachedFile = null; // { name, content }
658
+ let shouldAutoScroll = true;
659
+
660
+ // --- Init ---
661
+ async function init() {
662
+ checkHealth();
663
+ detectModel();
664
+
665
+ const msgContainer = document.getElementById('messages');
666
+ msgContainer.addEventListener('scroll', function() {
667
+ const atBottom = msgContainer.scrollHeight - msgContainer.scrollTop - msgContainer.clientHeight < 60;
668
+ shouldAutoScroll = atBottom;
669
+ });
670
+ }
671
+
672
+ function scrollToBottom() {
673
+ if (!shouldAutoScroll) return;
674
+ const c = document.getElementById('messages');
675
+ c.scrollTop = c.scrollHeight;
676
+ }
677
+
678
+ async function checkHealth() {
679
+ const dot = document.getElementById('status-dot');
680
+ const txt = document.getElementById('status-text');
681
+ try {
682
+ const r = await fetch(BASE + '/health');
683
+ if (r.ok) {
684
+ dot.className = 'connected';
685
+ txt.textContent = 'Ready';
686
+ } else {
687
+ dot.className = 'error';
688
+ txt.textContent = 'Server error';
689
+ }
690
+ } catch {
691
+ dot.className = 'error';
692
+ txt.textContent = 'Not connected';
693
+ setTimeout(checkHealth, 3000);
694
+ }
695
+ }
696
+
697
+ async function detectModel() {
698
+ try {
699
+ const r = await fetch(BASE + '/v1/models');
700
+ const data = await r.json();
701
+ if (data.data && data.data.length > 0) {
702
+ modelId = data.data[0].id || '';
703
+ const filename = modelId.split('/').pop().replace('.gguf','');
704
+ const nameMap = {
705
+ 'evr-llama-3.1-8b': 'EVR-1 Maano-8b',
706
+ 'evr-llama-3.1-8b-instruct': 'EVR-1 Maano-8b-Instruct',
707
+ 'evr-deepseek-r1-llama-8b-reasoning': 'EVR-1 Bafethu-8b-Reasoning',
708
+ };
709
+ const name = nameMap[filename] || filename;
710
+ document.getElementById('model-name').textContent = name;
711
+
712
+ // Detect type from model name
713
+ const lower = name.toLowerCase();
714
+ if (lower.includes('instruct') || lower.includes('reasoning') || lower.includes('deepseek') || lower.includes('r1')) {
715
+ modelType = 'chat';
716
+ } else {
717
+ modelType = 'completion';
718
+ }
719
+ }
720
+ } catch {}
721
+ }
722
+
723
+ // --- Chat ---
724
+ function handleKey(e) {
725
+ if (e.key === 'Enter' && !e.shiftKey) {
726
+ e.preventDefault();
727
+ sendMessage();
728
+ }
729
+ }
730
+
731
+ function autoResize(el) {
732
+ el.style.height = 'auto';
733
+ el.style.height = Math.min(el.scrollHeight, 160) + 'px';
734
+ }
735
+
736
+ async function sendMessage() {
737
+ const input = document.getElementById('user-input');
738
+ const text = input.value.trim();
739
+ if (!text || isGenerating) return;
740
+
741
+ // Remove welcome
742
+ const welcome = document.getElementById('welcome');
743
+ if (welcome) welcome.remove();
744
+
745
+ // Build content with attached file
746
+ let content = text;
747
+ let attachName = null;
748
+ if (attachedFile) {
749
+ attachName = attachedFile.name;
750
+ content = '[File: ' + attachedFile.name + ']\n' + attachedFile.content + '\n\n' + text;
751
+ clearAttachment();
752
+ }
753
+
754
+ // Add user message
755
+ appendMsg('user', text, attachName);
756
+ chatHistory.push({ role: 'user', content: content });
757
+ input.value = '';
758
+ input.style.height = 'auto';
759
+
760
+ // Generate
761
+ isGenerating = true;
762
+ document.getElementById('send-btn').disabled = true;
763
+
764
+ const aiMsg = appendMsg('ai', '');
765
+ const bodyEl = aiMsg.querySelector('.msg-body');
766
+
767
+ // Show pulsing loading state while waiting for first token
768
+ if (attachName) {
769
+ bodyEl.innerHTML = '<div class="file-loading-msg"><span class="file-spinner"></span>Reading ' + escapeHtml(attachName) + '...</div>';
770
+ } else {
771
+ bodyEl.innerHTML = '<div class="file-loading-msg"><span class="file-spinner"></span>Thinking...</div>';
772
+ }
773
+
774
+ try {
775
+ if (modelType === 'chat') {
776
+ await streamChat(bodyEl);
777
+ } else {
778
+ await streamCompletion(text, bodyEl);
779
+ }
780
+ } catch (e) {
781
+ if (e.name !== 'AbortError') {
782
+ bodyEl.innerHTML = '<span style="color:#ef4444">Error: ' + e.message + '</span>';
783
+ }
784
+ }
785
+
786
+ isGenerating = false;
787
+ document.getElementById('send-btn').disabled = false;
788
+ input.focus();
789
+ }
790
+
791
+ async function streamChat(bodyEl) {
792
+ const sysPrompt = document.getElementById('system-prompt').value.trim();
793
+ const messages = [];
794
+ if (sysPrompt) messages.push({ role: 'system', content: sysPrompt });
795
+ messages.push(...chatHistory);
796
+
797
+ abortCtrl = new AbortController();
798
+ let startTime = null;
799
+ let tokenCount = 0;
800
+ let fullText = '';
801
+
802
+ const r = await fetch(BASE + '/v1/chat/completions', {
803
+ method: 'POST',
804
+ headers: { 'Content-Type': 'application/json' },
805
+ body: JSON.stringify(buildRequestBody({ messages: messages })),
806
+ signal: abortCtrl.signal
807
+ });
808
+
809
+ if (!r.ok) {
810
+ const err = await r.json().catch(() => null);
811
+ throw new Error(err?.error?.message || 'Server error (' + r.status + ')');
812
+ }
813
+
814
+ const reader = r.body.getReader();
815
+ const decoder = new TextDecoder();
816
+ let buffer = '';
817
+
818
+ while (true) {
819
+ const { done, value } = await reader.read();
820
+ if (done) break;
821
+
822
+ buffer += decoder.decode(value, { stream: true });
823
+ const lines = buffer.split('\n');
824
+ buffer = lines.pop();
825
+
826
+ for (const line of lines) {
827
+ if (!line.startsWith('data: ')) continue;
828
+ const payload = line.slice(6);
829
+ if (payload === '[DONE]') break;
830
+
831
+ try {
832
+ const j = JSON.parse(payload);
833
+ const delta = j.choices?.[0]?.delta?.content || '';
834
+ if (delta) {
835
+ if (!startTime) startTime = performance.now();
836
+ fullText += delta;
837
+ tokenCount++;
838
+ renderContent(bodyEl, fullText, true);
839
+ updateSpeed(tokenCount, startTime);
840
+ }
841
+ } catch {}
842
+ }
843
+ }
844
+
845
+ renderContent(bodyEl, fullText, false);
846
+ chatHistory.push({ role: 'assistant', content: fullText });
847
+ }
848
+
849
+ async function streamCompletion(prompt, bodyEl) {
850
+ // Build context from history for completion mode
851
+ let fullPrompt = '';
852
+ for (const m of chatHistory) {
853
+ if (m.role === 'user') fullPrompt += m.content + '\n';
854
+ else if (m.role === 'assistant') fullPrompt += m.content + '\n';
855
+ }
856
+
857
+ abortCtrl = new AbortController();
858
+ let startTime = null;
859
+ let tokenCount = 0;
860
+ let fullText = '';
861
+
862
+ const r = await fetch(BASE + '/v1/completions', {
863
+ method: 'POST',
864
+ headers: { 'Content-Type': 'application/json' },
865
+ body: JSON.stringify(buildRequestBody({ prompt: fullPrompt })),
866
+ signal: abortCtrl.signal
867
+ });
868
+
869
+ if (!r.ok) {
870
+ const err = await r.json().catch(() => null);
871
+ throw new Error(err?.error?.message || 'Server error (' + r.status + ')');
872
+ }
873
+
874
+ const reader = r.body.getReader();
875
+ const decoder = new TextDecoder();
876
+ let buffer = '';
877
+
878
+ while (true) {
879
+ const { done, value } = await reader.read();
880
+ if (done) break;
881
+
882
+ buffer += decoder.decode(value, { stream: true });
883
+ const lines = buffer.split('\n');
884
+ buffer = lines.pop();
885
+
886
+ for (const line of lines) {
887
+ if (!line.startsWith('data: ')) continue;
888
+ const payload = line.slice(6);
889
+ if (payload === '[DONE]') break;
890
+
891
+ try {
892
+ const j = JSON.parse(payload);
893
+ const text = j.choices?.[0]?.text || '';
894
+ if (text) {
895
+ if (!startTime) startTime = performance.now();
896
+ fullText += text;
897
+ tokenCount++;
898
+ renderContent(bodyEl, fullText, true);
899
+ updateSpeed(tokenCount, startTime);
900
+ }
901
+ } catch {}
902
+ }
903
+ }
904
+
905
+ renderContent(bodyEl, fullText, false);
906
+ chatHistory.push({ role: 'assistant', content: fullText });
907
+ }
908
+
909
+ // --- Rendering ---
910
+ function appendMsg(role, text, attachName) {
911
+ const container = document.getElementById('messages');
912
+ const div = document.createElement('div');
913
+ div.className = 'msg msg-' + (role === 'user' ? 'user' : 'ai');
914
+ let html = '<div class="msg-label">' + (role === 'user' ? 'You' : 'Evrmind') + '</div>';
915
+ if (attachName) html += '<div class="msg-attachment"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-1px;margin-right:4px"><path d="M21.44 11.05l-9.19 9.19a6 6 0 01-8.49-8.49l9.19-9.19a4 4 0 015.66 5.66l-9.2 9.19a2 2 0 01-2.83-2.83l8.49-8.48"/></svg>' + escapeHtml(attachName) + '</div>';
916
+ html += '<div class="msg-body">' + (text ? escapeHtml(text) : '') + '</div>';
917
+ div.innerHTML = html;
918
+ container.appendChild(div);
919
+ if (role === 'user') shouldAutoScroll = true;
920
+ scrollToBottom();
921
+ return div;
922
+ }
923
+
924
+ function renderContent(el, raw, streaming) {
925
+ // Handle <think> blocks for reasoning models
926
+ const thinkMatch = raw.match(/^<think>([\s\S]*?)(<\/think>|$)/);
927
+
928
+ if (thinkMatch) {
929
+ const thinkContent = thinkMatch[1];
930
+ const afterThink = raw.slice(thinkMatch[0].length);
931
+ const thinkDone = raw.includes('</think>');
932
+
933
+ // Build DOM structure once, then update only text on subsequent calls
934
+ let block = el.querySelector('.think-block');
935
+ if (!block) {
936
+ el.innerHTML = '<div class="think-block">' +
937
+ '<div class="think-toggle"><span class="think-arrow">&#9654;</span><span class="think-label">Thinking...</span></div>' +
938
+ '<div class="think-content"></div>' +
939
+ '</div><div class="think-answer"></div>';
940
+ block = el.querySelector('.think-block');
941
+ block.querySelector('.think-toggle').addEventListener('click', function() {
942
+ block.classList.toggle('open');
943
+ });
944
+ }
945
+
946
+ // Update label
947
+ block.querySelector('.think-label').textContent = thinkDone ? 'Thinking' : 'Thinking...';
948
+
949
+ // Update think content
950
+ const contentEl = block.querySelector('.think-content');
951
+ contentEl.innerHTML = formatText(thinkContent) + (streaming && !thinkDone ? '<span class="cursor"></span>' : '');
952
+
953
+ // Update answer area
954
+ const answerEl = el.querySelector('.think-answer');
955
+ if (afterThink.trim()) {
956
+ answerEl.innerHTML = formatText(afterThink) + (streaming ? '<span class="cursor"></span>' : '');
957
+ } else if (thinkDone && streaming) {
958
+ answerEl.innerHTML = '<span class="cursor"></span>';
959
+ } else {
960
+ answerEl.innerHTML = '';
961
+ }
962
+ } else {
963
+ el.innerHTML = formatText(raw) + (streaming ? '<span class="cursor"></span>' : '');
964
+ }
965
+
966
+ scrollToBottom();
967
+ }
968
+
969
+ function formatText(text) {
970
+ // Simple markdown: code blocks, inline code, bold, italic, lists
971
+ let html = escapeHtml(text);
972
+
973
+ // Code blocks
974
+ html = html.replace(/```(\w*)\n([\s\S]*?)```/g, '<pre><code>$2</code></pre>');
975
+ html = html.replace(/```([\s\S]*?)```/g, '<pre><code>$1</code></pre>');
976
+
977
+ // Inline code
978
+ html = html.replace(/`([^`]+)`/g, '<code>$1</code>');
979
+
980
+ // Bold
981
+ html = html.replace(/\*\*([^*]+)\*\*/g, '<strong>$1</strong>');
982
+
983
+ // Italic
984
+ html = html.replace(/\*([^*]+)\*/g, '<em>$1</em>');
985
+
986
+ // Numbered lists
987
+ html = html.replace(/^(\d+)\.\s+(.+)$/gm, '<li>$2</li>');
988
+ html = html.replace(/(<li>.*<\/li>\n?)+/g, '<ol>$&</ol>');
989
+
990
+ // Paragraphs
991
+ html = html.replace(/\n\n/g, '</p><p>');
992
+ html = '<p>' + html + '</p>';
993
+ html = html.replace(/<p>\s*<\/p>/g, '');
994
+
995
+ return html;
996
+ }
997
+
998
+ function escapeHtml(s) {
999
+ const d = document.createElement('div');
1000
+ d.textContent = s;
1001
+ return d.innerHTML;
1002
+ }
1003
+
1004
+ function updateSpeed(tokens, startTime) {
1005
+ const elapsed = (performance.now() - startTime) / 1000;
1006
+ const tps = elapsed > 0 ? (tokens / elapsed).toFixed(1) : '...';
1007
+ document.getElementById('speed-info').textContent = tps + ' tok/s';
1008
+ }
1009
+
1010
+ // --- Settings ---
1011
+ function toggleSettings() {
1012
+ document.getElementById('settings-panel').classList.toggle('open');
1013
+ document.getElementById('settings-overlay').classList.toggle('open');
1014
+ }
1015
+
1016
+ function buildRequestBody(extra) {
1017
+ const body = {
1018
+ ...extra,
1019
+ temperature: parseFloat(document.getElementById('temp').value),
1020
+ top_p: parseFloat(document.getElementById('top-p').value),
1021
+ min_p: parseFloat(document.getElementById('min-p').value),
1022
+ repeat_penalty: parseFloat(document.getElementById('repeat-penalty').value),
1023
+ max_tokens: parseInt(document.getElementById('max-tokens').value),
1024
+ stream: true
1025
+ };
1026
+ const seed = parseInt(document.getElementById('seed').value);
1027
+ if (seed >= 0) body.seed = seed;
1028
+ return body;
1029
+ }
1030
+
1031
+ function onSettingChange(valId, val) {
1032
+ document.getElementById(valId).textContent = parseFloat(val).toFixed(2);
1033
+ clearActivePreset();
1034
+ }
1035
+
1036
+ function clearActivePreset() {
1037
+ document.querySelectorAll('.preset-btn').forEach(b => b.classList.remove('active'));
1038
+ }
1039
+
1040
+ const presets = {
1041
+ creative: { temp: 1.0, top_p: 0.95, min_p: 0.03, repeat: 1.05 },
1042
+ balanced: { temp: 0.7, top_p: 0.90, min_p: 0.05, repeat: 1.10 },
1043
+ precise: { temp: 0.3, top_p: 0.80, min_p: 0.10, repeat: 1.15 }
1044
+ };
1045
+
1046
+ function applyPreset(name) {
1047
+ const p = presets[name];
1048
+ setSlider('temp', 'temp-val', p.temp);
1049
+ setSlider('top-p', 'topp-val', p.top_p);
1050
+ setSlider('min-p', 'minp-val', p.min_p);
1051
+ setSlider('repeat-penalty', 'repeat-val', p.repeat);
1052
+ document.querySelectorAll('.preset-btn').forEach(b => b.classList.remove('active'));
1053
+ event.target.classList.add('active');
1054
+ }
1055
+
1056
+ function setSlider(sliderId, valId, val) {
1057
+ const el = document.getElementById(sliderId);
1058
+ el.value = val;
1059
+ const display = sliderId === 'temp' ? val : parseFloat(val).toFixed(2);
1060
+ document.getElementById(valId).textContent = display;
1061
+ }
1062
+
1063
+ // --- File Attachment ---
1064
+ async function handleFileAttach(input) {
1065
+ const file = input.files[0];
1066
+ if (!file) return;
1067
+ input.value = '';
1068
+
1069
+ const maxSize = 512 * 1024; // 512KB text limit
1070
+ if (file.size > 2 * 1024 * 1024) {
1071
+ alert('File too large. Maximum 2MB.');
1072
+ return;
1073
+ }
1074
+
1075
+ showFileLoading(file.name);
1076
+
1077
+ try {
1078
+ let content;
1079
+ if (file.name.toLowerCase().endsWith('.pdf')) {
1080
+ content = await extractPdfText(file);
1081
+ } else {
1082
+ content = await readTextFile(file);
1083
+ }
1084
+
1085
+ if (content.length > maxSize) {
1086
+ content = content.substring(0, maxSize) + '\n[...truncated at 512KB]';
1087
+ }
1088
+
1089
+ attachedFile = { name: file.name, content: content };
1090
+ showFilePreview(file.name);
1091
+ } catch (e) {
1092
+ clearAttachment();
1093
+ alert('Could not read file: ' + e.message);
1094
+ }
1095
+ }
1096
+
1097
+ function readTextFile(file) {
1098
+ return new Promise((resolve, reject) => {
1099
+ const reader = new FileReader();
1100
+ reader.onload = () => resolve(reader.result);
1101
+ reader.onerror = () => reject(new Error('Failed to read file'));
1102
+ reader.readAsText(file);
1103
+ });
1104
+ }
1105
+
1106
+ async function extractPdfText(file) {
1107
+ if (typeof pdfjsLib === 'undefined') throw new Error('PDF support not loaded');
1108
+ const buf = await file.arrayBuffer();
1109
+ const pdf = await pdfjsLib.getDocument({ data: buf }).promise;
1110
+ let text = '';
1111
+ for (let i = 1; i <= pdf.numPages; i++) {
1112
+ const page = await pdf.getPage(i);
1113
+ const content = await page.getTextContent();
1114
+ text += content.items.map(item => item.str).join(' ') + '\n';
1115
+ }
1116
+ return text.trim();
1117
+ }
1118
+
1119
+ function showFileLoading(name) {
1120
+ const preview = document.getElementById('file-preview');
1121
+ preview.style.display = 'block';
1122
+ preview.innerHTML = '<div class="file-chip loading"><span class="file-spinner"></span><span>Reading ' + escapeHtml(name) + '...</span></div>';
1123
+ }
1124
+
1125
+ function waitForPaint() {
1126
+ return new Promise(r => requestAnimationFrame(() => requestAnimationFrame(r)));
1127
+ }
1128
+
1129
+ function showFilePreview(name) {
1130
+ const preview = document.getElementById('file-preview');
1131
+ preview.style.display = 'block';
1132
+ preview.innerHTML = '<div class="file-chip"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px"><path d="M21.44 11.05l-9.19 9.19a6 6 0 01-8.49-8.49l9.19-9.19a4 4 0 015.66 5.66l-9.2 9.19a2 2 0 01-2.83-2.83l8.49-8.48"/></svg><span>' + escapeHtml(name) + '</span><button class="file-chip-remove" onclick="clearAttachment()" title="Remove">&times;</button></div>';
1133
+ }
1134
+
1135
+ function clearAttachment() {
1136
+ attachedFile = null;
1137
+ const preview = document.getElementById('file-preview');
1138
+ preview.style.display = 'none';
1139
+ preview.innerHTML = '';
1140
+ }
1141
+
1142
+ // --- Start ---
1143
+ init();
1144
+ document.getElementById('user-input').focus();
1145
+ </script>
1146
+ </body>
1147
+ </html>