add documents

This commit is contained in:
Xin Wang
2026-01-08 17:35:09 +08:00
parent 6a6d736991
commit f1bd12353a
21 changed files with 4268 additions and 0 deletions

16
docs-requirements.txt Normal file
View 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

View 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

View 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

View 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

View 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
View 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
View 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
View 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
View 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
View 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
View 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/)

View 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

View 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

View 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
View 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
View 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

View 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

View 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

View 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
View 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
View 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