unisi 0.3.18__py3-none-any.whl → 0.3.20__py3-none-any.whl
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.
- unisi/common.py +5 -5
- unisi/llmrag.py +70 -6
- unisi/server.py +5 -5
- unisi/units.py +6 -5
- unisi/users.py +3 -1
- unisi/web/css/565.f35d8840.css +1 -0
- unisi/web/css/72.9393078c.css +1 -0
- unisi/web/css/{vendor.f7e3cefe.css → app.36cc37f3.css} +3 -3
- unisi/web/css/app.36cc37f3.css.gz +0 -0
- unisi/web/fonts/KFOMCnqEu92Fr1ME7kSn66aGLdTylUAMQXC89YmC2DPNWuYjalmUiAw.2cafd699.woff +0 -0
- unisi/web/fonts/KFOMCnqEu92Fr1ME7kSn66aGLdTylUAMQXC89YmC2DPNWuZtalmUiAw.7f471697.woff +0 -0
- unisi/web/fonts/KFOMCnqEu92Fr1ME7kSn66aGLdTylUAMQXC89YmC2DPNWuaabVmUiAw.b69d1cce.woff +0 -0
- unisi/web/fonts/KFOMCnqEu92Fr1ME7kSn66aGLdTylUAMQXC89YmC2DPNWub2bVmUiAw.2115c3bd.woff +0 -0
- unisi/web/fonts/KFOMCnqEu92Fr1ME7kSn66aGLdTylUAMQXC89YmC2DPNWubEbFmUiAw.bb8ee9ee.woff +0 -0
- unisi/web/fonts/KFOMCnqEu92Fr1ME7kSn66aGLdTylUAMQXC89YmC2DPNWubEbVmUiAw.eb9d7304.woff +0 -0
- unisi/web/index.html +1 -1
- unisi/web/js/260.1d50abd6.js +1 -0
- unisi/web/js/565.437dc595.js +3 -0
- unisi/web/js/565.437dc595.js.gz +0 -0
- unisi/web/js/609.a5c4177e.js +1 -0
- unisi/web/js/72.f1673470.js +1 -0
- unisi/web/js/935.a10cb1a0.js +1 -0
- unisi/web/js/app.aa62bd3c.js +1 -0
- unisi/web/js/echart.8f773fb7.js +1 -0
- unisi/web/js/echart.8f773fb7.js.gz +0 -0
- unisi/web/js/sigma.ce21336a.js +1 -0
- unisi/web/js/sigma.ce21336a.js.gz +0 -0
- unisi/web/js/vendor.6a64dcc5.js +57 -0
- unisi/web/js/vendor.6a64dcc5.js.gz +0 -0
- {unisi-0.3.18.dist-info → unisi-0.3.20.dist-info}/METADATA +1 -1
- unisi-0.3.20.dist-info/RECORD +58 -0
- unisi/web/css/131.703d8f36.css +0 -1
- unisi/web/css/app.31d6cfe0.css +0 -0
- unisi/web/fonts/KFOkCnqEu92Fr1MmgVxIIzQ.68bb21d0.woff +0 -0
- unisi/web/fonts/KFOlCnqEu92Fr1MmEU9fBBc-.48af7707.woff +0 -0
- unisi/web/fonts/KFOlCnqEu92Fr1MmSU5fBBc-.c2f7ab22.woff +0 -0
- unisi/web/fonts/KFOlCnqEu92Fr1MmWUlfBBc-.77ecb942.woff +0 -0
- unisi/web/fonts/KFOlCnqEu92Fr1MmYUtfBBc-.f5677eb2.woff +0 -0
- unisi/web/fonts/KFOmCnqEu92Fr1Mu4mxM.f1e2a767.woff +0 -0
- unisi/web/js/131.76c61515.js +0 -3
- unisi/web/js/609.35dc13d3.js +0 -1
- unisi/web/js/935.cc0c012c.js +0 -1
- unisi/web/js/app.6f20f926.js +0 -1
- unisi/web/js/vendor.1bb14e9d.js +0 -45
- unisi-0.3.18.dist-info/RECORD +0 -49
- {unisi-0.3.18.dist-info → unisi-0.3.20.dist-info}/WHEEL +0 -0
- {unisi-0.3.18.dist-info → unisi-0.3.20.dist-info}/entry_points.txt +0 -0
- {unisi-0.3.18.dist-info → unisi-0.3.20.dist-info}/licenses/LICENSE +0 -0
unisi/common.py
CHANGED
@@ -120,17 +120,17 @@ class Message:
|
|
120
120
|
|
121
121
|
def fill_paths4(self, user):
|
122
122
|
if hasattr(self, 'updates'):
|
123
|
-
|
123
|
+
invisible = []
|
124
124
|
for update in self.updates:
|
125
125
|
data = update["data"]
|
126
126
|
path = user.find_path(data)
|
127
127
|
if path:
|
128
128
|
update['path'] = path
|
129
129
|
else:
|
130
|
-
|
131
|
-
user.log(f'
|
132
|
-
Such element not on the screen!')
|
133
|
-
for inv in
|
130
|
+
invisible.append(update)
|
131
|
+
user.log(f'Invisible element update {data.name}, type {data.type}.\n\
|
132
|
+
Such element not on the screen!', type = 'warning')
|
133
|
+
for inv in invisible:
|
134
134
|
self.updates.remove(inv)
|
135
135
|
|
136
136
|
def contains(self, unit):
|
unisi/llmrag.py
CHANGED
@@ -9,9 +9,50 @@ from langchain_google_genai import (
|
|
9
9
|
HarmCategory,
|
10
10
|
)
|
11
11
|
from datetime import datetime
|
12
|
-
import
|
12
|
+
import os, inspect, re, json
|
13
13
|
from typing import get_origin, get_args
|
14
14
|
|
15
|
+
class QueryCache:
|
16
|
+
ITEM_SEPARATOR = "§¶†‡◊•→±"
|
17
|
+
ENTRY_SEPARATOR = "€£¥¢≠≈∆√"
|
18
|
+
|
19
|
+
def __init__(self, file_path):
|
20
|
+
self.file_path = file_path
|
21
|
+
self.cache = {}
|
22
|
+
self._load_cache()
|
23
|
+
|
24
|
+
def _load_cache(self):
|
25
|
+
if os.path.exists(self.file_path):
|
26
|
+
with open(self.file_path, 'r', encoding='utf-8') as f:
|
27
|
+
content = f.read()
|
28
|
+
entries = content.split(self.ENTRY_SEPARATOR)
|
29
|
+
for entry in entries:
|
30
|
+
if not entry.strip():
|
31
|
+
continue
|
32
|
+
parts = entry.split(self.ITEM_SEPARATOR)
|
33
|
+
if len(parts) == 2:
|
34
|
+
query, result = parts
|
35
|
+
self.cache[query] = result
|
36
|
+
|
37
|
+
def get(self, query):
|
38
|
+
return self.cache.get(query)
|
39
|
+
|
40
|
+
def set(self, query, result):
|
41
|
+
entry_data = f"{query}{self.ITEM_SEPARATOR}{result}"
|
42
|
+
prepend_separator = bool(self.cache)
|
43
|
+
|
44
|
+
try:
|
45
|
+
with open(self.file_path, 'a', encoding='utf-8') as f:
|
46
|
+
if prepend_separator:
|
47
|
+
f.write(self.ENTRY_SEPARATOR)
|
48
|
+
f.write(entry_data)
|
49
|
+
|
50
|
+
self.cache[query] = result
|
51
|
+
return True
|
52
|
+
except Exception as e:
|
53
|
+
print(f"Error caching result: {e}")
|
54
|
+
return False
|
55
|
+
|
15
56
|
def jstype(type_value):
|
16
57
|
if isinstance(type_value, type):
|
17
58
|
if type_value == int:
|
@@ -80,6 +121,13 @@ def is_type(variable, expected_type):
|
|
80
121
|
|
81
122
|
return False
|
82
123
|
|
124
|
+
def remove_comments(json_str):
|
125
|
+
# Regular expression to remove single-line comments (// ...)
|
126
|
+
json_str = re.sub(r'//.*', '', json_str)
|
127
|
+
# Regular expression to remove multi-line comments (/* ... */)
|
128
|
+
json_str = re.sub(r'/\*.*?\*/', '', json_str, flags=re.DOTALL)
|
129
|
+
return json_str
|
130
|
+
|
83
131
|
def Q(str_prompt, type_value = str, blank = True, **format_model):
|
84
132
|
"""returns LLM async call for a question"""
|
85
133
|
llm = Unishare.llm_model
|
@@ -90,13 +138,26 @@ def Q(str_prompt, type_value = str, blank = True, **format_model):
|
|
90
138
|
if not re.search(r'json', str_prompt, re.IGNORECASE):
|
91
139
|
jtype = jstype(type_value)
|
92
140
|
format = " dd/mm/yyyy string" if type_value == 'date' else f'a JSON {jtype}' if jtype != 'string' else jtype
|
93
|
-
str_prompt = f"System: You are an intelligent and extremely smart assistant. Output STRONGLY {format}.
|
141
|
+
str_prompt = f"System: You are an intelligent and extremely smart assistant. Output STRONGLY {format}. DO NOT OUTPUT ANY COMMENTARY." + str_prompt
|
94
142
|
async def f():
|
95
|
-
|
96
|
-
|
143
|
+
if Unishare.llm_cache:
|
144
|
+
if content := Unishare.llm_cache.get(str_prompt):
|
145
|
+
pass
|
146
|
+
else:
|
147
|
+
io = await llm.ainvoke(str_prompt)
|
148
|
+
content = io.content
|
149
|
+
Unishare.llm_cache.set(str_prompt, content)
|
150
|
+
else:
|
151
|
+
io = await llm.ainvoke(str_prompt)
|
152
|
+
content = io.content
|
153
|
+
js = content.strip().strip('`').replace('json', '')
|
97
154
|
if type_value == str or type_value == 'date':
|
98
155
|
return js
|
99
|
-
|
156
|
+
try:
|
157
|
+
clean_js = remove_comments(js)
|
158
|
+
parsed = json.loads(clean_js)
|
159
|
+
except json.JSONDecodeError as e:
|
160
|
+
raise ValueError(f'Invalid JSON: {js}, \n Query: {str_prompt}')
|
100
161
|
if isinstance(type_value, dict):
|
101
162
|
for k, v in type_value.items():
|
102
163
|
if k not in parsed:
|
@@ -114,7 +175,7 @@ def Q(str_prompt, type_value = str, blank = True, **format_model):
|
|
114
175
|
raise TypeError(f'Invalid type for {k}: {type(parsed[k])} != {v}')
|
115
176
|
else:
|
116
177
|
if not is_type(parsed, type_value):
|
117
|
-
raise TypeError(f'Invalid type: {type(parsed)} != {type_value}')
|
178
|
+
raise TypeError(f'Invalid type: {type(parsed)} != {type_value}')
|
118
179
|
return parsed
|
119
180
|
return f()
|
120
181
|
|
@@ -169,6 +230,9 @@ def setup_llmrag():
|
|
169
230
|
max_retries=2,
|
170
231
|
# other params...
|
171
232
|
)
|
233
|
+
|
234
|
+
if hasattr(config, 'llm_cache'):
|
235
|
+
Unishare.llm_cache = QueryCache(config.llm_cache)
|
172
236
|
|
173
237
|
async def get_property(name, context = '', type = str, options = None):
|
174
238
|
if type == str and re.search(r'date', name, re.IGNORECASE):
|
unisi/server.py
CHANGED
@@ -173,12 +173,12 @@ def start(user_type = User, http_handlers = []):
|
|
173
173
|
|
174
174
|
User.type = user_type
|
175
175
|
run_tests(User.init_user())
|
176
|
-
|
177
|
-
http_handlers
|
178
|
-
|
179
|
-
web.get('/{tail:.*}', static_serve), web.post('/', post_handler)]
|
176
|
+
#http_handlers has to be the first argument
|
177
|
+
server_handlers = http_handlers + [web.get('/ws', websocket_handler),
|
178
|
+
web.static(f'/{config.upload_dir}', upload_dir),
|
179
|
+
web.get('/{tail:.*}', static_serve), web.post('/', post_handler)]
|
180
180
|
|
181
181
|
app = web.Application()
|
182
|
-
app.add_routes(
|
182
|
+
app.add_routes(server_handlers)
|
183
183
|
web.run_app(app, port = port)
|
184
184
|
|
unisi/units.py
CHANGED
@@ -111,11 +111,12 @@ class Unit:
|
|
111
111
|
super().__setattr__(name, value)
|
112
112
|
|
113
113
|
def mutate(self, obj):
|
114
|
-
self
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
self._mark_changed
|
114
|
+
if self is not obj:
|
115
|
+
self.__dict__.clear()
|
116
|
+
for key, value in obj.__dict__.items():
|
117
|
+
setattr(self, key, value)
|
118
|
+
if self._mark_changed:
|
119
|
+
self._mark_changed()
|
119
120
|
|
120
121
|
def accept(self, value):
|
121
122
|
if hasattr(self, 'changed'):
|
unisi/users.py
CHANGED
@@ -229,7 +229,9 @@ class User:
|
|
229
229
|
match raw:
|
230
230
|
case None:
|
231
231
|
if self.changed_units:
|
232
|
-
raw = Message(*self.changed_units, user = self)
|
232
|
+
raw = Message(*self.changed_units, user = self)
|
233
|
+
if not raw.updates:
|
234
|
+
raw = None
|
233
235
|
case Message():
|
234
236
|
if self.changed_units:
|
235
237
|
message_units = [x['data'] for x in raw.updates]
|
@@ -0,0 +1 @@
|
|
1
|
+
thead tr:first-child th{-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);position:sticky;top:0;z-index:1000}:root{--scrollbar-width-height:10px;--scrollbar-thumb-hover:#2176d2;--scrollbar-thumb-dark:#2176d2;--scrollbar-thumb-hover-dark:#2176d2}::-webkit-scrollbar{height:var(--scrollbar-width-height);width:var(--scrollbar-width-height)}::-webkit-scrollbar-track{box-shadow:inset 0 0 4px var(--scrollbar-track-dark)}::-webkit-scrollbar-corner{background:var(--scrollbar-track-dark)}::-webkit-scrollbar-thumb{background:var(--scrollbar-thumb-dark);border-radius:5px}::-webkit-scrollbar-thumb:hover{background:var(--scrollbar-thumb-hover-dark)}body[data-v-6398f67f]{display:flex;justify-content:center}.custom-caption[data-v-6398f67f]{padding:5px!important}.web-camera-container[data-v-6398f67f]{align-items:center;border:1px solid #ccc;border-radius:4px;display:flex;flex-direction:column;justify-content:center;margin-bottom:2rem;margin-top:2rem;padding:2rem;width:500px}.web-camera-container .camera-button[data-v-6398f67f]{margin-bottom:2rem}.web-camera-container .camera-box .camera-shutter[data-v-6398f67f]{background-color:#fff;height:337.5px;opacity:0;position:absolute;width:450px}.web-camera-container .camera-box .camera-shutter.flash[data-v-6398f67f]{opacity:1}.web-camera-container .camera-shoot[data-v-6398f67f]{margin:1rem 0}.web-camera-container .camera-shoot button[data-v-6398f67f]{align-items:center;border-radius:100%;display:flex;height:60px;justify-content:center;width:60px}.web-camera-container .camera-shoot button img[data-v-6398f67f]{height:35px;object-fit:cover}.web-camera-container .camera-loading[data-v-6398f67f]{height:100%;margin:3rem 0 0 -1.2rem;min-height:150px;overflow:hidden;position:absolute;width:100%}.web-camera-container .camera-loading ul[data-v-6398f67f]{height:100%;margin:0;position:absolute;width:100%;z-index:999999}.web-camera-container .camera-loading .loader-circle[data-v-6398f67f]{display:block;height:14px;left:100%;margin:0 auto;padding:0;position:absolute;top:50%;transform:translateY(-50%);transform:translateX(-50%);width:100%}.web-camera-container .camera-loading .loader-circle li[data-v-6398f67f]{animation:preload-6398f67f 1s infinite;background:#999;border-radius:100%;display:block;float:left;height:10px;line-height:10px;margin:0 0 0 4px;padding:0;position:relative;top:-50%;width:10px}.web-camera-container .camera-loading .loader-circle li[data-v-6398f67f]:nth-child(2){animation-delay:.2s}.web-camera-container .camera-loading .loader-circle li[data-v-6398f67f]:nth-child(3){animation-delay:.4s}@keyframes preload-6398f67f{0%{opacity:1}50%{opacity:.4}to{opacity:1}}.container[data-v-6398f67f]{position:relative}.frame[data-v-6398f67f]{border:2px solid #573497;border-radius:8px;height:100%;left:0;pointer-events:none;position:absolute;top:0;width:100%;z-index:10}.container{position:relative}.frame{border:2px solid #573497;border-radius:8px;height:100%;left:0;pointer-events:none;position:absolute;top:0;width:100%;z-index:10}.q-tab__label{font-size:16px;font-weight:700}
|
@@ -0,0 +1 @@
|
|
1
|
+
#header[data-v-a6b7e7b0]{font-size:16px;font-weight:700;left:10px;pointer-events:none;position:absolute;top:10px;z-index:2}#graph[data-v-a6b7e7b0]{border:1px solid #ccc;height:600px;position:relative;width:100%}
|