aisbf 0.1.0__py3-none-any.whl → 0.1.1__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.
- aisbf-0.1.1.data/data/share/aisbf/main.py +125 -0
- aisbf-0.1.1.data/data/share/aisbf/providers.json +156 -0
- aisbf-0.1.1.data/data/share/aisbf/requirements.txt +11 -0
- aisbf-0.1.1.data/data/share/aisbf/rotations.json +94 -0
- {aisbf-0.1.0.dist-info → aisbf-0.1.1.dist-info}/METADATA +14 -3
- aisbf-0.1.1.dist-info/RECORD +15 -0
- aisbf-0.1.1.dist-info/entry_points.txt +2 -0
- aisbf-0.1.0.dist-info/RECORD +0 -10
- {aisbf-0.1.0.dist-info → aisbf-0.1.1.dist-info}/WHEEL +0 -0
- {aisbf-0.1.0.dist-info → aisbf-0.1.1.dist-info}/licenses/LICENSE.txt +0 -0
- {aisbf-0.1.0.dist-info → aisbf-0.1.1.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Copyleft (C) 2026 Stefy Lanza <stefy@nexlab.net>
|
|
3
|
+
|
|
4
|
+
AISBF - AI Service Broker Framework || AI Should Be Free
|
|
5
|
+
|
|
6
|
+
Main application for AISBF.
|
|
7
|
+
|
|
8
|
+
This program is free software: you can redistribute it and/or modify
|
|
9
|
+
it under the terms of the GNU General Public License as published by
|
|
10
|
+
the Free Software Foundation, either version 3 of the License, or
|
|
11
|
+
(at your option) any later version.
|
|
12
|
+
|
|
13
|
+
This program is distributed in the hope that it will be useful,
|
|
14
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
15
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
16
|
+
GNU General Public License for more details.
|
|
17
|
+
|
|
18
|
+
You should have received a copy of the GNU General Public License
|
|
19
|
+
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
20
|
+
|
|
21
|
+
Why did the programmer quit his job? Because he didn't get arrays!
|
|
22
|
+
|
|
23
|
+
Main application for AISBF.
|
|
24
|
+
"""
|
|
25
|
+
from fastapi import FastAPI, HTTPException, Request, status
|
|
26
|
+
from fastapi.responses import JSONResponse, StreamingResponse
|
|
27
|
+
from fastapi.middleware.cors import CORSMiddleware
|
|
28
|
+
from aisbf.models import ChatCompletionRequest, ChatCompletionResponse
|
|
29
|
+
from aisbf.handlers import RequestHandler, RotationHandler
|
|
30
|
+
from aisbf.config import config
|
|
31
|
+
import time
|
|
32
|
+
import logging
|
|
33
|
+
from datetime import datetime, timedelta
|
|
34
|
+
from collections import defaultdict
|
|
35
|
+
|
|
36
|
+
# Configure logging
|
|
37
|
+
logging.basicConfig(level=logging.DEBUG)
|
|
38
|
+
logger = logging.getLogger(__name__)
|
|
39
|
+
|
|
40
|
+
# Initialize handlers
|
|
41
|
+
request_handler = RequestHandler()
|
|
42
|
+
rotation_handler = RotationHandler()
|
|
43
|
+
|
|
44
|
+
app = FastAPI(title="AI Proxy Server")
|
|
45
|
+
|
|
46
|
+
# CORS middleware
|
|
47
|
+
app.add_middleware(
|
|
48
|
+
CORSMiddleware,
|
|
49
|
+
allow_origins=["*"],
|
|
50
|
+
allow_credentials=True,
|
|
51
|
+
allow_methods=["*"],
|
|
52
|
+
allow_headers=["*"],
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
@app.get("/")
|
|
56
|
+
async def root():
|
|
57
|
+
return {"message": "AI Proxy Server is running", "providers": list(config.providers.keys())}
|
|
58
|
+
|
|
59
|
+
@app.post("/api/{provider_id}/chat/completions")
|
|
60
|
+
async def chat_completions(provider_id: str, request: Request, body: ChatCompletionRequest):
|
|
61
|
+
logger.debug(f"Received chat_completions request for provider: {provider_id}")
|
|
62
|
+
logger.debug(f"Request headers: {dict(request.headers)}")
|
|
63
|
+
logger.debug(f"Request body: {body}")
|
|
64
|
+
|
|
65
|
+
body_dict = body.model_dump()
|
|
66
|
+
|
|
67
|
+
# Check if it's a rotation
|
|
68
|
+
if provider_id in config.rotations:
|
|
69
|
+
logger.debug("Handling rotation request")
|
|
70
|
+
return await rotation_handler.handle_rotation_request(provider_id, body_dict)
|
|
71
|
+
|
|
72
|
+
# Check if it's a provider
|
|
73
|
+
if provider_id not in config.providers:
|
|
74
|
+
logger.error(f"Provider {provider_id} not found")
|
|
75
|
+
raise HTTPException(status_code=400, detail=f"Provider {provider_id} not found")
|
|
76
|
+
|
|
77
|
+
provider_config = config.get_provider(provider_id)
|
|
78
|
+
logger.debug(f"Provider config: {provider_config}")
|
|
79
|
+
|
|
80
|
+
try:
|
|
81
|
+
if body.stream:
|
|
82
|
+
logger.debug("Handling streaming chat completion")
|
|
83
|
+
return await request_handler.handle_streaming_chat_completion(request, provider_id, body_dict)
|
|
84
|
+
else:
|
|
85
|
+
logger.debug("Handling non-streaming chat completion")
|
|
86
|
+
result = await request_handler.handle_chat_completion(request, provider_id, body_dict)
|
|
87
|
+
logger.debug(f"Response result: {result}")
|
|
88
|
+
return result
|
|
89
|
+
except Exception as e:
|
|
90
|
+
logger.error(f"Error handling chat_completions: {str(e)}", exc_info=True)
|
|
91
|
+
raise
|
|
92
|
+
|
|
93
|
+
@app.get("/api/{provider_id}/models")
|
|
94
|
+
async def list_models(request: Request, provider_id: str):
|
|
95
|
+
logger.debug(f"Received list_models request for provider: {provider_id}")
|
|
96
|
+
|
|
97
|
+
# Check if it's a rotation
|
|
98
|
+
if provider_id in config.rotations:
|
|
99
|
+
logger.debug("Handling rotation model list request")
|
|
100
|
+
return await rotation_handler.handle_rotation_model_list(provider_id)
|
|
101
|
+
|
|
102
|
+
# Check if it's a provider
|
|
103
|
+
if provider_id not in config.providers:
|
|
104
|
+
logger.error(f"Provider {provider_id} not found")
|
|
105
|
+
raise HTTPException(status_code=400, detail=f"Provider {provider_id} not found")
|
|
106
|
+
|
|
107
|
+
provider_config = config.get_provider(provider_id)
|
|
108
|
+
|
|
109
|
+
try:
|
|
110
|
+
logger.debug("Handling model list request")
|
|
111
|
+
result = await request_handler.handle_model_list(request, provider_id)
|
|
112
|
+
logger.debug(f"Models result: {result}")
|
|
113
|
+
return result
|
|
114
|
+
except Exception as e:
|
|
115
|
+
logger.error(f"Error handling list_models: {str(e)}", exc_info=True)
|
|
116
|
+
raise
|
|
117
|
+
|
|
118
|
+
def main():
|
|
119
|
+
"""Main entry point for the AISBF server"""
|
|
120
|
+
import uvicorn
|
|
121
|
+
logger.info("Starting AI Proxy Server on http://localhost:8000")
|
|
122
|
+
uvicorn.run(app, host="0.0.0.0", port=8000)
|
|
123
|
+
|
|
124
|
+
if __name__ == "__main__":
|
|
125
|
+
main()
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
{
|
|
2
|
+
"providers": {
|
|
3
|
+
"gemini": {
|
|
4
|
+
"id": "gemini",
|
|
5
|
+
"name": "Google AI Studio",
|
|
6
|
+
"endpoint": "https://generativelanguage.googleapis.com/v1beta",
|
|
7
|
+
"type": "google",
|
|
8
|
+
"api_key_required": true,
|
|
9
|
+
"rate_limit": 0
|
|
10
|
+
},
|
|
11
|
+
"openai": {
|
|
12
|
+
"id": "openai",
|
|
13
|
+
"name": "OpenAI",
|
|
14
|
+
"endpoint": "https://api.openai.com/v1",
|
|
15
|
+
"type": "openai",
|
|
16
|
+
"api_key_required": true,
|
|
17
|
+
"rate_limit": 0
|
|
18
|
+
},
|
|
19
|
+
"anthropic": {
|
|
20
|
+
"id": "anthropic",
|
|
21
|
+
"name": "Anthropic",
|
|
22
|
+
"endpoint": "https://api.anthropic.com/v1",
|
|
23
|
+
"type": "anthropic",
|
|
24
|
+
"api_key_required": true,
|
|
25
|
+
"rate_limit": 0
|
|
26
|
+
},
|
|
27
|
+
"ollama": {
|
|
28
|
+
"id": "ollama",
|
|
29
|
+
"name": "Ollama",
|
|
30
|
+
"endpoint": "http://localhost:11434",
|
|
31
|
+
"type": "ollama",
|
|
32
|
+
"api_key_required": false,
|
|
33
|
+
"rate_limit": 0
|
|
34
|
+
},
|
|
35
|
+
"azure_openai": {
|
|
36
|
+
"id": "azure_openai",
|
|
37
|
+
"name": "Azure OpenAI",
|
|
38
|
+
"endpoint": "https://your-azure-endpoint.openai.azure.com",
|
|
39
|
+
"type": "openai",
|
|
40
|
+
"api_key_required": true,
|
|
41
|
+
"rate_limit": 0
|
|
42
|
+
},
|
|
43
|
+
"cohere": {
|
|
44
|
+
"id": "cohere",
|
|
45
|
+
"name": "Cohere",
|
|
46
|
+
"endpoint": "https://api.cohere.com/v1",
|
|
47
|
+
"type": "cohere",
|
|
48
|
+
"api_key_required": true,
|
|
49
|
+
"rate_limit": 0
|
|
50
|
+
},
|
|
51
|
+
"huggingface": {
|
|
52
|
+
"id": "huggingface",
|
|
53
|
+
"name": "Hugging Face",
|
|
54
|
+
"endpoint": "https://api-inference.huggingface.co",
|
|
55
|
+
"type": "huggingface",
|
|
56
|
+
"api_key_required": true,
|
|
57
|
+
"rate_limit": 0
|
|
58
|
+
},
|
|
59
|
+
"replicate": {
|
|
60
|
+
"id": "replicate",
|
|
61
|
+
"name": "Replicate",
|
|
62
|
+
"endpoint": "https://api.replicate.com/v1",
|
|
63
|
+
"type": "replicate",
|
|
64
|
+
"api_key_required": true,
|
|
65
|
+
"rate_limit": 0
|
|
66
|
+
},
|
|
67
|
+
"togetherai": {
|
|
68
|
+
"id": "togetherai",
|
|
69
|
+
"name": "Together AI",
|
|
70
|
+
"endpoint": "https://api.together.xyz/v1",
|
|
71
|
+
"type": "openai",
|
|
72
|
+
"api_key_required": true,
|
|
73
|
+
"rate_limit": 0
|
|
74
|
+
},
|
|
75
|
+
"groq": {
|
|
76
|
+
"id": "groq",
|
|
77
|
+
"name": "Groq",
|
|
78
|
+
"endpoint": "https://api.groq.com/openai/v1",
|
|
79
|
+
"type": "openai",
|
|
80
|
+
"api_key_required": true,
|
|
81
|
+
"rate_limit": 0
|
|
82
|
+
},
|
|
83
|
+
"mistralai": {
|
|
84
|
+
"id": "mistralai",
|
|
85
|
+
"name": "Mistral AI",
|
|
86
|
+
"endpoint": "https://api.mistral.ai/v1",
|
|
87
|
+
"type": "openai",
|
|
88
|
+
"api_key_required": true,
|
|
89
|
+
"rate_limit": 0
|
|
90
|
+
},
|
|
91
|
+
"stabilityai": {
|
|
92
|
+
"id": "stabilityai",
|
|
93
|
+
"name": "Stability AI",
|
|
94
|
+
"endpoint": "https://api.stability.ai/v2beta",
|
|
95
|
+
"type": "stabilityai",
|
|
96
|
+
"api_key_required": true,
|
|
97
|
+
"rate_limit": 0
|
|
98
|
+
},
|
|
99
|
+
"kilo": {
|
|
100
|
+
"id": "kilo",
|
|
101
|
+
"name": "KiloCode",
|
|
102
|
+
"endpoint": "https://kilocode.ai/api/openrouter",
|
|
103
|
+
"type": "openai",
|
|
104
|
+
"api_key_required": true,
|
|
105
|
+
"rate_limit": 0
|
|
106
|
+
},
|
|
107
|
+
"perplexity": {
|
|
108
|
+
"id": "perplexity",
|
|
109
|
+
"name": "Perplexity AI",
|
|
110
|
+
"endpoint": "https://api.perplexity.ai",
|
|
111
|
+
"type": "openai",
|
|
112
|
+
"api_key_required": true,
|
|
113
|
+
"rate_limit": 0
|
|
114
|
+
},
|
|
115
|
+
"poe": {
|
|
116
|
+
"id": "poe",
|
|
117
|
+
"name": "Poe",
|
|
118
|
+
"endpoint": "https://api.poe.com/v1",
|
|
119
|
+
"type": "poe",
|
|
120
|
+
"api_key_required": true,
|
|
121
|
+
"rate_limit": 0
|
|
122
|
+
},
|
|
123
|
+
"lanai": {
|
|
124
|
+
"id": "lanai",
|
|
125
|
+
"name": "Llama AI",
|
|
126
|
+
"endpoint": "https://api.lanai.ai/v1",
|
|
127
|
+
"type": "lanai",
|
|
128
|
+
"api_key_required": true,
|
|
129
|
+
"rate_limit": 0
|
|
130
|
+
},
|
|
131
|
+
"amazon": {
|
|
132
|
+
"id": "amazon",
|
|
133
|
+
"name": "Amazon Bedrock",
|
|
134
|
+
"endpoint": "https://api.amazon.com/bedrock/v1",
|
|
135
|
+
"type": "amazon",
|
|
136
|
+
"api_key_required": true,
|
|
137
|
+
"rate_limit": 0
|
|
138
|
+
},
|
|
139
|
+
"ibm": {
|
|
140
|
+
"id": "ibm",
|
|
141
|
+
"name": "IBM Watson",
|
|
142
|
+
"endpoint": "https://api.ibm.com/watson/v1",
|
|
143
|
+
"type": "ibm",
|
|
144
|
+
"api_key_required": true,
|
|
145
|
+
"rate_limit": 0
|
|
146
|
+
},
|
|
147
|
+
"microsoft": {
|
|
148
|
+
"id": "microsoft",
|
|
149
|
+
"name": "Microsoft Azure AI",
|
|
150
|
+
"endpoint": "https://api.microsoft.com/v1",
|
|
151
|
+
"type": "microsoft",
|
|
152
|
+
"api_key_required": true,
|
|
153
|
+
"rate_limit": 0
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
{
|
|
2
|
+
"rotations": {
|
|
3
|
+
"coding": {
|
|
4
|
+
"model_name": "coding",
|
|
5
|
+
"providers": [
|
|
6
|
+
{
|
|
7
|
+
"provider_id": "gemini",
|
|
8
|
+
"api_key": "YOUR_GEMINI_API_KEY",
|
|
9
|
+
"models": [
|
|
10
|
+
{
|
|
11
|
+
"name": "gemini-2.0-flash",
|
|
12
|
+
"weight": 3,
|
|
13
|
+
"rate_limit": 0
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"name": "gemini-1.5-pro",
|
|
17
|
+
"weight": 1,
|
|
18
|
+
"rate_limit": 0
|
|
19
|
+
}
|
|
20
|
+
]
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"provider_id": "openai",
|
|
24
|
+
"api_key": "YOUR_OPENAI_API_KEY",
|
|
25
|
+
"models": [
|
|
26
|
+
{
|
|
27
|
+
"name": "gpt-4",
|
|
28
|
+
"weight": 2,
|
|
29
|
+
"rate_limit": 0
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"name": "gpt-3.5-turbo",
|
|
33
|
+
"weight": 1,
|
|
34
|
+
"rate_limit": 0
|
|
35
|
+
}
|
|
36
|
+
]
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"provider_id": "anthropic",
|
|
40
|
+
"api_key": "YOUR_ANTHROPIC_API_KEY",
|
|
41
|
+
"models": [
|
|
42
|
+
{
|
|
43
|
+
"name": "claude-3-5-sonnet-20241022",
|
|
44
|
+
"weight": 2,
|
|
45
|
+
"rate_limit": 0
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"name": "claude-3-haiku-20240307",
|
|
49
|
+
"weight": 1,
|
|
50
|
+
"rate_limit": 0
|
|
51
|
+
}
|
|
52
|
+
]
|
|
53
|
+
}
|
|
54
|
+
]
|
|
55
|
+
},
|
|
56
|
+
"general": {
|
|
57
|
+
"model_name": "general",
|
|
58
|
+
"providers": [
|
|
59
|
+
{
|
|
60
|
+
"provider_id": "gemini",
|
|
61
|
+
"api_key": "YOUR_GEMINI_API_KEY",
|
|
62
|
+
"models": [
|
|
63
|
+
{
|
|
64
|
+
"name": "gemini-1.5-pro",
|
|
65
|
+
"weight": 2,
|
|
66
|
+
"rate_limit": 0
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
"name": "gemini-2.0-flash",
|
|
70
|
+
"weight": 1,
|
|
71
|
+
"rate_limit": 0
|
|
72
|
+
}
|
|
73
|
+
]
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"provider_id": "openai",
|
|
77
|
+
"api_key": "YOUR_OPENAI_API_KEY",
|
|
78
|
+
"models": [
|
|
79
|
+
{
|
|
80
|
+
"name": "gpt-4",
|
|
81
|
+
"weight": 2,
|
|
82
|
+
"rate_limit": 0
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
"name": "gpt-3.5-turbo",
|
|
86
|
+
"weight": 1,
|
|
87
|
+
"rate_limit": 0
|
|
88
|
+
}
|
|
89
|
+
]
|
|
90
|
+
}
|
|
91
|
+
]
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: aisbf
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.1
|
|
4
4
|
Summary: AISBF - AI Service Broker Framework || AI Should Be Free - A modular proxy server for managing multiple AI provider integrations
|
|
5
5
|
Home-page: https://git.nexlab.net/nexlab/aisbf.git
|
|
6
6
|
Author: AISBF Contributors
|
|
7
7
|
Author-email: stefy@nexlab.net
|
|
8
8
|
Maintainer-email: Stefy Lanza <stefy@nexlab.net>
|
|
9
|
-
License: GPL-3.0-or-later
|
|
9
|
+
License-Expression: GPL-3.0-or-later
|
|
10
10
|
Project-URL: Homepage, https://git.nexlab.net/nexlab/aisbf.git
|
|
11
11
|
Project-URL: Repository, https://git.nexlab.net/nexlab/aisbf.git
|
|
12
12
|
Project-URL: Documentation, https://git.nexlab.net/nexlab/aisbf.git
|
|
@@ -15,7 +15,6 @@ Keywords: ai,proxy,api,openai,anthropic,google,ollama,llm,chat,broker
|
|
|
15
15
|
Classifier: Development Status :: 3 - Alpha
|
|
16
16
|
Classifier: Intended Audience :: Developers
|
|
17
17
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
18
|
-
Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
|
|
19
18
|
Classifier: Programming Language :: Python :: 3
|
|
20
19
|
Classifier: Programming Language :: Python :: 3.8
|
|
21
20
|
Classifier: Programming Language :: Python :: 3.9
|
|
@@ -26,9 +25,21 @@ Classifier: Operating System :: OS Independent
|
|
|
26
25
|
Requires-Python: >=3.8
|
|
27
26
|
Description-Content-Type: text/markdown
|
|
28
27
|
License-File: LICENSE.txt
|
|
28
|
+
Requires-Dist: fastapi
|
|
29
|
+
Requires-Dist: uvicorn
|
|
30
|
+
Requires-Dist: python-multipart
|
|
31
|
+
Requires-Dist: pydantic
|
|
32
|
+
Requires-Dist: httpx
|
|
33
|
+
Requires-Dist: python-jose[cryptography]
|
|
34
|
+
Requires-Dist: passlib[bcrypt]
|
|
35
|
+
Requires-Dist: python-dotenv
|
|
36
|
+
Requires-Dist: google-genai
|
|
37
|
+
Requires-Dist: openai
|
|
38
|
+
Requires-Dist: anthropic
|
|
29
39
|
Dynamic: author-email
|
|
30
40
|
Dynamic: home-page
|
|
31
41
|
Dynamic: license-file
|
|
42
|
+
Dynamic: requires-dist
|
|
32
43
|
Dynamic: requires-python
|
|
33
44
|
|
|
34
45
|
# AISBF - AI Service Broker Framework || AI Should Be Free
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
aisbf/__init__.py,sha256=GbB1LZegRn_u5RHETw9iLnZUeS5_mkNYZ5s7jaL3Xp4,1971
|
|
2
|
+
aisbf/config.py,sha256=6n7izwrZw8CBLY9aI8dMxi8EaVVIXaWbe1mc9xsjW_g,5277
|
|
3
|
+
aisbf/handlers.py,sha256=Az7OVUDGLORwrfrQYqtaQ4bOPDE3NZJyYqub2DFZVfs,7479
|
|
4
|
+
aisbf/models.py,sha256=LT1NaQVAw0VWXL-j3hdfNlXCA9HeiET_O3GDj3t9XC4,1883
|
|
5
|
+
aisbf/providers.py,sha256=jQGKYqrb-1RB3s4XrKK7AbX-7W5Cl3HG7Yc_riMkcyA,11942
|
|
6
|
+
aisbf-0.1.1.data/data/share/aisbf/main.py,sha256=MnsDZQH-vFT4KMhlVtVK8uGyeYiRa3orka4AVH_nLIc,4550
|
|
7
|
+
aisbf-0.1.1.data/data/share/aisbf/providers.json,sha256=9L5GO6sQ2Z6zndGed0AckvYNV1DMr9r7tSdZ9fJxYlA,3934
|
|
8
|
+
aisbf-0.1.1.data/data/share/aisbf/requirements.txt,sha256=lp6cPakAO3lpTCwQ27THf-PNz_HIpzCELrtpdgo6-2o,133
|
|
9
|
+
aisbf-0.1.1.data/data/share/aisbf/rotations.json,sha256=SzbmMeTRR0vVTrYTMwxSPxjXLVr8zxjaI4HYRxjyExQ,2123
|
|
10
|
+
aisbf-0.1.1.dist-info/licenses/LICENSE.txt,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
11
|
+
aisbf-0.1.1.dist-info/METADATA,sha256=jgGUF13YI-sXxjRf2hgqD3cJ7G8WyLSEh2YMNyEn-jg,4190
|
|
12
|
+
aisbf-0.1.1.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
13
|
+
aisbf-0.1.1.dist-info/entry_points.txt,sha256=zYLNG5rYg0OM6zVQuJnxt7yKd6bf2OM9jiHy1ydPudY,36
|
|
14
|
+
aisbf-0.1.1.dist-info/top_level.txt,sha256=D7THOopMCIUH203TRSRdc1e_MBOC4OLJTCrMGBcn4Gc,6
|
|
15
|
+
aisbf-0.1.1.dist-info/RECORD,,
|
aisbf-0.1.0.dist-info/RECORD
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
aisbf/__init__.py,sha256=GbB1LZegRn_u5RHETw9iLnZUeS5_mkNYZ5s7jaL3Xp4,1971
|
|
2
|
-
aisbf/config.py,sha256=6n7izwrZw8CBLY9aI8dMxi8EaVVIXaWbe1mc9xsjW_g,5277
|
|
3
|
-
aisbf/handlers.py,sha256=Az7OVUDGLORwrfrQYqtaQ4bOPDE3NZJyYqub2DFZVfs,7479
|
|
4
|
-
aisbf/models.py,sha256=LT1NaQVAw0VWXL-j3hdfNlXCA9HeiET_O3GDj3t9XC4,1883
|
|
5
|
-
aisbf/providers.py,sha256=jQGKYqrb-1RB3s4XrKK7AbX-7W5Cl3HG7Yc_riMkcyA,11942
|
|
6
|
-
aisbf-0.1.0.dist-info/licenses/LICENSE.txt,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
7
|
-
aisbf-0.1.0.dist-info/METADATA,sha256=y6_cawA4qVHCibOHbGzYoZWEV3L21qY89lJPb57G6NA,3944
|
|
8
|
-
aisbf-0.1.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
9
|
-
aisbf-0.1.0.dist-info/top_level.txt,sha256=D7THOopMCIUH203TRSRdc1e_MBOC4OLJTCrMGBcn4Gc,6
|
|
10
|
-
aisbf-0.1.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|