Text Generation
GGUF
English
llama.cpp
llama
llama-3.1
3-bit
quantization
evr
evrmind
instruct
chat
on-device
maano
conversational
Instructions to use Evrmind/EVR-1-Maano-8b-Instruct with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- llama-cpp-python
How to use Evrmind/EVR-1-Maano-8b-Instruct with llama-cpp-python:
# !pip install llama-cpp-python from llama_cpp import Llama llm = Llama.from_pretrained( repo_id="Evrmind/EVR-1-Maano-8b-Instruct", filename="evr-llama-3.1-8b-instruct.gguf", )
llm.create_chat_completion( messages = [ { "role": "user", "content": "What is the capital of France?" } ] ) - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- llama.cpp
How to use Evrmind/EVR-1-Maano-8b-Instruct with llama.cpp:
Install from brew
brew install llama.cpp # Start a local OpenAI-compatible server with a web UI: llama-server -hf Evrmind/EVR-1-Maano-8b-Instruct # Run inference directly in the terminal: llama-cli -hf Evrmind/EVR-1-Maano-8b-Instruct
Install from WinGet (Windows)
winget install llama.cpp # Start a local OpenAI-compatible server with a web UI: llama-server -hf Evrmind/EVR-1-Maano-8b-Instruct # Run inference directly in the terminal: llama-cli -hf Evrmind/EVR-1-Maano-8b-Instruct
Use pre-built binary
# Download pre-built binary from: # https://github.com/ggerganov/llama.cpp/releases # Start a local OpenAI-compatible server with a web UI: ./llama-server -hf Evrmind/EVR-1-Maano-8b-Instruct # Run inference directly in the terminal: ./llama-cli -hf Evrmind/EVR-1-Maano-8b-Instruct
Build from source code
git clone https://github.com/ggerganov/llama.cpp.git cd llama.cpp cmake -B build cmake --build build -j --target llama-server llama-cli # Start a local OpenAI-compatible server with a web UI: ./build/bin/llama-server -hf Evrmind/EVR-1-Maano-8b-Instruct # Run inference directly in the terminal: ./build/bin/llama-cli -hf Evrmind/EVR-1-Maano-8b-Instruct
Use Docker
docker model run hf.co/Evrmind/EVR-1-Maano-8b-Instruct
- LM Studio
- Jan
- vLLM
How to use Evrmind/EVR-1-Maano-8b-Instruct with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "Evrmind/EVR-1-Maano-8b-Instruct" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "Evrmind/EVR-1-Maano-8b-Instruct", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }'Use Docker
docker model run hf.co/Evrmind/EVR-1-Maano-8b-Instruct
- Ollama
How to use Evrmind/EVR-1-Maano-8b-Instruct with Ollama:
ollama run hf.co/Evrmind/EVR-1-Maano-8b-Instruct
- Unsloth Studio
How to use Evrmind/EVR-1-Maano-8b-Instruct with Unsloth Studio:
Install Unsloth Studio (macOS, Linux, WSL)
curl -fsSL https://unsloth.ai/install.sh | sh # Run unsloth studio unsloth studio -H 0.0.0.0 -p 8888 # Then open http://localhost:8888 in your browser # Search for Evrmind/EVR-1-Maano-8b-Instruct to start chatting
Install Unsloth Studio (Windows)
irm https://unsloth.ai/install.ps1 | iex # Run unsloth studio unsloth studio -H 0.0.0.0 -p 8888 # Then open http://localhost:8888 in your browser # Search for Evrmind/EVR-1-Maano-8b-Instruct to start chatting
Using HuggingFace Spaces for Unsloth
# No setup required # Open https://huggingface.co/spaces/unsloth/studio in your browser # Search for Evrmind/EVR-1-Maano-8b-Instruct to start chatting
- Pi
How to use Evrmind/EVR-1-Maano-8b-Instruct with Pi:
Start the llama.cpp server
# Install llama.cpp: brew install llama.cpp # Start a local OpenAI-compatible server: llama-server -hf Evrmind/EVR-1-Maano-8b-Instruct
Configure the model in Pi
# Install Pi: npm install -g @mariozechner/pi-coding-agent # Add to ~/.pi/agent/models.json: { "providers": { "llama-cpp": { "baseUrl": "http://localhost:8080/v1", "api": "openai-completions", "apiKey": "none", "models": [ { "id": "Evrmind/EVR-1-Maano-8b-Instruct" } ] } } }Run Pi
# Start Pi in your project directory: pi
- Hermes Agent new
How to use Evrmind/EVR-1-Maano-8b-Instruct with Hermes Agent:
Start the llama.cpp server
# Install llama.cpp: brew install llama.cpp # Start a local OpenAI-compatible server: llama-server -hf Evrmind/EVR-1-Maano-8b-Instruct
Configure Hermes
# Install Hermes: curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bash hermes setup # Point Hermes at the local server: hermes config set model.provider custom hermes config set model.base_url http://127.0.0.1:8080/v1 hermes config set model.default Evrmind/EVR-1-Maano-8b-Instruct
Run Hermes
hermes
- Atomic Chat new
- Docker Model Runner
How to use Evrmind/EVR-1-Maano-8b-Instruct with Docker Model Runner:
docker model run hf.co/Evrmind/EVR-1-Maano-8b-Instruct
- Lemonade
How to use Evrmind/EVR-1-Maano-8b-Instruct with Lemonade:
Pull the model
# Download Lemonade from https://lemonade-server.ai/ lemonade pull Evrmind/EVR-1-Maano-8b-Instruct
Run and chat with the model
lemonade run user.EVR-1-Maano-8b-Instruct-{{QUANT_TAG}}List all available models
lemonade list
Upload folder using huggingface_hub
Browse files- .gitattributes +7 -35
- BENCHMARK_RESULTS.md +161 -0
- LICENSE.md +33 -0
- META_LLAMA_LICENSE.md +48 -0
- MODEL_CARD.md +189 -0
- NOTICE.md +3 -0
- README.md +256 -0
- SHA256SUMS.txt +7 -0
- WEB_UI.md +92 -0
- evr-llama-3.1-8b-instruct.gguf +3 -0
- evrmind-android-vulkan.tar.gz +3 -0
- evrmind-linux-cuda.tar.gz +3 -0
- evrmind-linux-vulkan.tar.gz +3 -0
- evrmind-macos-metal.tar.gz +3 -0
- evrmind-windows-cuda.zip +3 -0
- evrmind-windows-vulkan.zip +3 -0
- start-server.bat +75 -0
- start-server.sh +128 -0
- webui/index.html +1147 -0
.gitattributes
CHANGED
|
@@ -1,35 +1,7 @@
|
|
| 1 |
-
*.
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 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">⚙</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">▶</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">▶</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">×</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>
|