askai-python 0.1.5__py3-none-any.whl → 0.2.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.
ask_ai/base.py CHANGED
@@ -82,8 +82,51 @@ class BaseProvider:
82
82
  # 3. Check for specific output_type override (e.g. user forced image)
83
83
  output_type = kwargs.get('output_type')
84
84
 
85
- # 4. Call Provider Implementation
86
- return self._send_request(messages, final_config, output_type)
85
+ # 4. Extract timeout and retry safely
86
+ timeout_val = kwargs.get('timeout', final_config.extra.get('timeout', 30))
87
+ retry_val = kwargs.get('retry', final_config.extra.get('retry', 0))
88
+
89
+ timeout = float(timeout_val) if timeout_val is not None else 30.0
90
+ retry = int(retry_val) if retry_val is not None else 0
91
+
92
+ final_config.extra['timeout'] = timeout # Pass down to providers
93
+
94
+ # 5. Execute with Retry Logic
95
+ attempts = 0
96
+ last_error = None
97
+ while attempts <= retry:
98
+ try:
99
+ return self._send_request(messages, final_config, output_type)
100
+ except Exception as e:
101
+ last_error = e
102
+ if self._is_retryable_error(e) and attempts < retry:
103
+ attempts += 1
104
+ delay = 2 ** attempts # 2s, 4s, 8s...
105
+ print(f"[ask-ai] Transient error ({e.__class__.__name__}). Retrying in {delay}s... ({attempts}/{retry})")
106
+ import time
107
+ time.sleep(delay)
108
+ else:
109
+ raise e
110
+
111
+ # Fallback if loop exits without returning
112
+ from .exceptions import AskAINetworkError
113
+ raise AskAINetworkError(f"Request failed after {retry} retries. Last error: {last_error}")
114
+
115
+ def _is_retryable_error(self, e: Exception) -> bool:
116
+ """Dynamically detect rate limits and network timeouts across different provider SDKs."""
117
+ err_str = str(e).lower()
118
+ err_cls = e.__class__.__name__.lower()
119
+
120
+ # Explicit ask-ai errors
121
+ from .exceptions import AskAINetworkError, AskAIRateLimitError
122
+ if isinstance(e, (AskAINetworkError, AskAIRateLimitError)): return True
123
+
124
+ # Heuristics for underlying provider SDKs (OpenAI, Anthropic, etc.)
125
+ if "ratelimit" in err_cls or "rate_limit" in err_cls or "429" in err_str: return True
126
+ if "timeout" in err_cls or "timeout" in err_str: return True
127
+ if "connection" in err_cls or "connecterror" in err_cls: return True
128
+
129
+ return False
87
130
 
88
131
  def _merge_configs(self, global_conf: AdvancedConfig, req_conf: AdvancedConfig) -> AdvancedConfig:
89
132
  return global_conf.merge(req_conf) # We need to implement merge logic in AdvancedConfig properly or here
ask_ai/exceptions.py CHANGED
@@ -2,14 +2,25 @@ class AskAIError(Exception):
2
2
  """Base exception for all ask-ai errors."""
3
3
  pass
4
4
 
5
- class APIKeyError(AskAIError):
6
- """Raised when API key is missing or invalid."""
5
+ class AskAIConfigError(AskAIError):
6
+ """Raised when configuration (like API keys) is missing or invalid."""
7
+ pass
8
+
9
+ class AskAINetworkError(AskAIError):
10
+ """Raised when a network connection fails (timeout, disconnect)."""
11
+ pass
12
+
13
+ class AskAIRateLimitError(AskAIError):
14
+ """Raised when the provider rate limits the request (429)."""
7
15
  pass
8
16
 
9
17
  class ProviderError(AskAIError):
10
- """Raised when the provider API fails (e.g. 500 error)."""
18
+ """Raised when the provider API fails (e.g. 500 error or bad request)."""
11
19
  pass
12
20
 
13
21
  class MediaTypeNotSupportedError(AskAIError):
14
22
  """Raised when a provider can't handle the requested media type."""
15
23
  pass
24
+
25
+ # Alias for backwards compatibility internally
26
+ APIKeyError = AskAIConfigError
@@ -0,0 +1,120 @@
1
+ Metadata-Version: 2.4
2
+ Name: askai-python
3
+ Version: 0.2.0
4
+ Summary: AI Made Stupid Simple. Unified API for OpenAI, Groq, Google, and more.
5
+ Author-email: Hossein Ghorbani <hosseingh1068@gmail.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://hosseinghorbani0.ir/
8
+ Project-URL: Bug Tracker, https://github.com/Hosseinghorbani0/ask-ai/issues
9
+ Requires-Python: >=3.8
10
+ Description-Content-Type: text/markdown
11
+ License-File: LICENSE
12
+ Requires-Dist: openai>=1.0.0
13
+ Requires-Dist: groq
14
+ Requires-Dist: google-generativeai
15
+ Requires-Dist: anthropic
16
+ Requires-Dist: requests
17
+ Requires-Dist: Pillow
18
+ Dynamic: license-file
19
+
20
+ # askai-python 🚀
21
+
22
+ **A minimal Python SDK to switch between LLM providers in one line.**
23
+ No frameworks. No servers. No overengineering.
24
+
25
+ [![PyPI version](https://img.shields.io/pypi/v/askai-python.svg)](https://pypi.org/project/askai-python/)
26
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
27
+ [![GitHub](https://img.shields.io/badge/GitHub-View%20Source-blue.svg)](https://github.com/Hosseinghorbani0/ask-ai)
28
+
29
+ ---
30
+
31
+ ## ⚡ Quick Start (5 seconds)
32
+
33
+ ```bash
34
+ pip install askai-python
35
+ ```
36
+
37
+ ```python
38
+ from ask_ai import OpenAI, Groq
39
+
40
+ # Auto-detects OPENAI_API_KEY from environment
41
+ print(OpenAI().ask("Explain black holes like I'm 5").text)
42
+
43
+ # Switch provider instantly
44
+ print(Groq().ask("Explain black holes like I'm 5").text)
45
+ ```
46
+
47
+ ---
48
+
49
+ ## 🧐 Why ask-ai?
50
+
51
+ - **One function**: Just call `.ask()`
52
+ - **Multiple providers**: OpenAI, Anthropic, Google Gemini, Groq, Azure, OpenRouter
53
+ - **Zero config**: Keys are pulled from the environment automatically
54
+ - **SDK-first, not a framework**: It stays out of your way.
55
+
56
+ ## ⚖️ How it compares
57
+
58
+ | Feature | ask-ai | LangChain |
59
+ | -------------- | ------ | --------- |
60
+ | Setup time | 30 sec | 1 hour |
61
+ | Learning curve | ⭐ | ⭐⭐⭐⭐⭐ |
62
+ | Async support | ⏳ *(Coming soon)* | ⚠️ Complex |
63
+ | Retry/Timeout | ✅ Built-in | ❌ Manual |
64
+ | Gateway needed | ❌ No | ❌ No |
65
+
66
+ ## 🚫 What this project is NOT
67
+
68
+ > ❌ Not an AI framework
69
+ > ❌ Not an API gateway
70
+ > ❌ Not an agent memory system
71
+
72
+ It does one thing perfectly: **Simplifying the API call to LLMs.**
73
+
74
+ ---
75
+
76
+ ## 🚀 Built-in Resiliency (Retries & Timeouts)
77
+
78
+ Build reliable apps without writing your own loops. `askai-python` handles rate limits (`429`) and network drops via an internal exponential backoff.
79
+
80
+ ```python
81
+ from ask_ai import OpenAI
82
+
83
+ ai = OpenAI()
84
+
85
+ # Automatically retries up to 3 times on transient errors, with a 15-second timeout
86
+ response = ai.ask(
87
+ "Write a complex python script",
88
+ retry=3,
89
+ timeout=15
90
+ )
91
+ ```
92
+
93
+ ## 🔌 Supported Providers
94
+
95
+ | Provider | Class | Capabilities |
96
+ |----------|-------|-------------|
97
+ | **OpenAI** | `OpenAI` | Text, Images (DALL-E), Vision |
98
+ | **Anthropic** | `Anthropic` | Text, Vision (Claude 3.5) |
99
+ | **Google** | `Google` | Text, Images, Video, Audio |
100
+ | **Groq** | `Groq` | Ultra-fast Llama 3 & Mixtral |
101
+ | **Azure** | `Azure` | Enterprise-grade OpenAI |
102
+ | **OpenRouter**| `OpenRouter`| 100+ community models |
103
+
104
+ ---
105
+
106
+ ## 🗺️ Roadmap
107
+
108
+ - [x] Baseline multiple providers
109
+ - [x] Automated Retry & Timeout controls
110
+ - [ ] Async API (`await ask_async`)
111
+ - [ ] Provider Fallback (`fallback=[Groq()]`)
112
+ - [ ] Structured Outputs (Pydantic Support)
113
+
114
+ ---
115
+
116
+ ## 🔗 Important Links
117
+
118
+ - **GitHub Repository**: [Hosseinghorbani0/ask-ai](https://github.com/Hosseinghorbani0/ask-ai) (Star us! ⭐)
119
+ - **Official Website**: [hosseinghorbani0.ir](https://hosseinghorbani0.ir/)
120
+ - **Bug Tracker**: [Report an Issue](https://github.com/Hosseinghorbani0/ask-ai/issues)
@@ -1,9 +1,9 @@
1
1
  ask_ai/__init__.py,sha256=i08NdBtFsjV3vT9ZqhEsroXd7vvZrWDojsOW-79iTV4,439
2
2
  ask_ai/__main__.py,sha256=MSmt_5Xg84uHqzTN38JwgseJK8rsJn_11A8WD99VtEo,61
3
- ask_ai/base.py,sha256=2-SnoQiy-RAmjCceiAsx-rqwbh20xAMpLdtPiiJdNUk,5389
3
+ ask_ai/base.py,sha256=N3U_O_alfhTyiIz_ts-z7YYdoJlR3yJcQxvD3Z9NNpY,7402
4
4
  ask_ai/cli.py,sha256=8oeRLsT2lrcuG0vDq_a4CVqvzzmwDG3HxHW4BYg3IxM,2708
5
5
  ask_ai/config.py,sha256=oP5RjdbbdDve8G-FlcbNaMXPorBw96GxhCbfFWnfbIw,1934
6
- ask_ai/exceptions.py,sha256=JT2XbhsaWCFn3bPJD37RVH9HehV1ngus5s05v6xc1Tg,414
6
+ ask_ai/exceptions.py,sha256=V7IVUL-oNkUYXnek0J4Bt66MaxgvJQCVk8bBTpqsMk4,769
7
7
  ask_ai/media.py,sha256=cxPZ0XoY0iU3Y8bY-YV3MGPlNFOJ_FjjwMATgo-jcFw,1821
8
8
  ask_ai/providers/__init__.py,sha256=tVSW-FfSMPzCYK_TZy93W5ckdVe2PBPyzogpKXH_jhg,341
9
9
  ask_ai/providers/anthropic_provider.py,sha256=NL_6E7eNTYAoYpym4ewD8Vj8tF_ewuFjFkRR0Jj0L-U,3670
@@ -12,8 +12,8 @@ ask_ai/providers/google_provider.py,sha256=DsIgu_cBC7ta0lKclAlge1PYfcp3zXKPLjWSe
12
12
  ask_ai/providers/groq_provider.py,sha256=iU7BTpvmBniE78VdTQETrCXrJzdXTpWH2oN9_sUgnFk,3268
13
13
  ask_ai/providers/openai_provider.py,sha256=b6grPbsUIY19HkABDrUIAZAIcJCKQup5tooU2LFlkvo,4793
14
14
  ask_ai/providers/openrouter_provider.py,sha256=LCGK-vNxy_maY2Fle6xh_i8MVm7a_bhjCaF7Uj0H3AM,1986
15
- askai_python-0.1.5.dist-info/licenses/LICENSE,sha256=SUSbAUsh_Uqw7NDEKwAGRVPS7sojihBHIBGBx6WZxvg,1073
16
- askai_python-0.1.5.dist-info/METADATA,sha256=erWf9yHx043bmdtRoLfoBlnkwLmLizCxREY_dY4wvP8,3850
17
- askai_python-0.1.5.dist-info/WHEEL,sha256=YLJXdYXQ2FQ0Uqn2J-6iEIC-3iOey8lH3xCtvFLkd8Q,91
18
- askai_python-0.1.5.dist-info/top_level.txt,sha256=fW2GapXaz6f-2UAuzVVPUPNfZUK_ZS1dpLyCllcE03s,7
19
- askai_python-0.1.5.dist-info/RECORD,,
15
+ askai_python-0.2.0.dist-info/licenses/LICENSE,sha256=SUSbAUsh_Uqw7NDEKwAGRVPS7sojihBHIBGBx6WZxvg,1073
16
+ askai_python-0.2.0.dist-info/METADATA,sha256=EHGGvSOedlST4YqUG8KD3uT0rmmK3VSJt3A35dAfjqM,3609
17
+ askai_python-0.2.0.dist-info/WHEEL,sha256=YCfwYGOYMi5Jhw2fU4yNgwErybb2IX5PEwBKV4ZbdBo,91
18
+ askai_python-0.2.0.dist-info/top_level.txt,sha256=fW2GapXaz6f-2UAuzVVPUPNfZUK_ZS1dpLyCllcE03s,7
19
+ askai_python-0.2.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (81.0.0)
2
+ Generator: setuptools (82.0.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,135 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: askai-python
3
- Version: 0.1.5
4
- Summary: AI Made Stupid Simple. Unified API for OpenAI, Groq, Google, and more.
5
- Author-email: Hossein Ghorbani <hosseingh1068@gmail.com>
6
- License: MIT
7
- Project-URL: Homepage, https://hosseinghorbani0.ir/
8
- Project-URL: Bug Tracker, https://github.com/Hosseinghorbani0/ask-ai/issues
9
- Requires-Python: >=3.8
10
- Description-Content-Type: text/markdown
11
- License-File: LICENSE
12
- Requires-Dist: openai>=1.0.0
13
- Requires-Dist: groq
14
- Requires-Dist: google-generativeai
15
- Requires-Dist: anthropic
16
- Requires-Dist: requests
17
- Requires-Dist: Pillow
18
- Dynamic: license-file
19
-
20
- # askai-python 🚀
21
-
22
- **AI Made Stupid Simple.** One unified Python client for OpenAI, Claude, Gemini, Groq, and Azure.
23
-
24
- [![PyPI version](https://img.shields.io/pypi/v/askai-python.svg)](https://pypi.org/project/askai-python/)
25
- [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
26
- [![GitHub](https://img.shields.io/badge/GitHub-View%20Source-blue.svg)](https://github.com/Hosseinghorbani0/ask-ai)
27
-
28
- ---
29
-
30
- ## ⚡ What is askai-python?
31
-
32
- `askai-python` is a lightweight, zero-dependency-logic wrapper that provides a **single API** for all major AI providers. Stop learning multiple SDKs; just call `.ask()` and get your answer.
33
-
34
- - **Unified Interface**: One syntax for OpenAI, Anthropic, Google, and more.
35
- - **Zero-Config**: Seamlessly uses environment variables for API keys.
36
- - **Smart Media**: Easy handling of images and audio (Provider permitting).
37
- - **Production Grade**: Built-in robust error handling and type hints.
38
-
39
- ---
40
-
41
- ## 📦 Installation
42
-
43
- ```bash
44
- pip install askai-python
45
- ```
46
-
47
- ---
48
-
49
- ## 🚀 Examples & Tutorials
50
-
51
- ### 1. Basic Usage (The 3-Line Magic)
52
- ```python
53
- from ask_ai import OpenAI
54
-
55
- ai = OpenAI() # Auto-loads OPENAI_API_KEY from env
56
- print(ai.ask("What is the capital of France?").text)
57
- ```
58
-
59
- ### 2. Multi-Provider Mastery
60
- Switching between top-tier models has never been easier:
61
-
62
- ```python
63
- from ask_ai import OpenAI, Anthropic, Google
64
-
65
- prompt = "Explain quantum computing to a 5-year-old."
66
-
67
- # OpenAI (GPT-4o)
68
- print(OpenAI().ask(prompt).text)
69
-
70
- # Anthropic (Claude 3.5 Sonnet)
71
- print(Anthropic().ask(prompt).text)
72
-
73
- # Google (Gemini 1.5 Pro)
74
- print(Google().ask(prompt).text)
75
- ```
76
-
77
- ### 3. Advanced Configuration (System Personas)
78
- You can set a system prompt and temperature globally for an instance or per-request.
79
-
80
- ```python
81
- from ask_ai import OpenAI
82
-
83
- ai = OpenAI()
84
-
85
- # Global config
86
- ai.advanced(
87
- prompt="You are a sarcastic robot from the year 3000.",
88
- temperature=0.9
89
- )
90
-
91
- print(ai.ask("What is love?").text)
92
-
93
- # Per-request override
94
- print(ai.ask("What is 1+1?", temperature=0.1).text)
95
- ```
96
-
97
- ### 4. Handling Structured Exceptions
98
- Build reliable apps by catching specific AI errors:
99
-
100
- ```python
101
- from ask_ai import OpenAI
102
- from ask_ai.exceptions import AskAIError, APIKeyError
103
-
104
- try:
105
- ai = OpenAI(api_key="invalid-key")
106
- ai.ask("Hello")
107
- except APIKeyError:
108
- print("Check your API keys!")
109
- except AskAIError as e:
110
- print(f"An AI error occurred: {e}")
111
- ```
112
-
113
- ---
114
-
115
- ## 🔌 Supported Providers
116
-
117
- | Provider | Class | Capabilities |
118
- |----------|-------|-------------|
119
- | **OpenAI** | `OpenAI` | Text, Images (DALL-E), Vision |
120
- | **Anthropic** | `Anthropic` | Text, Vision (Claude 3.5) |
121
- | **Google** | `Google` | Text, Images, Video, Audio |
122
- | **Groq** | `Groq` | Ultra-fast Llama 3 & Mixtral |
123
- | **Azure** | `Azure` | Enterprise-grade OpenAI |
124
- | **OpenRouter**| `OpenRouter`| 100+ community models |
125
-
126
- ---
127
-
128
- ## 🔗 Important Links
129
-
130
- - **GitHub Repository**: [Hosseinghorbani0/ask-ai](https://github.com/Hosseinghorbani0/ask-ai) (Star us! ⭐)
131
- - **Official Website**: [hosseinghorbani0.ir](https://hosseinghorbani0.ir/)
132
- - **Bug Tracker**: [Report an Issue](https://github.com/Hosseinghorbani0/ask-ai/issues)
133
-
134
- ---
135
- *Built with ❤️ by [Hossein Ghorbani](https://github.com/Hosseinghorbani0).*