aisberg 0.1.0__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.
Files changed (43) hide show
  1. aisberg/__init__.py +7 -0
  2. aisberg/abstract/__init__.py +0 -0
  3. aisberg/abstract/modules.py +57 -0
  4. aisberg/api/__init__.py +0 -0
  5. aisberg/api/async_endpoints.py +333 -0
  6. aisberg/api/endpoints.py +328 -0
  7. aisberg/async_client.py +107 -0
  8. aisberg/client.py +108 -0
  9. aisberg/config.py +17 -0
  10. aisberg/exceptions.py +22 -0
  11. aisberg/models/__init__.py +0 -0
  12. aisberg/models/chat.py +143 -0
  13. aisberg/models/collections.py +36 -0
  14. aisberg/models/embeddings.py +92 -0
  15. aisberg/models/models.py +39 -0
  16. aisberg/models/requests.py +11 -0
  17. aisberg/models/token.py +11 -0
  18. aisberg/models/tools.py +73 -0
  19. aisberg/models/workflows.py +66 -0
  20. aisberg/modules/__init__.py +23 -0
  21. aisberg/modules/chat.py +403 -0
  22. aisberg/modules/collections.py +117 -0
  23. aisberg/modules/document.py +117 -0
  24. aisberg/modules/embeddings.py +309 -0
  25. aisberg/modules/me.py +77 -0
  26. aisberg/modules/models.py +108 -0
  27. aisberg/modules/tools.py +78 -0
  28. aisberg/modules/workflows.py +140 -0
  29. aisberg/requests/__init__.py +0 -0
  30. aisberg/requests/async_requests.py +85 -0
  31. aisberg/requests/sync_requests.py +85 -0
  32. aisberg/utils.py +111 -0
  33. aisberg-0.1.0.dist-info/METADATA +212 -0
  34. aisberg-0.1.0.dist-info/RECORD +43 -0
  35. aisberg-0.1.0.dist-info/WHEEL +5 -0
  36. aisberg-0.1.0.dist-info/licenses/LICENSE +9 -0
  37. aisberg-0.1.0.dist-info/top_level.txt +3 -0
  38. tests/integration/test_collections_integration.py +115 -0
  39. tests/unit/test_collections_sync.py +104 -0
  40. tmp/test.py +33 -0
  41. tmp/test_async.py +126 -0
  42. tmp/test_doc_parse.py +12 -0
  43. tmp/test_sync.py +146 -0
aisberg/models/chat.py ADDED
@@ -0,0 +1,143 @@
1
+ from typing import Union, Sequence, Tuple, Dict, Any, List, Optional, Literal
2
+ from pydantic import BaseModel, Field
3
+ from enum import Enum
4
+
5
+
6
+ class RoleEnum(str, Enum):
7
+ user = "user"
8
+ assistant = "assistant"
9
+ system = "system"
10
+ tool = "tool"
11
+
12
+
13
+ class ToolCall(BaseModel):
14
+ id: str
15
+ type: str = "function"
16
+ function: "FunctionCall"
17
+
18
+
19
+ class FunctionCall(BaseModel):
20
+ name: str
21
+ arguments: str # JSON string des arguments
22
+
23
+
24
+ class BaseMessage(BaseModel):
25
+ role: RoleEnum
26
+ content: Union[str, None]
27
+
28
+
29
+ class HumanMessage(BaseMessage):
30
+ role: RoleEnum = Field(default=RoleEnum.user, frozen=True)
31
+
32
+
33
+ class AIMessage(BaseMessage):
34
+ role: RoleEnum = Field(default=RoleEnum.assistant, frozen=True)
35
+ tool_calls: Optional[List[ToolCall]] = None
36
+
37
+
38
+ class SystemMessage(BaseMessage):
39
+ role: RoleEnum = Field(default=RoleEnum.system, frozen=True)
40
+
41
+
42
+ class ToolMessage(BaseMessage):
43
+ role: RoleEnum = Field(default=RoleEnum.tool, frozen=True)
44
+ tool_call_id: str # ID du tool_call auquel ce message répond
45
+
46
+
47
+ # Types de représentations acceptées comme "message"
48
+ MessageLikeRepresentation = Union[
49
+ BaseMessage, # BaseMessage ou ses sous-classes
50
+ str, # Simple string message
51
+ Tuple[str, str], # (role, content)
52
+ Dict[str, Any], # dict style {"role": "user", "content": "..."}
53
+ ]
54
+
55
+ # Entrée possible pour un LLM
56
+ LanguageModelInput = Union[str, Sequence[MessageLikeRepresentation]]
57
+
58
+
59
+ class ChatMessageContent(BaseModel):
60
+ role: str
61
+ content: Optional[str] = ""
62
+ refusal: Optional[str] = None
63
+ annotations: Optional[Dict[str, Any]] = None
64
+ function_call: Optional[FunctionCall] = None
65
+ tool_calls: Optional[List[ToolCall]] = None
66
+ reasoning_content: Optional[str] = None
67
+
68
+
69
+ class Delta(BaseModel):
70
+ content: Optional[str] = ""
71
+ function_call: Optional[dict] = None
72
+ tool_calls: Optional[list] = None
73
+
74
+
75
+ class ChatChoice(BaseModel):
76
+ index: int
77
+ message: ChatMessageContent
78
+ finish_reason: Optional[str]
79
+
80
+
81
+ class ChoiceChunk(BaseModel):
82
+ index: int
83
+ delta: Delta
84
+ finish_reason: Optional[str]
85
+
86
+
87
+ class ChatUsage(BaseModel):
88
+ prompt_tokens: int
89
+ completion_tokens: int
90
+ total_tokens: int
91
+
92
+
93
+ class ChatCompletionResponse(BaseModel):
94
+ id: str
95
+ object: str
96
+ created: int
97
+ model: str
98
+ choices: List[ChatChoice]
99
+ usage: Optional[ChatUsage] = None
100
+
101
+
102
+ class ChatCompletionChunk(BaseModel):
103
+ id: str
104
+ object: Literal["chat.completion.chunk"]
105
+ created: int
106
+ model: str
107
+ choices: List[ChoiceChunk]
108
+ usage: Optional[ChatUsage] = None
109
+
110
+
111
+ def parse_message(msg: MessageLikeRepresentation) -> BaseMessage:
112
+ if isinstance(msg, BaseMessage):
113
+ return msg
114
+ elif isinstance(msg, HumanMessage):
115
+ return msg
116
+ elif isinstance(msg, AIMessage):
117
+ return msg
118
+ elif isinstance(msg, SystemMessage):
119
+ return msg
120
+ elif isinstance(msg, ToolMessage):
121
+ return msg
122
+ elif isinstance(msg, str):
123
+ return HumanMessage(content=msg)
124
+ elif isinstance(msg, tuple) and len(msg) == 2:
125
+ return BaseMessage(role=RoleEnum(msg[0]), content=msg[1])
126
+ elif isinstance(msg, dict):
127
+ return BaseMessage(**msg)
128
+ else:
129
+ raise ValueError(f"Invalid message representation: {msg}")
130
+
131
+
132
+ def format_messages(input: LanguageModelInput) -> list[dict]:
133
+ """
134
+ Normalise et formate les messages pour l’API LLM (OpenAI-like).
135
+ """
136
+ if isinstance(input, str):
137
+ messages = [HumanMessage(content=input)]
138
+ else:
139
+ messages = [parse_message(msg) for msg in input]
140
+ return [
141
+ msg.model_dump(include={"role", "content", "tool_calls", "tool_call_id"})
142
+ for msg in messages
143
+ ]
@@ -0,0 +1,36 @@
1
+ from typing import List, Optional, Union
2
+ from pydantic import BaseModel
3
+
4
+
5
+ class Collection(BaseModel):
6
+ name: str
7
+
8
+
9
+ class GroupCollections(BaseModel):
10
+ group: str
11
+ collections: List[Collection]
12
+
13
+
14
+ # Modèle plus structuré pour payload
15
+ class Payload(BaseModel):
16
+ method: Optional[str] = None
17
+ norm: Optional[Union[str, bool]] = None
18
+ filetype: Optional[str] = None
19
+ filename: Optional[str] = None
20
+ dense_encoder: Optional[str] = None
21
+ Category: Optional[str] = None
22
+ text: Optional[str] = None
23
+ timestamp: Optional[str] = None
24
+ collection_name: Optional[str] = None
25
+ sparse_encoder: Optional[str] = None
26
+
27
+
28
+ class PointDetails(BaseModel):
29
+ id: str
30
+ payload: Payload
31
+
32
+
33
+ class CollectionDetails(BaseModel):
34
+ name: str
35
+ group: str
36
+ points: List[PointDetails]
@@ -0,0 +1,92 @@
1
+ from typing import List, Optional, Dict, Any, Literal, Union
2
+ from pydantic import BaseModel, RootModel, ConfigDict
3
+
4
+
5
+ class EmbeddingItem(BaseModel):
6
+ embedding: List[float]
7
+ index: int
8
+ object: str
9
+
10
+
11
+ class UsageDetails(BaseModel):
12
+ prompt_tokens: int
13
+ total_tokens: int
14
+ completion_tokens: int
15
+ prompt_tokens_details: Optional[dict] = None
16
+
17
+
18
+ class EncodingResponse(BaseModel):
19
+ id: str
20
+ object: str
21
+ model: str
22
+ created: int
23
+ data: List[EmbeddingItem]
24
+ usage: UsageDetails
25
+
26
+
27
+ class ChunkData(BaseModel):
28
+ id: str
29
+ idx: int
30
+ filename: str
31
+ text: str
32
+ collection_name: str
33
+ filetype: str
34
+ dense_encoder: str
35
+ sparse_encoder: str
36
+ timestamp: str
37
+ norm: Optional[Union[bool, str]] = None
38
+ rrf_score: Optional[float] = None
39
+ chunk_method: Optional[str] = None
40
+
41
+ # Pour permettre l'ajout de clés dynamiques pour les métadonnées
42
+ model_config = ConfigDict(extra="allow")
43
+
44
+ def metadata(self) -> Dict[str, Any]:
45
+ """Retourne les métadonnées du ChunkData."""
46
+ fields = set(self.model_fields.keys())
47
+ return {k: v for k, v in self.model_dump().items() if k not in fields}
48
+
49
+
50
+ class ChunksDataList(RootModel[List[ChunkData]]):
51
+ def metadata(self) -> List[Dict[str, Any]]:
52
+ """Retourne une liste des métadonnées de chaque ChunkData."""
53
+ return [chunk.metadata() for chunk in self.root]
54
+
55
+ def texts(self) -> List[str]:
56
+ """Retourne une liste des textes de chaque ChunkData."""
57
+ return [chunk.text for chunk in self.root]
58
+
59
+ def __iter__(self):
60
+ return iter(self.root)
61
+
62
+ def __len__(self):
63
+ return len(self.root)
64
+
65
+
66
+ class RerankerDocument(BaseModel):
67
+ text: str
68
+
69
+
70
+ class RerankerResult(BaseModel):
71
+ index: int
72
+ document: RerankerDocument
73
+ relevance_score: float
74
+
75
+
76
+ class RerankerResponse(BaseModel):
77
+ id: str
78
+ model: str
79
+ usage: Dict[str, int]
80
+ results: List[RerankerResult]
81
+
82
+ def filter_by_relevance_score(self, threshold: float) -> "RerankerResponse":
83
+ """Retourne une nouvelle instance filtrée de RerankerResponse."""
84
+ filtered_results = [
85
+ result for result in self.results if result.relevance_score >= threshold
86
+ ]
87
+ return RerankerResponse(
88
+ id=self.id, model=self.model, usage=self.usage, results=filtered_results
89
+ )
90
+
91
+
92
+ EncodingFormat = Optional[Literal["float", "base64"]]
@@ -0,0 +1,39 @@
1
+ from typing import Optional, List, Any
2
+ from pydantic import BaseModel
3
+
4
+
5
+ class ModelPermission(BaseModel):
6
+ id: Optional[str] = None
7
+ object: Optional[str] = None
8
+ created: Optional[int] = None
9
+ allow_create_engine: Optional[bool] = None
10
+ allow_sampling: Optional[bool] = None
11
+ allow_logprobs: Optional[bool] = None
12
+ allow_search_indices: Optional[bool] = None
13
+ allow_view: Optional[bool] = None
14
+ allow_fine_tuning: Optional[bool] = None
15
+ organization: Optional[str] = None
16
+ group: Optional[Any] = None
17
+ is_blocking: Optional[bool] = None
18
+
19
+
20
+ class ModelMeta(BaseModel):
21
+ vocab_type: Optional[int] = None
22
+ n_vocab: Optional[int] = None
23
+ n_ctx_train: Optional[int] = None
24
+ n_embd: Optional[int] = None
25
+ n_params: Optional[int] = None
26
+ size: Optional[int] = None
27
+
28
+
29
+ class Model(BaseModel):
30
+ id: Optional[str] = None
31
+ created: Optional[int] = None
32
+ object: Optional[str] = None
33
+ owned_by: Optional[str] = None
34
+ root: Optional[str] = None
35
+ parent: Optional[Any] = None
36
+ max_model_len: Optional[int] = None
37
+ permission: Optional[List[ModelPermission]] = None
38
+ language: Optional[List[str]] = None
39
+ meta: Optional[ModelMeta] = None
@@ -0,0 +1,11 @@
1
+ from typing import List, Any
2
+
3
+ from pydantic import BaseModel, RootModel, ConfigDict
4
+
5
+
6
+ class AnyDict(BaseModel):
7
+ model_config = ConfigDict(extra="allow")
8
+
9
+
10
+ class AnyList(RootModel[List[Any]]):
11
+ pass
@@ -0,0 +1,11 @@
1
+ from pydantic import BaseModel
2
+ from typing import List
3
+
4
+
5
+ class TokenInfo(BaseModel):
6
+ message: str
7
+ id: str
8
+ username: str
9
+ email: str
10
+ groups: List[str]
11
+ roles: List[str]
@@ -0,0 +1,73 @@
1
+ from typing import Dict, List, Iterable
2
+ from pydantic import BaseModel, Field
3
+
4
+
5
+ class Property(BaseModel):
6
+ type: str = Field(..., examples=["string"])
7
+ description: str
8
+
9
+
10
+ class Parameters(BaseModel):
11
+ """Schéma JSON Schema standard OpenAI pour les paramètres."""
12
+
13
+ type: str = Field(default="object", frozen=True)
14
+ properties: Dict[str, Property]
15
+ required: List[str]
16
+
17
+
18
+ class Function(BaseModel):
19
+ name: str
20
+ description: str
21
+ parameters: Parameters
22
+
23
+
24
+ class Tool(BaseModel):
25
+ type: str = Field(default="function", frozen=True)
26
+ function: Function
27
+
28
+
29
+ def make_tool(
30
+ *,
31
+ name: str,
32
+ description: str,
33
+ params: Dict[str, str], # {"param": "description", ...}
34
+ ) -> Tool:
35
+ """Crée un objet `Tool` à partir des paramètres fournis.
36
+
37
+ Args:
38
+ name: Nom de la fonction.
39
+ description: Description de la fonction.
40
+ params: Dictionnaire des paramètres avec leur description.
41
+
42
+ Returns:
43
+ Un objet `Tool` prêt à être utilisé.
44
+ """
45
+ properties = {
46
+ key: Property(type="string", description=desc) # <-- adapt typage si besoin
47
+ for key, desc in params.items()
48
+ }
49
+ return Tool(
50
+ function=Function(
51
+ name=name,
52
+ description=description,
53
+ parameters=Parameters(
54
+ properties=properties,
55
+ required=list(params.keys()),
56
+ ),
57
+ )
58
+ )
59
+
60
+
61
+ def tools_to_payload(tools: Iterable[Tool]) -> List[Dict]:
62
+ """
63
+ Convertit des objets `Tool` (Pydantic) en payload brut..
64
+
65
+ Args:
66
+ tools: Un itérable d'instances `Tool`.
67
+ Returns:
68
+ Une liste de dicts sérialisables en JSON.
69
+ """
70
+ if not isinstance(tools, Iterable) or not tools:
71
+ return []
72
+
73
+ return [tool.model_dump(mode="json", exclude_none=True) for tool in tools]
@@ -0,0 +1,66 @@
1
+ from datetime import datetime
2
+ from typing import Optional, List, Dict, Any
3
+ from pydantic import BaseModel, ConfigDict
4
+
5
+
6
+ class Workflow(BaseModel):
7
+ name: str
8
+ id: str
9
+ group: str
10
+ createdAt: datetime
11
+ updatedAt: datetime
12
+ description: Optional[str] = None
13
+ isActive: Optional[bool] = True
14
+
15
+
16
+ class Input(BaseModel):
17
+ input_id: str
18
+ input_type: str
19
+ input_name: str
20
+ value: Dict[str, Any]
21
+ linkable: bool
22
+
23
+
24
+ class Output(BaseModel):
25
+ output_id: str
26
+ output_type: str
27
+ output_name: str
28
+ linkable: bool
29
+
30
+
31
+ class Position(BaseModel):
32
+ x: float
33
+ y: float
34
+ _id: str
35
+
36
+
37
+ class Node(BaseModel):
38
+ inputs: List[Input]
39
+ outputs: List[Output]
40
+ node_id: str
41
+ name: str
42
+ source_nodes_id: Optional[List[str]]
43
+ type: str
44
+ target_nodes: List[Dict[str, Any]]
45
+ position: Position
46
+ _id: str
47
+
48
+
49
+ class WorkflowDetails(BaseModel):
50
+ id: str
51
+ group: str
52
+ name: str
53
+ createdAt: datetime
54
+ updatedAt: datetime
55
+ starting_node_id: str
56
+ nodes: List[Node]
57
+
58
+
59
+ class WorkflowRunChunk(BaseModel):
60
+ response: Optional[str] = None
61
+ model_config = ConfigDict(extra="allow")
62
+
63
+
64
+ class WorkflowRunResult(BaseModel):
65
+ response: Optional[str] = None
66
+ model_config = ConfigDict(extra="allow")
@@ -0,0 +1,23 @@
1
+ from .chat import AsyncChatModule, SyncChatModule
2
+ from .collections import AsyncCollectionsModule, SyncCollectionsModule
3
+ from .embeddings import AsyncEmbeddingsModule, SyncEmbeddingsModule
4
+ from .me import AsyncMeModule, SyncMeModule
5
+ from .models import AsyncModelsModule, SyncModelsModule
6
+ from .workflows import AsyncWorkflowsModule, SyncWorkflowsModule
7
+ from .tools import ToolsModule
8
+
9
+ __all__ = [
10
+ "AsyncChatModule",
11
+ "SyncChatModule",
12
+ "AsyncCollectionsModule",
13
+ "SyncCollectionsModule",
14
+ "AsyncEmbeddingsModule",
15
+ "SyncEmbeddingsModule",
16
+ "AsyncMeModule",
17
+ "SyncMeModule",
18
+ "AsyncModelsModule",
19
+ "SyncModelsModule",
20
+ "AsyncWorkflowsModule",
21
+ "SyncWorkflowsModule",
22
+ "ToolsModule",
23
+ ]