LangSC 2.1.0__tar.gz → 2.2.2__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.
- langsc-2.2.2/LangSC/__version__.py +7 -0
- {langsc-2.1.0 → langsc-2.2.2}/LangSC/base.lex +0 -0
- {langsc-2.1.0 → langsc-2.2.2}/LangSC/bcc.py +5 -5
- langsc-2.2.2/LangSC/bcclib.dll +0 -0
- {langsc-2.1.0 → langsc-2.2.2}/LangSC/gpf.py +5 -5
- langsc-2.2.2/LangSC/gpflib.dll +0 -0
- {langsc-2.1.0 → langsc-2.2.2}/LangSC/jss.py +122 -9
- langsc-2.2.2/LangSC/jsslib.dll +0 -0
- langsc-2.2.2/LangSC/libbcclib.dylib +0 -0
- {langsc-2.1.0 → langsc-2.2.2}/LangSC/libgpflib.dylib +0 -0
- {langsc-2.1.0 → langsc-2.2.2}/LangSC/libjsslib.dylib +0 -0
- {langsc-2.1.0 → langsc-2.2.2/LangSC.egg-info}/PKG-INFO +1 -1
- {langsc-2.1.0 → langsc-2.2.2}/LangSC.egg-info/SOURCES.txt +2 -1
- {langsc-2.1.0/LangSC.egg-info → langsc-2.2.2}/PKG-INFO +1 -1
- {langsc-2.1.0 → langsc-2.2.2}/setup.cfg +1 -1
- langsc-2.2.2/tests/test_win_smoke.py +138 -0
- langsc-2.1.0/LangSC/__version__.py +0 -3
- langsc-2.1.0/LangSC/bcclib.dll +0 -0
- langsc-2.1.0/LangSC/gpflib.dll +0 -0
- langsc-2.1.0/LangSC/jsslib.dll +0 -0
- langsc-2.1.0/LangSC/libbcclib.dylib +0 -0
- {langsc-2.1.0 → langsc-2.2.2}/LICENSE +0 -0
- {langsc-2.1.0 → langsc-2.2.2}/LangSC/BCCconfig.txt +0 -0
- {langsc-2.1.0 → langsc-2.2.2}/LangSC/GPFconfig.txt +0 -0
- {langsc-2.1.0 → langsc-2.2.2}/LangSC/Graph/Pathplan.dll +0 -0
- {langsc-2.1.0 → langsc-2.2.2}/LangSC/Graph/cdt.dll +0 -0
- {langsc-2.1.0 → langsc-2.2.2}/LangSC/Graph/cgraph.dll +0 -0
- {langsc-2.1.0 → langsc-2.2.2}/LangSC/Graph/config6 +0 -0
- {langsc-2.1.0 → langsc-2.2.2}/LangSC/Graph/dot.exe +0 -0
- {langsc-2.1.0 → langsc-2.2.2}/LangSC/Graph/fontconfig.dll +0 -0
- {langsc-2.1.0 → langsc-2.2.2}/LangSC/Graph/fontconfig_fix.dll +0 -0
- {langsc-2.1.0 → langsc-2.2.2}/LangSC/Graph/freetype6.dll +0 -0
- {langsc-2.1.0 → langsc-2.2.2}/LangSC/Graph/gvc.dll +0 -0
- {langsc-2.1.0 → langsc-2.2.2}/LangSC/Graph/gvplugin_core.dll +0 -0
- {langsc-2.1.0 → langsc-2.2.2}/LangSC/Graph/gvplugin_dot_layout.dll +0 -0
- {langsc-2.1.0 → langsc-2.2.2}/LangSC/Graph/gvplugin_gd.dll +0 -0
- {langsc-2.1.0 → langsc-2.2.2}/LangSC/Graph/gvplugin_pango.dll +0 -0
- {langsc-2.1.0 → langsc-2.2.2}/LangSC/Graph/iconv.dll +0 -0
- {langsc-2.1.0 → langsc-2.2.2}/LangSC/Graph/intl.dll +0 -0
- {langsc-2.1.0 → langsc-2.2.2}/LangSC/Graph/jpeg62.dll +0 -0
- {langsc-2.1.0 → langsc-2.2.2}/LangSC/Graph/libcairo-2.dll +0 -0
- {langsc-2.1.0 → langsc-2.2.2}/LangSC/Graph/libexpat-1.dll +0 -0
- {langsc-2.1.0 → langsc-2.2.2}/LangSC/Graph/libexpat.dll +0 -0
- {langsc-2.1.0 → langsc-2.2.2}/LangSC/Graph/libfontconfig-1.dll +0 -0
- {langsc-2.1.0 → langsc-2.2.2}/LangSC/Graph/libfreetype-6.dll +0 -0
- {langsc-2.1.0 → langsc-2.2.2}/LangSC/Graph/libgdk_pixbuf-2.0-0.dll +0 -0
- {langsc-2.1.0 → langsc-2.2.2}/LangSC/Graph/libglade-2.0-0.dll +0 -0
- {langsc-2.1.0 → langsc-2.2.2}/LangSC/Graph/libglib-2.0-0.dll +0 -0
- {langsc-2.1.0 → langsc-2.2.2}/LangSC/Graph/libgmodule-2.0-0.dll +0 -0
- {langsc-2.1.0 → langsc-2.2.2}/LangSC/Graph/libgobject-2.0-0.dll +0 -0
- {langsc-2.1.0 → langsc-2.2.2}/LangSC/Graph/libgthread-2.0-0.dll +0 -0
- {langsc-2.1.0 → langsc-2.2.2}/LangSC/Graph/libgtkglext-win32-1.0-0.dll +0 -0
- {langsc-2.1.0 → langsc-2.2.2}/LangSC/Graph/libpango-1.0-0.dll +0 -0
- {langsc-2.1.0 → langsc-2.2.2}/LangSC/Graph/libpangocairo-1.0-0.dll +0 -0
- {langsc-2.1.0 → langsc-2.2.2}/LangSC/Graph/libpangoft2-1.0-0.dll +0 -0
- {langsc-2.1.0 → langsc-2.2.2}/LangSC/Graph/libpangowin32-1.0-0.dll +0 -0
- {langsc-2.1.0 → langsc-2.2.2}/LangSC/Graph/libpng14-14.dll +0 -0
- {langsc-2.1.0 → langsc-2.2.2}/LangSC/Graph/librsvg-2-2.dll +0 -0
- {langsc-2.1.0 → langsc-2.2.2}/LangSC/Graph/libxml2.dll +0 -0
- {langsc-2.1.0 → langsc-2.2.2}/LangSC/Graph/ltdl.dll +0 -0
- {langsc-2.1.0 → langsc-2.2.2}/LangSC/Graph/zlib1.dll +0 -0
- {langsc-2.1.0 → langsc-2.2.2}/LangSC/Parser.lua +0 -0
- {langsc-2.1.0 → langsc-2.2.2}/LangSC/Segment.dat +0 -0
- {langsc-2.1.0 → langsc-2.2.2}/LangSC/__init__.py +0 -0
- {langsc-2.1.0 → langsc-2.2.2}/LangSC/_utils.py +0 -0
- {langsc-2.1.0 → langsc-2.2.2}/LangSC/idxPOS.dat +0 -0
- {langsc-2.1.0 → langsc-2.2.2}/LangSC/libbcclib.so +0 -0
- {langsc-2.1.0 → langsc-2.2.2}/LangSC/libgpflib.so +0 -0
- {langsc-2.1.0 → langsc-2.2.2}/LangSC/libjsslib.so +0 -0
- {langsc-2.1.0 → langsc-2.2.2}/LangSC.egg-info/dependency_links.txt +0 -0
- {langsc-2.1.0 → langsc-2.2.2}/LangSC.egg-info/not-zip-safe +0 -0
- {langsc-2.1.0 → langsc-2.2.2}/LangSC.egg-info/requires.txt +0 -0
- {langsc-2.1.0 → langsc-2.2.2}/LangSC.egg-info/top_level.txt +0 -0
- {langsc-2.1.0 → langsc-2.2.2}/MANIFEST.in +0 -0
- {langsc-2.1.0 → langsc-2.2.2}/README.md +0 -0
- {langsc-2.1.0 → langsc-2.2.2}/pyproject.toml +0 -0
- {langsc-2.1.0 → langsc-2.2.2}/setup.py +0 -0
- {langsc-2.1.0 → langsc-2.2.2}/tests/test_gpf_threadsafe.py +0 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# Single source of truth for the package version.
|
|
2
|
+
# Keep __version__ a plain string literal: setup.cfg reads it statically via
|
|
3
|
+
# `version = attr: LangSC.__version__.__version__`, so it must stay AST-parseable
|
|
4
|
+
# (no computed expression) to avoid importing the package at build time.
|
|
5
|
+
__version__ = "2.2.2"
|
|
6
|
+
|
|
7
|
+
VERSION = tuple(int(x) for x in __version__.split("."))
|
|
Binary file
|
|
@@ -24,12 +24,12 @@ lock = threading.Lock()
|
|
|
24
24
|
class BCC:
|
|
25
25
|
def __init__(self, dataPath="./data"):
|
|
26
26
|
dataPath = dataPath.replace("\\", "/")
|
|
27
|
-
if dataPath
|
|
27
|
+
if len(dataPath) > 1 and dataPath.endswith("/"):
|
|
28
28
|
dataPath = dataPath[:-1]
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
29
|
+
# 相对路径规范为 "./" 前缀;绝对路径(/... 或 X:/...)原样保留
|
|
30
|
+
if not (os.path.isabs(dataPath) or (len(dataPath) >= 2 and dataPath[1] == ":")):
|
|
31
|
+
if not dataPath.startswith("./"):
|
|
32
|
+
dataPath = "./" + dataPath
|
|
33
33
|
|
|
34
34
|
dll_name_bcc = ''
|
|
35
35
|
self.g_IdxLog = "IdxLog_BCC.txt"
|
|
Binary file
|
|
@@ -28,12 +28,12 @@ lock = threading.Lock()
|
|
|
28
28
|
class GPF:
|
|
29
29
|
def __init__(self, dataPath="./data"):
|
|
30
30
|
dataPath = dataPath.replace("\\", "/")
|
|
31
|
-
if dataPath
|
|
31
|
+
if len(dataPath) > 1 and dataPath.endswith("/"):
|
|
32
32
|
dataPath = dataPath[:-1]
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
# 相对路径规范为 "./" 前缀;绝对路径(/... 或 X:/...)原样保留
|
|
34
|
+
if not (os.path.isabs(dataPath) or (len(dataPath) >= 2 and dataPath[1] == ":")):
|
|
35
|
+
if not dataPath.startswith("./"):
|
|
36
|
+
dataPath = "./" + dataPath
|
|
37
37
|
|
|
38
38
|
dll_name_gpf = ''
|
|
39
39
|
self.g_IdxLog = "IdxLog_GPF.txt"
|
|
Binary file
|
|
@@ -1,10 +1,23 @@
|
|
|
1
|
-
"""JSS (JSON Structure Search) class wrapping jsslib.dll.
|
|
1
|
+
"""JSS (JSON Structure Search) class wrapping jsslib.dll.
|
|
2
2
|
|
|
3
|
+
Besides local SQL search over jsslib.dll, the JSS class also exposes a set of
|
|
4
|
+
``KG*`` methods for the remote **knowledge-graph** service. That service runs in
|
|
5
|
+
the same process as the language-element search API (route prefix ``/kg/*``,
|
|
6
|
+
Neo4j backend); the ``KG*`` methods talk to it over HTTP via ``requests`` and do
|
|
7
|
+
NOT touch the local DLL. The default entry is the public gateway
|
|
8
|
+
``https://cit.blcu.edu.cn/jss`` (use ``http://127.0.0.1:8100`` for a direct
|
|
9
|
+
local service); override it with the ``kg_url`` constructor argument.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
import io
|
|
3
13
|
import os
|
|
14
|
+
import zipfile
|
|
4
15
|
import platform
|
|
5
16
|
import json
|
|
6
17
|
from ctypes import *
|
|
7
18
|
|
|
19
|
+
import requests
|
|
20
|
+
|
|
8
21
|
from ._utils import (
|
|
9
22
|
detect_file_encoding, get_idx_info, get_jss_file_info, is_same,
|
|
10
23
|
get_jss_files, write_idx_log,
|
|
@@ -14,16 +27,23 @@ OS = platform.system()
|
|
|
14
27
|
if OS == "Windows":
|
|
15
28
|
import win32api
|
|
16
29
|
|
|
30
|
+
# 知识图谱服务默认入口(公网 nginx)。直连本机服务用 http://127.0.0.1:8100
|
|
31
|
+
DEFAULT_KG_BASE = "https://cit.blcu.edu.cn/jss"
|
|
32
|
+
|
|
17
33
|
|
|
18
34
|
class JSS:
|
|
19
|
-
def __init__(self, dataPath, log_level=0, log_filename=''):
|
|
35
|
+
def __init__(self, dataPath, log_level=0, log_filename='', kg_url=DEFAULT_KG_BASE, kg_timeout=60):
|
|
36
|
+
# Knowledge-graph remote service (independent of the local DLL below)
|
|
37
|
+
self.kg_url = (kg_url or DEFAULT_KG_BASE).rstrip("/")
|
|
38
|
+
self.kg_timeout = kg_timeout
|
|
39
|
+
|
|
20
40
|
dataPath = dataPath.replace("\\", "/")
|
|
21
|
-
if dataPath
|
|
41
|
+
if len(dataPath) > 1 and dataPath.endswith("/"):
|
|
22
42
|
dataPath = dataPath[:-1]
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
43
|
+
# 相对路径规范为 "./" 前缀;绝对路径(/... 或 X:/...)原样保留
|
|
44
|
+
if not (os.path.isabs(dataPath) or (len(dataPath) >= 2 and dataPath[1] == ":")):
|
|
45
|
+
if not dataPath.startswith("./"):
|
|
46
|
+
dataPath = "./" + dataPath
|
|
27
47
|
|
|
28
48
|
dll_name_jss = ''
|
|
29
49
|
|
|
@@ -178,9 +198,10 @@ class JSS:
|
|
|
178
198
|
else:
|
|
179
199
|
seg_fullname = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'base.lex')
|
|
180
200
|
|
|
201
|
+
# JL_CreateTable 第 7 参数 pBuildToolInfo(当前引擎 API;旧版 6 参数 DLL 在 cdecl 下忽略多余实参,向后兼容)
|
|
181
202
|
self.library_jss.JL_CreateTable.restype = c_int
|
|
182
|
-
self.library_jss.JL_CreateTable.argtypes = [c_char_p, c_char_p, c_char_p, c_char_p, c_int, c_char_p]
|
|
183
|
-
ret = self.library_jss.JL_CreateTable(cfg_filename.encode(), seg_fullname.encode(), dat_pathname.encode(), out_pathname.encode(), self.log_level, self.log_filename.encode())
|
|
203
|
+
self.library_jss.JL_CreateTable.argtypes = [c_char_p, c_char_p, c_char_p, c_char_p, c_int, c_char_p, c_char_p]
|
|
204
|
+
ret = self.library_jss.JL_CreateTable(cfg_filename.encode(), seg_fullname.encode(), dat_pathname.encode(), out_pathname.encode(), self.log_level, self.log_filename.encode(), b"LangSC")
|
|
184
205
|
return ret
|
|
185
206
|
|
|
186
207
|
def _load_table(self, filename, name=""):
|
|
@@ -214,3 +235,95 @@ class JSS:
|
|
|
214
235
|
self.library_jss.JL_Terminate(handle)
|
|
215
236
|
self.handles = {}
|
|
216
237
|
self.is_init = False
|
|
238
|
+
|
|
239
|
+
# ── Knowledge Graph (remote HTTP, /kg/* on self.kg_url) ──────────────────
|
|
240
|
+
# 这些方法走 HTTP(requests),不依赖本地 jsslib.dll,也不需要已加载的本地表。
|
|
241
|
+
# 后端为 Neo4j;服务不可用(未起 Neo4j / KG_ENABLED=0 等)时接口返回 HTTP 503。
|
|
242
|
+
# 节点统一结构 {id,label,type,graph_id,props?},边 {id,source,target,type,label,graph_id,props?}。
|
|
243
|
+
|
|
244
|
+
def _kg_url(self, path):
|
|
245
|
+
return self.kg_url + "/" + path.lstrip("/")
|
|
246
|
+
|
|
247
|
+
def _kg_result(self, resp, ctx):
|
|
248
|
+
"""Parse a /kg/* response; raise RuntimeError on any non-2xx (e.g. 400/404/503)."""
|
|
249
|
+
try:
|
|
250
|
+
parsed = resp.json()
|
|
251
|
+
except ValueError:
|
|
252
|
+
parsed = None
|
|
253
|
+
if not (200 <= resp.status_code < 300):
|
|
254
|
+
detail = parsed if parsed is not None else resp.text
|
|
255
|
+
raise RuntimeError("KG {} failed: HTTP {}: {}".format(ctx, resp.status_code, detail))
|
|
256
|
+
return parsed
|
|
257
|
+
|
|
258
|
+
@staticmethod
|
|
259
|
+
def _kg_zip_dir(dir_path):
|
|
260
|
+
"""Pack a jss-kg/v1 package directory into zip bytes (files under an inner dir named after it)."""
|
|
261
|
+
base = os.path.basename(os.path.normpath(dir_path))
|
|
262
|
+
buf = io.BytesIO()
|
|
263
|
+
with zipfile.ZipFile(buf, "w", compression=zipfile.ZIP_DEFLATED) as zf:
|
|
264
|
+
for name in ("graph.json", "nodes.jsonl", "edges.jsonl", "nodes.csv", "edges.csv"):
|
|
265
|
+
full = os.path.join(dir_path, name)
|
|
266
|
+
if os.path.isfile(full):
|
|
267
|
+
zf.write(full, arcname="{}/{}".format(base, name))
|
|
268
|
+
return buf.getvalue()
|
|
269
|
+
|
|
270
|
+
def KGImport(self, package, allow_reserved=False):
|
|
271
|
+
"""Import a jss-kg/v1 package by upload (POST /kg/graphs/import, multipart).
|
|
272
|
+
|
|
273
|
+
``package`` may be a .zip file path, a package directory
|
|
274
|
+
(containing graph.json + nodes.jsonl + edges.jsonl), or raw zip bytes.
|
|
275
|
+
Returns {graph_id, name, nodes, edges, warnings, replaced}.
|
|
276
|
+
"""
|
|
277
|
+
if isinstance(package, (bytes, bytearray)):
|
|
278
|
+
zip_bytes = bytes(package)
|
|
279
|
+
elif os.path.isdir(package):
|
|
280
|
+
zip_bytes = self._kg_zip_dir(package)
|
|
281
|
+
else:
|
|
282
|
+
with open(package, "rb") as f:
|
|
283
|
+
zip_bytes = f.read()
|
|
284
|
+
files = {"file": ("graph.zip", zip_bytes, "application/zip")}
|
|
285
|
+
data = {"allow_reserved": "true"} if allow_reserved else {}
|
|
286
|
+
resp = requests.post(self._kg_url("kg/graphs/import"), files=files, data=data, timeout=self.kg_timeout)
|
|
287
|
+
return self._kg_result(resp, "import")
|
|
288
|
+
|
|
289
|
+
def KGImportPath(self, path, allow_reserved=False):
|
|
290
|
+
"""Import a package already on the server under KG_IMPORT_ROOT, by relative path
|
|
291
|
+
(POST /kg/graphs/import_path, JSON). Returns the same shape as KGImport."""
|
|
292
|
+
payload = {"path": path, "allow_reserved": allow_reserved}
|
|
293
|
+
resp = requests.post(self._kg_url("kg/graphs/import_path"), json=payload, timeout=self.kg_timeout)
|
|
294
|
+
return self._kg_result(resp, "import_path")
|
|
295
|
+
|
|
296
|
+
def KGList(self):
|
|
297
|
+
"""List imported graphs (GET /kg/graphs). Returns a list of graph-metadata dicts
|
|
298
|
+
[{graph_id, name, description, node_count, edge_count, default_hops, updated_at}], possibly empty."""
|
|
299
|
+
resp = requests.get(self._kg_url("kg/graphs"), timeout=self.kg_timeout)
|
|
300
|
+
parsed = self._kg_result(resp, "graphs")
|
|
301
|
+
if isinstance(parsed, dict):
|
|
302
|
+
return parsed.get("data", [])
|
|
303
|
+
return []
|
|
304
|
+
|
|
305
|
+
def KGDelete(self, graph_id):
|
|
306
|
+
"""Delete a graph by id (DELETE /kg/graphs/{graph_id}). Returns {"deleted": graph_id}."""
|
|
307
|
+
resp = requests.delete(self._kg_url("kg/graphs/" + graph_id), timeout=self.kg_timeout)
|
|
308
|
+
return self._kg_result(resp, "delete")
|
|
309
|
+
|
|
310
|
+
def KGSubgraph(self, graph_id, q, hops=2, limit=200):
|
|
311
|
+
"""Fetch a subgraph around seed ``q`` (POST /kg/subgraph).
|
|
312
|
+
|
|
313
|
+
Seed is matched by node id first, then by label. ``hops`` in {1,2,3};
|
|
314
|
+
``limit`` in 1..2000. Returns {seed, nodes, edges}; on no match
|
|
315
|
+
{"nodes": [], "edges": [], "seed": None} with HTTP 200.
|
|
316
|
+
"""
|
|
317
|
+
payload = {"graph_id": graph_id, "q": q, "hops": hops, "limit": limit}
|
|
318
|
+
resp = requests.post(self._kg_url("kg/subgraph"), json=payload, timeout=self.kg_timeout)
|
|
319
|
+
return self._kg_result(resp, "subgraph")
|
|
320
|
+
|
|
321
|
+
def KGExpand(self, graph_id, node_id, limit=50):
|
|
322
|
+
"""Expand one hop around node ``node_id`` — by node id, NOT label (POST /kg/expand).
|
|
323
|
+
|
|
324
|
+
``limit`` in 1..500. Returns {seed, nodes, edges}; {"nodes": [], "edges": [],
|
|
325
|
+
"seed": None} with HTTP 200 if the node does not exist.
|
|
326
|
+
"""
|
|
327
|
+
payload = {"graph_id": graph_id, "id": node_id, "limit": limit}
|
|
328
|
+
resp = requests.post(self._kg_url("kg/expand"), json=payload, timeout=self.kg_timeout)
|
|
329
|
+
return self._kg_result(resp, "expand")
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""LangSC 功能 + 集成冒烟测试(Windows 本地 DLL)。
|
|
3
|
+
|
|
4
|
+
覆盖四个面:
|
|
5
|
+
GPF — 分词/词性(本地 gpflib.dll + Segment.dat/idxPOS.dat)
|
|
6
|
+
JSS — 由内联 JSONL 建表 + SQL 检索(本地 jsslib.dll + base.lex)
|
|
7
|
+
BCC — 由内联语料建索引 + 频次检索(本地 bcclib.dll + Parser.lua)
|
|
8
|
+
KG — 知识图谱远程集成(JSS.KG*,HTTP 到 cit.blcu.edu.cn;无网则跳过,不计失败)
|
|
9
|
+
|
|
10
|
+
独立运行:python tests/test_win_smoke.py
|
|
11
|
+
退出码 0 表示本地三引擎功能全通过(KG 为集成项,网络不可用时跳过)。
|
|
12
|
+
"""
|
|
13
|
+
import os
|
|
14
|
+
import sys
|
|
15
|
+
import json
|
|
16
|
+
import shutil
|
|
17
|
+
import tempfile
|
|
18
|
+
|
|
19
|
+
try:
|
|
20
|
+
sys.stdout.reconfigure(encoding="utf-8")
|
|
21
|
+
except Exception:
|
|
22
|
+
pass
|
|
23
|
+
|
|
24
|
+
# 使 `import LangSC` 可用(tests/ 的上上级是包父目录)
|
|
25
|
+
PKG_PARENT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
26
|
+
sys.path.insert(0, PKG_PARENT)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def section(title):
|
|
30
|
+
print("\n==================== {} ====================".format(title))
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def run_gpf():
|
|
34
|
+
from LangSC import GPF
|
|
35
|
+
tmp = tempfile.mkdtemp(prefix="lsc_gpf_")
|
|
36
|
+
g = GPF(tmp)
|
|
37
|
+
text = "我们到北京大学学习自然语言处理"
|
|
38
|
+
seg = json.loads(g.Parse(text, Structure="Segment"))
|
|
39
|
+
pos = json.loads(g.Parse(text, Structure="POS"))
|
|
40
|
+
print("Segment:", seg)
|
|
41
|
+
print("POS :", pos)
|
|
42
|
+
assert isinstance(seg, list) and len(seg) >= 2, "分词结果应为多词列表"
|
|
43
|
+
assert isinstance(pos, list) and len(pos) >= 2, "词性结果应为多项列表"
|
|
44
|
+
assert any("/" in x for x in pos), "POS 项应形如 词/词性"
|
|
45
|
+
return True
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def run_jss():
|
|
49
|
+
# 注意:LangSC 的 dataPath 以相对路径使用(构造器会给非 "./" 开头的路径加前缀,
|
|
50
|
+
# 绝对路径会被破坏),故 chdir 到临时目录、用相对目录名。
|
|
51
|
+
from LangSC import JSS
|
|
52
|
+
base = tempfile.mkdtemp(prefix="lsc_jss_")
|
|
53
|
+
cwd = os.getcwd()
|
|
54
|
+
os.chdir(base)
|
|
55
|
+
try:
|
|
56
|
+
os.makedirs("data")
|
|
57
|
+
with open("data/doc.jsonl", "w", encoding="utf-8") as f:
|
|
58
|
+
f.write(json.dumps({"id": 1, "title": "学习汉语", "body": "我们在北京大学学习"}, ensure_ascii=False) + "\n")
|
|
59
|
+
f.write(json.dumps({"id": 2, "title": "自然语言处理", "body": "分词与词性标注"}, ensure_ascii=False) + "\n")
|
|
60
|
+
jss = JSS("data") # 自动建索引 + 加载
|
|
61
|
+
rows = jss.Run("SELECT id, title FROM doc WHERE id > 0;")
|
|
62
|
+
print("JSS rows:", rows)
|
|
63
|
+
assert isinstance(rows, list) and len(rows) == 2, "应检索到 2 条记录"
|
|
64
|
+
jss.Terminate()
|
|
65
|
+
finally:
|
|
66
|
+
os.chdir(cwd)
|
|
67
|
+
return True
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def run_bcc():
|
|
71
|
+
from LangSC import BCC
|
|
72
|
+
base = tempfile.mkdtemp(prefix="lsc_bcc_")
|
|
73
|
+
cwd = os.getcwd()
|
|
74
|
+
os.chdir(base)
|
|
75
|
+
try:
|
|
76
|
+
os.makedirs("corpus")
|
|
77
|
+
with open("corpus/text.txt", "w", encoding="utf-8") as f:
|
|
78
|
+
f.write("我们在北京大学学习自然语言处理。\n")
|
|
79
|
+
f.write("学习语言需要大量语料。\n")
|
|
80
|
+
f.write("自然语言处理很有意思。\n")
|
|
81
|
+
bcc = BCC("corpus") # 自动分词建索引
|
|
82
|
+
ret = bcc.Run("学习", Command="Freq")
|
|
83
|
+
print("BCC Freq(学习):", str(ret)[:300])
|
|
84
|
+
env = json.loads(ret) if isinstance(ret, str) else ret
|
|
85
|
+
assert isinstance(env, dict) and env.get("type") == "Freq", "应返回 Freq 信封"
|
|
86
|
+
finally:
|
|
87
|
+
os.chdir(cwd)
|
|
88
|
+
return True
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def run_kg():
|
|
92
|
+
from LangSC import JSS
|
|
93
|
+
tmp = tempfile.mkdtemp(prefix="lsc_kg_")
|
|
94
|
+
os.makedirs(os.path.join(tmp, "d"))
|
|
95
|
+
jss = JSS(os.path.join(tmp, "d"))
|
|
96
|
+
graphs = jss.KGList() # 远程 HTTP
|
|
97
|
+
print("KG graphs:", [g.get("graph_id") for g in graphs] if isinstance(graphs, list) else graphs)
|
|
98
|
+
sg = jss.KGSubgraph("demo", "学习", hops=1, limit=20)
|
|
99
|
+
print("KG subgraph demo/学习: nodes=%d edges=%d" % (len(sg.get("nodes", [])), len(sg.get("edges", []))))
|
|
100
|
+
assert isinstance(graphs, list), "KGList 应返回列表"
|
|
101
|
+
return True
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def main():
|
|
105
|
+
# 默认只跑可靠、不会挂起的核心项:GPF(本地功能)+ KG(远程集成)。
|
|
106
|
+
# JSS/BCC 的建表/建索引走引擎 JL_CreateTable / BCC_IndexBCC,合成小数据下
|
|
107
|
+
# 目前会挂起或抛 C++ 异常(新旧 DLL 皆然,属引擎+数据问题,非构建回归),
|
|
108
|
+
# 故设为 opt-in:设 LSC_TEST_ENGINES=1 且提供真实数据目录时再启用。
|
|
109
|
+
cases = [
|
|
110
|
+
("GPF 分词/词性", run_gpf, False),
|
|
111
|
+
("KG 远程集成", run_kg, True),
|
|
112
|
+
]
|
|
113
|
+
if os.environ.get("LSC_TEST_ENGINES") == "1":
|
|
114
|
+
cases.insert(1, ("JSS 建表/SQL", run_jss, False))
|
|
115
|
+
cases.insert(2, ("BCC 语料/频次", run_bcc, False))
|
|
116
|
+
|
|
117
|
+
results = []
|
|
118
|
+
for name, fn, integration in cases:
|
|
119
|
+
section(name)
|
|
120
|
+
try:
|
|
121
|
+
fn()
|
|
122
|
+
results.append((name, "PASS", integration))
|
|
123
|
+
except Exception as exc:
|
|
124
|
+
import traceback
|
|
125
|
+
traceback.print_exc()
|
|
126
|
+
results.append((name, "SKIP(net)" if integration else "FAIL", integration))
|
|
127
|
+
|
|
128
|
+
print("\n==================== SUMMARY ====================")
|
|
129
|
+
hard_fail = False
|
|
130
|
+
for name, status, integration in results:
|
|
131
|
+
print(" [{}] {}".format(status, name))
|
|
132
|
+
if status == "FAIL":
|
|
133
|
+
hard_fail = True
|
|
134
|
+
sys.exit(1 if hard_fail else 0)
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
if __name__ == "__main__":
|
|
138
|
+
main()
|
langsc-2.1.0/LangSC/bcclib.dll
DELETED
|
Binary file
|
langsc-2.1.0/LangSC/gpflib.dll
DELETED
|
Binary file
|
langsc-2.1.0/LangSC/jsslib.dll
DELETED
|
Binary file
|
|
Binary file
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|