qlam 2.0.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.
- qlam-2.0.0/PKG-INFO +13 -0
- qlam-2.0.0/README.md +17 -0
- qlam-2.0.0/qlam.egg-info/PKG-INFO +13 -0
- qlam-2.0.0/qlam.egg-info/SOURCES.txt +7 -0
- qlam-2.0.0/qlam.egg-info/dependency_links.txt +1 -0
- qlam-2.0.0/qlam.egg-info/top_level.txt +1 -0
- qlam-2.0.0/qlam.py +180 -0
- qlam-2.0.0/setup.cfg +4 -0
- qlam-2.0.0/setup.py +15 -0
qlam-2.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: qlam
|
|
3
|
+
Version: 2.0.0
|
|
4
|
+
Summary: Python SDK for Qalam Document Format (.qlm)
|
|
5
|
+
Author: Antigravity
|
|
6
|
+
Classifier: Programming Language :: Python :: 3
|
|
7
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
8
|
+
Classifier: Operating System :: OS Independent
|
|
9
|
+
Requires-Python: >=3.6
|
|
10
|
+
Dynamic: author
|
|
11
|
+
Dynamic: classifier
|
|
12
|
+
Dynamic: requires-python
|
|
13
|
+
Dynamic: summary
|
qlam-2.0.0/README.md
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# qalam_android
|
|
2
|
+
|
|
3
|
+
A new Flutter project.
|
|
4
|
+
|
|
5
|
+
## Getting Started
|
|
6
|
+
|
|
7
|
+
This project is a starting point for a Flutter application.
|
|
8
|
+
|
|
9
|
+
A few resources to get you started if this is your first Flutter project:
|
|
10
|
+
|
|
11
|
+
- [Learn Flutter](https://docs.flutter.dev/get-started/learn-flutter)
|
|
12
|
+
- [Write your first Flutter app](https://docs.flutter.dev/get-started/codelab)
|
|
13
|
+
- [Flutter learning resources](https://docs.flutter.dev/reference/learning-resources)
|
|
14
|
+
|
|
15
|
+
For help getting started with Flutter development, view the
|
|
16
|
+
[online documentation](https://docs.flutter.dev/), which offers tutorials,
|
|
17
|
+
samples, guidance on mobile development, and a full API reference.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: qlam
|
|
3
|
+
Version: 2.0.0
|
|
4
|
+
Summary: Python SDK for Qalam Document Format (.qlm)
|
|
5
|
+
Author: Antigravity
|
|
6
|
+
Classifier: Programming Language :: Python :: 3
|
|
7
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
8
|
+
Classifier: Operating System :: OS Independent
|
|
9
|
+
Requires-Python: >=3.6
|
|
10
|
+
Dynamic: author
|
|
11
|
+
Dynamic: classifier
|
|
12
|
+
Dynamic: requires-python
|
|
13
|
+
Dynamic: summary
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
qlam
|
qlam-2.0.0/qlam.py
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import os
|
|
3
|
+
import struct
|
|
4
|
+
|
|
5
|
+
class QlmNode:
|
|
6
|
+
"""Represents a structured node block in a QLM document."""
|
|
7
|
+
def __init__(self, node_type, title, data=None, parent_id=None, asset_bytes=None, display_style=None):
|
|
8
|
+
self.id = f"node_{os.urandom(8).hex()}"
|
|
9
|
+
self.parent_id = parent_id
|
|
10
|
+
self.type = node_type # text, model3d, image, docx, zip, pdf, etc.
|
|
11
|
+
self.title = title
|
|
12
|
+
self.data = data or {}
|
|
13
|
+
self.display_style = display_style or {"width_ratio": 1.0, "collapsed": False}
|
|
14
|
+
self.asset_bytes = asset_bytes
|
|
15
|
+
|
|
16
|
+
def to_dict(self):
|
|
17
|
+
return {
|
|
18
|
+
"id": self.id,
|
|
19
|
+
"parent_id": self.parent_id,
|
|
20
|
+
"type": self.type,
|
|
21
|
+
"title": self.title,
|
|
22
|
+
"data": self.data,
|
|
23
|
+
"display_style": self.display_style
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
class QlmDocument:
|
|
27
|
+
"""Core class for compiling and reading unified .qlm files in Python."""
|
|
28
|
+
def __init__(self, title, author="Anonim"):
|
|
29
|
+
self.id = f"doc_{os.urandom(8).hex()}"
|
|
30
|
+
self.metadata = {
|
|
31
|
+
"title": title,
|
|
32
|
+
"author": author,
|
|
33
|
+
"description": "",
|
|
34
|
+
"language": "tr",
|
|
35
|
+
"created_at": 0,
|
|
36
|
+
"version": "2.0.0",
|
|
37
|
+
"is_encrypted": False,
|
|
38
|
+
"tags": []
|
|
39
|
+
}
|
|
40
|
+
self.nodes = []
|
|
41
|
+
self.relationships = []
|
|
42
|
+
|
|
43
|
+
def add_text(self, title, content, level=3, parent_id=None):
|
|
44
|
+
node = QlmNode(
|
|
45
|
+
node_type="text",
|
|
46
|
+
title=title,
|
|
47
|
+
data={"content": content, "level": level},
|
|
48
|
+
parent_id=parent_id
|
|
49
|
+
)
|
|
50
|
+
self.nodes.append(node)
|
|
51
|
+
return node
|
|
52
|
+
|
|
53
|
+
def add_embed(self, node_type, title, asset_path, mime_type, parent_id=None):
|
|
54
|
+
"""Embeds any binary file (3D, docx, zip, image, mp4) to the document."""
|
|
55
|
+
if not os.path.exists(asset_path):
|
|
56
|
+
raise FileNotFoundError(f"Asset file not found: {asset_path}")
|
|
57
|
+
|
|
58
|
+
with open(asset_path, "rb") as f:
|
|
59
|
+
data_bytes = f.read()
|
|
60
|
+
|
|
61
|
+
node = QlmNode(
|
|
62
|
+
node_type=node_type,
|
|
63
|
+
title=title,
|
|
64
|
+
data={"mime": mime_type, "asset_length": len(data_bytes)},
|
|
65
|
+
parent_id=parent_id,
|
|
66
|
+
asset_bytes=data_bytes
|
|
67
|
+
)
|
|
68
|
+
self.nodes.append(node)
|
|
69
|
+
return node
|
|
70
|
+
|
|
71
|
+
def compile(self, output_path):
|
|
72
|
+
"""Compiles the document into a high performance manifest-indexed binary QLM document."""
|
|
73
|
+
buffer = bytearray()
|
|
74
|
+
|
|
75
|
+
# 1. Header (14 bytes)
|
|
76
|
+
buffer.extend(b"QLAM")
|
|
77
|
+
# Version (2 bytes) = 2 (u16 little endian)
|
|
78
|
+
buffer.extend(struct.pack("<H", 2))
|
|
79
|
+
# Manifest Offset Placeholder (8 bytes, updated at end)
|
|
80
|
+
manifest_offset_pos = len(buffer)
|
|
81
|
+
buffer.extend(struct.pack("<Q", 0))
|
|
82
|
+
|
|
83
|
+
# 2. Write binary payloads and update node manifests
|
|
84
|
+
nodes_dict = []
|
|
85
|
+
for node in self.nodes:
|
|
86
|
+
node_dict = node.to_dict()
|
|
87
|
+
if node.asset_bytes:
|
|
88
|
+
start_byte = len(buffer)
|
|
89
|
+
buffer.extend(node.asset_bytes)
|
|
90
|
+
|
|
91
|
+
# Update json manifest offsets
|
|
92
|
+
node_dict["data"]["asset_start_byte"] = start_byte
|
|
93
|
+
node_dict["data"]["asset_length"] = len(node.asset_bytes)
|
|
94
|
+
|
|
95
|
+
# 8-byte alignment padding
|
|
96
|
+
padding = (8 - (len(buffer) % 8)) % 8
|
|
97
|
+
buffer.extend(b"\x00" * padding)
|
|
98
|
+
|
|
99
|
+
nodes_dict.append(node_dict)
|
|
100
|
+
|
|
101
|
+
# 3. Calculate final manifest offset and write manifest JSON
|
|
102
|
+
manifest_offset = len(buffer)
|
|
103
|
+
|
|
104
|
+
manifest_doc = {
|
|
105
|
+
"id": self.id,
|
|
106
|
+
"metadata": self.metadata,
|
|
107
|
+
"nodes": nodes_dict,
|
|
108
|
+
"relationships": self.relationships
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
manifest_json = json.dumps(manifest_doc).encode("utf-8")
|
|
112
|
+
buffer.extend(manifest_json)
|
|
113
|
+
|
|
114
|
+
# 4. Fill in the header manifest offset
|
|
115
|
+
struct.pack_into("<Q", buffer, manifest_offset_pos, manifest_offset)
|
|
116
|
+
|
|
117
|
+
# 5. Write to file
|
|
118
|
+
with open(output_path, "wb") as f:
|
|
119
|
+
f.write(buffer)
|
|
120
|
+
|
|
121
|
+
print(f"[QLM] Compiled '{self.metadata['title']}' to {output_path} ({len(buffer)} bytes)")
|
|
122
|
+
|
|
123
|
+
@classmethod
|
|
124
|
+
def load(cls, file_path):
|
|
125
|
+
"""Loads and parses a .qlm document into a Python object."""
|
|
126
|
+
if not os.path.exists(file_path):
|
|
127
|
+
raise FileNotFoundError(f"QLM file not found: {file_path}")
|
|
128
|
+
|
|
129
|
+
with open(file_path, "rb") as f:
|
|
130
|
+
data = f.read()
|
|
131
|
+
|
|
132
|
+
if len(data) < 14:
|
|
133
|
+
raise ValueError("Invalid QLM file: too short")
|
|
134
|
+
|
|
135
|
+
# Read magic & version
|
|
136
|
+
magic = data[0:4]
|
|
137
|
+
if magic != b"QLAM":
|
|
138
|
+
raise ValueError(f"Invalid QLM signature: {magic}")
|
|
139
|
+
|
|
140
|
+
version = struct.unpack("<H", data[4:6])[0]
|
|
141
|
+
if version != 2:
|
|
142
|
+
raise ValueError(f"Unsupported QLM version: {version}")
|
|
143
|
+
|
|
144
|
+
# Read manifest offset
|
|
145
|
+
manifest_offset = struct.unpack("<Q", data[6:14])[0]
|
|
146
|
+
if manifest_offset >= len(data):
|
|
147
|
+
raise ValueError("Invalid manifest offset")
|
|
148
|
+
|
|
149
|
+
# Parse JSON manifest
|
|
150
|
+
manifest_json = data[manifest_offset:].decode("utf-8")
|
|
151
|
+
doc_dict = json.loads(manifest_json)
|
|
152
|
+
|
|
153
|
+
# Construct Python QlmDocument instance
|
|
154
|
+
doc = cls(title=doc_dict["metadata"]["title"])
|
|
155
|
+
doc.id = doc_dict["id"]
|
|
156
|
+
doc.metadata = doc_dict["metadata"]
|
|
157
|
+
doc.relationships = doc_dict.get("relationships", [])
|
|
158
|
+
|
|
159
|
+
# Build node tree models and attach internal asset slices
|
|
160
|
+
for node_dict in doc_dict.get("nodes", []):
|
|
161
|
+
asset_bytes = None
|
|
162
|
+
if "asset_start_byte" in node_dict["data"]:
|
|
163
|
+
start = node_dict["data"]["asset_start_byte"]
|
|
164
|
+
length = node_dict["data"]["asset_length"]
|
|
165
|
+
if start + length <= len(data):
|
|
166
|
+
# Zero-copy reference slicing of binary file payload
|
|
167
|
+
asset_bytes = data[start:start+length]
|
|
168
|
+
|
|
169
|
+
node = QlmNode(
|
|
170
|
+
node_type=node_dict["type"],
|
|
171
|
+
title=node_dict["title"],
|
|
172
|
+
data=node_dict["data"],
|
|
173
|
+
parent_id=node_dict.get("parent_id"),
|
|
174
|
+
asset_bytes=asset_bytes,
|
|
175
|
+
display_style=node_dict.get("display_style")
|
|
176
|
+
)
|
|
177
|
+
node.id = node_dict["id"]
|
|
178
|
+
doc.nodes.append(node)
|
|
179
|
+
|
|
180
|
+
return doc
|
qlam-2.0.0/setup.cfg
ADDED
qlam-2.0.0/setup.py
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from setuptools import setup, find_packages
|
|
2
|
+
|
|
3
|
+
setup(
|
|
4
|
+
name="qlam",
|
|
5
|
+
version="2.0.0",
|
|
6
|
+
description="Python SDK for Qalam Document Format (.qlm)",
|
|
7
|
+
author="Antigravity",
|
|
8
|
+
py_modules=["qlam"],
|
|
9
|
+
classifiers=[
|
|
10
|
+
"Programming Language :: Python :: 3",
|
|
11
|
+
"License :: OSI Approved :: MIT License",
|
|
12
|
+
"Operating System :: OS Independent",
|
|
13
|
+
],
|
|
14
|
+
python_requires=">=3.6",
|
|
15
|
+
)
|