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