fiuai-sdk-python 0.2.6__tar.gz → 0.2.9__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.
- {fiuai_sdk_python-0.2.6 → fiuai_sdk_python-0.2.9}/PKG-INFO +1 -1
- {fiuai_sdk_python-0.2.6 → fiuai_sdk_python-0.2.9}/pyproject.toml +1 -1
- {fiuai_sdk_python-0.2.6 → fiuai_sdk_python-0.2.9}/src/fiuai_sdk_python/client.py +38 -9
- {fiuai_sdk_python-0.2.6 → fiuai_sdk_python-0.2.9}/src/fiuai_sdk_python/setup.py +15 -10
- {fiuai_sdk_python-0.2.6 → fiuai_sdk_python-0.2.9}/src/fiuai_sdk_python/type.py +17 -1
- {fiuai_sdk_python-0.2.6 → fiuai_sdk_python-0.2.9}/src/fiuai_sdk_python/util.py +0 -16
- {fiuai_sdk_python-0.2.6 → fiuai_sdk_python-0.2.9}/.gitignore +0 -0
- {fiuai_sdk_python-0.2.6 → fiuai_sdk_python-0.2.9}/CHANGELOG.md +0 -0
- {fiuai_sdk_python-0.2.6 → fiuai_sdk_python-0.2.9}/LICENSE +0 -0
- {fiuai_sdk_python-0.2.6 → fiuai_sdk_python-0.2.9}/README.md +0 -0
- {fiuai_sdk_python-0.2.6 → fiuai_sdk_python-0.2.9}/src/fiuai_sdk_python/__init__.py +0 -0
- {fiuai_sdk_python-0.2.6 → fiuai_sdk_python-0.2.9}/src/fiuai_sdk_python/bank.py +0 -0
- {fiuai_sdk_python-0.2.6 → fiuai_sdk_python-0.2.9}/src/fiuai_sdk_python/company.py +0 -0
- {fiuai_sdk_python-0.2.6 → fiuai_sdk_python-0.2.9}/src/fiuai_sdk_python/const.py +0 -0
- {fiuai_sdk_python-0.2.6 → fiuai_sdk_python-0.2.9}/src/fiuai_sdk_python/error.py +0 -0
- {fiuai_sdk_python-0.2.6 → fiuai_sdk_python-0.2.9}/src/fiuai_sdk_python/item.py +0 -0
- {fiuai_sdk_python-0.2.6 → fiuai_sdk_python-0.2.9}/src/fiuai_sdk_python/perm.py +0 -0
- {fiuai_sdk_python-0.2.6 → fiuai_sdk_python-0.2.9}/src/fiuai_sdk_python/token.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fiuai_sdk_python
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.9
|
|
4
4
|
Summary: FiuAI Python SDK - 企业级AI服务集成开发工具包
|
|
5
5
|
Project-URL: Homepage, https://github.com/fiuai/fiuai-sdk-python
|
|
6
6
|
Project-URL: Documentation, https://github.com/fiuai/fiuai-sdk-python#readme
|
|
@@ -4,7 +4,7 @@ import json
|
|
|
4
4
|
from urllib.parse import quote
|
|
5
5
|
from typing import Any, Literal
|
|
6
6
|
|
|
7
|
-
from .util import
|
|
7
|
+
from .util import get_tokens, get_client_config, is_initialized
|
|
8
8
|
from .error import FiuaiGeneralError, FiuaiAuthError
|
|
9
9
|
from logging import getLogger
|
|
10
10
|
from .type import UserProfile
|
|
@@ -34,7 +34,16 @@ class FiuaiSDK(object):
|
|
|
34
34
|
self.username = username
|
|
35
35
|
|
|
36
36
|
self.auth_type = auth_type
|
|
37
|
-
self.headers =
|
|
37
|
+
self.headers = {
|
|
38
|
+
"Accept": "application/json",
|
|
39
|
+
"Fiuai-Internal-Auth": "false",
|
|
40
|
+
"Fiuai-Internal-Key": "",
|
|
41
|
+
"Fiuai-Internal-Secret": "",
|
|
42
|
+
"Fiuai-Internal-User": "",
|
|
43
|
+
"Fiuai-Internal-Tenant": "",
|
|
44
|
+
"Fiuai-Internal-Company": "",
|
|
45
|
+
"Fiuai-Internal-Current-Company": "",
|
|
46
|
+
}
|
|
38
47
|
self.verify = verify
|
|
39
48
|
self.url = url
|
|
40
49
|
self.max_api_retry = max_api_retry
|
|
@@ -50,12 +59,15 @@ class FiuaiSDK(object):
|
|
|
50
59
|
case "internal":
|
|
51
60
|
if token_key == "" or token_secret == "":
|
|
52
61
|
raise FiuaiGeneralError("Token key and secret are required")
|
|
53
|
-
self.headers =
|
|
62
|
+
self.headers["Fiuai-Internal-Auth"] = "true"
|
|
63
|
+
self.headers["Fiuai-Internal-Key"] = token_key
|
|
64
|
+
self.headers["Fiuai-Internal-Secret"] = token_secret
|
|
65
|
+
self.headers["Fiuai-Internal-User"] = username
|
|
54
66
|
case "password":
|
|
55
67
|
if username == "" or password == "":
|
|
56
68
|
raise FiuaiGeneralError("Username and password are required")
|
|
57
69
|
|
|
58
|
-
self.headers =
|
|
70
|
+
self.headers["Fiuai-Internal-Auth"] = "false"
|
|
59
71
|
self._login(username, password)
|
|
60
72
|
case _:
|
|
61
73
|
raise FiuaiGeneralError(f"Invalid auth type: {self.auth_type}")
|
|
@@ -71,6 +83,10 @@ class FiuaiSDK(object):
|
|
|
71
83
|
if r.json().get('message') == "Logged In":
|
|
72
84
|
self.can_download = []
|
|
73
85
|
logger.info(f"Login to {self.url} success")
|
|
86
|
+
|
|
87
|
+
### 获取cookie
|
|
88
|
+
self.headers["Fiuai-Internal-Company"] = r.cookies.get("current_company")
|
|
89
|
+
self.headers["Fiuai-Internal-Tenant"] = r.cookies.get("tenant")
|
|
74
90
|
return r.json()
|
|
75
91
|
else:
|
|
76
92
|
raise FiuaiAuthError(f"Login failed: {r.json().get('message')}")
|
|
@@ -96,14 +112,17 @@ class FiuaiSDK(object):
|
|
|
96
112
|
return self.post_process(r)
|
|
97
113
|
|
|
98
114
|
def swith_company(self, tenant: str = "", company: str = "") -> bool:
|
|
115
|
+
|
|
116
|
+
self.headers["Fiuai-Internal-Tenant"] = tenant
|
|
117
|
+
self.headers["Fiuai-Internal-Company"] = company
|
|
118
|
+
|
|
99
119
|
if company == "":
|
|
100
120
|
raise FiuaiAuthError("Company is required when using password auth")
|
|
101
121
|
|
|
102
122
|
if self.auth_type == "internal":
|
|
103
123
|
if tenant == "":
|
|
104
124
|
raise FiuaiAuthError("Tenant is required when using internal auth")
|
|
105
|
-
|
|
106
|
-
self.headers["Fiuai-Internal-Company"] = company
|
|
125
|
+
|
|
107
126
|
else:
|
|
108
127
|
r = self.client.post(self.url + "/api/method/frappe.sessions.change_current_company",
|
|
109
128
|
data={"auth_company_id": company})
|
|
@@ -113,6 +132,12 @@ class FiuaiSDK(object):
|
|
|
113
132
|
return False
|
|
114
133
|
else:
|
|
115
134
|
return True
|
|
135
|
+
|
|
136
|
+
def get_tenant(self) -> str:
|
|
137
|
+
return self.headers["Fiuai-Internal-Tenant"]
|
|
138
|
+
|
|
139
|
+
def get_company(self) -> str:
|
|
140
|
+
return self.headers["Fiuai-Internal-Company"]
|
|
116
141
|
|
|
117
142
|
def get_user_profile(self) -> UserProfile:
|
|
118
143
|
d = self.get_doc("User", self.username, fields=["name", "full_name", "email", "phone", "roles", "auth_tenant_id", "default_company_id"])
|
|
@@ -209,10 +234,14 @@ class FiuaiSDK(object):
|
|
|
209
234
|
|
|
210
235
|
|
|
211
236
|
docs = self.post_process(res)
|
|
212
|
-
|
|
213
|
-
|
|
237
|
+
|
|
238
|
+
if not docs:
|
|
239
|
+
return None
|
|
214
240
|
else:
|
|
215
|
-
|
|
241
|
+
if isinstance(docs, list):
|
|
242
|
+
return docs[0]
|
|
243
|
+
else:
|
|
244
|
+
return docs
|
|
216
245
|
|
|
217
246
|
|
|
218
247
|
def get_api(self, method, params={}):
|
|
@@ -73,7 +73,7 @@ def load_language_data(client: FiuaiSDK)-> List[Language]:
|
|
|
73
73
|
)
|
|
74
74
|
return [Language(name=language["name"], language_name=language["language_name"]) for language in language_list]
|
|
75
75
|
|
|
76
|
-
def load_doctype_meta(client: FiuaiSDK, doctype: str, max_api_retry: int = 3)-> DocTypeMeta:
|
|
76
|
+
def load_doctype_meta(client: FiuaiSDK, doctype: str, max_api_retry: int = 3, only_has_prompt: bool = True, show_hidden: bool = False)-> DocTypeMeta:
|
|
77
77
|
"""
|
|
78
78
|
从frappe获取doctype数据
|
|
79
79
|
"""
|
|
@@ -82,7 +82,7 @@ def load_doctype_meta(client: FiuaiSDK, doctype: str, max_api_retry: int = 3)->
|
|
|
82
82
|
doc_meta = None
|
|
83
83
|
while retry_count < max_api_retry:
|
|
84
84
|
|
|
85
|
-
doc_meta = _get_meta(client, doctype)
|
|
85
|
+
doc_meta = _get_meta(client, doctype, only_has_prompt, show_hidden)
|
|
86
86
|
|
|
87
87
|
if doc_meta:
|
|
88
88
|
break
|
|
@@ -91,7 +91,7 @@ def load_doctype_meta(client: FiuaiSDK, doctype: str, max_api_retry: int = 3)->
|
|
|
91
91
|
|
|
92
92
|
return doc_meta
|
|
93
93
|
|
|
94
|
-
def _get_meta(client: FiuaiSDK, doctype: str) -> DocTypeMeta:
|
|
94
|
+
def _get_meta(client: FiuaiSDK, doctype: str, only_has_prompt: bool = True, show_hidden: bool = False) -> DocTypeMeta:
|
|
95
95
|
try:
|
|
96
96
|
m = client.get_meta(doctype)
|
|
97
97
|
|
|
@@ -109,6 +109,7 @@ def _get_meta(client: FiuaiSDK, doctype: str) -> DocTypeMeta:
|
|
|
109
109
|
hidden = _f.get("hidden", 0)
|
|
110
110
|
reqd = _f.get("reqd", 0)
|
|
111
111
|
read_only = _f.get("read_only", 0)
|
|
112
|
+
description = _f.get("description", "")
|
|
112
113
|
|
|
113
114
|
options = []
|
|
114
115
|
match field_type:
|
|
@@ -124,22 +125,26 @@ def _get_meta(client: FiuaiSDK, doctype: str) -> DocTypeMeta:
|
|
|
124
125
|
pass
|
|
125
126
|
|
|
126
127
|
|
|
127
|
-
if field_prompt == "":
|
|
128
|
+
if field_prompt == "" and only_has_prompt:
|
|
128
129
|
# 仅有prompt的field才是应该关心的字段,降低复杂度
|
|
129
130
|
continue
|
|
130
|
-
if hidden == 1:
|
|
131
|
+
if hidden == 1 and not show_hidden:
|
|
131
132
|
continue
|
|
132
133
|
|
|
133
134
|
|
|
134
135
|
_fields.append(DocField(
|
|
135
136
|
fieldname=field_name,
|
|
137
|
+
description=description,
|
|
136
138
|
fieldtype=field_type,
|
|
137
139
|
hidden=True if _f.get("hidden", 0) == 1 else False,
|
|
138
140
|
read_only=True if _f.get("read_only", 0) == 1 else False,
|
|
139
141
|
reqd=True if _f.get("reqd", 0) == 1 else False,
|
|
140
142
|
options=options,
|
|
141
143
|
field_prompt=field_prompt,
|
|
142
|
-
|
|
144
|
+
mandatory=True if _f.get("mandatory", 0) == 1 else False,
|
|
145
|
+
in_list_view=True if _f.get("in_list_view", 0) == 1 else False,
|
|
146
|
+
in_mobile_view=True if _f.get("in_mobile_view", 0) == 1 else False,
|
|
147
|
+
# ai_recognition_value=AiRecognitionValue(value=None, confidence=0, ai_comment="")
|
|
143
148
|
))
|
|
144
149
|
|
|
145
150
|
# links, child 去重
|
|
@@ -148,23 +153,23 @@ def _get_meta(client: FiuaiSDK, doctype: str) -> DocTypeMeta:
|
|
|
148
153
|
|
|
149
154
|
doc_meta = DocTypeMeta(
|
|
150
155
|
name=doctype,
|
|
151
|
-
doctype_prompts=m
|
|
156
|
+
doctype_prompts=m.get("doctype_prompts", ""),
|
|
152
157
|
fields=_fields,
|
|
153
158
|
link_docs=links,
|
|
154
159
|
child_docs=child_docs
|
|
155
160
|
)
|
|
156
161
|
return doc_meta
|
|
157
162
|
except Exception as e:
|
|
158
|
-
logger.error(f"load doctype meta failed: {e.args}")
|
|
163
|
+
logger.error(f"load doctype {doctype} meta failed: {e.args}")
|
|
159
164
|
return None
|
|
160
165
|
|
|
161
166
|
|
|
162
|
-
def load_all_allowed_doctype_meta(client: FiuaiSDK)-> List[DocTypeMeta]:
|
|
167
|
+
def load_all_allowed_doctype_meta(client: FiuaiSDK, only_has_prompt: bool = True, show_hidden: bool = False)-> List[DocTypeMeta]:
|
|
163
168
|
"""
|
|
164
169
|
从frappe获取doctype数据
|
|
165
170
|
"""
|
|
166
171
|
r = []
|
|
167
172
|
for _d in AI_ALLOWED_DOCTYPE_META:
|
|
168
|
-
m = load_doctype_meta(client, _d)
|
|
173
|
+
m = load_doctype_meta(client, _d, only_has_prompt, show_hidden)
|
|
169
174
|
r.append(m)
|
|
170
175
|
return r
|
|
@@ -124,12 +124,16 @@ class DocField(BaseModel):
|
|
|
124
124
|
frappe 文档字段文档数据
|
|
125
125
|
"""
|
|
126
126
|
fieldname: str = Field(description="字段名称,比如Invoice,Purchase Order,etc.")
|
|
127
|
+
description: str = Field(description="字段描述", default="")
|
|
127
128
|
hidden: bool = Field(description="字段是否隐藏")
|
|
128
129
|
reqd: bool = Field(description="字段是否必填")
|
|
129
130
|
read_only: bool = Field(description="字段是否只读")
|
|
130
131
|
fieldtype: str = Field(description="字段类型,比如Data,Float,Link,etc.")
|
|
131
132
|
options: List[str] = Field(description="字段选项,Select类型的字段的枚举值, Link类型字段的Link目标表名")
|
|
132
133
|
field_prompt: str = Field(description="字段对应的prompt")
|
|
134
|
+
mandatory: bool = Field(description="字段是否必填", default=False)
|
|
135
|
+
in_list_view: bool = Field(description="字段是否在列表视图中显示", default=False)
|
|
136
|
+
in_mobile_view: bool = Field(description="字段是否在移动端视图中显示", default=False)
|
|
133
137
|
# ai_recognition_value: AiRecognitionValue = Field(description="字段对应的AI识别结果", default=None)
|
|
134
138
|
|
|
135
139
|
|
|
@@ -211,6 +215,18 @@ class DocTypeMeta(BaseModel):
|
|
|
211
215
|
r.append(i.model_dump_json())
|
|
212
216
|
return r
|
|
213
217
|
|
|
218
|
+
|
|
219
|
+
##### 获取单个field
|
|
220
|
+
def get_field(self, fieldname: str) -> DocField | None:
|
|
221
|
+
for field in self.fields:
|
|
222
|
+
if field.fieldname == fieldname:
|
|
223
|
+
return field
|
|
224
|
+
return None
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
#### create datas
|
|
214
230
|
def create_empty_data_json(self, mock_type: Literal["full", "json"]="json", with_child_tables: bool = False) -> str:
|
|
215
231
|
return json.dumps(self.create_empty_data(mock_type, with_child_tables), indent=4)
|
|
216
232
|
|
|
@@ -248,7 +264,7 @@ class DocTypeMeta(BaseModel):
|
|
|
248
264
|
if with_child_tables:
|
|
249
265
|
try:
|
|
250
266
|
# 动态导入避免循环依赖
|
|
251
|
-
from
|
|
267
|
+
from .setup import load_doctype_meta
|
|
252
268
|
# 自动加载子表元数据
|
|
253
269
|
child_meta = load_doctype_meta(child_doctype)
|
|
254
270
|
if child_meta:
|
|
@@ -80,22 +80,6 @@ def get_client_config():
|
|
|
80
80
|
def is_initialized():
|
|
81
81
|
return _config.is_initialized()
|
|
82
82
|
|
|
83
|
-
def create_headers(key, secret, user, tenant="", company=""):
|
|
84
|
-
|
|
85
|
-
headers = {
|
|
86
|
-
"Fiuai-Internal-Auth": "true",
|
|
87
|
-
"Fiuai-Internal-Key": key,
|
|
88
|
-
"Fiuai-Internal-Secret": secret,
|
|
89
|
-
"Fiuai-Internal-User": user,
|
|
90
|
-
"Fiuai-Internal-Tenant": tenant,
|
|
91
|
-
"Fiuai-Internal-Company": company,
|
|
92
|
-
"Accept": "application/json",
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
return headers
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
83
|
|
|
100
84
|
def init_fiuai(
|
|
101
85
|
url: str,
|
|
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
|