fiuai-sdk-python 0.2.7__tar.gz → 0.3.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.
- {fiuai_sdk_python-0.2.7 → fiuai_sdk_python-0.3.0}/PKG-INFO +1 -1
- {fiuai_sdk_python-0.2.7 → fiuai_sdk_python-0.3.0}/pyproject.toml +1 -1
- {fiuai_sdk_python-0.2.7 → fiuai_sdk_python-0.3.0}/src/fiuai_sdk_python/__init__.py +5 -1
- {fiuai_sdk_python-0.2.7 → fiuai_sdk_python-0.3.0}/src/fiuai_sdk_python/client.py +21 -4
- fiuai_sdk_python-0.3.0/src/fiuai_sdk_python/profile.py +95 -0
- {fiuai_sdk_python-0.2.7 → fiuai_sdk_python-0.3.0}/src/fiuai_sdk_python/setup.py +15 -10
- {fiuai_sdk_python-0.2.7 → fiuai_sdk_python-0.3.0}/src/fiuai_sdk_python/type.py +17 -1
- {fiuai_sdk_python-0.2.7 → fiuai_sdk_python-0.3.0}/.gitignore +0 -0
- {fiuai_sdk_python-0.2.7 → fiuai_sdk_python-0.3.0}/CHANGELOG.md +0 -0
- {fiuai_sdk_python-0.2.7 → fiuai_sdk_python-0.3.0}/LICENSE +0 -0
- {fiuai_sdk_python-0.2.7 → fiuai_sdk_python-0.3.0}/README.md +0 -0
- {fiuai_sdk_python-0.2.7 → fiuai_sdk_python-0.3.0}/src/fiuai_sdk_python/bank.py +0 -0
- {fiuai_sdk_python-0.2.7 → fiuai_sdk_python-0.3.0}/src/fiuai_sdk_python/company.py +0 -0
- {fiuai_sdk_python-0.2.7 → fiuai_sdk_python-0.3.0}/src/fiuai_sdk_python/const.py +0 -0
- {fiuai_sdk_python-0.2.7 → fiuai_sdk_python-0.3.0}/src/fiuai_sdk_python/error.py +0 -0
- {fiuai_sdk_python-0.2.7 → fiuai_sdk_python-0.3.0}/src/fiuai_sdk_python/item.py +0 -0
- {fiuai_sdk_python-0.2.7 → fiuai_sdk_python-0.3.0}/src/fiuai_sdk_python/perm.py +0 -0
- {fiuai_sdk_python-0.2.7 → fiuai_sdk_python-0.3.0}/src/fiuai_sdk_python/token.py +0 -0
- {fiuai_sdk_python-0.2.7 → fiuai_sdk_python-0.3.0}/src/fiuai_sdk_python/util.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fiuai_sdk_python
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
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
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
from .client import FiuaiSDK, get_client
|
|
2
2
|
from .token import TokenConfig
|
|
3
3
|
from .util import init_fiuai
|
|
4
|
+
from .profile import UserProfileInfo
|
|
5
|
+
from .type import UserProfile
|
|
4
6
|
|
|
5
7
|
__all__ = [
|
|
6
8
|
'FiuaiSDK',
|
|
7
9
|
'TokenConfig',
|
|
8
10
|
'init_fiuai',
|
|
9
|
-
'get_client'
|
|
11
|
+
'get_client',
|
|
12
|
+
'UserProfileInfo',
|
|
13
|
+
'UserProfile'
|
|
10
14
|
]
|
|
@@ -4,10 +4,11 @@ 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
|
|
11
|
+
from .profile import UserProfileInfo
|
|
11
12
|
|
|
12
13
|
|
|
13
14
|
logger = getLogger(__name__)
|
|
@@ -140,6 +141,7 @@ class FiuaiSDK(object):
|
|
|
140
141
|
return self.headers["Fiuai-Internal-Company"]
|
|
141
142
|
|
|
142
143
|
def get_user_profile(self) -> UserProfile:
|
|
144
|
+
"""获取简单的用户信息"""
|
|
143
145
|
d = self.get_doc("User", self.username, fields=["name", "full_name", "email", "phone", "roles", "auth_tenant_id", "default_company_id"])
|
|
144
146
|
return UserProfile(
|
|
145
147
|
name=self.username,
|
|
@@ -151,6 +153,17 @@ class FiuaiSDK(object):
|
|
|
151
153
|
default_company_id=d.get("default_company_id") or "",
|
|
152
154
|
)
|
|
153
155
|
|
|
156
|
+
|
|
157
|
+
def get_user_profile_info(self, user_id: str) -> UserProfileInfo:
|
|
158
|
+
"""获取详细的用户信息"""
|
|
159
|
+
d = self.get_v2_api(f"internal/user/profile/{user_id}")
|
|
160
|
+
|
|
161
|
+
if not d:
|
|
162
|
+
return None
|
|
163
|
+
|
|
164
|
+
return UserProfileInfo.model_validate(d)
|
|
165
|
+
|
|
166
|
+
|
|
154
167
|
def get_list(self, doctype, fields='"*"', filters=None, limit_start=0, limit_page_length=0, order_by=None):
|
|
155
168
|
'''Returns list of records of a particular type'''
|
|
156
169
|
if not isinstance(fields, str):
|
|
@@ -234,10 +247,14 @@ class FiuaiSDK(object):
|
|
|
234
247
|
|
|
235
248
|
|
|
236
249
|
docs = self.post_process(res)
|
|
237
|
-
|
|
238
|
-
|
|
250
|
+
|
|
251
|
+
if not docs:
|
|
252
|
+
return None
|
|
239
253
|
else:
|
|
240
|
-
|
|
254
|
+
if isinstance(docs, list):
|
|
255
|
+
return docs[0]
|
|
256
|
+
else:
|
|
257
|
+
return docs
|
|
241
258
|
|
|
242
259
|
|
|
243
260
|
def get_api(self, method, params={}):
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# -- coding: utf-8 --
|
|
2
|
+
# Project: fiuai_sdk_python
|
|
3
|
+
# Created Date: 2025 09 Th
|
|
4
|
+
# Author: liming
|
|
5
|
+
# Email: lmlala@aliyun.com
|
|
6
|
+
# Copyright (c) 2025 FiuAI
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
# -- coding: utf-8 --
|
|
10
|
+
# Project: response
|
|
11
|
+
# Created Date: 2025 05 Tu
|
|
12
|
+
# Author: liming
|
|
13
|
+
# Email: lmlala@aliyun.com
|
|
14
|
+
# Copyright (c) 2025 FiuAI
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
from pydantic import BaseModel, Field
|
|
18
|
+
from typing import List, Literal
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class UserCompanyInfo(BaseModel):
|
|
22
|
+
name: str = Field(description="公司id")
|
|
23
|
+
full_name: str = Field(description="公司名称")
|
|
24
|
+
|
|
25
|
+
class UserBaseInfo(BaseModel):
|
|
26
|
+
name: str = Field(description="用户名id")
|
|
27
|
+
email: str = Field(description="邮箱")
|
|
28
|
+
first_name: str = Field(description="名")
|
|
29
|
+
full_name: str = Field(description="全名")
|
|
30
|
+
language: str = Field(description="语言")
|
|
31
|
+
time_zone: str = Field(description="时区")
|
|
32
|
+
auth_tenant_id: str = Field(description="租户id")
|
|
33
|
+
current_company: str = Field(description="当前公司")
|
|
34
|
+
available_companies: List[UserCompanyInfo] = Field(description="用户在租户下可以访问的公司列表", default_factory=list)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class UserPermissionInfo(BaseModel):
|
|
38
|
+
can_select: List[str] = Field(description="可以查询的文档", default_factory=list)
|
|
39
|
+
can_read: List[str] = Field(description="可以读取的文档", default_factory=list)
|
|
40
|
+
can_write: List[str] = Field(description="可以写入的文档", default_factory=list)
|
|
41
|
+
can_create: List[str] = Field(description="可以创建的文档", default_factory=list)
|
|
42
|
+
can_delete: List[str] = Field(description="可以删除的文档", default_factory=list)
|
|
43
|
+
can_submit: List[str] = Field(description="可以提交的文档", default_factory=list)
|
|
44
|
+
can_cancel: List[str] = Field(description="可以取消的文档", default_factory=list)
|
|
45
|
+
can_search: List[str] = Field(description="可以搜索的文档", default_factory=list)
|
|
46
|
+
|
|
47
|
+
# def __init__(self, user: str):
|
|
48
|
+
# super().__init__()
|
|
49
|
+
|
|
50
|
+
# def can_select(self, doctype: str) -> bool:
|
|
51
|
+
# return doctype in self.can_select
|
|
52
|
+
|
|
53
|
+
# def can_read(self, doctype: str) -> bool:
|
|
54
|
+
# return doctype in self.can_read
|
|
55
|
+
|
|
56
|
+
# def can_write(self, doctype: str) -> bool:
|
|
57
|
+
# return doctype in self.can_write
|
|
58
|
+
|
|
59
|
+
# def can_create(self, doctype: str) -> bool:
|
|
60
|
+
# return doctype in self.can_create
|
|
61
|
+
|
|
62
|
+
# def can_delete(self, doctype: str) -> bool:
|
|
63
|
+
# return doctype in self.can_delete
|
|
64
|
+
|
|
65
|
+
# def can_submit(self, doctype: str) -> bool:
|
|
66
|
+
# return doctype in self.can_submit
|
|
67
|
+
|
|
68
|
+
# def can_cancel(self, doctype: str) -> bool:
|
|
69
|
+
# return doctype in self.can_cancel
|
|
70
|
+
|
|
71
|
+
# def can_search(self, doctype: str) -> bool:
|
|
72
|
+
# return doctype in self.can_search
|
|
73
|
+
|
|
74
|
+
class UserTenantInfo(BaseModel):
|
|
75
|
+
name: str = Field(description="租户id")
|
|
76
|
+
tenant_name: str = Field(description="租户名称")
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
class UserCurrentCompanyInfo(BaseModel):
|
|
80
|
+
name: str = Field(description="公司id")
|
|
81
|
+
full_name: str = Field(description="公司名称")
|
|
82
|
+
unique_no: str = Field(description="公司唯一编号")
|
|
83
|
+
country_region: str = Field(description="国家")
|
|
84
|
+
default_currency: str = Field(description="货币")
|
|
85
|
+
company_size: str = Field(description="公司规模")
|
|
86
|
+
entity_type: Literal["Enterprise", "Individual", "Other"] = Field(description="公司类型")
|
|
87
|
+
company_profile: str = Field(description="公司业务特点提示词", default="")
|
|
88
|
+
|
|
89
|
+
class UserProfileInfo(BaseModel):
|
|
90
|
+
user_base_info: UserBaseInfo = Field(description="用户基础信息")
|
|
91
|
+
user_permissions: UserPermissionInfo = Field(description="用户权限")
|
|
92
|
+
user_tenant_info: UserTenantInfo = Field(description="用户租户信息")
|
|
93
|
+
user_current_company_info: UserCurrentCompanyInfo = Field(description="用户当前公司信息")
|
|
94
|
+
|
|
95
|
+
|
|
@@ -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:
|
|
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
|