LocalAdapt 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- localadapt-0.1.0/LocalAdapt/__init__.py +19 -0
- localadapt-0.1.0/LocalAdapt/adapters/__init__.py +7 -0
- localadapt-0.1.0/LocalAdapt/adapters/base_adapter.py +41 -0
- localadapt-0.1.0/LocalAdapt/adapters/diffusion.py +0 -0
- localadapt-0.1.0/LocalAdapt/adapters/ersgan.py +0 -0
- localadapt-0.1.0/LocalAdapt/adapters/llm.py +121 -0
- localadapt-0.1.0/LocalAdapt/adapters/router.py +16 -0
- localadapt-0.1.0/LocalAdapt/common.py +14 -0
- localadapt-0.1.0/LocalAdapt/install.py +52 -0
- localadapt-0.1.0/LocalAdapt/test.py +53 -0
- localadapt-0.1.0/LocalAdapt.egg-info/PKG-INFO +5 -0
- localadapt-0.1.0/LocalAdapt.egg-info/SOURCES.txt +15 -0
- localadapt-0.1.0/LocalAdapt.egg-info/dependency_links.txt +1 -0
- localadapt-0.1.0/LocalAdapt.egg-info/top_level.txt +1 -0
- localadapt-0.1.0/PKG-INFO +5 -0
- localadapt-0.1.0/pyproject.toml +11 -0
- localadapt-0.1.0/setup.cfg +4 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import os
|
|
2
|
+
|
|
3
|
+
def _ensure_runtime():
|
|
4
|
+
try:
|
|
5
|
+
from . import adapters, test
|
|
6
|
+
return True
|
|
7
|
+
except ImportError:
|
|
8
|
+
return False
|
|
9
|
+
|
|
10
|
+
if not _ensure_runtime():
|
|
11
|
+
try:
|
|
12
|
+
from . import install
|
|
13
|
+
install.main()
|
|
14
|
+
|
|
15
|
+
# Nach Installation nochmal versuchen
|
|
16
|
+
from . import adapters, test
|
|
17
|
+
|
|
18
|
+
except Exception as e:
|
|
19
|
+
print("LocalAdapt initialization failed:", e)
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# adapters/router.py
|
|
2
|
+
from abc import ABC, abstractmethod
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from PIL import Image
|
|
5
|
+
|
|
6
|
+
@dataclass
|
|
7
|
+
class Value:
|
|
8
|
+
text:str = None
|
|
9
|
+
image:Image = None
|
|
10
|
+
path:str = None
|
|
11
|
+
done:bool = False
|
|
12
|
+
|
|
13
|
+
class BaseAdapter(ABC):
|
|
14
|
+
def __init__(self):
|
|
15
|
+
super().__init__()
|
|
16
|
+
self.model = None
|
|
17
|
+
|
|
18
|
+
@abstractmethod
|
|
19
|
+
def supports(self, request: dict) -> bool:
|
|
20
|
+
"""Return True if this adapter can handle the request."""
|
|
21
|
+
pass
|
|
22
|
+
|
|
23
|
+
@abstractmethod
|
|
24
|
+
def register_model(self, **kwargs):
|
|
25
|
+
"""Return a Dataclass for the given model and parameters."""
|
|
26
|
+
pass
|
|
27
|
+
|
|
28
|
+
@abstractmethod
|
|
29
|
+
def load(self, model):
|
|
30
|
+
"""Loads an model into the Adapter(Lazy load)."""
|
|
31
|
+
pass
|
|
32
|
+
|
|
33
|
+
@abstractmethod
|
|
34
|
+
def unload(self):
|
|
35
|
+
"""Unloads the loaded model."""
|
|
36
|
+
self.model = None
|
|
37
|
+
|
|
38
|
+
@abstractmethod
|
|
39
|
+
def run(self, request) -> Value:
|
|
40
|
+
"""Runs the loaded model with the given request and returns the result as an Value object."""
|
|
41
|
+
pass
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
from .base_adapter import BaseAdapter, Value
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
import torch
|
|
4
|
+
from transformers import AutoModelForCausalLM, AutoTokenizer, TextIteratorStreamer
|
|
5
|
+
import threading
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass
|
|
9
|
+
class LLM:
|
|
10
|
+
model_path: str
|
|
11
|
+
device: str = "cuda" if torch.cuda.is_available() else "cpu"
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class LLMAdapter(BaseAdapter):
|
|
15
|
+
def __init__(self):
|
|
16
|
+
self.model = None
|
|
17
|
+
self.tokenizer = None
|
|
18
|
+
|
|
19
|
+
def supports(self, request):
|
|
20
|
+
return request.get("type") == "llm"
|
|
21
|
+
|
|
22
|
+
def register_model(self, **kwargs) -> LLM:
|
|
23
|
+
return LLM(**kwargs)
|
|
24
|
+
|
|
25
|
+
def load(self, model: LLM):
|
|
26
|
+
self.tokenizer = AutoTokenizer.from_pretrained(model.model_path)
|
|
27
|
+
self.model = AutoModelForCausalLM.from_pretrained(
|
|
28
|
+
model.model_path
|
|
29
|
+
).to(model.device)
|
|
30
|
+
|
|
31
|
+
print(f"Model {model.model_path} loaded")
|
|
32
|
+
print(f"You can now run it on {model.device}")
|
|
33
|
+
|
|
34
|
+
def unload(self):
|
|
35
|
+
if self.model:
|
|
36
|
+
del self.model
|
|
37
|
+
self.model = None
|
|
38
|
+
|
|
39
|
+
if self.tokenizer:
|
|
40
|
+
del self.tokenizer
|
|
41
|
+
self.tokenizer = None
|
|
42
|
+
|
|
43
|
+
torch.cuda.empty_cache()
|
|
44
|
+
return super().unload()
|
|
45
|
+
|
|
46
|
+
def run(self, request: dict) -> Value:
|
|
47
|
+
if not self.model or not self.tokenizer:
|
|
48
|
+
raise ValueError("You have to load a model first!")
|
|
49
|
+
|
|
50
|
+
prompt = request.get("prompt", "")
|
|
51
|
+
max_new_tokens = request.get("max_length", 100)
|
|
52
|
+
stream = request.get("stream", False)
|
|
53
|
+
do_sample = request.get("do_sample", True)
|
|
54
|
+
temperature = request.get("temperature", 1.0)
|
|
55
|
+
|
|
56
|
+
result = Value(text="")
|
|
57
|
+
|
|
58
|
+
messages = request.get("history", []).copy()
|
|
59
|
+
|
|
60
|
+
inputs = self.tokenizer.apply_chat_template(
|
|
61
|
+
messages,
|
|
62
|
+
return_tensors="pt",
|
|
63
|
+
add_generation_prompt=True
|
|
64
|
+
).to(self.model.device)
|
|
65
|
+
|
|
66
|
+
if stream:
|
|
67
|
+
streamer = TextIteratorStreamer(
|
|
68
|
+
self.tokenizer,
|
|
69
|
+
skip_special_tokens=True,
|
|
70
|
+
clean_up_tokenization_spaces=False
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
def generate():
|
|
74
|
+
with torch.no_grad():
|
|
75
|
+
top_p = request.get("top_p", 0.9)
|
|
76
|
+
repetition_penalty = request.get("repetition_penalty", 1.1)
|
|
77
|
+
self.model.generate(
|
|
78
|
+
**inputs,
|
|
79
|
+
max_new_tokens=max_new_tokens,
|
|
80
|
+
do_sample=do_sample,
|
|
81
|
+
temperature=temperature,
|
|
82
|
+
eos_token_id=self.tokenizer.eos_token_id,
|
|
83
|
+
pad_token_id=self.tokenizer.eos_token_id,
|
|
84
|
+
streamer=streamer,
|
|
85
|
+
top_p=top_p,
|
|
86
|
+
repetition_penalty=repetition_penalty
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
threading.Thread(target=generate, daemon=True).start()
|
|
90
|
+
|
|
91
|
+
def stream_output():
|
|
92
|
+
for text in streamer:
|
|
93
|
+
result.text += text
|
|
94
|
+
result.done = True
|
|
95
|
+
|
|
96
|
+
threading.Thread(target=stream_output, daemon=True).start()
|
|
97
|
+
|
|
98
|
+
return result
|
|
99
|
+
|
|
100
|
+
else:
|
|
101
|
+
with torch.no_grad():
|
|
102
|
+
output_ids = self.model.generate(
|
|
103
|
+
**inputs,
|
|
104
|
+
max_new_tokens=max_new_tokens,
|
|
105
|
+
do_sample=do_sample,
|
|
106
|
+
temperature=temperature,
|
|
107
|
+
eos_token_id=self.tokenizer.eos_token_id,
|
|
108
|
+
pad_token_id=self.tokenizer.eos_token_id
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
input_length = inputs["input_ids"].shape[1]
|
|
112
|
+
new_tokens = output_ids[0][input_length:]
|
|
113
|
+
|
|
114
|
+
result.text = self.tokenizer.decode(
|
|
115
|
+
new_tokens,
|
|
116
|
+
skip_special_tokens=True,
|
|
117
|
+
clean_up_tokenization_spaces=False
|
|
118
|
+
)
|
|
119
|
+
result.done = True
|
|
120
|
+
|
|
121
|
+
return result
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from .base_adapter import BaseAdapter, Value
|
|
2
|
+
|
|
3
|
+
class Router:
|
|
4
|
+
def __init__(self):
|
|
5
|
+
self.adapters:list[BaseAdapter] = []
|
|
6
|
+
|
|
7
|
+
def register_adapter(self, adapter:BaseAdapter):
|
|
8
|
+
self.adapters.append(adapter)
|
|
9
|
+
|
|
10
|
+
def route(self, request:dict):
|
|
11
|
+
for adapter in self.adapters:
|
|
12
|
+
if adapter.supports(request):
|
|
13
|
+
if adapter.model is None:
|
|
14
|
+
adapter.load(adapter.register_model(**request.get("model_kwargs", {})))
|
|
15
|
+
return adapter.run(request)
|
|
16
|
+
raise ValueError(f"Couldn't find adapter for request: {request}")
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from enum import Enum
|
|
2
|
+
|
|
3
|
+
class Color(Enum):
|
|
4
|
+
RESET = "\033[0m"
|
|
5
|
+
RED = "\033[31m"
|
|
6
|
+
GREEN = "\033[32m"
|
|
7
|
+
YELLOW = "\033[33m"
|
|
8
|
+
BLUE = "\033[34m"
|
|
9
|
+
MAGENTA = "\033[35m"
|
|
10
|
+
CYAN = "\033[36m"
|
|
11
|
+
WHITE = "\033[37m"
|
|
12
|
+
|
|
13
|
+
def print_col(txt, col:Color, pref="", suff=""):
|
|
14
|
+
print(f"{pref}{col.value}{txt}{Color.RESET.value}{suff}")
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import subprocess
|
|
2
|
+
import sys
|
|
3
|
+
from . import common
|
|
4
|
+
import shutil
|
|
5
|
+
|
|
6
|
+
# ===========================
|
|
7
|
+
# Hilfsfunktionen
|
|
8
|
+
# ===========================
|
|
9
|
+
|
|
10
|
+
def run(cmd):
|
|
11
|
+
"""Führt Shell-Befehle aus und bricht bei Fehlern ab."""
|
|
12
|
+
common.print_col(cmd, common.Color.CYAN, pref="> ")
|
|
13
|
+
result = subprocess.run(cmd, shell=True)
|
|
14
|
+
if result.returncode != 0:
|
|
15
|
+
common.print_col(f"Fehler beim Ausführen: {cmd}", common.Color.RED)
|
|
16
|
+
sys.exit(1)
|
|
17
|
+
|
|
18
|
+
def write_requirements(packages):
|
|
19
|
+
with open("requirements.txt", "w") as f:
|
|
20
|
+
for pkg in packages:
|
|
21
|
+
f.write(f"{pkg}\n")
|
|
22
|
+
common.print_col("requirements.txt erstellt!", common.Color.BLUE)
|
|
23
|
+
|
|
24
|
+
def main():
|
|
25
|
+
common.print_col("Upgrading pip if necessary...", common.Color.BLUE)
|
|
26
|
+
run("python.exe -m pip install --upgrade pip")
|
|
27
|
+
|
|
28
|
+
common.print_col("Checking CUDA avaibility...", common.Color.BLUE)
|
|
29
|
+
cuda_available = False
|
|
30
|
+
if shutil.which("nvidia-smi") is not None:
|
|
31
|
+
try:
|
|
32
|
+
output = subprocess.check_output("nvidia-smi", shell=True)
|
|
33
|
+
if b"NVIDIA" in output:
|
|
34
|
+
cuda_available = True
|
|
35
|
+
except subprocess.CalledProcessError:
|
|
36
|
+
cuda_available = False
|
|
37
|
+
|
|
38
|
+
packages = ["transformers", "Pillow", "PySide6"]
|
|
39
|
+
|
|
40
|
+
if cuda_available:
|
|
41
|
+
common.print_col("CUDA-enabled GPU detected! Install PyTorch with CUDA...", common.Color.BLUE)
|
|
42
|
+
packages.append("torch --index-url https://download.pytorch.org/whl/cu121")
|
|
43
|
+
else:
|
|
44
|
+
common.print_col("No CUDA GPU found. Installing CPU version of PyTorch...", common.Color.YELLOW)
|
|
45
|
+
packages.append("torch")
|
|
46
|
+
|
|
47
|
+
for pkg in packages:
|
|
48
|
+
run(f"{sys.executable} -m pip install {pkg}")
|
|
49
|
+
|
|
50
|
+
write_requirements(packages)
|
|
51
|
+
|
|
52
|
+
common.print_col("Installation abgeschlossen ✅", common.Color.GREEN)
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
from .adapters import router
|
|
2
|
+
import os
|
|
3
|
+
import time
|
|
4
|
+
|
|
5
|
+
def main():
|
|
6
|
+
print("Start")
|
|
7
|
+
|
|
8
|
+
os.environ["HF_HOME"] = "D:/AnyAI/models"
|
|
9
|
+
|
|
10
|
+
model_path = "TinyLlama/TinyLlama-1.1B-Chat-v1.0"
|
|
11
|
+
max_length = 200
|
|
12
|
+
|
|
13
|
+
request = {
|
|
14
|
+
"type": "llm",
|
|
15
|
+
"max_length": max_length,
|
|
16
|
+
"do_sample": True,
|
|
17
|
+
"temperature": 0.8,
|
|
18
|
+
"stream": True,
|
|
19
|
+
"history": [],
|
|
20
|
+
"model_kwargs": {
|
|
21
|
+
"model_path": model_path
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
router.adapters[0].load(router.adapters[0].register_model(**request["model_kwargs"]))
|
|
25
|
+
os.system("cls")
|
|
26
|
+
# Repl-artige Schleife
|
|
27
|
+
history = [{"role": "system", "content": """You are a helpful and concise assistant.
|
|
28
|
+
Answer the user questions factually and briefly.
|
|
29
|
+
Do not provide examples, do not speculate, do not invent code or explanations unless explicitly asked.
|
|
30
|
+
Stop after giving a direct answer."""}]
|
|
31
|
+
while True:
|
|
32
|
+
prompt = input(">>> ")
|
|
33
|
+
request["prompt"] = prompt
|
|
34
|
+
history.append({"role": "user", "content": prompt})
|
|
35
|
+
request["history"] = history
|
|
36
|
+
result = router.route(request)
|
|
37
|
+
|
|
38
|
+
last_len = 0
|
|
39
|
+
while True:
|
|
40
|
+
if len(result.text) > last_len:
|
|
41
|
+
print(result.text[last_len:], end="", flush=True)
|
|
42
|
+
last_len = len(result.text)
|
|
43
|
+
|
|
44
|
+
# Check if stream finished
|
|
45
|
+
if getattr(result, "done", False):
|
|
46
|
+
print() # Neue Zeile am Ende
|
|
47
|
+
break
|
|
48
|
+
|
|
49
|
+
time.sleep(0.05)
|
|
50
|
+
history.append({"role": "assistant", "content": result.text})
|
|
51
|
+
|
|
52
|
+
if __name__ == '__main__':
|
|
53
|
+
main()
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
pyproject.toml
|
|
2
|
+
LocalAdapt/__init__.py
|
|
3
|
+
LocalAdapt/common.py
|
|
4
|
+
LocalAdapt/install.py
|
|
5
|
+
LocalAdapt/test.py
|
|
6
|
+
LocalAdapt.egg-info/PKG-INFO
|
|
7
|
+
LocalAdapt.egg-info/SOURCES.txt
|
|
8
|
+
LocalAdapt.egg-info/dependency_links.txt
|
|
9
|
+
LocalAdapt.egg-info/top_level.txt
|
|
10
|
+
LocalAdapt/adapters/__init__.py
|
|
11
|
+
LocalAdapt/adapters/base_adapter.py
|
|
12
|
+
LocalAdapt/adapters/diffusion.py
|
|
13
|
+
LocalAdapt/adapters/ersgan.py
|
|
14
|
+
LocalAdapt/adapters/llm.py
|
|
15
|
+
LocalAdapt/adapters/router.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
LocalAdapt
|