add documents
This commit is contained in:
16
docs-requirements.txt
Normal file
16
docs-requirements.txt
Normal file
@@ -0,0 +1,16 @@
|
||||
# FastGPT Python SDK - Documentation Requirements
|
||||
|
||||
# Install with:
|
||||
# pip install -r docs-requirements.txt
|
||||
|
||||
# Core documentation tools
|
||||
mkdocs>=1.5.0
|
||||
mkdocs-material>=9.5.0
|
||||
|
||||
# API documentation generation
|
||||
mkdocstrings[python]>=0.24.0
|
||||
|
||||
# Optional: For additional features
|
||||
# mkdocs-awesome-pages-plugin # For better page organization
|
||||
# mkdocs-minify-plugin # For minifying HTML output
|
||||
# mkdocs-redirects # For setting up redirects
|
||||
343
docs/advanced/detail_mode.md
Normal file
343
docs/advanced/detail_mode.md
Normal file
@@ -0,0 +1,343 @@
|
||||
# Detail Mode
|
||||
|
||||
Learn how to use FastGPT's detail mode to get comprehensive execution data for your requests.
|
||||
|
||||
## What is Detail Mode?
|
||||
|
||||
When `detail=True`, FastGPT returns extensive execution information including:
|
||||
|
||||
- Module-by-module execution details
|
||||
- Token usage per module
|
||||
- Execution time for each node
|
||||
- Knowledge base citations
|
||||
- Complete message contexts
|
||||
- Cost information
|
||||
|
||||
## Enabling Detail Mode
|
||||
|
||||
```python
|
||||
from fastgpt_client import ChatClient
|
||||
|
||||
with ChatClient(api_key="fastgpt-xxxxx") as client:
|
||||
response = client.create_chat_completion(
|
||||
messages=[{"role": "user", "content": "Explain AI"}],
|
||||
detail=True, # Enable detail mode
|
||||
stream=False
|
||||
)
|
||||
result = response.json()
|
||||
```
|
||||
|
||||
## Response Structure with Detail Mode
|
||||
|
||||
### Basic Response (detail=False)
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "chatcmpl-xxx",
|
||||
"choices": [{
|
||||
"message": {"content": "AI is..."}
|
||||
}],
|
||||
"usage": {
|
||||
"prompt_tokens": 10,
|
||||
"completion_tokens": 50,
|
||||
"total_tokens": 60
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Detailed Response (detail=True)
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "chatcmpl-xxx",
|
||||
"choices": [{
|
||||
"message": {"content": "AI is..."}
|
||||
}],
|
||||
"usage": {
|
||||
"prompt_tokens": 10,
|
||||
"completion_tokens": 50,
|
||||
"total_tokens": 60
|
||||
},
|
||||
"responseData": [
|
||||
{
|
||||
"moduleName": "Chat Node",
|
||||
"moduleType": "chatNode",
|
||||
"tokens": 60,
|
||||
"price": 0.0012,
|
||||
"runningTime": 1.5,
|
||||
"quoteList": [
|
||||
{
|
||||
"sourceId": "kb_123",
|
||||
"sourceName": "AI Knowledge Base",
|
||||
"text": "AI stands for Artificial Intelligence..."
|
||||
}
|
||||
],
|
||||
"completeMessages": [...]
|
||||
},
|
||||
{
|
||||
"moduleName": "Dataset Search",
|
||||
"moduleType": "datasetSearchNode",
|
||||
"tokens": 20,
|
||||
"price": 0.0004,
|
||||
"runningTime": 0.5
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Parsing Detailed Responses
|
||||
|
||||
```python
|
||||
def parse_detail_response(response_data: dict):
|
||||
"""Parse and display detailed execution data."""
|
||||
|
||||
# Basic response info
|
||||
content = response_data['choices'][0]['message']['content']
|
||||
usage = response_data.get('usage', {})
|
||||
print(f"Response: {content[:100]}...")
|
||||
print(f"Total Tokens: {usage.get('total_tokens', 0)}")
|
||||
|
||||
# Detailed execution data
|
||||
response_details = response_data.get('responseData', [])
|
||||
|
||||
if response_details:
|
||||
print("\n=== Execution Details ===")
|
||||
|
||||
for module in response_details:
|
||||
module_name = module.get('moduleName', 'Unknown')
|
||||
module_type = module.get('moduleType', 'Unknown')
|
||||
tokens = module.get('tokens', 0)
|
||||
price = module.get('price', 0)
|
||||
running_time = module.get('runningTime', 0)
|
||||
|
||||
print(f"\nModule: {module_name} ({module_type})")
|
||||
print(f" Tokens: {tokens}")
|
||||
print(f" Price: ${price:.6f}")
|
||||
print(f" Runtime: {running_time}s")
|
||||
|
||||
# Knowledge base citations
|
||||
quote_list = module.get('quoteList', [])
|
||||
if quote_list:
|
||||
print(f" Citations:")
|
||||
for quote in quote_list:
|
||||
source = quote.get('sourceName', 'Unknown')
|
||||
text = quote.get('text', '')[:100]
|
||||
print(f" - {source}: {text}...")
|
||||
|
||||
|
||||
# Usage
|
||||
with ChatClient(api_key="fastgpt-xxxxx") as client:
|
||||
response = client.create_chat_completion(
|
||||
messages=[{"role": "user", "content": "What is AI?"}],
|
||||
detail=True,
|
||||
stream=False
|
||||
)
|
||||
result = response.json()
|
||||
parse_detail_response(result)
|
||||
```
|
||||
|
||||
## Streaming with Detail Mode
|
||||
|
||||
```python
|
||||
import json
|
||||
from fastgpt_client import ChatClient
|
||||
|
||||
def stream_with_detail(client, messages):
|
||||
"""Stream with detail mode events."""
|
||||
|
||||
response = client.create_chat_completion(
|
||||
messages=messages,
|
||||
detail=True,
|
||||
stream=True
|
||||
)
|
||||
|
||||
modules = []
|
||||
|
||||
for line in response.iter_lines():
|
||||
if line.startswith("event:flowNodeStatus"):
|
||||
# Node status updates
|
||||
data = json.loads(line[6:].split('data:', 1)[1])
|
||||
status = data.get('status')
|
||||
node = data.get('moduleName')
|
||||
print(f"[{status.upper()}] {node}")
|
||||
|
||||
elif line.startswith("event:flowResponses"):
|
||||
# Complete module execution data
|
||||
data = json.loads(line[6:].split('data:', 1)[1])
|
||||
modules.append(data)
|
||||
|
||||
elif line.startswith("data:"):
|
||||
# Standard response chunks
|
||||
data = line[5:].strip()
|
||||
if data and data != "[DONE]":
|
||||
chunk = json.loads(data)
|
||||
if "choices" in chunk and chunk["choices"]:
|
||||
delta = chunk["choices"][0].get("delta", {})
|
||||
content = delta.get("content", "")
|
||||
if content:
|
||||
print(content, end="", flush=True)
|
||||
|
||||
print("\n\n=== Module Summary ===")
|
||||
for module in modules:
|
||||
print(f"{module.get('moduleName')}: {module.get('tokens')} tokens")
|
||||
|
||||
|
||||
# Usage
|
||||
with ChatClient(api_key="fastgpt-xxxxx") as client:
|
||||
stream_with_detail(
|
||||
client,
|
||||
[{"role": "user", "content": "Explain quantum computing"}]
|
||||
)
|
||||
```
|
||||
|
||||
## Extracting Knowledge Base Citations
|
||||
|
||||
```python
|
||||
def get_citations(response_data: dict) -> list[dict]:
|
||||
"""Extract knowledge base citations from detailed response."""
|
||||
|
||||
citations = []
|
||||
response_details = response_data.get('responseData', [])
|
||||
|
||||
for module in response_details:
|
||||
quote_list = module.get('quoteList', [])
|
||||
for quote in quote_list:
|
||||
citations.append({
|
||||
'source': quote.get('sourceName', 'Unknown'),
|
||||
'source_id': quote.get('sourceId', ''),
|
||||
'text': quote.get('text', ''),
|
||||
'module': module.get('moduleName', 'Unknown')
|
||||
})
|
||||
|
||||
return citations
|
||||
|
||||
|
||||
# Usage
|
||||
with ChatClient(api_key="fastgpt-xxxxx") as client:
|
||||
response = client.create_chat_completion(
|
||||
messages=[{"role": "user", "content": "What is machine learning?"}],
|
||||
detail=True,
|
||||
stream=False
|
||||
)
|
||||
result = response.json()
|
||||
|
||||
citations = get_citations(result)
|
||||
print(f"Found {len(citations)} citations:")
|
||||
for i, citation in enumerate(citations, 1):
|
||||
print(f"\n{i}. {citation['source']}")
|
||||
print(f" {citation['text'][:150]}...")
|
||||
```
|
||||
|
||||
## Calculating Costs
|
||||
|
||||
```python
|
||||
def calculate_costs(response_data: dict) -> dict:
|
||||
"""Calculate total and per-module costs."""
|
||||
|
||||
total_cost = 0
|
||||
total_tokens = 0
|
||||
module_costs = []
|
||||
|
||||
response_details = response_data.get('responseData', [])
|
||||
|
||||
for module in response_details:
|
||||
cost = module.get('price', 0)
|
||||
tokens = module.get('tokens', 0)
|
||||
module_name = module.get('moduleName', 'Unknown')
|
||||
|
||||
total_cost += cost
|
||||
total_tokens += tokens
|
||||
|
||||
module_costs.append({
|
||||
'module': module_name,
|
||||
'cost': cost,
|
||||
'tokens': tokens
|
||||
})
|
||||
|
||||
return {
|
||||
'total_cost': total_cost,
|
||||
'total_tokens': total_tokens,
|
||||
'modules': module_costs
|
||||
}
|
||||
|
||||
|
||||
# Usage
|
||||
with ChatClient(api_key="fastgpt-xxxxx") as client:
|
||||
response = client.create_chat_completion(
|
||||
messages=[{"role": "user", "content": "Tell me about AI"}],
|
||||
detail=True,
|
||||
stream=False
|
||||
)
|
||||
result = response.json()
|
||||
|
||||
costs = calculate_costs(result)
|
||||
print(f"Total Cost: ${costs['total_cost']:.6f}")
|
||||
print(f"Total Tokens: {costs['total_tokens']}")
|
||||
print("\nPer-Module Costs:")
|
||||
for module in costs['modules']:
|
||||
print(f" {module['module']}: ${module['cost']:.6f} ({module['tokens']} tokens)")
|
||||
```
|
||||
|
||||
## Analyzing Execution Time
|
||||
|
||||
```python
|
||||
def analyze_performance(response_data: dict) -> dict:
|
||||
"""Analyze module execution performance."""
|
||||
|
||||
total_time = 0
|
||||
modules = []
|
||||
|
||||
for module in response_data.get('responseData', []):
|
||||
runtime = module.get('runningTime', 0)
|
||||
module_name = module.get('moduleName', 'Unknown')
|
||||
|
||||
total_time += runtime
|
||||
modules.append({
|
||||
'module': module_name,
|
||||
'runtime': runtime
|
||||
})
|
||||
|
||||
# Sort by runtime
|
||||
modules.sort(key=lambda x: x['runtime'], reverse=True)
|
||||
|
||||
return {
|
||||
'total_time': total_time,
|
||||
'modules': modules
|
||||
}
|
||||
|
||||
|
||||
# Usage
|
||||
with ChatClient(api_key="fastgpt-xxxxx") as client:
|
||||
response = client.create_chat_completion(
|
||||
messages=[{"role": "user", "content": "Analyze this data"}],
|
||||
detail=True,
|
||||
stream=False
|
||||
)
|
||||
result = response.json()
|
||||
|
||||
perf = analyze_performance(result)
|
||||
print(f"Total Runtime: {perf['total_time']:.2f}s")
|
||||
print("\nModule Execution Times:")
|
||||
for module in perf['modules']:
|
||||
print(f" {module['module']}: {module['runtime']:.2f}s")
|
||||
```
|
||||
|
||||
## Use Cases
|
||||
|
||||
1. **Debugging** - Identify slow or expensive modules
|
||||
2. **Cost Optimization** - Track token usage and costs
|
||||
3. **Transparency** - Show sources and reasoning to users
|
||||
4. **Analytics** - Monitor application performance
|
||||
5. **Compliance** - Track AI-generated content sources
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Use selectively** - Detail mode adds overhead
|
||||
2. **Cache results** - Store detailed data for analysis
|
||||
3. **Monitor costs** - Track token usage over time
|
||||
4. **Optimize workflows** - Use performance data to improve
|
||||
|
||||
## See Also
|
||||
|
||||
- [Streaming Events](streaming_events.md) - Real-time execution events
|
||||
- [Record Detail API](../api/chat_client.md#get_record_detail) - Get details for past records
|
||||
319
docs/advanced/error_handling.md
Normal file
319
docs/advanced/error_handling.md
Normal file
@@ -0,0 +1,319 @@
|
||||
# Error Handling
|
||||
|
||||
A comprehensive guide to handling errors in the FastGPT Python SDK.
|
||||
|
||||
## Exception Types
|
||||
|
||||
The SDK provides specific exceptions for different error scenarios:
|
||||
|
||||
| Exception | Status Code | When to Use |
|
||||
|-----------|-------------|-------------|
|
||||
| `AuthenticationError` | 401 | Invalid API key |
|
||||
| `RateLimitError` | 429 | Too many requests |
|
||||
| `ValidationError` | 422 | Invalid parameters |
|
||||
| `APIError` | 4xx/5xx | General API errors |
|
||||
|
||||
## Basic Error Handling
|
||||
|
||||
```python
|
||||
from fastgpt_client import ChatClient
|
||||
from fastgpt_client.exceptions import (
|
||||
APIError,
|
||||
AuthenticationError,
|
||||
RateLimitError,
|
||||
ValidationError
|
||||
)
|
||||
|
||||
try:
|
||||
with ChatClient(api_key="fastgpt-xxxxx") as client:
|
||||
response = client.create_chat_completion(
|
||||
messages=[{"role": "user", "content": "Hello"}],
|
||||
stream=False
|
||||
)
|
||||
response.raise_for_status()
|
||||
result = response.json()
|
||||
print(result['choices'][0]['message']['content'])
|
||||
|
||||
except AuthenticationError:
|
||||
print("Authentication failed. Check your API key.")
|
||||
|
||||
except RateLimitError as e:
|
||||
print(f"Rate limit exceeded. Retry after: {e.retry_after}")
|
||||
|
||||
except ValidationError as e:
|
||||
print(f"Invalid parameters: {e.message}")
|
||||
|
||||
except APIError as e:
|
||||
print(f"API error: {e.message}")
|
||||
```
|
||||
|
||||
## Comprehensive Error Handler
|
||||
|
||||
```python
|
||||
from fastgpt_client import ChatClient
|
||||
from fastgpt_client.exceptions import FastGPTError
|
||||
import logging
|
||||
|
||||
logging.basicConfig(level=logging.ERROR)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ChatService:
|
||||
"""Chat service with comprehensive error handling."""
|
||||
|
||||
def __init__(self, api_key: str, base_url: str):
|
||||
self.client = ChatClient(api_key=api_key, base_url=base_url)
|
||||
|
||||
def send_message(self, message: str) -> str | None:
|
||||
"""Send a message with error handling."""
|
||||
try:
|
||||
response = self.client.create_chat_completion(
|
||||
messages=[{"role": "user", "content": message}],
|
||||
stream=False
|
||||
)
|
||||
response.raise_for_status()
|
||||
result = response.json()
|
||||
return result['choices'][0]['message']['content']
|
||||
|
||||
except AuthenticationError:
|
||||
logger.error("Invalid API key")
|
||||
return "Error: Authentication failed. Please check your API key."
|
||||
|
||||
except RateLimitError as e:
|
||||
logger.error(f"Rate limit exceeded: {e}")
|
||||
wait_time = int(e.retry_after) if e.retry_after else 5
|
||||
return f"Error: Too many requests. Please wait {wait_time} seconds."
|
||||
|
||||
except ValidationError as e:
|
||||
logger.error(f"Validation error: {e}")
|
||||
return f"Error: Invalid request - {e.message}"
|
||||
|
||||
except APIError as e:
|
||||
logger.error(f"API error: {e}")
|
||||
return f"Error: Server error - {e.message}"
|
||||
|
||||
except Exception as e:
|
||||
logger.exception(f"Unexpected error: {e}")
|
||||
return "Error: An unexpected error occurred."
|
||||
|
||||
def close(self):
|
||||
"""Close the client."""
|
||||
self.client.close()
|
||||
```
|
||||
|
||||
## Retry Logic
|
||||
|
||||
### Simple Retry
|
||||
|
||||
```python
|
||||
import time
|
||||
from fastgpt_client import ChatClient
|
||||
from fastgpt_client.exceptions import RateLimitError
|
||||
|
||||
def chat_with_retry(client, messages, max_retries=3):
|
||||
"""Retry chat completion on rate limit errors."""
|
||||
for attempt in range(max_retries):
|
||||
try:
|
||||
response = client.create_chat_completion(
|
||||
messages=messages,
|
||||
stream=False
|
||||
)
|
||||
response.raise_for_status()
|
||||
return response.json()
|
||||
|
||||
except RateLimitError as e:
|
||||
if attempt < max_retries - 1:
|
||||
wait_time = int(e.retry_after) if e.retry_after else 5
|
||||
print(f"Rate limited. Waiting {wait_time} seconds...")
|
||||
time.sleep(wait_time)
|
||||
else:
|
||||
raise
|
||||
```
|
||||
|
||||
### Exponential Backoff
|
||||
|
||||
```python
|
||||
import time
|
||||
from fastgpt_client import ChatClient
|
||||
from fastgpt_client.exceptions import APIError
|
||||
|
||||
def chat_with_backoff(client, messages, max_retries=5):
|
||||
"""Retry with exponential backoff."""
|
||||
base_delay = 1 # seconds
|
||||
|
||||
for attempt in range(max_retries):
|
||||
try:
|
||||
response = client.create_chat_completion(
|
||||
messages=messages,
|
||||
stream=False
|
||||
)
|
||||
response.raise_for_status()
|
||||
return response.json()
|
||||
|
||||
except APIError as e:
|
||||
if attempt < max_retries - 1 and e.status_code >= 500:
|
||||
# Exponential backoff for server errors
|
||||
delay = base_delay * (2 ** attempt)
|
||||
print(f"Server error. Retrying in {delay} seconds...")
|
||||
time.sleep(delay)
|
||||
else:
|
||||
raise
|
||||
```
|
||||
|
||||
## Streaming Error Handling
|
||||
|
||||
```python
|
||||
import json
|
||||
from fastgpt_client import ChatClient
|
||||
from fastgpt_client.exceptions import FastGPTError
|
||||
|
||||
def stream_chat_safely(client, messages):
|
||||
"""Handle streaming with error recovery."""
|
||||
try:
|
||||
response = client.create_chat_completion(
|
||||
messages=messages,
|
||||
stream=True
|
||||
)
|
||||
|
||||
for line in response.iter_lines():
|
||||
try:
|
||||
if line.startswith("data:"):
|
||||
data = line[5:].strip()
|
||||
if data and data != "[DONE]":
|
||||
chunk = json.loads(data)
|
||||
if "choices" in chunk and chunk["choices"]:
|
||||
delta = chunk["choices"][0].get("delta", {})
|
||||
content = delta.get("content", "")
|
||||
if content:
|
||||
print(content, end="", flush=True)
|
||||
except json.JSONDecodeError:
|
||||
# Skip malformed JSON chunks
|
||||
continue
|
||||
|
||||
except FastGPTError as e:
|
||||
print(f"\nStream error: {e}")
|
||||
```
|
||||
|
||||
## Response Validation
|
||||
|
||||
```python
|
||||
def validate_response(response_data: dict) -> bool:
|
||||
"""Validate API response structure."""
|
||||
if "choices" not in response_data:
|
||||
raise ValueError("Response missing 'choices' field")
|
||||
|
||||
if not response_data["choices"]:
|
||||
raise ValueError("Empty choices array")
|
||||
|
||||
choice = response_data["choices"][0]
|
||||
if "message" not in choice:
|
||||
raise ValueError("Choice missing 'message' field")
|
||||
|
||||
message = choice["message"]
|
||||
if "content" not in message:
|
||||
raise ValueError("Message missing 'content' field")
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def safe_chat_completion(client, messages):
|
||||
"""Chat with response validation."""
|
||||
response = client.create_chat_completion(
|
||||
messages=messages,
|
||||
stream=False
|
||||
)
|
||||
response.raise_for_status()
|
||||
result = response.json()
|
||||
|
||||
try:
|
||||
validate_response(result)
|
||||
return result['choices'][0]['message']['content']
|
||||
except ValueError as e:
|
||||
print(f"Invalid response format: {e}")
|
||||
return None
|
||||
```
|
||||
|
||||
## Logging Errors
|
||||
|
||||
```python
|
||||
import logging
|
||||
from fastgpt_client import ChatClient
|
||||
from fastgpt_client.exceptions import FastGPTError
|
||||
|
||||
# Configure logging
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
||||
)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
def log_errors(client, messages):
|
||||
"""Log errors with context."""
|
||||
try:
|
||||
response = client.create_chat_completion(
|
||||
messages=messages,
|
||||
stream=False
|
||||
)
|
||||
response.raise_for_status()
|
||||
return response.json()
|
||||
|
||||
except FastGPTError as e:
|
||||
logger.error(
|
||||
f"API Error: {type(e).__name__} - {e.message}",
|
||||
extra={
|
||||
"status_code": e.status_code,
|
||||
"response_data": e.response_data,
|
||||
}
|
||||
)
|
||||
raise
|
||||
```
|
||||
|
||||
## Custom Exception Handler
|
||||
|
||||
```python
|
||||
from functools import wraps
|
||||
from fastgpt_client.exceptions import FastGPTError
|
||||
|
||||
def handle_fastgpt_errors(func):
|
||||
"""Decorator for handling FastGPT errors."""
|
||||
|
||||
@wraps(func)
|
||||
def wrapper(*args, **kwargs):
|
||||
try:
|
||||
return func(*args, **kwargs)
|
||||
except FastGPTError as e:
|
||||
print(f"FastGPT Error: {e}")
|
||||
return None
|
||||
except Exception as e:
|
||||
print(f"Unexpected Error: {e}")
|
||||
return None
|
||||
|
||||
return wrapper
|
||||
|
||||
|
||||
@handle_fastgpt_errors
|
||||
def send_message(client, message: str):
|
||||
"""Send message with automatic error handling."""
|
||||
response = client.create_chat_completion(
|
||||
messages=[{"role": "user", "content": message}],
|
||||
stream=False
|
||||
)
|
||||
response.raise_for_status()
|
||||
result = response.json()
|
||||
return result['choices'][0]['message']['content']
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Always use `raise_for_status()`** - Catches HTTP errors early
|
||||
2. **Handle specific exceptions** - Use except blocks for known error types
|
||||
3. **Log all errors** - Helps with debugging and monitoring
|
||||
4. **Provide user feedback** - Show meaningful error messages
|
||||
5. **Implement retries** - For transient errors (rate limits, server errors)
|
||||
6. **Validate responses** - Ensure data structure is correct
|
||||
7. **Use context managers** - Ensures proper cleanup
|
||||
|
||||
## See Also
|
||||
|
||||
- [Exceptions Reference](../api/exceptions.md) - Exception types and attributes
|
||||
- [Rate Limiting](rate_limiting.md) - Handling rate limits effectively
|
||||
298
docs/advanced/rate_limiting.md
Normal file
298
docs/advanced/rate_limiting.md
Normal file
@@ -0,0 +1,298 @@
|
||||
# Rate Limiting
|
||||
|
||||
Understanding and handling rate limits in the FastGPT API.
|
||||
|
||||
## Understanding Rate Limits
|
||||
|
||||
FastGPT API may enforce rate limits to:
|
||||
|
||||
- Prevent API abuse
|
||||
- Ensure fair resource allocation
|
||||
- Maintain system stability
|
||||
|
||||
When you exceed the rate limit, you'll receive a `429 Too Many Requests` response.
|
||||
|
||||
## RateLimitError
|
||||
|
||||
The SDK raises `RateLimitError` when rate limits are exceeded:
|
||||
|
||||
```python
|
||||
from fastgpt_client import ChatClient
|
||||
from fastgpt_client.exceptions import RateLimitError
|
||||
|
||||
try:
|
||||
response = client.create_chat_completion(
|
||||
messages=[{"role": "user", "content": "Hello"}]
|
||||
)
|
||||
except RateLimitError as e:
|
||||
print(f"Rate limit exceeded!")
|
||||
print(f"Status code: {e.status_code}") # 429
|
||||
print(f"Retry after: {e.retry_after}") # Suggested wait time
|
||||
```
|
||||
|
||||
## Handling Rate Limits
|
||||
|
||||
### 1. Simple Retry with Delay
|
||||
|
||||
```python
|
||||
import time
|
||||
from fastgpt_client.exceptions import RateLimitError
|
||||
|
||||
def chat_with_retry(client, messages, max_retries=3):
|
||||
"""Retry on rate limit with fixed delay."""
|
||||
for attempt in range(max_retries):
|
||||
try:
|
||||
response = client.create_chat_completion(
|
||||
messages=messages,
|
||||
stream=False
|
||||
)
|
||||
response.raise_for_status()
|
||||
return response.json()
|
||||
|
||||
except RateLimitError as e:
|
||||
if attempt < max_retries - 1:
|
||||
# Use Retry-After header or default to 5 seconds
|
||||
wait_time = int(e.retry_after) if e.retry_after else 5
|
||||
print(f"Rate limited. Waiting {wait_time} seconds...")
|
||||
time.sleep(wait_time)
|
||||
else:
|
||||
print("Max retries exceeded")
|
||||
raise
|
||||
```
|
||||
|
||||
### 2. Exponential Backoff
|
||||
|
||||
```python
|
||||
import time
|
||||
|
||||
def chat_with_backoff(client, messages, max_retries=5):
|
||||
"""Retry with exponential backoff."""
|
||||
base_delay = 1 # Start with 1 second
|
||||
|
||||
for attempt in range(max_retries):
|
||||
try:
|
||||
response = client.create_chat_completion(
|
||||
messages=messages,
|
||||
stream=False
|
||||
)
|
||||
response.raise_for_status()
|
||||
return response.json()
|
||||
|
||||
except RateLimitError as e:
|
||||
if attempt < max_retries - 1:
|
||||
# Exponential backoff with jitter
|
||||
delay = base_delay * (2 ** attempt)
|
||||
# Add jitter to avoid thundering herd
|
||||
import random
|
||||
jitter = random.uniform(0, 0.5 * delay)
|
||||
wait_time = delay + jitter
|
||||
|
||||
print(f"Rate limited. Waiting {wait_time:.1f} seconds...")
|
||||
time.sleep(wait_time)
|
||||
else:
|
||||
raise
|
||||
```
|
||||
|
||||
### 3. Async Retry with Backoff
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
|
||||
async def async_chat_with_retry(client, messages, max_retries=5):
|
||||
"""Async retry with exponential backoff."""
|
||||
base_delay = 1
|
||||
|
||||
for attempt in range(max_retries):
|
||||
try:
|
||||
response = await client.create_chat_completion(
|
||||
messages=messages,
|
||||
stream=False
|
||||
)
|
||||
response.raise_for_status()
|
||||
return response.json()
|
||||
|
||||
except RateLimitError as e:
|
||||
if attempt < max_retries - 1:
|
||||
delay = base_delay * (2 ** attempt)
|
||||
print(f"Rate limited. Waiting {delay} seconds...")
|
||||
await asyncio.sleep(delay)
|
||||
else:
|
||||
raise
|
||||
```
|
||||
|
||||
### 4. Rate Limiter Class
|
||||
|
||||
```python
|
||||
import time
|
||||
from collections import deque
|
||||
from threading import Lock
|
||||
|
||||
class RateLimiter:
|
||||
"""Token bucket rate limiter."""
|
||||
|
||||
def __init__(self, rate: int, per: float = 60.0):
|
||||
"""
|
||||
Args:
|
||||
rate: Number of requests allowed
|
||||
per: Time period in seconds
|
||||
"""
|
||||
self.rate = rate
|
||||
self.per = per
|
||||
self.allowance = rate
|
||||
self.last_check = time.time()
|
||||
self.lock = Lock()
|
||||
|
||||
def acquire(self, block: bool = True, timeout: float = None) -> bool:
|
||||
"""Acquire a token from the bucket."""
|
||||
with self.lock:
|
||||
current = time.time()
|
||||
time_passed = current - self.last_check
|
||||
self.last_check = current
|
||||
|
||||
# Refill bucket
|
||||
self.allowance += time_passed * (self.rate / self.per)
|
||||
|
||||
if self.allowance > self.rate:
|
||||
self.allowance = self.rate
|
||||
|
||||
if self.allowance < 1.0:
|
||||
if not block:
|
||||
return False
|
||||
|
||||
# Calculate wait time
|
||||
sleep_time = (1.0 - self.allowance) * (self.per / self.rate)
|
||||
|
||||
if timeout is not None and sleep_time > timeout:
|
||||
return False
|
||||
|
||||
time.sleep(sleep_time)
|
||||
self.allowance = 0.0
|
||||
else:
|
||||
self.allowance -= 1.0
|
||||
|
||||
return True
|
||||
|
||||
|
||||
# Usage
|
||||
rate_limiter = RateLimiter(rate=10, per=60) # 10 requests per minute
|
||||
|
||||
for i in range(15):
|
||||
if rate_limiter.acquire():
|
||||
response = client.create_chat_completion(
|
||||
messages=[{"role": "user", "content": f"Message {i}"}]
|
||||
)
|
||||
print(f"Sent message {i}")
|
||||
else:
|
||||
print(f"Rate limited, skipping message {i}")
|
||||
```
|
||||
|
||||
### 5. Decorator for Rate Limiting
|
||||
|
||||
```python
|
||||
import time
|
||||
import functools
|
||||
from fastgpt_client.exceptions import RateLimitError
|
||||
|
||||
def rate_limit_retry(max_retries=3, base_delay=1):
|
||||
"""Decorator to handle rate limiting with retries."""
|
||||
|
||||
def decorator(func):
|
||||
@functools.wraps(func)
|
||||
def wrapper(*args, **kwargs):
|
||||
for attempt in range(max_retries):
|
||||
try:
|
||||
return func(*args, **kwargs)
|
||||
except RateLimitError as e:
|
||||
if attempt < max_retries - 1:
|
||||
delay = base_delay * (2 ** attempt)
|
||||
wait_time = int(e.retry_after) if e.retry_after else delay
|
||||
print(f"Rate limited. Waiting {wait_time} seconds...")
|
||||
time.sleep(wait_time)
|
||||
else:
|
||||
raise
|
||||
return wrapper
|
||||
return decorator
|
||||
|
||||
|
||||
# Usage
|
||||
@rate_limit_retry(max_retries=3, base_delay=2)
|
||||
def send_message(client, message: str):
|
||||
response = client.create_chat_completion(
|
||||
messages=[{"role": "user", "content": message}],
|
||||
stream=False
|
||||
)
|
||||
response.raise_for_status()
|
||||
return response.json()
|
||||
```
|
||||
|
||||
## Monitoring Rate Limits
|
||||
|
||||
```python
|
||||
import time
|
||||
from collections import defaultdict
|
||||
|
||||
class RequestMonitor:
|
||||
"""Monitor API request rates."""
|
||||
|
||||
def __init__(self, window_seconds=60):
|
||||
self.window = window_seconds
|
||||
self.requests = defaultdict(list)
|
||||
self.lock = Lock()
|
||||
|
||||
def record_request(self, endpoint: str):
|
||||
"""Record an API request."""
|
||||
with self.lock:
|
||||
now = time.time()
|
||||
self.requests[endpoint].append(now)
|
||||
|
||||
# Remove old requests outside the window
|
||||
cutoff = now - self.window
|
||||
self.requests[endpoint] = [
|
||||
t for t in self.requests[endpoint] if t > cutoff
|
||||
]
|
||||
|
||||
def get_rate(self, endpoint: str) -> float:
|
||||
"""Get requests per second for an endpoint."""
|
||||
with self.lock:
|
||||
recent = self.requests[endpoint]
|
||||
if not recent:
|
||||
return 0.0
|
||||
return len(recent) / self.window
|
||||
|
||||
def is_rate_limited(self, endpoint: str, limit: int) -> bool:
|
||||
"""Check if endpoint is rate limited."""
|
||||
with self.lock:
|
||||
cutoff = time.time() - self.window
|
||||
recent = [t for t in self.requests[endpoint] if t > cutoff]
|
||||
return len(recent) >= limit
|
||||
|
||||
|
||||
# Usage
|
||||
monitor = RequestMonitor(window_seconds=60)
|
||||
|
||||
def make_request(client, messages):
|
||||
endpoint = "/api/v1/chat/completions"
|
||||
|
||||
# Check if we're rate limited
|
||||
if monitor.is_rate_limited(endpoint, limit=100):
|
||||
print("Approaching rate limit, slowing down...")
|
||||
time.sleep(1)
|
||||
|
||||
monitor.record_request(endpoint)
|
||||
response = client.create_chat_completion(messages=messages)
|
||||
return response
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Implement backoff** - Use exponential backoff for retries
|
||||
2. **Respect Retry-After** - Use the `retry_after` header when available
|
||||
3. **Monitor usage** - Track request rates to avoid hitting limits
|
||||
4. **Queue requests** - For batch operations, use rate limiting
|
||||
5. **Handle gracefully** - Show user-friendly messages when rate limited
|
||||
6. **Use async** - Better resource utilization with concurrent requests
|
||||
|
||||
## See Also
|
||||
|
||||
- [Error Handling](error_handling.md) - Comprehensive error handling guide
|
||||
- [Exceptions Reference](../api/exceptions.md) - Exception types and attributes
|
||||
284
docs/advanced/streaming_events.md
Normal file
284
docs/advanced/streaming_events.md
Normal file
@@ -0,0 +1,284 @@
|
||||
# Streaming Events
|
||||
|
||||
FastGPT uses Server-Sent Events (SSE) for streaming responses. This guide covers all event types you may encounter.
|
||||
|
||||
## SSE Format
|
||||
|
||||
FastGPT sends events in this format:
|
||||
|
||||
```
|
||||
event: eventType
|
||||
data: {"key": "value"}
|
||||
|
||||
event: anotherEvent
|
||||
data: {"key": "value"}
|
||||
```
|
||||
|
||||
## Event Types
|
||||
|
||||
### 1. `data` Event
|
||||
|
||||
The main streaming event, compatible with OpenAI's format:
|
||||
|
||||
```python
|
||||
import json
|
||||
|
||||
for line in response.iter_lines():
|
||||
if line.startswith("data:"):
|
||||
data = line[5:].strip()
|
||||
if data and data != "[DONE]":
|
||||
chunk = json.loads(data)
|
||||
# Process OpenAI-compatible response
|
||||
if "choices" in chunk and chunk["choices"]:
|
||||
delta = chunk["choices"][0].get("delta", {})
|
||||
content = delta.get("content", "")
|
||||
if content:
|
||||
print(content, end="", flush=True)
|
||||
```
|
||||
|
||||
### 2. `answer` Event
|
||||
|
||||
Main chat response content (alternative format):
|
||||
|
||||
```python
|
||||
for line in response.iter_lines():
|
||||
if line.startswith("event:answer"):
|
||||
# Next line contains the data
|
||||
answer_data = json.loads(next_line[5:])
|
||||
print(answer_data.get("text", ""), end="", flush=True)
|
||||
```
|
||||
|
||||
### 3. `fastAnswer` Event
|
||||
|
||||
Quick reply content:
|
||||
|
||||
```python
|
||||
for line in response.iter_lines():
|
||||
if line.startswith("event:fastAnswer"):
|
||||
fast_answer_data = json.loads(next_line[5:])
|
||||
print(f"Quick reply: {fast_answer_data}")
|
||||
```
|
||||
|
||||
### 4. `flowNodeStatus` Event
|
||||
|
||||
Workflow node status updates:
|
||||
|
||||
```python
|
||||
for line in response.iter_lines():
|
||||
if line.startswith("event:flowNodeStatus"):
|
||||
status_data = json.loads(next_line[5:])
|
||||
status = status_data.get("status") # "running", "completed", "error"
|
||||
node_name = status_data.get("nodeName")
|
||||
print(f"[{status.upper()}] {node_name}")
|
||||
```
|
||||
|
||||
### 5. `flowResponses` Event
|
||||
|
||||
Complete node response data (requires `detail=True`):
|
||||
|
||||
```python
|
||||
client.create_chat_completion(
|
||||
messages=[{"role": "user", "content": "Hello"}],
|
||||
stream=True,
|
||||
detail=True # Enable detailed responses
|
||||
)
|
||||
|
||||
# Then in the stream:
|
||||
for line in response.iter_lines():
|
||||
if line.startswith("event:flowResponses"):
|
||||
response_data = json.loads(next_line[5:])
|
||||
# Contains module execution details
|
||||
module_name = response_data.get("moduleName")
|
||||
tokens = response_data.get("tokens")
|
||||
print(f"Module: {module_name}, Tokens: {tokens}")
|
||||
```
|
||||
|
||||
### 6. `interactive` Event
|
||||
|
||||
Interactive node (requires user input or selection):
|
||||
|
||||
```python
|
||||
for line in response.iter_lines():
|
||||
if line.startswith("event:interactive"):
|
||||
interactive_data = json.loads(next_line[5:])
|
||||
interactive_type = interactive_data.get("type")
|
||||
|
||||
if interactive_type == "userSelect":
|
||||
options = interactive_data["params"]["userSelectOptions"]
|
||||
print("Please select an option:")
|
||||
for i, option in enumerate(options):
|
||||
print(f"{i + 1}. {option['value']}")
|
||||
|
||||
elif interactive_type == "userInput":
|
||||
form_fields = interactive_data["params"]["inputForm"]
|
||||
print("Please provide the following information:")
|
||||
for field in form_fields:
|
||||
print(f"- {field['label']}")
|
||||
```
|
||||
|
||||
### 7. `updateVariables` Event
|
||||
|
||||
Variable updates during execution:
|
||||
|
||||
```python
|
||||
for line in response.iter_lines():
|
||||
if line.startswith("event:updateVariables"):
|
||||
var_data = json.loads(next_line[5:])
|
||||
variables = var_data.get("variables", {})
|
||||
print(f"Variables updated: {variables}")
|
||||
```
|
||||
|
||||
### 8. `error` Event
|
||||
|
||||
Error events:
|
||||
|
||||
```python
|
||||
for line in response.iter_lines():
|
||||
if line.startswith("event:error"):
|
||||
error_data = json.loads(next_line[5:])
|
||||
error_message = error_data.get("message", "Unknown error")
|
||||
error_type = error_data.get("type", "Error")
|
||||
print(f"Error [{error_type}]: {error_message}")
|
||||
```
|
||||
|
||||
### 9. `toolCall`, `toolParams`, `toolResponse` Events
|
||||
|
||||
Tool/agent operation events:
|
||||
|
||||
```python
|
||||
for line in response.iter_lines():
|
||||
if line.startswith("event:toolCall"):
|
||||
tool_data = json.loads(next_line[5:])
|
||||
tool_name = tool_data.get("toolName")
|
||||
print(f"Tool called: {tool_name}")
|
||||
|
||||
elif line.startswith("event:toolParams"):
|
||||
params_data = json.loads(next_line[5:])
|
||||
print(f"Tool parameters: {params_data}")
|
||||
|
||||
elif line.startswith("event:toolResponse"):
|
||||
response_data = json.loads(next_line[5:])
|
||||
print(f"Tool response: {response_data}")
|
||||
```
|
||||
|
||||
## Complete Event Handler
|
||||
|
||||
```python
|
||||
import json
|
||||
from fastgpt_client import ChatClient
|
||||
|
||||
def handle_all_events(response):
|
||||
"""Handle all streaming event types."""
|
||||
|
||||
buffer = ""
|
||||
current_event = None
|
||||
|
||||
for line in response.iter_lines():
|
||||
if not line:
|
||||
continue
|
||||
|
||||
# Event type line
|
||||
if line.startswith("event:"):
|
||||
current_event = line[6:].strip()
|
||||
|
||||
# Data line
|
||||
elif line.startswith("data:"):
|
||||
data = line[5:].strip()
|
||||
if not data or data == "[DONE]":
|
||||
continue
|
||||
|
||||
try:
|
||||
data_obj = json.loads(data)
|
||||
except json.JSONDecodeError:
|
||||
continue
|
||||
|
||||
# Handle based on event type
|
||||
if current_event is None:
|
||||
# Default: OpenAI-compatible format
|
||||
if "choices" in data_obj and data_obj["choices"]:
|
||||
delta = data_obj["choices"][0].get("delta", {})
|
||||
content = delta.get("content", "")
|
||||
if content:
|
||||
buffer += content
|
||||
print(content, end="", flush=True)
|
||||
|
||||
elif current_event == "answer":
|
||||
text = data_obj.get("text", "")
|
||||
if text:
|
||||
buffer += text
|
||||
print(text, end="", flush=True)
|
||||
|
||||
elif current_event == "flowNodeStatus":
|
||||
status = data_obj.get("status")
|
||||
node = data_obj.get("nodeName", "Unknown")
|
||||
print(f"\n[{status.upper()}] {node}")
|
||||
|
||||
elif current_event == "interactive":
|
||||
interactive_type = data_obj.get("type")
|
||||
print(f"\n[INTERACTIVE] {interactive_type}")
|
||||
print(f"Details: {data_obj.get('params', {})}")
|
||||
|
||||
elif current_event == "error":
|
||||
print(f"\n[ERROR] {data_obj.get('message', 'Unknown error')}")
|
||||
|
||||
elif current_event == "toolCall":
|
||||
print(f"\n[TOOL] Calling: {data_obj.get('toolName')}")
|
||||
|
||||
# Reset event
|
||||
current_event = None
|
||||
|
||||
return buffer
|
||||
|
||||
|
||||
# Usage
|
||||
with ChatClient(api_key="fastgpt-xxxxx") as client:
|
||||
response = client.create_chat_completion(
|
||||
messages=[{"role": "user", "content": "Hello"}],
|
||||
stream=True,
|
||||
detail=True # Enable flow responses
|
||||
)
|
||||
|
||||
full_response = handle_all_events(response)
|
||||
print(f"\n\nFull response: {full_response}")
|
||||
```
|
||||
|
||||
## Event Flow Example
|
||||
|
||||
A typical streaming conversation might generate events like:
|
||||
|
||||
```
|
||||
event:flowNodeStatus
|
||||
data:{"status": "running", "nodeName": "Chat Node"}
|
||||
|
||||
event:answer
|
||||
data:{"text": "Hello"}
|
||||
|
||||
event:answer
|
||||
data:{"text": "! How"}
|
||||
|
||||
event:answer
|
||||
data:{"text": " can I help"}
|
||||
|
||||
event:flowNodeStatus
|
||||
data:{"status": "completed", "nodeName": "Chat Node"}
|
||||
|
||||
event:flowResponses
|
||||
data:{"moduleName": "Chat Node", "tokens": 50}
|
||||
|
||||
data:{"choices": [{"delta": {"content": "Hello! How can I help"}}], "usage": {"total_tokens": 50}}
|
||||
|
||||
data:[DONE]
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Handle `[DONE]`** - Check for end of stream
|
||||
2. **Validate JSON** - Use try/except for parsing
|
||||
3. **Buffer content** - Accumulate text for display
|
||||
4. **Handle errors** - Watch for error events
|
||||
5. **Check event types** - Use `startswith("event:")` to detect events
|
||||
|
||||
## See Also
|
||||
|
||||
- [Streaming Example](../examples/streaming.md) - Basic streaming usage
|
||||
- [Detail Mode](detail_mode.md) - Enable detailed execution data
|
||||
93
docs/api/app_client.md
Normal file
93
docs/api/app_client.md
Normal file
@@ -0,0 +1,93 @@
|
||||
# AppClient
|
||||
|
||||
The `AppClient` provides methods for application analytics and logs.
|
||||
|
||||
## Initialization
|
||||
|
||||
```python
|
||||
from fastgpt_client import AppClient
|
||||
|
||||
client = AppClient(
|
||||
api_key="fastgpt-xxxxx",
|
||||
base_url="http://localhost:3000"
|
||||
)
|
||||
```
|
||||
|
||||
## Methods
|
||||
|
||||
### get_app_logs_chart
|
||||
|
||||
Get application analytics chart data.
|
||||
|
||||
```python
|
||||
client.get_app_logs_chart(
|
||||
appId: str,
|
||||
dateStart: str,
|
||||
dateEnd: str,
|
||||
offset: int = 1,
|
||||
source: list[str] | None = None,
|
||||
userTimespan: str = "day",
|
||||
chatTimespan: str = "day",
|
||||
appTimespan: str = "day"
|
||||
) -> httpx.Response
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `appId` | `str` | Yes | Application ID |
|
||||
| `dateStart` | `str` | Yes | Start date (ISO 8601 format: `YYYY-MM-DD`) |
|
||||
| `dateEnd` | `str` | Yes | End date (ISO 8601 format: `YYYY-MM-DD`) |
|
||||
| `offset` | `int` | No | Offset value (default: `1`) |
|
||||
| `source` | `list[str]` | No | List of sources (default: `["api"]`) |
|
||||
| `userTimespan` | `str` | No | User data timespan: `day`, `week`, or `month` (default: `"day"`) |
|
||||
| `chatTimespan` | `str` | No | Chat data timespan: `day`, `week`, or `month` (default: `"day"`) |
|
||||
| `appTimespan` | `str` | No | App data timespan: `day`, `week`, or `month` (default: `"day"`) |
|
||||
|
||||
**Source Options:**
|
||||
|
||||
- `"api"` - API interactions
|
||||
- `"online"` - Online usage
|
||||
- `"share"` - Shared links
|
||||
- `"test"` - Test interactions
|
||||
|
||||
**Example:**
|
||||
|
||||
```python
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
with AppClient(api_key="fastgpt-xxxxx") as client:
|
||||
# Get analytics for the last 7 days
|
||||
end_date = datetime.now()
|
||||
start_date = end_date - timedelta(days=7)
|
||||
|
||||
response = client.get_app_logs_chart(
|
||||
appId="your-app-id",
|
||||
dateStart=start_date.strftime("%Y-%m-%d"),
|
||||
dateEnd=end_date.strftime("%Y-%m-%d"),
|
||||
source=["api", "online"],
|
||||
userTimespan="day",
|
||||
chatTimespan="day",
|
||||
appTimespan="day"
|
||||
)
|
||||
|
||||
data = response.json()
|
||||
|
||||
# Access analytics data
|
||||
print(f"Users: {data['data'].get('users', {})}")
|
||||
print(f"Chats: {data['data'].get('chats', {})}")
|
||||
print(f"App metrics: {data['data'].get('app', {})}")
|
||||
```
|
||||
|
||||
**Response Structure:**
|
||||
|
||||
The response contains analytics data with the following possible keys:
|
||||
|
||||
- `users` - User engagement metrics
|
||||
- `chats` - Chat interaction metrics
|
||||
- `app` - Application-level metrics
|
||||
- `tokens` - Token usage statistics
|
||||
- `prices` - Cost information
|
||||
|
||||
Each metric may be organized by the specified timespan (day/week/month).
|
||||
201
docs/api/async_clients.md
Normal file
201
docs/api/async_clients.md
Normal file
@@ -0,0 +1,201 @@
|
||||
# Async Clients
|
||||
|
||||
The SDK provides full async/await support for high-performance applications. All synchronous clients have async equivalents.
|
||||
|
||||
## Async ChatClient
|
||||
|
||||
### Initialization
|
||||
|
||||
```python
|
||||
from fastgpt_client import AsyncChatClient
|
||||
|
||||
client = AsyncChatClient(
|
||||
api_key="fastgpt-xxxxx",
|
||||
base_url="http://localhost:3000"
|
||||
)
|
||||
```
|
||||
|
||||
### Basic Usage
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
from fastgpt_client import AsyncChatClient
|
||||
|
||||
async def main():
|
||||
async with AsyncChatClient(api_key="fastgpt-xxxxx") as client:
|
||||
response = await client.create_chat_completion(
|
||||
messages=[{"role": "user", "content": "Hello!"}],
|
||||
stream=False
|
||||
)
|
||||
response.raise_for_status()
|
||||
result = response.json()
|
||||
print(result['choices'][0]['message']['content'])
|
||||
|
||||
asyncio.run(main())
|
||||
```
|
||||
|
||||
### Streaming with Async
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
import json
|
||||
from fastgpt_client import AsyncChatClient
|
||||
|
||||
async def stream_chat():
|
||||
async with AsyncChatClient(api_key="fastgpt-xxxxx") as client:
|
||||
response = await client.create_chat_completion(
|
||||
messages=[{"role": "user", "content": "Tell me a story"}],
|
||||
stream=True
|
||||
)
|
||||
|
||||
async for line in response.aiter_lines():
|
||||
if line.startswith("data:"):
|
||||
data = line[5:].strip()
|
||||
if data and data != "[DONE]":
|
||||
chunk = json.loads(data)
|
||||
if "choices" in chunk and chunk["choices"]:
|
||||
delta = chunk["choices"][0].get("delta", {})
|
||||
content = delta.get("content", "")
|
||||
if content:
|
||||
print(content, end="", flush=True)
|
||||
|
||||
asyncio.run(stream_chat())
|
||||
```
|
||||
|
||||
### Multiple Concurrent Requests
|
||||
|
||||
One of the main benefits of async is handling multiple requests concurrently:
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
from fastgpt_client import AsyncChatClient
|
||||
|
||||
async def fetch_multiple():
|
||||
async with AsyncChatClient(api_key="fastgpt-xxxxx") as client:
|
||||
# Create multiple chat completions concurrently
|
||||
tasks = [
|
||||
client.create_chat_completion(
|
||||
messages=[{"role": "user", "content": f"What is {concept}?"}],
|
||||
stream=False
|
||||
)
|
||||
for concept in ["AI", "Machine Learning", "Deep Learning"]
|
||||
]
|
||||
|
||||
responses = await asyncio.gather(*tasks)
|
||||
|
||||
for i, response in enumerate(responses):
|
||||
response.raise_for_status()
|
||||
result = response.json()
|
||||
concept = ["AI", "Machine Learning", "Deep Learning"][i]
|
||||
print(f"\n{concept}:")
|
||||
print(result['choices'][0]['message']['content'])
|
||||
|
||||
asyncio.run(fetch_multiple())
|
||||
```
|
||||
|
||||
## Async AppClient
|
||||
|
||||
### Basic Usage
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
from fastgpt_client import AsyncAppClient
|
||||
|
||||
async def get_analytics():
|
||||
async with AsyncAppClient(api_key="fastgpt-xxxxx") as client:
|
||||
response = await client.get_app_logs_chart(
|
||||
appId="your-app-id",
|
||||
dateStart="2024-01-01",
|
||||
dateEnd="2024-12-31",
|
||||
source=["api"]
|
||||
)
|
||||
response.raise_for_status()
|
||||
data = response.json()
|
||||
print(data)
|
||||
|
||||
asyncio.run(get_analytics())
|
||||
```
|
||||
|
||||
## Complete Example: Async Chat Application
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
from fastgpt_client import AsyncChatClient
|
||||
|
||||
class AsyncChatApp:
|
||||
def __init__(self, api_key: str, base_url: str):
|
||||
self.client = AsyncChatClient(api_key=api_key, base_url=base_url)
|
||||
self.chat_id = None
|
||||
|
||||
async def start(self):
|
||||
await self.client.__aenter__()
|
||||
|
||||
async def stop(self):
|
||||
await self.client.__aexit__(None, None, None)
|
||||
|
||||
async def send_message(self, content: str) -> str:
|
||||
response = await self.client.create_chat_completion(
|
||||
messages=[{"role": "user", "content": content}],
|
||||
chatId=self.chat_id,
|
||||
stream=False
|
||||
)
|
||||
response.raise_for_status()
|
||||
result = response.json()
|
||||
|
||||
# Update chat_id after first message
|
||||
if not self.chat_id:
|
||||
self.chat_id = result.get('chatId')
|
||||
|
||||
return result['choices'][0]['message']['content']
|
||||
|
||||
async def chat(self):
|
||||
await self.start()
|
||||
try:
|
||||
while True:
|
||||
user_input = input("\nYou: ")
|
||||
if user_input.lower() in ['quit', 'exit']:
|
||||
break
|
||||
|
||||
print("AI: ", end="", flush=True)
|
||||
response = await self.send_message(user_input)
|
||||
print(response)
|
||||
finally:
|
||||
await self.stop()
|
||||
|
||||
async def main():
|
||||
app = AsyncChatApp(
|
||||
api_key="fastgpt-xxxxx",
|
||||
base_url="http://localhost:3000"
|
||||
)
|
||||
await app.chat()
|
||||
|
||||
asyncio.run(main())
|
||||
```
|
||||
|
||||
## Key Differences from Sync Clients
|
||||
|
||||
| Aspect | Sync | Async |
|
||||
|--------|------|-------|
|
||||
| Context Manager | `with` | `async with` |
|
||||
| Method Call | `client.method()` | `await client.method()` |
|
||||
| Streaming | `for line in response.iter_lines()` | `async for line in response.aiter_lines()` |
|
||||
| Close | `client.close()` | `await client.close()` |
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Always use `async with`** for automatic resource cleanup
|
||||
2. **Use `asyncio.gather()`** for concurrent requests
|
||||
3. **Handle exceptions properly** with try/except blocks
|
||||
4. **Close clients** when done (or use context managers)
|
||||
5. **Avoid mixing sync and async** code in the same application
|
||||
|
||||
## When to Use Async
|
||||
|
||||
Use async clients when you need to:
|
||||
|
||||
- Handle many concurrent requests
|
||||
- Integrate with other async libraries (FastAPI, aiohttp, etc.)
|
||||
- Build real-time applications with streaming
|
||||
- Maximize throughput in I/O-bound applications
|
||||
|
||||
For simple scripts or applications with low concurrency, sync clients are often simpler and equally effective.
|
||||
315
docs/api/chat_client.md
Normal file
315
docs/api/chat_client.md
Normal file
@@ -0,0 +1,315 @@
|
||||
# ChatClient
|
||||
|
||||
The `ChatClient` provides methods for chat completions and conversation management.
|
||||
|
||||
## Initialization
|
||||
|
||||
```python
|
||||
from fastgpt_client import ChatClient
|
||||
|
||||
client = ChatClient(
|
||||
api_key="fastgpt-xxxxx",
|
||||
base_url="http://localhost:3000"
|
||||
)
|
||||
```
|
||||
|
||||
## Methods
|
||||
|
||||
### create_chat_completion
|
||||
|
||||
Create a chat completion (synchronous or streaming).
|
||||
|
||||
```python
|
||||
client.create_chat_completion(
|
||||
messages: list[dict],
|
||||
stream: bool = False,
|
||||
chatId: str | None = None,
|
||||
detail: bool = False,
|
||||
variables: dict[str, Any] | None = None,
|
||||
responseChatItemId: str | None = None
|
||||
) -> httpx.Response
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `messages` | `list[dict]` | Yes | Array of message objects with `role` and `content` |
|
||||
| `stream` | `bool` | No | Whether to stream the response (default: `False`) |
|
||||
| `chatId` | `str` | No | Chat ID for conversation context |
|
||||
| `detail` | `bool` | No | Whether to return detailed execution data (default: `False`) |
|
||||
| `variables` | `dict` | No | Template variables for substitution |
|
||||
| `responseChatItemId` | `str` | No | Custom ID for the response message |
|
||||
|
||||
**Example:**
|
||||
|
||||
```python
|
||||
response = client.create_chat_completion(
|
||||
messages=[
|
||||
{"role": "user", "content": "Hello!"},
|
||||
{"role": "assistant", "content": "Hi there!"},
|
||||
{"role": "user", "content": "How are you?"}
|
||||
],
|
||||
stream=False
|
||||
)
|
||||
result = response.json()
|
||||
print(result['choices'][0]['message']['content'])
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### get_chat_histories
|
||||
|
||||
Get chat histories for an application.
|
||||
|
||||
```python
|
||||
client.get_chat_histories(
|
||||
appId: str,
|
||||
offset: int = 0,
|
||||
pageSize: int = 20,
|
||||
source: Literal["api", "online", "share", "test"] = "api"
|
||||
) -> httpx.Response
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `appId` | `str` | Yes | Application ID |
|
||||
| `offset` | `int` | No | Offset for pagination (default: `0`) |
|
||||
| `pageSize` | `int` | No | Number of records per page (default: `20`) |
|
||||
| `source` | `str` | No | Source filter (default: `"api"`) |
|
||||
|
||||
**Example:**
|
||||
|
||||
```python
|
||||
response = client.get_chat_histories(
|
||||
appId="app-123",
|
||||
offset=0,
|
||||
pageSize=20,
|
||||
source="api"
|
||||
)
|
||||
data = response.json()
|
||||
for chat in data['data']['list']:
|
||||
print(f"{chat['title']}: {chat['chatId']}")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### get_chat_init
|
||||
|
||||
Get chat initialization information.
|
||||
|
||||
```python
|
||||
client.get_chat_init(
|
||||
appId: str,
|
||||
chatId: str
|
||||
) -> httpx.Response
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `appId` | `str` | Yes | Application ID |
|
||||
| `chatId` | `str` | Yes | Chat ID |
|
||||
|
||||
---
|
||||
|
||||
### get_chat_records
|
||||
|
||||
Get chat records for a specific chat.
|
||||
|
||||
```python
|
||||
client.get_chat_records(
|
||||
appId: str,
|
||||
chatId: str,
|
||||
offset: int = 0,
|
||||
pageSize: int = 10,
|
||||
loadCustomFeedbacks: bool = False
|
||||
) -> httpx.Response
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `appId` | `str` | Yes | Application ID |
|
||||
| `chatId` | `str` | Yes | Chat ID |
|
||||
| `offset` | `int` | No | Offset for pagination (default: `0`) |
|
||||
| `pageSize` | `int` | No | Number of records per page (default: `10`) |
|
||||
| `loadCustomFeedbacks` | `bool` | No | Whether to load custom feedbacks (default: `False`) |
|
||||
|
||||
---
|
||||
|
||||
### get_record_detail
|
||||
|
||||
Get detailed execution data for a specific record.
|
||||
|
||||
```python
|
||||
client.get_record_detail(
|
||||
appId: str,
|
||||
chatId: str,
|
||||
dataId: str
|
||||
) -> httpx.Response
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `appId` | `str` | Yes | Application ID |
|
||||
| `chatId` | `str` | Yes | Chat ID |
|
||||
| `dataId` | `str` | Yes | Record ID |
|
||||
|
||||
---
|
||||
|
||||
### update_chat_history
|
||||
|
||||
Update chat history (title or pin status).
|
||||
|
||||
```python
|
||||
client.update_chat_history(
|
||||
appId: str,
|
||||
chatId: str,
|
||||
customTitle: str | None = None,
|
||||
top: bool | None = None
|
||||
) -> httpx.Response
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `appId` | `str` | Yes | Application ID |
|
||||
| `chatId` | `str` | Yes | Chat ID |
|
||||
| `customTitle` | `str` | No | Custom title for the chat |
|
||||
| `top` | `bool` | No | Whether to pin the chat |
|
||||
|
||||
---
|
||||
|
||||
### delete_chat_history
|
||||
|
||||
Delete a chat history.
|
||||
|
||||
```python
|
||||
client.delete_chat_history(
|
||||
appId: str,
|
||||
chatId: str
|
||||
) -> httpx.Response
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `appId` | `str` | Yes | Application ID |
|
||||
| `chatId` | `str` | Yes | Chat ID |
|
||||
|
||||
---
|
||||
|
||||
### clear_chat_histories
|
||||
|
||||
Clear all chat histories for an application.
|
||||
|
||||
```python
|
||||
client.clear_chat_histories(
|
||||
appId: str
|
||||
) -> httpx.Response
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `appId` | `str` | Yes | Application ID |
|
||||
|
||||
---
|
||||
|
||||
### delete_chat_record
|
||||
|
||||
Delete a single chat record.
|
||||
|
||||
```python
|
||||
client.delete_chat_record(
|
||||
appId: str,
|
||||
chatId: str,
|
||||
contentId: str
|
||||
) -> httpx.Response
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `appId` | `str` | Yes | Application ID |
|
||||
| `chatId` | `str` | Yes | Chat ID |
|
||||
| `contentId` | `str` | Yes | Content ID of the record |
|
||||
|
||||
---
|
||||
|
||||
### send_feedback
|
||||
|
||||
Send feedback for a chat message (like/dislike).
|
||||
|
||||
```python
|
||||
client.send_feedback(
|
||||
appId: str,
|
||||
chatId: str,
|
||||
dataId: str,
|
||||
userGoodFeedback: str | None = None,
|
||||
userBadFeedback: str | None = None
|
||||
) -> httpx.Response
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `appId` | `str` | Yes | Application ID |
|
||||
| `chatId` | `str` | Yes | Chat ID |
|
||||
| `dataId` | `str` | Yes | Message ID |
|
||||
| `userGoodFeedback` | `str` | No | Positive feedback text |
|
||||
| `userBadFeedback` | `str` | No | Negative feedback text |
|
||||
|
||||
**Example:**
|
||||
|
||||
```python
|
||||
# Like a message
|
||||
client.send_feedback(
|
||||
appId="app-123",
|
||||
chatId="chat-123",
|
||||
dataId="msg-123",
|
||||
userGoodFeedback="Great answer!"
|
||||
)
|
||||
|
||||
# Dislike a message
|
||||
client.send_feedback(
|
||||
appId="app-123",
|
||||
chatId="chat-123",
|
||||
dataId="msg-123",
|
||||
userBadFeedback="Not helpful"
|
||||
)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### get_suggested_questions
|
||||
|
||||
Get suggested questions based on chat context.
|
||||
|
||||
```python
|
||||
client.get_suggested_questions(
|
||||
appId: str,
|
||||
chatId: str,
|
||||
questionGuide: dict[str, Any] | None = None
|
||||
) -> httpx.Response
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `appId` | `str` | Yes | Application ID |
|
||||
| `chatId` | `str` | Yes | Chat ID |
|
||||
| `questionGuide` | `dict` | No | Custom configuration for question guide |
|
||||
248
docs/api/exceptions.md
Normal file
248
docs/api/exceptions.md
Normal file
@@ -0,0 +1,248 @@
|
||||
# Exceptions
|
||||
|
||||
The SDK provides specific exceptions for different error types. All exceptions inherit from the base `FastGPTError`.
|
||||
|
||||
## Exception Hierarchy
|
||||
|
||||
```
|
||||
FastGPTError
|
||||
├── APIError
|
||||
├── AuthenticationError
|
||||
├── RateLimitError
|
||||
├── ValidationError
|
||||
└── StreamParseError
|
||||
```
|
||||
|
||||
## Exception Types
|
||||
|
||||
### FastGPTError
|
||||
|
||||
Base exception class for all FastGPT SDK errors.
|
||||
|
||||
```python
|
||||
from fastgpt_client.exceptions import FastGPTError
|
||||
|
||||
try:
|
||||
# SDK operation
|
||||
pass
|
||||
except FastGPTError as e:
|
||||
print(f"FastGPT error: {e}")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### APIError
|
||||
|
||||
General API error for 4xx and 5xx responses that don't have a specific exception type.
|
||||
|
||||
```python
|
||||
from fastgpt_client.exceptions import APIError
|
||||
|
||||
try:
|
||||
response = client.create_chat_completion(...)
|
||||
except APIError as e:
|
||||
print(f"API error: {e.message}")
|
||||
print(f"Status code: {e.status_code}")
|
||||
print(f"Response data: {e.response_data}")
|
||||
```
|
||||
|
||||
**Attributes:**
|
||||
|
||||
| Attribute | Type | Description |
|
||||
|-----------|------|-------------|
|
||||
| `message` | `str` | Error message |
|
||||
| `status_code` | `int` | HTTP status code |
|
||||
| `response_data` | `dict | None` | Full error response data |
|
||||
|
||||
---
|
||||
|
||||
### AuthenticationError
|
||||
|
||||
Raised when authentication fails (401 status code).
|
||||
|
||||
```python
|
||||
from fastgpt_client.exceptions import AuthenticationError
|
||||
|
||||
try:
|
||||
response = client.create_chat_completion(...)
|
||||
except AuthenticationError as e:
|
||||
print(f"Authentication failed: {e.message}")
|
||||
print("Please check your API key")
|
||||
```
|
||||
|
||||
**Common Causes:**
|
||||
|
||||
- Invalid API key
|
||||
- Missing API key
|
||||
- Expired API key
|
||||
- API key format incorrect
|
||||
|
||||
---
|
||||
|
||||
### RateLimitError
|
||||
|
||||
Raised when rate limit is exceeded (429 status code).
|
||||
|
||||
```python
|
||||
from fastgpt_client.exceptions import RateLimitError
|
||||
|
||||
try:
|
||||
response = client.create_chat_completion(...)
|
||||
except RateLimitError as e:
|
||||
print(f"Rate limit exceeded: {e.message}")
|
||||
if e.retry_after:
|
||||
print(f"Retry after {e.retry_after} seconds")
|
||||
```
|
||||
|
||||
**Attributes:**
|
||||
|
||||
| Attribute | Type | Description |
|
||||
|-----------|------|-------------|
|
||||
| `message` | `str` | Error message |
|
||||
| `retry_after` | `str | None` | Suggested retry delay (from `Retry-After` header) |
|
||||
| `status_code` | `int` | HTTP status code (429) |
|
||||
| `response_data` | `dict | None` | Full error response data |
|
||||
|
||||
---
|
||||
|
||||
### ValidationError
|
||||
|
||||
Raised when request validation fails (422 status code).
|
||||
|
||||
```python
|
||||
from fastgpt_client.exceptions import ValidationError
|
||||
|
||||
try:
|
||||
response = client.create_chat_completion(
|
||||
messages=[{"role": "user", "content": "Hello"}],
|
||||
invalid_param="value"
|
||||
)
|
||||
except ValidationError as e:
|
||||
print(f"Validation error: {e.message}")
|
||||
print(f"Response data: {e.response_data}")
|
||||
```
|
||||
|
||||
**Common Causes:**
|
||||
|
||||
- Invalid parameter values
|
||||
- Missing required parameters
|
||||
- Incorrect parameter types
|
||||
- Invalid message format
|
||||
|
||||
---
|
||||
|
||||
### StreamParseError
|
||||
|
||||
Raised when parsing streaming responses fails.
|
||||
|
||||
```python
|
||||
from fastgpt_client.exceptions import StreamParseError
|
||||
|
||||
try:
|
||||
for line in response.iter_lines():
|
||||
# Parse streaming data
|
||||
pass
|
||||
except StreamParseError as e:
|
||||
print(f"Stream parsing error: {e.message}")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Comprehensive Error Handling
|
||||
|
||||
```python
|
||||
from fastgpt_client import ChatClient
|
||||
from fastgpt_client.exceptions import (
|
||||
APIError,
|
||||
AuthenticationError,
|
||||
RateLimitError,
|
||||
ValidationError,
|
||||
FastGPTError
|
||||
)
|
||||
|
||||
def safe_chat_completion(client, messages):
|
||||
"""Handle chat completion with comprehensive error handling."""
|
||||
try:
|
||||
response = client.create_chat_completion(
|
||||
messages=messages,
|
||||
stream=False
|
||||
)
|
||||
response.raise_for_status()
|
||||
return response.json()
|
||||
|
||||
except AuthenticationError:
|
||||
print("Error: Invalid API key. Please check your credentials.")
|
||||
return None
|
||||
|
||||
except RateLimitError as e:
|
||||
print(f"Error: Rate limit exceeded. Please wait.")
|
||||
if e.retry_after:
|
||||
print(f"Retry after {e.retry_after} seconds")
|
||||
return None
|
||||
|
||||
except ValidationError as e:
|
||||
print(f"Error: Invalid request parameters: {e.message}")
|
||||
return None
|
||||
|
||||
except APIError as e:
|
||||
print(f"Error: API request failed: {e.message}")
|
||||
return None
|
||||
|
||||
except FastGPTError as e:
|
||||
print(f"Error: Unexpected FastGPT error: {e}")
|
||||
return None
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error: Unexpected error: {e}")
|
||||
return None
|
||||
|
||||
# Usage
|
||||
with ChatClient(api_key="fastgpt-xxxxx") as client:
|
||||
result = safe_chat_completion(
|
||||
client,
|
||||
[{"role": "user", "content": "Hello!"}]
|
||||
)
|
||||
```
|
||||
|
||||
## Error Handling Best Practices
|
||||
|
||||
1. **Always handle exceptions** when making API calls
|
||||
2. **Use specific exceptions** for better error handling
|
||||
3. **Log errors** for debugging purposes
|
||||
4. **Provide user-friendly messages** based on error type
|
||||
5. **Implement retry logic** for rate limit errors
|
||||
6. **Validate parameters** before making API calls
|
||||
|
||||
## Retry Logic for Rate Limiting
|
||||
|
||||
```python
|
||||
import time
|
||||
from fastgpt_client import ChatClient
|
||||
from fastgpt_client.exceptions import RateLimitError
|
||||
|
||||
def chat_with_retry(client, messages, max_retries=3):
|
||||
"""Retry chat completion on rate limit errors."""
|
||||
for attempt in range(max_retries):
|
||||
try:
|
||||
response = client.create_chat_completion(
|
||||
messages=messages,
|
||||
stream=False
|
||||
)
|
||||
response.raise_for_status()
|
||||
return response.json()
|
||||
|
||||
except RateLimitError as e:
|
||||
if attempt < max_retries - 1:
|
||||
# Use Retry-After header or default delay
|
||||
delay = int(e.retry_after) if e.retry_after else 5
|
||||
print(f"Rate limited. Waiting {delay} seconds...")
|
||||
time.sleep(delay)
|
||||
else:
|
||||
print(f"Max retries exceeded. Giving up.")
|
||||
raise
|
||||
```
|
||||
|
||||
## Next Steps
|
||||
|
||||
- [Error Handling Guide](../advanced/error_handling.md) - More error handling strategies
|
||||
- [Rate Limiting](../advanced/rate_limiting.md) - Handling rate limits effectively
|
||||
104
docs/api/overview.md
Normal file
104
docs/api/overview.md
Normal file
@@ -0,0 +1,104 @@
|
||||
# API Reference Overview
|
||||
|
||||
The FastGPT Python SDK provides three main client types:
|
||||
|
||||
## Clients
|
||||
|
||||
| Client | Sync | Async | Description |
|
||||
|--------|------|-------|-------------|
|
||||
| [`ChatClient`](chat_client.md) | ✅ | ✅ | Chat completions and conversation management |
|
||||
| [`AppClient`](app_client.md) | ✅ | ✅ | App analytics and logs |
|
||||
| `FastGPTClient` | ✅ | ✅ | Base client (usually used indirectly) |
|
||||
|
||||
## Base Client Options
|
||||
|
||||
All clients share these initialization parameters:
|
||||
|
||||
```python
|
||||
from fastgpt_client import ChatClient
|
||||
|
||||
client = ChatClient(
|
||||
api_key="fastgpt-xxxxx", # Required: Your API key
|
||||
base_url="http://localhost:3000", # Optional: API base URL
|
||||
timeout=60.0, # Optional: Request timeout (seconds)
|
||||
max_retries=3, # Optional: Max retry attempts
|
||||
retry_delay=1.0, # Optional: Delay between retries (seconds)
|
||||
enable_logging=False # Optional: Enable request logging
|
||||
)
|
||||
```
|
||||
|
||||
### Parameters
|
||||
|
||||
- **api_key** (`str`): Your FastGPT API key
|
||||
- **base_url** (`str`): Base URL for the FastGPT API (default: `"http://localhost:3000"`)
|
||||
- **timeout** (`float`): Request timeout in seconds (default: `60.0`)
|
||||
- **max_retries** (`int`): Maximum number of retry attempts (default: `3`)
|
||||
- **retry_delay** (`float`): Delay between retries in seconds (default: `1.0`)
|
||||
- **enable_logging** (`bool`): Whether to enable request logging (default: `False`)
|
||||
|
||||
## Context Manager Support
|
||||
|
||||
All clients support context managers for automatic resource cleanup:
|
||||
|
||||
```python
|
||||
# Synchronous
|
||||
with ChatClient(api_key="fastgpt-xxxxx") as client:
|
||||
response = client.create_chat_completion(...)
|
||||
# Client is automatically closed
|
||||
|
||||
# Asynchronous
|
||||
async with AsyncChatClient(api_key="fastgpt-xxxxx") as client:
|
||||
response = await client.create_chat_completion(...)
|
||||
# Client is automatically closed
|
||||
```
|
||||
|
||||
## Response Format
|
||||
|
||||
All API methods return `httpx.Response` objects. You can:
|
||||
|
||||
```python
|
||||
# Raise exception for 4xx/5xx responses
|
||||
response.raise_for_status()
|
||||
|
||||
# Get JSON data
|
||||
data = response.json()
|
||||
|
||||
# Get status code
|
||||
status = response.status_code
|
||||
|
||||
# Get headers
|
||||
headers = response.headers
|
||||
```
|
||||
|
||||
## Async Variants
|
||||
|
||||
All synchronous clients have async equivalents:
|
||||
|
||||
```python
|
||||
# Sync
|
||||
from fastgpt_client import ChatClient
|
||||
|
||||
with ChatClient(api_key="...") as client:
|
||||
response = client.create_chat_completion(...)
|
||||
|
||||
# Async
|
||||
from fastgpt_client import AsyncChatClient
|
||||
|
||||
async with AsyncChatClient(api_key="...") as client:
|
||||
response = await client.create_chat_completion(...)
|
||||
```
|
||||
|
||||
See [Async Clients](async_clients.md) for more details.
|
||||
|
||||
## Exceptions
|
||||
|
||||
The SDK provides specific exceptions for different error types:
|
||||
|
||||
| Exception | Status Code | Description |
|
||||
|-----------|-------------|-------------|
|
||||
| `AuthenticationError` | 401 | Invalid or missing API key |
|
||||
| `RateLimitError` | 429 | Too many requests |
|
||||
| `ValidationError` | 422 | Invalid request parameters |
|
||||
| `APIError` | 4xx/5xx | General API errors |
|
||||
|
||||
See [Exceptions](exceptions.md) for more details.
|
||||
223
docs/development.md
Normal file
223
docs/development.md
Normal file
@@ -0,0 +1,223 @@
|
||||
# Development Guide
|
||||
|
||||
This guide covers contributing to and developing the FastGPT Python SDK.
|
||||
|
||||
## Development Setup
|
||||
|
||||
### Clone the Repository
|
||||
|
||||
```bash
|
||||
git clone https://github.com/yourusername/fastgpt-python-sdk.git
|
||||
cd fastgpt-python-sdk
|
||||
```
|
||||
|
||||
### Install in Development Mode
|
||||
|
||||
```bash
|
||||
pip install -e ".[dev]"
|
||||
```
|
||||
|
||||
This installs:
|
||||
- The SDK in editable mode
|
||||
- Development dependencies (pytest, ruff, etc.)
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
fastgpt-python-sdk/
|
||||
├── fastgpt_client/
|
||||
│ ├── __init__.py # Public API exports
|
||||
│ ├── client.py # Sync clients (ChatClient, AppClient)
|
||||
│ ├── async_client.py # Async clients
|
||||
│ ├── base_client.py # Base functionality (retry, validation)
|
||||
│ └── exceptions.py # Custom exceptions
|
||||
├── tests/
|
||||
│ ├── test_chat_client.py # ChatClient tests
|
||||
│ ├── test_app_client.py # AppClient tests
|
||||
│ └── test_async_client.py # Async client tests
|
||||
├── examples/
|
||||
│ ├── basic_usage.py # Basic usage examples
|
||||
│ └── async_usage.py # Async usage examples
|
||||
├── docs/ # MkDocs documentation
|
||||
├── setup.py # Package setup
|
||||
├── pyproject.toml # Project configuration
|
||||
└── mkdocs.yml # Documentation config
|
||||
```
|
||||
|
||||
## Running Tests
|
||||
|
||||
### Run All Tests
|
||||
|
||||
```bash
|
||||
pytest
|
||||
```
|
||||
|
||||
### Run Specific Test File
|
||||
|
||||
```bash
|
||||
pytest tests/test_chat_client.py
|
||||
```
|
||||
|
||||
### Run with Coverage
|
||||
|
||||
```bash
|
||||
pytest --cov=fastgpt_client --cov-report=html
|
||||
```
|
||||
|
||||
### Run with Verbose Output
|
||||
|
||||
```bash
|
||||
pytest -v
|
||||
```
|
||||
|
||||
## Code Quality
|
||||
|
||||
### Lint with Ruff
|
||||
|
||||
```bash
|
||||
ruff check fastgpt_client/
|
||||
```
|
||||
|
||||
### Format with Ruff
|
||||
|
||||
```bash
|
||||
ruff format fastgpt_client/
|
||||
```
|
||||
|
||||
### Fix Linting Issues
|
||||
|
||||
```bash
|
||||
ruff check --fix fastgpt_client/
|
||||
```
|
||||
|
||||
## Building Documentation
|
||||
|
||||
### Install Documentation Dependencies
|
||||
|
||||
```bash
|
||||
pip install mkdocs-material mkdocstrings[python]
|
||||
```
|
||||
|
||||
### Build Documentation
|
||||
|
||||
```bash
|
||||
mkdocs build
|
||||
```
|
||||
|
||||
### Serve Documentation Locally
|
||||
|
||||
```bash
|
||||
mkdocs serve
|
||||
```
|
||||
|
||||
Then open http://127.0.0.1:8000 in your browser.
|
||||
|
||||
## Creating a Release
|
||||
|
||||
### Update Version
|
||||
|
||||
Update `fastgpt_client/__init__.py`:
|
||||
|
||||
```python
|
||||
__version__ = "0.2.0"
|
||||
```
|
||||
|
||||
### Build Package
|
||||
|
||||
```bash
|
||||
python -m build
|
||||
```
|
||||
|
||||
### Publish to PyPI
|
||||
|
||||
```bash
|
||||
twine upload dist/*
|
||||
```
|
||||
|
||||
## Contribution Guidelines
|
||||
|
||||
### Code Style
|
||||
|
||||
- Use **Google-style docstrings**
|
||||
- Follow **PEP 8** formatting (handled by Ruff)
|
||||
- Keep functions focused and single-purpose
|
||||
- Add type hints for all public methods
|
||||
|
||||
### Adding Features
|
||||
|
||||
1. **Create a feature branch**
|
||||
```bash
|
||||
git checkout -b feature/your-feature-name
|
||||
```
|
||||
|
||||
2. **Write tests first**
|
||||
```python
|
||||
def test_new_feature():
|
||||
client = ChatClient(api_key="test-key")
|
||||
result = client.new_method()
|
||||
assert result is not None
|
||||
```
|
||||
|
||||
3. **Implement the feature**
|
||||
```python
|
||||
def new_method(self):
|
||||
"""Do something new.
|
||||
|
||||
Returns:
|
||||
The result.
|
||||
"""
|
||||
# Implementation
|
||||
pass
|
||||
```
|
||||
|
||||
4. **Add documentation**
|
||||
- Update docstrings
|
||||
- Add usage examples
|
||||
- Update API reference
|
||||
|
||||
5. **Run tests**
|
||||
```bash
|
||||
pytest
|
||||
```
|
||||
|
||||
6. **Submit a pull request**
|
||||
|
||||
### Writing Tests
|
||||
|
||||
```python
|
||||
import pytest
|
||||
from fastgpt_client import ChatClient
|
||||
from httpx import Response
|
||||
|
||||
def test_create_chat_completion():
|
||||
"""Test chat completion creation."""
|
||||
client = ChatClient(api_key="test-key")
|
||||
|
||||
response = client.create_chat_completion(
|
||||
messages=[{"role": "user", "content": "Hello"}],
|
||||
stream=False
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
```
|
||||
|
||||
## Useful Commands
|
||||
|
||||
| Command | Description |
|
||||
|---------|-------------|
|
||||
| `pytest` | Run all tests |
|
||||
| `pytest -v` | Verbose test output |
|
||||
| `pytest --cov` | Run with coverage |
|
||||
| `ruff check` | Lint code |
|
||||
| `ruff format` | Format code |
|
||||
| `mkdocs serve` | Serve docs locally |
|
||||
| `mkdocs build` | Build docs |
|
||||
| `python -m build` | Build package |
|
||||
|
||||
## Resources
|
||||
|
||||
- [FastGPT Documentation](https://doc.fastgpt.io/)
|
||||
- [Chat API Docs](https://doc.fastgpt.io/docs/introduction/development/openapi/chat)
|
||||
- [PyPI Publishing Guide](https://packaging.python.org/tutorials/packaging-projects/)
|
||||
- [pytest Documentation](https://docs.pytest.org/)
|
||||
- [Ruff Documentation](https://docs.astral.sh/ruff/)
|
||||
340
docs/examples/async_usage.md
Normal file
340
docs/examples/async_usage.md
Normal file
@@ -0,0 +1,340 @@
|
||||
# Async Usage Example
|
||||
|
||||
Complete examples demonstrating asynchronous usage of the FastGPT Python SDK.
|
||||
|
||||
## Why Use Async?
|
||||
|
||||
Async is beneficial when you need to:
|
||||
|
||||
- Handle multiple concurrent requests efficiently
|
||||
- Integrate with async frameworks (FastAPI, aiohttp)
|
||||
- Build real-time streaming applications
|
||||
- Maximize throughput in I/O-bound applications
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
pip install fastgpt-client
|
||||
```
|
||||
|
||||
## Basic Async Chat
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
from fastgpt_client import AsyncChatClient
|
||||
|
||||
async def simple_chat():
|
||||
"""Simple async chat completion."""
|
||||
async with AsyncChatClient(api_key="fastgpt-xxxxx") as client:
|
||||
response = await client.create_chat_completion(
|
||||
messages=[{"role": "user", "content": "Hello! What's AI?"}],
|
||||
stream=False
|
||||
)
|
||||
response.raise_for_status()
|
||||
result = response.json()
|
||||
print(result['choices'][0]['message']['content'])
|
||||
|
||||
asyncio.run(simple_chat())
|
||||
```
|
||||
|
||||
## Async Streaming
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
import json
|
||||
from fastgpt_client import AsyncChatClient
|
||||
|
||||
async def stream_chat():
|
||||
"""Async streaming chat completion."""
|
||||
async with AsyncChatClient(api_key="fastgpt-xxxxx") as client:
|
||||
response = await client.create_chat_completion(
|
||||
messages=[{"role": "user", "content": "Tell me a short story"}],
|
||||
stream=True
|
||||
)
|
||||
|
||||
async for line in response.aiter_lines():
|
||||
if line.startswith("data:"):
|
||||
data = line[5:].strip()
|
||||
if data and data != "[DONE]":
|
||||
chunk = json.loads(data)
|
||||
if "choices" in chunk and chunk["choices"]:
|
||||
delta = chunk["choices"][0].get("delta", {})
|
||||
content = delta.get("content", "")
|
||||
if content:
|
||||
print(content, end="", flush=True)
|
||||
print()
|
||||
|
||||
asyncio.run(stream_chat())
|
||||
```
|
||||
|
||||
## Multiple Concurrent Requests
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
from fastgpt_client import AsyncChatClient
|
||||
|
||||
async def fetch_multiple():
|
||||
"""Run multiple requests concurrently."""
|
||||
async with AsyncChatClient(api_key="fastgpt-xxxxx") as client:
|
||||
# Create multiple tasks
|
||||
tasks = [
|
||||
client.create_chat_completion(
|
||||
messages=[{"role": "user", "content": f"What is {concept}?"}],
|
||||
stream=False
|
||||
)
|
||||
for concept in ["AI", "Machine Learning", "Deep Learning"]
|
||||
]
|
||||
|
||||
# Execute all tasks concurrently
|
||||
responses = await asyncio.gather(*tasks)
|
||||
|
||||
# Process results
|
||||
for i, response in enumerate(responses):
|
||||
response.raise_for_status()
|
||||
result = response.json()
|
||||
concept = ["AI", "Machine Learning", "Deep Learning"][i]
|
||||
print(f"\n{concept}:")
|
||||
print(f" {result['choices'][0]['message']['content'][:100]}...")
|
||||
|
||||
asyncio.run(fetch_multiple())
|
||||
```
|
||||
|
||||
## Complete Async Example
|
||||
|
||||
```python
|
||||
"""Complete async usage example for FastGPT Python SDK."""
|
||||
|
||||
import asyncio
|
||||
import json
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
from fastgpt_client import AsyncChatClient, AsyncAppClient
|
||||
|
||||
load_dotenv()
|
||||
|
||||
API_KEY = os.getenv("API_KEY")
|
||||
BASE_URL = os.getenv("BASE_URL")
|
||||
|
||||
|
||||
async def simple_chat():
|
||||
"""Simple async chat completion example."""
|
||||
async with AsyncChatClient(api_key=API_KEY, base_url=BASE_URL) as client:
|
||||
response = await client.create_chat_completion(
|
||||
messages=[{"role": "user", "content": "Hello! What's AI?"}],
|
||||
stream=False
|
||||
)
|
||||
response.raise_for_status()
|
||||
result = response.json()
|
||||
print("Response:", result['choices'][0]['message']['content'])
|
||||
|
||||
|
||||
async def streaming_chat():
|
||||
"""Async streaming chat completion example."""
|
||||
async with AsyncChatClient(api_key=API_KEY, base_url=BASE_URL) as client:
|
||||
response = await client.create_chat_completion(
|
||||
messages=[{"role": "user", "content": "Tell me a short story"}],
|
||||
stream=True
|
||||
)
|
||||
|
||||
print("Streaming response: ", end="", flush=True)
|
||||
async for line in response.aiter_lines():
|
||||
if line.startswith("data:"):
|
||||
data = line[5:].strip()
|
||||
if data and data != "[DONE]":
|
||||
chunk = json.loads(data)
|
||||
if "choices" in chunk and chunk["choices"]:
|
||||
delta = chunk["choices"][0].get("delta", {})
|
||||
content = delta.get("content", "")
|
||||
if content:
|
||||
print(content, end="", flush=True)
|
||||
print()
|
||||
|
||||
|
||||
async def chat_with_context():
|
||||
"""Async chat with context using chatId."""
|
||||
async with AsyncChatClient(api_key=API_KEY, base_url=BASE_URL) as client:
|
||||
chat_id = "my_async_chat_123"
|
||||
|
||||
# First message
|
||||
print("User: What's AI?")
|
||||
response = await client.create_chat_completion(
|
||||
messages=[{"role": "user", "content": "What's AI?"}],
|
||||
chatId=chat_id,
|
||||
stream=False
|
||||
)
|
||||
response.raise_for_status()
|
||||
result = response.json()
|
||||
print(f"AI: {result['choices'][0]['message']['content']}\n")
|
||||
|
||||
# Second message (continues the conversation)
|
||||
print("User: Tell me more about it")
|
||||
response = await client.create_chat_completion(
|
||||
messages=[{"role": "user", "content": "Tell me more about it"}],
|
||||
chatId=chat_id,
|
||||
stream=False
|
||||
)
|
||||
response.raise_for_status()
|
||||
result = response.json()
|
||||
print(f"AI: {result['choices'][0]['message']['content']}")
|
||||
|
||||
|
||||
async def get_histories():
|
||||
"""Async get chat histories."""
|
||||
async with AsyncChatClient(api_key=API_KEY, base_url=BASE_URL) as client:
|
||||
app_id = os.getenv("APP_ID", "default-app-id")
|
||||
|
||||
try:
|
||||
histories = await client.get_chat_histories(
|
||||
appId=app_id,
|
||||
offset=0,
|
||||
pageSize=20,
|
||||
source="api"
|
||||
)
|
||||
histories.raise_for_status()
|
||||
data = histories.json()
|
||||
print(f"Total chats: {data['data']['total']}")
|
||||
except Exception as e:
|
||||
print(f"Error: {e}")
|
||||
|
||||
|
||||
async def get_app_analytics():
|
||||
"""Async get app analytics."""
|
||||
async with AsyncAppClient(api_key=API_KEY, base_url=BASE_URL) as client:
|
||||
app_id = os.getenv("APP_ID", "default-app-id")
|
||||
|
||||
try:
|
||||
# Get analytics for the last 7 days
|
||||
end_date = datetime.now()
|
||||
start_date = end_date - timedelta(days=7)
|
||||
|
||||
logs = await client.get_app_logs_chart(
|
||||
appId=app_id,
|
||||
dateStart=start_date.strftime("%Y-%m-%d"),
|
||||
dateEnd=end_date.strftime("%Y-%m-%d"),
|
||||
source=["api"],
|
||||
userTimespan="day",
|
||||
chatTimespan="day",
|
||||
appTimespan="day"
|
||||
)
|
||||
logs.raise_for_status()
|
||||
data = logs.json()
|
||||
print("App Analytics (last 7 days):")
|
||||
print(f" Data keys: {list(data['data'].keys())}")
|
||||
except Exception as e:
|
||||
print(f"Error: {e}")
|
||||
|
||||
|
||||
async def multiple_requests():
|
||||
"""Run multiple async requests concurrently."""
|
||||
async with AsyncChatClient(api_key=API_KEY, base_url=BASE_URL) as client:
|
||||
# Create multiple chat completions concurrently
|
||||
tasks = [
|
||||
client.create_chat_completion(
|
||||
messages=[{"role": "user", "content": f"What is {concept}?"}],
|
||||
stream=False
|
||||
)
|
||||
for concept in ["AI", "Machine Learning", "Deep Learning"]
|
||||
]
|
||||
|
||||
responses = await asyncio.gather(*tasks)
|
||||
|
||||
for i, response in enumerate(responses):
|
||||
response.raise_for_status()
|
||||
result = response.json()
|
||||
concept = ["AI", "Machine Learning", "Deep Learning"][i]
|
||||
print(f"\n{concept}:")
|
||||
print(f" {result['choices'][0]['message']['content'][:100]}...")
|
||||
|
||||
|
||||
async def chat_with_variables():
|
||||
"""Async chat with template variables."""
|
||||
async with AsyncChatClient(api_key=API_KEY, base_url=BASE_URL) as client:
|
||||
response = await client.create_chat_completion(
|
||||
messages=[{"role": "user", "content": "Introduction"}],
|
||||
variables={
|
||||
"user_name": "Alice",
|
||||
"company": "Tech Corp",
|
||||
"language": "English"
|
||||
},
|
||||
stream=False
|
||||
)
|
||||
response.raise_for_status()
|
||||
result = response.json()
|
||||
print("Response with variables:", result['choices'][0]['message']['content'])
|
||||
|
||||
|
||||
async def main():
|
||||
"""Run all examples."""
|
||||
print("=== Simple Chat ===")
|
||||
try:
|
||||
await simple_chat()
|
||||
except Exception as e:
|
||||
print(f"Error: {e}")
|
||||
|
||||
print("\n=== Streaming Chat ===")
|
||||
try:
|
||||
await streaming_chat()
|
||||
except Exception as e:
|
||||
print(f"Error: {e}")
|
||||
|
||||
print("\n=== Chat with Context ===")
|
||||
try:
|
||||
await chat_with_context()
|
||||
except Exception as e:
|
||||
print(f"Error: {e}")
|
||||
|
||||
print("\n=== Multiple Requests (Concurrent) ===")
|
||||
try:
|
||||
await multiple_requests()
|
||||
except Exception as e:
|
||||
print(f"Error: {e}")
|
||||
|
||||
print("\n=== Chat with Variables ===")
|
||||
try:
|
||||
await chat_with_variables()
|
||||
except Exception as e:
|
||||
print(f"Error: {e}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
```
|
||||
|
||||
## Async with FastAPI
|
||||
|
||||
```python
|
||||
from fastapi import FastAPI
|
||||
from fastgpt_client import AsyncChatClient
|
||||
import os
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
# Initialize client at startup
|
||||
@app.on_event("startup")
|
||||
async def startup():
|
||||
app.state.client = AsyncChatClient(
|
||||
api_key=os.getenv("API_KEY"),
|
||||
base_url=os.getenv("BASE_URL")
|
||||
)
|
||||
|
||||
@app.on_event("shutdown")
|
||||
async def shutdown():
|
||||
await app.state.client.close()
|
||||
|
||||
@app.post("/chat")
|
||||
async def chat(message: str):
|
||||
response = await app.state.client.create_chat_completion(
|
||||
messages=[{"role": "user", "content": message}],
|
||||
stream=False
|
||||
)
|
||||
result = response.json()
|
||||
return {"response": result['choices'][0]['message']['content']}
|
||||
```
|
||||
|
||||
## See Also
|
||||
|
||||
- [Async Clients](../api/async_clients.md) - Complete async API reference
|
||||
- [Streaming](streaming.md) - Streaming examples
|
||||
- [Basic Usage](basic_usage.md) - Synchronous examples
|
||||
204
docs/examples/basic_usage.md
Normal file
204
docs/examples/basic_usage.md
Normal file
@@ -0,0 +1,204 @@
|
||||
# Basic Usage Example
|
||||
|
||||
A complete example demonstrating basic usage of the FastGPT Python SDK.
|
||||
|
||||
## Setup
|
||||
|
||||
First, install the SDK and create a `.env` file:
|
||||
|
||||
```bash
|
||||
pip install fastgpt-client python-dotenv
|
||||
```
|
||||
|
||||
```bash
|
||||
# .env
|
||||
API_KEY=fastgpt-xxxxx
|
||||
BASE_URL=http://localhost:3000
|
||||
```
|
||||
|
||||
## Complete Example
|
||||
|
||||
```python
|
||||
"""Basic usage example for FastGPT Python SDK."""
|
||||
|
||||
from fastgpt_client import ChatClient
|
||||
from dotenv import load_dotenv
|
||||
import os
|
||||
|
||||
load_dotenv()
|
||||
|
||||
# Configure your API key and base URL
|
||||
API_KEY = os.getenv("API_KEY")
|
||||
BASE_URL = os.getenv("BASE_URL")
|
||||
|
||||
|
||||
def simple_chat():
|
||||
"""Simple chat completion example."""
|
||||
with ChatClient(api_key=API_KEY, base_url=BASE_URL) as client:
|
||||
response = client.create_chat_completion(
|
||||
messages=[{"role": "user", "content": "Hello! What's AI?"}],
|
||||
stream=False
|
||||
)
|
||||
response.raise_for_status()
|
||||
result = response.json()
|
||||
|
||||
print("Response:", result['choices'][0]['message']['content'])
|
||||
|
||||
|
||||
def chat_with_history():
|
||||
"""Chat with message history example."""
|
||||
with ChatClient(api_key=API_KEY, base_url=BASE_URL) as client:
|
||||
response = client.create_chat_completion(
|
||||
messages=[
|
||||
{"role": "system", "content": "You are a helpful assistant."},
|
||||
{"role": "user", "content": "Hello!"},
|
||||
{"role": "assistant", "content": "Hi there! How can I help you?"},
|
||||
{"role": "user", "content": "What's the capital of France?"}
|
||||
],
|
||||
stream=False
|
||||
)
|
||||
response.raise_for_status()
|
||||
result = response.json()
|
||||
|
||||
print("Response:", result['choices'][0]['message']['content'])
|
||||
|
||||
|
||||
def multi_turn_conversation():
|
||||
"""Multi-turn conversation example."""
|
||||
with ChatClient(api_key=API_KEY, base_url=BASE_URL) as client:
|
||||
conversation = [
|
||||
{"role": "user", "content": "What's Python?"}
|
||||
]
|
||||
|
||||
# First turn
|
||||
response = client.create_chat_completion(
|
||||
messages=conversation,
|
||||
stream=False
|
||||
)
|
||||
response.raise_for_status()
|
||||
result = response.json()
|
||||
assistant_message = result['choices'][0]['message']['content']
|
||||
print(f"AI: {assistant_message}")
|
||||
|
||||
# Add assistant response to conversation
|
||||
conversation.append({"role": "assistant", "content": assistant_message})
|
||||
|
||||
# Second turn
|
||||
conversation.append({"role": "user", "content": "Give me an example"})
|
||||
response = client.create_chat_completion(
|
||||
messages=conversation,
|
||||
stream=False
|
||||
)
|
||||
response.raise_for_status()
|
||||
result = response.json()
|
||||
assistant_message = result['choices'][0]['message']['content']
|
||||
print(f"AI: {assistant_message}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("=== Simple Chat ===")
|
||||
try:
|
||||
simple_chat()
|
||||
except Exception as e:
|
||||
print(f"Error: {e}")
|
||||
|
||||
print("\n=== Chat with History ===")
|
||||
try:
|
||||
chat_with_history()
|
||||
except Exception as e:
|
||||
print(f"Error: {e}")
|
||||
|
||||
print("\n=== Multi-turn Conversation ===")
|
||||
try:
|
||||
multi_turn_conversation()
|
||||
except Exception as e:
|
||||
print(f"Error: {e}")
|
||||
```
|
||||
|
||||
## Running the Example
|
||||
|
||||
```bash
|
||||
python basic_usage.py
|
||||
```
|
||||
|
||||
## Expected Output
|
||||
|
||||
```
|
||||
=== Simple Chat ===
|
||||
Response: AI (Artificial Intelligence) is a branch of computer science...
|
||||
|
||||
=== Chat with History ===
|
||||
Response: The capital of France is Paris.
|
||||
|
||||
=== Multi-turn Conversation ===
|
||||
AI: Python is a high-level programming language...
|
||||
AI: Here's a simple example: print("Hello, World!")
|
||||
```
|
||||
|
||||
## Key Concepts
|
||||
|
||||
### Messages Array
|
||||
|
||||
The `messages` parameter is an array of message objects:
|
||||
|
||||
```python
|
||||
messages = [
|
||||
{"role": "system", "content": "You are a helpful assistant."},
|
||||
{"role": "user", "content": "Hello!"},
|
||||
{"role": "assistant", "content": "Hi there!"},
|
||||
{"role": "user", "content": "How are you?"}
|
||||
]
|
||||
```
|
||||
|
||||
### Response Structure
|
||||
|
||||
The response follows OpenAI's format:
|
||||
|
||||
```python
|
||||
{
|
||||
"id": "chatcmpl-xxx",
|
||||
"object": "chat.completion",
|
||||
"created": 1234567890,
|
||||
"model": "gpt-3.5-turbo",
|
||||
"choices": [
|
||||
{
|
||||
"index": 0,
|
||||
"message": {
|
||||
"role": "assistant",
|
||||
"content": "Response text here..."
|
||||
},
|
||||
"finish_reason": "stop"
|
||||
}
|
||||
],
|
||||
"usage": {
|
||||
"prompt_tokens": 20,
|
||||
"completion_tokens": 15,
|
||||
"total_tokens": 35
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Error Handling
|
||||
|
||||
Always handle potential errors:
|
||||
|
||||
```python
|
||||
from fastgpt_client import ChatClient
|
||||
from fastgpt_client.exceptions import APIError, AuthenticationError
|
||||
|
||||
try:
|
||||
with ChatClient(api_key=API_KEY) as client:
|
||||
response = client.create_chat_completion(...)
|
||||
response.raise_for_status()
|
||||
result = response.json()
|
||||
except AuthenticationError:
|
||||
print("Invalid API key")
|
||||
except APIError as e:
|
||||
print(f"API error: {e}")
|
||||
```
|
||||
|
||||
## See Also
|
||||
|
||||
- [Streaming Example](streaming.md) - Learn how to use streaming responses
|
||||
- [Async Usage](async_usage.md) - Asynchronous examples
|
||||
- [Chat Context](chat_context.md) - Managing conversation context
|
||||
251
docs/examples/chat_context.md
Normal file
251
docs/examples/chat_context.md
Normal file
@@ -0,0 +1,251 @@
|
||||
# Chat Context Example
|
||||
|
||||
Learn how to maintain conversation context across multiple requests using `chatId`.
|
||||
|
||||
## Understanding chatId
|
||||
|
||||
The `chatId` parameter allows you to:
|
||||
|
||||
- **Maintain conversation history** - The AI remembers previous messages
|
||||
- **Resume conversations** - Continue an existing chat session
|
||||
- **Organize conversations** - Keep separate conversations for different users/topics
|
||||
|
||||
## Basic Context Usage
|
||||
|
||||
```python
|
||||
from fastgpt_client import ChatClient
|
||||
|
||||
with ChatClient(api_key="fastgpt-xxxxx") as client:
|
||||
chat_id = "conversation_123"
|
||||
|
||||
# First message
|
||||
response = client.create_chat_completion(
|
||||
messages=[{"role": "user", "content": "My name is Alice"}],
|
||||
chatId=chat_id,
|
||||
stream=False
|
||||
)
|
||||
result = response.json()
|
||||
print(f"AI: {result['choices'][0]['message']['content']}")
|
||||
|
||||
# Second message - AI remembers the name!
|
||||
response = client.create_chat_completion(
|
||||
messages=[{"role": "user", "content": "What's my name?"}],
|
||||
chatId=chat_id, # Same chatId maintains context
|
||||
stream=False
|
||||
)
|
||||
result = response.json()
|
||||
print(f"AI: {result['choices'][0]['message']['content']}")
|
||||
# Output: "Your name is Alice!"
|
||||
```
|
||||
|
||||
## Multi-Turn Conversation Example
|
||||
|
||||
```python
|
||||
"""Multi-turn conversation with chatId."""
|
||||
|
||||
from fastgpt_client import ChatClient
|
||||
from dotenv import load_dotenv
|
||||
import os
|
||||
|
||||
load_dotenv()
|
||||
|
||||
API_KEY = os.getenv("API_KEY")
|
||||
BASE_URL = os.getenv("BASE_URL")
|
||||
|
||||
|
||||
def multi_turn_conversation():
|
||||
"""Maintain context across multiple turns."""
|
||||
with ChatClient(api_key=API_KEY, base_url=BASE_URL) as client:
|
||||
chat_id = "my_conversation"
|
||||
|
||||
conversation = [
|
||||
"Hi, I'm learning Python.",
|
||||
"What are the main data types in Python?",
|
||||
"Can you give me an example of a list?",
|
||||
"How do I add items to a list?",
|
||||
]
|
||||
|
||||
for user_message in conversation:
|
||||
print(f"\nUser: {user_message}")
|
||||
|
||||
response = client.create_chat_completion(
|
||||
messages=[{"role": "user", "content": user_message}],
|
||||
chatId=chat_id,
|
||||
stream=False
|
||||
)
|
||||
response.raise_for_status()
|
||||
result = response.json()
|
||||
|
||||
ai_message = result['choices'][0]['message']['content']
|
||||
print(f"AI: {ai_message}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
multi_turn_conversation()
|
||||
```
|
||||
|
||||
## Managing Multiple Conversations
|
||||
|
||||
```python
|
||||
def manage_multiple_conversations():
|
||||
"""Handle separate conversations for different users."""
|
||||
with ChatClient(api_key=API_KEY, base_url=BASE_URL) as client:
|
||||
# Conversation with user A
|
||||
chat_id_a = "user_123_conversation"
|
||||
response = client.create_chat_completion(
|
||||
messages=[{"role": "user", "content": "I like cats"}],
|
||||
chatId=chat_id_a,
|
||||
stream=False
|
||||
)
|
||||
|
||||
# Conversation with user B
|
||||
chat_id_b = "user_456_conversation"
|
||||
response = client.create_chat_completion(
|
||||
messages=[{"role": "user", "content": "I like dogs"}],
|
||||
chatId=chat_id_b,
|
||||
stream=False
|
||||
)
|
||||
|
||||
# Continue with user A
|
||||
response = client.create_chat_completion(
|
||||
messages=[{"role": "user", "content": "What did I say I like?"}],
|
||||
chatId=chat_id_a,
|
||||
stream=False
|
||||
)
|
||||
# Response: "You said you like cats"
|
||||
```
|
||||
|
||||
## Retrieving Chat History
|
||||
|
||||
```python
|
||||
def get_conversation_history():
|
||||
"""Retrieve and display chat history."""
|
||||
with ChatClient(api_key=API_KEY, base_url=BASE_URL) as client:
|
||||
app_id = os.getenv("APP_ID")
|
||||
|
||||
# Get all chat histories
|
||||
response = client.get_chat_histories(
|
||||
appId=app_id,
|
||||
offset=0,
|
||||
pageSize=20,
|
||||
source="api"
|
||||
)
|
||||
response.raise_for_status()
|
||||
data = response.json()
|
||||
|
||||
print("Chat Histories:")
|
||||
for chat in data['data']['list']:
|
||||
print(f" - {chat['title']}: {chat['chatId']}")
|
||||
|
||||
# Get records for a specific chat
|
||||
chat_id = data['data']['list'][0]['chatId']
|
||||
records_response = client.get_chat_records(
|
||||
appId=app_id,
|
||||
chatId=chat_id,
|
||||
offset=0,
|
||||
pageSize=10
|
||||
)
|
||||
records_response.raise_for_status()
|
||||
records_data = records_response.json()
|
||||
|
||||
print(f"\nRecords for {chat_id}:")
|
||||
for record in records_data['data']['list']:
|
||||
content = record.get('content', {})
|
||||
text = content.get('text', 'N/A')
|
||||
print(f" - {text[:50]}...")
|
||||
```
|
||||
|
||||
## Updating Chat Title
|
||||
|
||||
```python
|
||||
def update_chat_title():
|
||||
"""Update the title of a chat."""
|
||||
with ChatClient(api_key=API_KEY, base_url=BASE_URL) as client:
|
||||
app_id = os.getenv("APP_ID")
|
||||
chat_id = "my_conversation"
|
||||
|
||||
# Update the chat title
|
||||
response = client.update_chat_history(
|
||||
appId=app_id,
|
||||
chatId=chat_id,
|
||||
customTitle="Python Learning Session"
|
||||
)
|
||||
response.raise_for_status()
|
||||
print("Chat title updated!")
|
||||
```
|
||||
|
||||
## Pinning a Chat
|
||||
|
||||
```python
|
||||
def pin_chat():
|
||||
"""Pin a chat to the top."""
|
||||
with ChatClient(api_key=API_KEY, base_url=BASE_URL) as client:
|
||||
app_id = os.getenv("APP_ID")
|
||||
chat_id = "my_conversation"
|
||||
|
||||
# Pin the chat
|
||||
response = client.update_chat_history(
|
||||
appId=app_id,
|
||||
chatId=chat_id,
|
||||
top=True
|
||||
)
|
||||
response.raise_for_status()
|
||||
print("Chat pinned!")
|
||||
```
|
||||
|
||||
## Deleting a Chat
|
||||
|
||||
```python
|
||||
def delete_chat():
|
||||
"""Delete a chat conversation."""
|
||||
with ChatClient(api_key=API_KEY, base_url=BASE_URL) as client:
|
||||
app_id = os.getenv("APP_ID")
|
||||
chat_id = "old_conversation"
|
||||
|
||||
# Delete the chat
|
||||
response = client.delete_chat_history(
|
||||
appId=app_id,
|
||||
chatId=chat_id
|
||||
)
|
||||
response.raise_for_status()
|
||||
print("Chat deleted!")
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Use meaningful chat IDs** - Include user IDs or session IDs
|
||||
2. **Store chat IDs** - Keep them in your database for later retrieval
|
||||
3. **Handle missing chats** - Chat IDs may expire or be deleted
|
||||
4. **Clean up old chats** - Delete or archive conversations you no longer need
|
||||
|
||||
```python
|
||||
def robust_conversation():
|
||||
"""Handle chatId gracefully."""
|
||||
with ChatClient(api_key=API_KEY, base_url=BASE_URL) as client:
|
||||
chat_id = "user_123_session_456"
|
||||
|
||||
try:
|
||||
response = client.create_chat_completion(
|
||||
messages=[{"role": "user", "content": "Hello"}],
|
||||
chatId=chat_id,
|
||||
stream=False
|
||||
)
|
||||
response.raise_for_status()
|
||||
result = response.json()
|
||||
|
||||
# Store the chatId for future use
|
||||
returned_chat_id = result.get('chatId', chat_id)
|
||||
print(f"Chat ID: {returned_chat_id}")
|
||||
|
||||
except Exception as e:
|
||||
# Start a new conversation if this one fails
|
||||
print(f"Error with chatId: {e}")
|
||||
print("Starting new conversation...")
|
||||
# Create new chat without chatId
|
||||
```
|
||||
|
||||
## See Also
|
||||
|
||||
- [ChatClient API](../api/chat_client.md) - Complete method reference
|
||||
- [Variables](variables.md) - Using template variables
|
||||
- [Streaming](streaming.md) - Streaming with context
|
||||
233
docs/examples/streaming.md
Normal file
233
docs/examples/streaming.md
Normal file
@@ -0,0 +1,233 @@
|
||||
# Streaming Example
|
||||
|
||||
Learn how to use streaming responses with the FastGPT Python SDK.
|
||||
|
||||
## Why Use Streaming?
|
||||
|
||||
Streaming allows you to:
|
||||
|
||||
- **Display real-time responses** - Show text as it's generated
|
||||
- **Reduce perceived latency** - Users see content immediately
|
||||
- **Better user experience** - More interactive and engaging
|
||||
|
||||
## Basic Streaming
|
||||
|
||||
```python
|
||||
import json
|
||||
from fastgpt_client import ChatClient
|
||||
|
||||
with ChatClient(api_key="fastgpt-xxxxx") as client:
|
||||
response = client.create_chat_completion(
|
||||
messages=[{"role": "user", "content": "Tell me a short story"}],
|
||||
stream=True
|
||||
)
|
||||
|
||||
print("Story: ", end="", flush=True)
|
||||
for line in response.iter_lines():
|
||||
if line.startswith("data:"):
|
||||
data = line[5:].strip()
|
||||
if data and data != "[DONE]":
|
||||
chunk = json.loads(data)
|
||||
if "choices" in chunk and chunk["choices"]:
|
||||
delta = chunk["choices"][0].get("delta", {})
|
||||
content = delta.get("content", "")
|
||||
if content:
|
||||
print(content, end="", flush=True)
|
||||
print()
|
||||
```
|
||||
|
||||
## Complete Streaming Example
|
||||
|
||||
```python
|
||||
"""Streaming chat completion example."""
|
||||
|
||||
import json
|
||||
from fastgpt_client import ChatClient
|
||||
from dotenv import load_dotenv
|
||||
import os
|
||||
|
||||
load_dotenv()
|
||||
|
||||
API_KEY = os.getenv("API_KEY")
|
||||
BASE_URL = os.getenv("BASE_URL")
|
||||
|
||||
|
||||
def stream_chat():
|
||||
"""Simple streaming chat completion."""
|
||||
with ChatClient(api_key=API_KEY, base_url=BASE_URL) as client:
|
||||
response = client.create_chat_completion(
|
||||
messages=[{"role": "user", "content": "Tell me a short story about AI"}],
|
||||
stream=True
|
||||
)
|
||||
|
||||
print("\n=== Streaming Response ===\n")
|
||||
for line in response.iter_lines():
|
||||
if line.startswith("data:"):
|
||||
data = line[5:].strip()
|
||||
if data and data != "[DONE]":
|
||||
chunk = json.loads(data)
|
||||
if "choices" in chunk and chunk["choices"]:
|
||||
delta = chunk["choices"][0].get("delta", {})
|
||||
content = delta.get("content", "")
|
||||
if content:
|
||||
print(content, end="", flush=True)
|
||||
print("\n")
|
||||
|
||||
|
||||
def stream_with_progress():
|
||||
"""Stream with progress indicator."""
|
||||
with ChatClient(api_key=API_KEY, base_url=BASE_URL) as client:
|
||||
response = client.create_chat_completion(
|
||||
messages=[{"role": "user", "content": "Explain quantum computing"}],
|
||||
stream=True
|
||||
)
|
||||
|
||||
print("\n=== Streaming with Progress ===\n")
|
||||
token_count = 0
|
||||
for line in response.iter_lines():
|
||||
if line.startswith("data:"):
|
||||
data = line[5:].strip()
|
||||
if data and data != "[DONE]":
|
||||
chunk = json.loads(data)
|
||||
if "choices" in chunk and chunk["choices"]:
|
||||
delta = chunk["choices"][0].get("delta", {})
|
||||
content = delta.get("content", "")
|
||||
if content:
|
||||
print(content, end="", flush=True)
|
||||
token_count += 1
|
||||
print(f"\n\nTotal tokens: {token_count}")
|
||||
|
||||
|
||||
def stream_with_buffer():
|
||||
"""Stream with word buffering (print complete words only)."""
|
||||
with ChatClient(api_key=API_KEY, base_url=BASE_URL) as client:
|
||||
response = client.create_chat_completion(
|
||||
messages=[{"role": "user", "content": "What is machine learning?"}],
|
||||
stream=True
|
||||
)
|
||||
|
||||
print("\n=== Buffered Streaming ===\n")
|
||||
buffer = ""
|
||||
for line in response.iter_lines():
|
||||
if line.startswith("data:"):
|
||||
data = line[5:].strip()
|
||||
if data and data != "[DONE]":
|
||||
chunk = json.loads(data)
|
||||
if "choices" in chunk and chunk["choices"]:
|
||||
delta = chunk["choices"][0].get("delta", {})
|
||||
content = delta.get("content", "")
|
||||
if content:
|
||||
buffer += content
|
||||
# Print complete words
|
||||
if " " in buffer:
|
||||
parts = buffer.split(" ", 1)
|
||||
print(parts[0] + " ", end="", flush=True)
|
||||
buffer = parts[1] if len(parts) > 1 else ""
|
||||
# Print remaining content
|
||||
if buffer:
|
||||
print(buffer)
|
||||
print()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
stream_chat()
|
||||
except Exception as e:
|
||||
print(f"Error: {e}")
|
||||
|
||||
try:
|
||||
stream_with_progress()
|
||||
except Exception as e:
|
||||
print(f"Error: {e}")
|
||||
|
||||
try:
|
||||
stream_with_buffer()
|
||||
except Exception as e:
|
||||
print(f"Error: {e}")
|
||||
```
|
||||
|
||||
## Async Streaming
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
import json
|
||||
from fastgpt_client import AsyncChatClient
|
||||
|
||||
async def stream_async():
|
||||
"""Async streaming example."""
|
||||
async with AsyncChatClient(api_key="fastgpt-xxxxx") as client:
|
||||
response = await client.create_chat_completion(
|
||||
messages=[{"role": "user", "content": "Tell me about async/await"}],
|
||||
stream=True
|
||||
)
|
||||
|
||||
async for line in response.aiter_lines():
|
||||
if line.startswith("data:"):
|
||||
data = line[5:].strip()
|
||||
if data and data != "[DONE]":
|
||||
chunk = json.loads(data)
|
||||
if "choices" in chunk and chunk["choices"]:
|
||||
delta = chunk["choices"][0].get("delta", {})
|
||||
content = delta.get("content", "")
|
||||
if content:
|
||||
print(content, end="", flush=True)
|
||||
|
||||
asyncio.run(stream_async())
|
||||
```
|
||||
|
||||
## Streaming Event Types
|
||||
|
||||
FastGPT sends multiple SSE (Server-Sent Events) event types. The common ones are:
|
||||
|
||||
- `data` - Standard response chunks (OpenAI-compatible)
|
||||
- `answer` - Main chat response content
|
||||
- `fastAnswer` - Quick reply content
|
||||
- `flowNodeStatus` - Workflow node status updates
|
||||
- `interactive` - Interactive node prompts
|
||||
- `error` - Error events
|
||||
|
||||
For more details on event types, see [Streaming Events](../advanced/streaming_events.md).
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Always flush output**: Use `flush=True` when printing
|
||||
2. **Handle connection errors**: Streaming can fail mid-response
|
||||
3. **Use context managers**: Ensures proper cleanup
|
||||
4. **Buffer for better formatting**: Consider buffering for word boundaries
|
||||
|
||||
```python
|
||||
import time
|
||||
|
||||
def robust_stream():
|
||||
"""Handle streaming errors gracefully."""
|
||||
try:
|
||||
with ChatClient(api_key=API_KEY) as client:
|
||||
response = client.create_chat_completion(
|
||||
messages=[{"role": "user", "content": "Hello"}],
|
||||
stream=True
|
||||
)
|
||||
|
||||
for line in response.iter_lines():
|
||||
if line:
|
||||
try:
|
||||
data = line[5:].strip() if line.startswith("data:") else line
|
||||
if data and data != "[DONE]":
|
||||
chunk = json.loads(data)
|
||||
# Process chunk
|
||||
if "choices" in chunk and chunk["choices"]:
|
||||
delta = chunk["choices"][0].get("delta", {})
|
||||
content = delta.get("content", "")
|
||||
if content:
|
||||
print(content, end="", flush=True)
|
||||
except json.JSONDecodeError:
|
||||
continue
|
||||
|
||||
except Exception as e:
|
||||
print(f"\nStreaming error: {e}")
|
||||
```
|
||||
|
||||
## See Also
|
||||
|
||||
- [Streaming Events](../advanced/streaming_events.md) - Advanced SSE event handling
|
||||
- [Async Usage](async_usage.md) - Async streaming examples
|
||||
- [Error Handling](../advanced/error_handling.md) - Robust error handling
|
||||
319
docs/examples/variables.md
Normal file
319
docs/examples/variables.md
Normal file
@@ -0,0 +1,319 @@
|
||||
# Variables Example
|
||||
|
||||
Learn how to use template variables in your FastGPT workflows.
|
||||
|
||||
## What are Variables?
|
||||
|
||||
Variables allow you to dynamically replace placeholders in your FastGPT workflows. This is useful for:
|
||||
|
||||
- **Personalizing responses** - Insert user names, company names, etc.
|
||||
- **Conditional content** - Show different content based on user input
|
||||
- **Multi-language support** - Switch languages dynamically
|
||||
- **Configuration** - Pass settings to your workflow
|
||||
|
||||
## Basic Variable Usage
|
||||
|
||||
```python
|
||||
from fastgpt_client import ChatClient
|
||||
|
||||
with ChatClient(api_key="fastgpt-xxxxx") as client:
|
||||
response = client.create_chat_completion(
|
||||
messages=[{"role": "user", "content": "Introduction"}],
|
||||
variables={
|
||||
"user_name": "Alice",
|
||||
"company": "Tech Corp",
|
||||
"language": "English"
|
||||
},
|
||||
stream=False
|
||||
)
|
||||
result = response.json()
|
||||
print(result['choices'][0]['message']['content'])
|
||||
# Output might be: "Hello Alice! Welcome to Tech Corp..."
|
||||
```
|
||||
|
||||
## Complete Variables Example
|
||||
|
||||
```python
|
||||
"""Using template variables in FastGPT workflows."""
|
||||
|
||||
from fastgpt_client import ChatClient
|
||||
from dotenv import load_dotenv
|
||||
import os
|
||||
|
||||
load_dotenv()
|
||||
|
||||
API_KEY = os.getenv("API_KEY")
|
||||
BASE_URL = os.getenv("BASE_URL")
|
||||
|
||||
|
||||
def personalized_greeting():
|
||||
"""Personalized greeting with variables."""
|
||||
with ChatClient(api_key=API_KEY, base_url=BASE_URL) as client:
|
||||
response = client.create_chat_completion(
|
||||
messages=[{"role": "user", "content": "Greet me"}],
|
||||
variables={
|
||||
"user_name": "Alice",
|
||||
"time_of_day": "morning",
|
||||
"language": "English"
|
||||
},
|
||||
stream=False
|
||||
)
|
||||
response.raise_for_status()
|
||||
result = response.json()
|
||||
print("Response:", result['choices'][0]['message']['content'])
|
||||
|
||||
|
||||
def dynamic_content():
|
||||
"""Dynamic content based on variables."""
|
||||
with ChatClient(api_key=API_KEY, base_url=BASE_URL) as client:
|
||||
# Generate content for different audiences
|
||||
audiences = [
|
||||
{
|
||||
"audience": "technical",
|
||||
"detail_level": "high",
|
||||
"include_examples": True
|
||||
},
|
||||
{
|
||||
"audience": "business",
|
||||
"detail_level": "low",
|
||||
"include_examples": False
|
||||
},
|
||||
{
|
||||
"audience": "general",
|
||||
"detail_level": "medium",
|
||||
"include_examples": True
|
||||
}
|
||||
]
|
||||
|
||||
for config in audiences:
|
||||
print(f"\n--- Content for {config['audience']} audience ---")
|
||||
response = client.create_chat_completion(
|
||||
messages=[{"role": "user", "content": "Explain AI"}],
|
||||
variables=config,
|
||||
stream=False
|
||||
)
|
||||
response.raise_for_status()
|
||||
result = response.json()
|
||||
print(result['choices'][0]['message']['content'][:200] + "...")
|
||||
|
||||
|
||||
def multi_language():
|
||||
"""Multi-language support with variables."""
|
||||
with ChatClient(api_key=API_KEY, base_url=BASE_URL) as client:
|
||||
languages = [
|
||||
{"language": "English", "user_name": "Alice"},
|
||||
{"language": "Spanish", "user_name": "Carlos"},
|
||||
{"language": "French", "user_name": "Marie"},
|
||||
]
|
||||
|
||||
for lang_config in languages:
|
||||
print(f"\n--- Response in {lang_config['language']} ---")
|
||||
response = client.create_chat_completion(
|
||||
messages=[{"role": "user", "content": "Say hello"}],
|
||||
variables=lang_config,
|
||||
stream=False
|
||||
)
|
||||
response.raise_for_status()
|
||||
result = response.json()
|
||||
print(result['choices'][0]['message']['content'])
|
||||
|
||||
|
||||
def context_aware_response():
|
||||
"""Response with contextual variables."""
|
||||
with ChatClient(api_key=API_KEY, base_url=BASE_URL) as client:
|
||||
# User context
|
||||
user_context = {
|
||||
"user_name": "Alice",
|
||||
"user_level": "beginner",
|
||||
"topic": "Python programming",
|
||||
"goal": "learn data analysis"
|
||||
}
|
||||
|
||||
# Generate personalized learning plan
|
||||
response = client.create_chat_completion(
|
||||
messages=[
|
||||
{
|
||||
"role": "user",
|
||||
"content": "Create a learning plan for me"
|
||||
}
|
||||
],
|
||||
variables=user_context,
|
||||
stream=False
|
||||
)
|
||||
response.raise_for_status()
|
||||
result = response.json()
|
||||
print("Personalized Learning Plan:")
|
||||
print(result['choices'][0]['message']['content'])
|
||||
|
||||
|
||||
def workflow_with_variables():
|
||||
"""Complete workflow using multiple variables."""
|
||||
with ChatClient(api_key=API_KEY, base_url=BASE_URL) as client:
|
||||
# Scenario: Customer support chat
|
||||
customer_context = {
|
||||
"customer_name": "John Doe",
|
||||
"company": "Acme Corp",
|
||||
"plan": "enterprise",
|
||||
"issue_type": "technical",
|
||||
"urgency": "high",
|
||||
"language": "English",
|
||||
"account_id": "12345"
|
||||
}
|
||||
|
||||
# Generate personalized support response
|
||||
response = client.create_chat_completion(
|
||||
messages=[
|
||||
{
|
||||
"role": "user",
|
||||
"content": "I need help with my account"
|
||||
}
|
||||
],
|
||||
variables=customer_context,
|
||||
stream=False
|
||||
)
|
||||
response.raise_for_status()
|
||||
result = response.json()
|
||||
print("Support Response:")
|
||||
print(result['choices'][0]['message']['content'])
|
||||
|
||||
|
||||
def streaming_with_variables():
|
||||
"""Streaming response with variables."""
|
||||
import json
|
||||
|
||||
with ChatClient(api_key=API_KEY, base_url=BASE_URL) as client:
|
||||
response = client.create_chat_completion(
|
||||
messages=[{"role": "user", "content": "Tell me a story"}],
|
||||
variables={
|
||||
"genre": "science fiction",
|
||||
"length": "short",
|
||||
"protagonist": "AI robot"
|
||||
},
|
||||
stream=True
|
||||
)
|
||||
|
||||
print("Streaming story: ", end="", flush=True)
|
||||
for line in response.iter_lines():
|
||||
if line.startswith("data:"):
|
||||
data = line[5:].strip()
|
||||
if data and data != "[DONE]":
|
||||
chunk = json.loads(data)
|
||||
if "choices" in chunk and chunk["choices"]:
|
||||
delta = chunk["choices"][0].get("delta", {})
|
||||
content = delta.get("content", "")
|
||||
if content:
|
||||
print(content, end="", flush=True)
|
||||
print()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("=== Personalized Greeting ===")
|
||||
try:
|
||||
personalized_greeting()
|
||||
except Exception as e:
|
||||
print(f"Error: {e}")
|
||||
|
||||
print("\n=== Dynamic Content ===")
|
||||
try:
|
||||
dynamic_content()
|
||||
except Exception as e:
|
||||
print(f"Error: {e}")
|
||||
|
||||
print("\n=== Multi-Language ===")
|
||||
try:
|
||||
multi_language()
|
||||
except Exception as e:
|
||||
print(f"Error: {e}")
|
||||
|
||||
print("\n=== Context-Aware Response ===")
|
||||
try:
|
||||
context_aware_response()
|
||||
except Exception as e:
|
||||
print(f"Error: {e}")
|
||||
|
||||
print("\n=== Workflow with Variables ===")
|
||||
try:
|
||||
workflow_with_variables()
|
||||
except Exception as e:
|
||||
print(f"Error: {e}")
|
||||
|
||||
print("\n=== Streaming with Variables ===")
|
||||
try:
|
||||
streaming_with_variables()
|
||||
except Exception as e:
|
||||
print(f"Error: {e}")
|
||||
```
|
||||
|
||||
## Common Use Cases
|
||||
|
||||
### 1. Personalization
|
||||
|
||||
```python
|
||||
variables = {
|
||||
"user_name": "Alice",
|
||||
"company": "Tech Corp",
|
||||
"role": "Developer"
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Localization
|
||||
|
||||
```python
|
||||
variables = {
|
||||
"language": "Spanish",
|
||||
"region": "Latin America",
|
||||
"currency": "USD"
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Conditional Logic
|
||||
|
||||
```python
|
||||
variables = {
|
||||
"user_tier": "premium",
|
||||
"feature_set": "advanced",
|
||||
"support_level": "24/7"
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Content Generation
|
||||
|
||||
```python
|
||||
variables = {
|
||||
"topic": "AI",
|
||||
"tone": "professional",
|
||||
"length": "500",
|
||||
"format": "blog post"
|
||||
}
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Use descriptive variable names** - `user_name` instead of `n`
|
||||
2. **Validate variables** - Ensure required variables are provided
|
||||
3. **Document your variables** - Keep a list of expected variables
|
||||
4. **Use defaults** - Provide fallback values when possible
|
||||
|
||||
```python
|
||||
def get_variables(user_input):
|
||||
"""Validate and prepare variables."""
|
||||
required_vars = ["user_name", "language"]
|
||||
variables = {
|
||||
"user_name": user_input.get("name", "Guest"),
|
||||
"language": user_input.get("language", "English"),
|
||||
"company": user_input.get("company", ""),
|
||||
}
|
||||
|
||||
# Validate required variables
|
||||
missing = [var for var in required_vars if not variables.get(var)]
|
||||
if missing:
|
||||
raise ValueError(f"Missing required variables: {missing}")
|
||||
|
||||
return variables
|
||||
```
|
||||
|
||||
## See Also
|
||||
|
||||
- [ChatClient API](../api/chat_client.md) - Complete API reference
|
||||
- [Chat Context](chat_context.md) - Managing conversation context
|
||||
- [Streaming](streaming.md) - Streaming responses
|
||||
126
docs/getting_started/authentication.md
Normal file
126
docs/getting_started/authentication.md
Normal file
@@ -0,0 +1,126 @@
|
||||
# Authentication
|
||||
|
||||
FastGPT API uses API keys for authentication. This guide covers how to securely manage and use your API keys with the SDK.
|
||||
|
||||
## API Key Format
|
||||
|
||||
FastGPT API keys typically start with `fastgpt-`:
|
||||
|
||||
```
|
||||
fastgpt-xxxxxxxxxxxxxxxxxxxxxx
|
||||
```
|
||||
|
||||
## Setting Your API Key
|
||||
|
||||
### Method 1: Directly in Code (Not Recommended)
|
||||
|
||||
```python
|
||||
from fastgpt_client import ChatClient
|
||||
|
||||
client = ChatClient(api_key="fastgpt-xxxxx")
|
||||
```
|
||||
|
||||
!!! warning
|
||||
Never commit API keys to version control!
|
||||
|
||||
### Method 2: Environment Variables (Recommended)
|
||||
|
||||
Create a `.env` file:
|
||||
|
||||
```bash
|
||||
API_KEY=fastgpt-xxxxx
|
||||
BASE_URL=http://localhost:3000
|
||||
```
|
||||
|
||||
Use `python-dotenv` to load it:
|
||||
|
||||
```python
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from fastgpt_client import ChatClient
|
||||
|
||||
load_dotenv()
|
||||
|
||||
client = ChatClient(
|
||||
api_key=os.getenv("API_KEY"),
|
||||
base_url=os.getenv("BASE_URL")
|
||||
)
|
||||
```
|
||||
|
||||
Add `.env` to your `.gitignore`:
|
||||
|
||||
```
|
||||
.env
|
||||
```
|
||||
|
||||
### Method 3: System Environment Variables
|
||||
|
||||
Set the environment variable in your shell:
|
||||
|
||||
```bash
|
||||
# Linux/macOS
|
||||
export FASTGPT_API_KEY="fastgpt-xxxxx"
|
||||
export FASTGPT_BASE_URL="http://localhost:3000"
|
||||
|
||||
# Windows (Command Prompt)
|
||||
set FASTGPT_API_KEY=fastgpt-xxxxx
|
||||
set FASTGPT_BASE_URL=http://localhost:3000
|
||||
|
||||
# Windows (PowerShell)
|
||||
$env:FASTGPT_API_KEY="fastgpt-xxxxx"
|
||||
$env:FASTGPT_BASE_URL="http://localhost:3000"
|
||||
```
|
||||
|
||||
Then use it in Python:
|
||||
|
||||
```python
|
||||
import os
|
||||
from fastgpt_client import ChatClient
|
||||
|
||||
client = ChatClient(
|
||||
api_key=os.getenv("FASTGPT_API_KEY"),
|
||||
base_url=os.getenv("FASTGPT_BASE_URL", "http://localhost:3000")
|
||||
)
|
||||
```
|
||||
|
||||
## Base URL Configuration
|
||||
|
||||
The default base URL is `http://localhost:3000`. If you're using a different FastGPT instance:
|
||||
|
||||
```python
|
||||
client = ChatClient(
|
||||
api_key="fastgpt-xxxxx",
|
||||
base_url="https://your-fastgpt-instance.com"
|
||||
)
|
||||
```
|
||||
|
||||
## Authentication Errors
|
||||
|
||||
If authentication fails, the SDK raises an `AuthenticationError`:
|
||||
|
||||
```python
|
||||
from fastgpt_client import ChatClient
|
||||
from fastgpt_client.exceptions import AuthenticationError
|
||||
|
||||
try:
|
||||
with ChatClient(api_key="invalid-key") as client:
|
||||
response = client.create_chat_completion(
|
||||
messages=[{"role": "user", "content": "Hello"}]
|
||||
)
|
||||
except AuthenticationError as e:
|
||||
print(f"Authentication failed: {e}")
|
||||
```
|
||||
|
||||
## Security Best Practices
|
||||
|
||||
1. **Never expose API keys** in client-side code (browsers, mobile apps)
|
||||
2. **Use environment variables** to store keys
|
||||
3. **Rotate keys regularly** for production applications
|
||||
4. **Use separate keys** for different environments (dev, staging, prod)
|
||||
5. **Monitor usage** to detect unauthorized access
|
||||
6. **Commit `.env` to `.gitignore`** to prevent accidental commits
|
||||
|
||||
## Next Steps
|
||||
|
||||
- [Quick Start](quick_start.md) - Start using the SDK
|
||||
- [Error Handling](../advanced/error_handling.md) - Learn to handle errors properly
|
||||
45
docs/getting_started/installation.md
Normal file
45
docs/getting_started/installation.md
Normal file
@@ -0,0 +1,45 @@
|
||||
# Installation
|
||||
|
||||
## Requirements
|
||||
|
||||
- Python 3.8 or higher
|
||||
- A FastGPT API key
|
||||
|
||||
## Install with pip
|
||||
|
||||
```bash
|
||||
pip install fastgpt-client
|
||||
```
|
||||
|
||||
## Install for Development
|
||||
|
||||
If you want to contribute to the SDK or run tests:
|
||||
|
||||
```bash
|
||||
# Clone the repository
|
||||
git clone https://github.com/yourusername/fastgpt-python-sdk.git
|
||||
cd fastgpt-python-sdk
|
||||
|
||||
# Install in development mode
|
||||
pip install -e ".[dev]"
|
||||
```
|
||||
|
||||
### Development Dependencies
|
||||
|
||||
The `[dev]` extra includes:
|
||||
- `pytest` - Testing framework
|
||||
- `ruff` - Linting and formatting
|
||||
- `httpx` - HTTP client (already included)
|
||||
- `python-dotenv` - Environment variable management
|
||||
|
||||
## Verify Installation
|
||||
|
||||
```python
|
||||
from fastgpt_client import ChatClient, AppClient
|
||||
print("FastGPT SDK installed successfully!")
|
||||
```
|
||||
|
||||
## Next Steps
|
||||
|
||||
- [Quick Start Guide](quick_start.md) - Learn the basics
|
||||
- [Authentication](authentication.md) - Set up your API key
|
||||
147
docs/getting_started/quick_start.md
Normal file
147
docs/getting_started/quick_start.md
Normal file
@@ -0,0 +1,147 @@
|
||||
# Quick Start
|
||||
|
||||
This guide will help you get started with the FastGPT Python SDK in just a few minutes.
|
||||
|
||||
## 1. Get Your API Key
|
||||
|
||||
You'll need a FastGPT API key to use the SDK. You can obtain one from your FastGPT instance:
|
||||
|
||||
1. Log in to your FastGPT instance
|
||||
2. Navigate to Settings → API Keys
|
||||
3. Create a new API key
|
||||
4. Copy the key (it will start with `fastgpt-`)
|
||||
|
||||
## 2. Basic Chat Completion
|
||||
|
||||
The simplest way to use the SDK is with a basic chat completion:
|
||||
|
||||
```python
|
||||
from fastgpt_client import ChatClient
|
||||
|
||||
# Initialize the client
|
||||
with ChatClient(
|
||||
api_key="fastgpt-xxxxx",
|
||||
base_url="http://localhost:3000"
|
||||
) as client:
|
||||
# Send a message
|
||||
response = client.create_chat_completion(
|
||||
messages=[{"role": "user", "content": "Hello! What's AI?"}],
|
||||
stream=False
|
||||
)
|
||||
response.raise_for_status()
|
||||
result = response.json()
|
||||
|
||||
# Print the response
|
||||
print(result['choices'][0]['message']['content'])
|
||||
```
|
||||
|
||||
## 3. Streaming Responses
|
||||
|
||||
For real-time responses, use streaming:
|
||||
|
||||
```python
|
||||
import json
|
||||
|
||||
with ChatClient(api_key="fastgpt-xxxxx") as client:
|
||||
response = client.create_chat_completion(
|
||||
messages=[{"role": "user", "content": "Tell me a short story"}],
|
||||
stream=True
|
||||
)
|
||||
|
||||
for line in response.iter_lines():
|
||||
if line.startswith("data:"):
|
||||
data = line[5:].strip()
|
||||
if data and data != "[DONE]":
|
||||
chunk = json.loads(data)
|
||||
if "choices" in chunk and chunk["choices"]:
|
||||
delta = chunk["choices"][0].get("delta", {})
|
||||
content = delta.get("content", "")
|
||||
if content:
|
||||
print(content, end="", flush=True)
|
||||
```
|
||||
|
||||
## 4. Using Context (chatId)
|
||||
|
||||
To maintain a conversation across multiple requests, use `chatId`:
|
||||
|
||||
```python
|
||||
with ChatClient(api_key="fastgpt-xxxxx") as client:
|
||||
chat_id = "my_conversation_123"
|
||||
|
||||
# First message
|
||||
response = client.create_chat_completion(
|
||||
messages=[{"role": "user", "content": "What's AI?"}],
|
||||
chatId=chat_id,
|
||||
stream=False
|
||||
)
|
||||
|
||||
# Second message (continues the conversation)
|
||||
response = client.create_chat_completion(
|
||||
messages=[{"role": "user", "content": "Tell me more"}],
|
||||
chatId=chat_id, # Same chatId maintains context
|
||||
stream=False
|
||||
)
|
||||
```
|
||||
|
||||
## 5. Using Variables
|
||||
|
||||
You can use template variables in your FastGPT workflows:
|
||||
|
||||
```python
|
||||
with ChatClient(api_key="fastgpt-xxxxx") as client:
|
||||
response = client.create_chat_completion(
|
||||
messages=[{"role": "user", "content": "Hello [name]!"}],
|
||||
variables={"name": "Alice"}, # Replaces [name] placeholder
|
||||
stream=False
|
||||
)
|
||||
```
|
||||
|
||||
## 6. Get Chat Histories
|
||||
|
||||
Retrieve your chat histories:
|
||||
|
||||
```python
|
||||
with ChatClient(api_key="fastgpt-xxxxx") as client:
|
||||
histories = client.get_chat_histories(
|
||||
appId="your-app-id",
|
||||
offset=0,
|
||||
pageSize=20,
|
||||
source="api"
|
||||
)
|
||||
histories.raise_for_status()
|
||||
data = histories.json()
|
||||
|
||||
for chat in data['data']['list']:
|
||||
print(f"{chat['title']}: {chat['chatId']}")
|
||||
```
|
||||
|
||||
## Environment Variables
|
||||
|
||||
For better security, use environment variables for your API key:
|
||||
|
||||
```bash
|
||||
# .env file
|
||||
API_KEY=fastgpt-xxxxx
|
||||
BASE_URL=http://localhost:3000
|
||||
```
|
||||
|
||||
```python
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from fastgpt_client import ChatClient
|
||||
|
||||
load_dotenv()
|
||||
|
||||
with ChatClient(
|
||||
api_key=os.getenv("API_KEY"),
|
||||
base_url=os.getenv("BASE_URL")
|
||||
) as client:
|
||||
# Your code here
|
||||
pass
|
||||
```
|
||||
|
||||
## Next Steps
|
||||
|
||||
- [Authentication](authentication.md) - Learn more about securing your API key
|
||||
- [API Reference](../api/overview.md) - Explore all available methods
|
||||
- [Examples](../examples/basic_usage.md) - More usage examples
|
||||
61
docs/index.md
Normal file
61
docs/index.md
Normal file
@@ -0,0 +1,61 @@
|
||||
# FastGPT Python SDK
|
||||
|
||||
The official Python SDK for interacting with FastGPT's OpenAPI.
|
||||
|
||||
## Overview
|
||||
|
||||
FastGPT Python SDK is a client library that provides a simple, Pythonic interface to FastGPT's powerful AI platform. It supports both synchronous and asynchronous operations, with built-in retry logic, error handling, and connection pooling.
|
||||
|
||||
### Key Features
|
||||
|
||||
- **Easy to Use**: Simple, intuitive API design following Python best practices
|
||||
- **OpenAI-Compatible**: The `/api/v1/chat/completions` endpoint is fully OpenAI-compatible
|
||||
- **Context Manager Support**: Automatic resource cleanup with `with` statements
|
||||
- **Async Support**: Full async/await support for high-performance applications
|
||||
- **Built-in Retry Logic**: Automatic retries with configurable backoff
|
||||
- **Streaming**: Support for streaming responses
|
||||
- **Chat Context**: Maintain conversation history with `chatId`
|
||||
- **Template Variables**: Dynamic content substitution with variables
|
||||
|
||||
## Quick Example
|
||||
|
||||
```python
|
||||
from fastgpt_client import ChatClient
|
||||
|
||||
# Basic chat completion
|
||||
with ChatClient(api_key="fastgpt-xxxxx") as client:
|
||||
response = client.create_chat_completion(
|
||||
messages=[{"role": "user", "content": "Hello!"}],
|
||||
stream=False
|
||||
)
|
||||
result = response.json()
|
||||
print(result['choices'][0]['message']['content'])
|
||||
```
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
pip install fastgpt-client
|
||||
```
|
||||
|
||||
## Client Types
|
||||
|
||||
| Client | Description |
|
||||
|--------|-------------|
|
||||
| `ChatClient` | For chat operations and conversation management |
|
||||
| `AppClient` | For app analytics and logs |
|
||||
| `AsyncChatClient` | Async version of ChatClient |
|
||||
| `AsyncAppClient` | Async version of AppClient |
|
||||
|
||||
## Documentation
|
||||
|
||||
- **[Getting Started](getting_started/installation.md)** - Installation and setup
|
||||
- **[API Reference](api/overview.md)** - Complete API documentation
|
||||
- **[Examples](examples/basic_usage.md)** - Usage examples
|
||||
- **[Advanced Topics](advanced/error_handling.md)** - Advanced features
|
||||
|
||||
## Links
|
||||
|
||||
- [FastGPT Documentation](https://doc.fastgpt.io/)
|
||||
- [Chat API Documentation](https://doc.fastgpt.io/docs/introduction/development/openapi/chat)
|
||||
- [GitHub Repository](https://github.com/yourusername/fastgpt-python-sdk)
|
||||
98
mkdocs.yml
Normal file
98
mkdocs.yml
Normal file
@@ -0,0 +1,98 @@
|
||||
site_name: FastGPT Python SDK
|
||||
site_description: Python SDK for FastGPT OpenAPI
|
||||
site_author: FastGPT
|
||||
repo_url: https://github.com/yourusername/fastgpt-python-sdk
|
||||
repo_name: fastgpt-python-sdk
|
||||
|
||||
theme:
|
||||
name: material
|
||||
palette:
|
||||
- scheme: default
|
||||
primary: indigo
|
||||
accent: indigo
|
||||
toggle:
|
||||
icon: material/brightness-7
|
||||
name: Switch to dark mode
|
||||
- scheme: slate
|
||||
primary: indigo
|
||||
accent: indigo
|
||||
toggle:
|
||||
icon: material/brightness-4
|
||||
name: Switch to light mode
|
||||
features:
|
||||
- search.suggest
|
||||
- search.highlight
|
||||
- navigation.tabs
|
||||
- navigation.sections
|
||||
- navigation.expand
|
||||
- navigation.top
|
||||
- content.code.copy
|
||||
- content.tabs.link
|
||||
icon:
|
||||
repo: fontawesome/brands/github
|
||||
|
||||
plugins:
|
||||
- search
|
||||
- mkdocstrings:
|
||||
handlers:
|
||||
python:
|
||||
options:
|
||||
docstring_style: google
|
||||
show_source: true
|
||||
show_root_heading: true
|
||||
show_root_members_full_path: false
|
||||
show_object_full_path: false
|
||||
show_signature_annotations: true
|
||||
signature_crossrefs: true
|
||||
merge_init_into_class: true
|
||||
|
||||
markdown_extensions:
|
||||
- pymdownx.highlight:
|
||||
anchor_linenums: true
|
||||
line_spans: __span
|
||||
pygments_lang_class: true
|
||||
- pymdownx.inlinehilite
|
||||
- pymdownx.snippets
|
||||
- pymdownx.superfences:
|
||||
custom_fences:
|
||||
- name: mermaid
|
||||
class: mermaid
|
||||
format: !!python/name:pymdownx.superfences.fence_code_format
|
||||
- pymdownx.tabbed:
|
||||
alternate_style: true
|
||||
- admonition
|
||||
- pymdownx.details
|
||||
- attr_list
|
||||
- md_in_html
|
||||
|
||||
extra:
|
||||
social:
|
||||
- icon: fontawesome/brands/github
|
||||
link: https://github.com/yourusername/fastgpt-python-sdk
|
||||
- icon: fontawesome/solid/globe
|
||||
link: https://doc.fastgpt.io/
|
||||
|
||||
nav:
|
||||
- Home: index.md
|
||||
- Getting Started:
|
||||
- Installation: getting_started/installation.md
|
||||
- Quick Start: getting_started/quick_start.md
|
||||
- Authentication: getting_started/authentication.md
|
||||
- API Reference:
|
||||
- Overview: api/overview.md
|
||||
- ChatClient: api/chat_client.md
|
||||
- AppClient: api/app_client.md
|
||||
- Async Clients: api/async_clients.md
|
||||
- Exceptions: api/exceptions.md
|
||||
- Examples:
|
||||
- Basic Usage: examples/basic_usage.md
|
||||
- Streaming: examples/streaming.md
|
||||
- Async Usage: examples/async_usage.md
|
||||
- Chat Context: examples/chat_context.md
|
||||
- Variables: examples/variables.md
|
||||
- Advanced Topics:
|
||||
- Error Handling: advanced/error_handling.md
|
||||
- Streaming Events: advanced/streaming_events.md
|
||||
- Rate Limiting: advanced/rate_limiting.md
|
||||
- Detail Mode: advanced/detail_mode.md
|
||||
- Development: development.md
|
||||
Reference in New Issue
Block a user