Spaces:
Running
Running
liuzhao521
commited on
Commit
·
f12ea8b
1
Parent(s):
054b72c
Update app.py and add model discovery tools
Browse files- .github/workflows/docker-publish.yml +0 -98
- app.py +18 -0
- available_models.txt +2 -0
- check_docs.py +79 -0
- discover_models.py +256 -0
- model_search_results.json +47 -0
- openapi_spec.json +699 -0
- query_amazon_models.py +140 -0
- quick_test.py +86 -0
- test_models.py +188 -0
.github/workflows/docker-publish.yml
DELETED
|
@@ -1,98 +0,0 @@
|
|
| 1 |
-
name: Docker
|
| 2 |
-
|
| 3 |
-
# This workflow uses actions that are not certified by GitHub.
|
| 4 |
-
# They are provided by a third-party and are governed by
|
| 5 |
-
# separate terms of service, privacy policy, and support
|
| 6 |
-
# documentation.
|
| 7 |
-
|
| 8 |
-
on:
|
| 9 |
-
schedule:
|
| 10 |
-
- cron: '17 23 * * *'
|
| 11 |
-
push:
|
| 12 |
-
branches: [ "main" ]
|
| 13 |
-
# Publish semver tags as releases.
|
| 14 |
-
tags: [ 'v*.*.*' ]
|
| 15 |
-
pull_request:
|
| 16 |
-
branches: [ "main" ]
|
| 17 |
-
|
| 18 |
-
env:
|
| 19 |
-
# Use docker.io for Docker Hub if empty
|
| 20 |
-
REGISTRY: ghcr.io
|
| 21 |
-
# github.repository as <account>/<repo>
|
| 22 |
-
IMAGE_NAME: ${{ github.repository }}
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
jobs:
|
| 26 |
-
build:
|
| 27 |
-
|
| 28 |
-
runs-on: ubuntu-latest
|
| 29 |
-
permissions:
|
| 30 |
-
contents: read
|
| 31 |
-
packages: write
|
| 32 |
-
# This is used to complete the identity challenge
|
| 33 |
-
# with sigstore/fulcio when running outside of PRs.
|
| 34 |
-
id-token: write
|
| 35 |
-
|
| 36 |
-
steps:
|
| 37 |
-
- name: Checkout repository
|
| 38 |
-
uses: actions/checkout@v4
|
| 39 |
-
|
| 40 |
-
# Install the cosign tool except on PR
|
| 41 |
-
# https://github.com/sigstore/cosign-installer
|
| 42 |
-
- name: Install cosign
|
| 43 |
-
if: github.event_name != 'pull_request'
|
| 44 |
-
uses: sigstore/cosign-installer@59acb6260d9c0ba8f4a2f9d9b48431a222b68e20 #v3.5.0
|
| 45 |
-
with:
|
| 46 |
-
cosign-release: 'v2.2.4'
|
| 47 |
-
|
| 48 |
-
# Set up BuildKit Docker container builder to be able to build
|
| 49 |
-
# multi-platform images and export cache
|
| 50 |
-
# https://github.com/docker/setup-buildx-action
|
| 51 |
-
- name: Set up Docker Buildx
|
| 52 |
-
uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3.0.0
|
| 53 |
-
|
| 54 |
-
# Login against a Docker registry except on PR
|
| 55 |
-
# https://github.com/docker/login-action
|
| 56 |
-
- name: Log into registry ${{ env.REGISTRY }}
|
| 57 |
-
if: github.event_name != 'pull_request'
|
| 58 |
-
uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d # v3.0.0
|
| 59 |
-
with:
|
| 60 |
-
registry: ${{ env.REGISTRY }}
|
| 61 |
-
username: ${{ github.actor }}
|
| 62 |
-
password: ${{ secrets.GITHUB_TOKEN }}
|
| 63 |
-
|
| 64 |
-
# Extract metadata (tags, labels) for Docker
|
| 65 |
-
# https://github.com/docker/metadata-action
|
| 66 |
-
- name: Extract Docker metadata
|
| 67 |
-
id: meta
|
| 68 |
-
uses: docker/metadata-action@96383f45573cb7f253c731d3b3ab81c87ef81934 # v5.0.0
|
| 69 |
-
with:
|
| 70 |
-
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
| 71 |
-
|
| 72 |
-
# Build and push Docker image with Buildx (don't push on PR)
|
| 73 |
-
# https://github.com/docker/build-push-action
|
| 74 |
-
- name: Build and push Docker image
|
| 75 |
-
id: build-and-push
|
| 76 |
-
uses: docker/build-push-action@0565240e2d4ab88bba5387d719585280857ece09 # v5.0.0
|
| 77 |
-
with:
|
| 78 |
-
context: .
|
| 79 |
-
push: ${{ github.event_name != 'pull_request' }}
|
| 80 |
-
tags: ${{ steps.meta.outputs.tags }}
|
| 81 |
-
labels: ${{ steps.meta.outputs.labels }}
|
| 82 |
-
cache-from: type=gha
|
| 83 |
-
cache-to: type=gha,mode=max
|
| 84 |
-
|
| 85 |
-
# Sign the resulting Docker image digest except on PRs.
|
| 86 |
-
# This will only write to the public Rekor transparency log when the Docker
|
| 87 |
-
# repository is public to avoid leaking data. If you would like to publish
|
| 88 |
-
# transparency data even for private images, pass --force to cosign below.
|
| 89 |
-
# https://github.com/sigstore/cosign
|
| 90 |
-
- name: Sign the published Docker image
|
| 91 |
-
if: ${{ github.event_name != 'pull_request' }}
|
| 92 |
-
env:
|
| 93 |
-
# https://docs.github.com/en/actions/security-guides/security-hardening-for-github-actions#using-an-intermediate-environment-variable
|
| 94 |
-
TAGS: ${{ steps.meta.outputs.tags }}
|
| 95 |
-
DIGEST: ${{ steps.build-and-push.outputs.digest }}
|
| 96 |
-
# This step uses the identity token to provision an ephemeral certificate
|
| 97 |
-
# against the sigstore community Fulcio instance.
|
| 98 |
-
run: echo "${TAGS}" | xargs -I {} cosign sign --yes {}@${DIGEST}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
app.py
CHANGED
|
@@ -374,6 +374,24 @@ def _openai_non_streaming_response(text: str, model: Optional[str]) -> Dict[str,
|
|
| 374 |
def _sse_format(obj: Dict[str, Any]) -> str:
|
| 375 |
return f"data: {json.dumps(obj, ensure_ascii=False)}\n\n"
|
| 376 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 377 |
@app.post("/v1/chat/completions")
|
| 378 |
def chat_completions(req: ChatCompletionRequest, account: Dict[str, Any] = Depends(require_account)):
|
| 379 |
"""
|
|
|
|
| 374 |
def _sse_format(obj: Dict[str, Any]) -> str:
|
| 375 |
return f"data: {json.dumps(obj, ensure_ascii=False)}\n\n"
|
| 376 |
|
| 377 |
+
@app.get("/v1/models")
|
| 378 |
+
def list_models():
|
| 379 |
+
"""
|
| 380 |
+
OpenAI-compatible models endpoint.
|
| 381 |
+
Returns the available models that can be used with this API.
|
| 382 |
+
"""
|
| 383 |
+
return {
|
| 384 |
+
"object": "list",
|
| 385 |
+
"data": [
|
| 386 |
+
{
|
| 387 |
+
"id": "claude-sonnet-4",
|
| 388 |
+
"object": "model",
|
| 389 |
+
"created": int(time.time()),
|
| 390 |
+
"owned_by": "amazon-q"
|
| 391 |
+
}
|
| 392 |
+
]
|
| 393 |
+
}
|
| 394 |
+
|
| 395 |
@app.post("/v1/chat/completions")
|
| 396 |
def chat_completions(req: ChatCompletionRequest, account: Dict[str, Any] = Depends(require_account)):
|
| 397 |
"""
|
available_models.txt
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
可用模型列表:
|
| 2 |
+
claude-sonnet-4
|
check_docs.py
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""
|
| 3 |
+
检查 API 文档和规范
|
| 4 |
+
"""
|
| 5 |
+
|
| 6 |
+
import requests
|
| 7 |
+
import json
|
| 8 |
+
|
| 9 |
+
def check_openapi_spec():
|
| 10 |
+
"""检查 OpenAPI 规范"""
|
| 11 |
+
try:
|
| 12 |
+
response = requests.get("http://localhost:8000/openapi.json", timeout=10)
|
| 13 |
+
if response.status_code == 200:
|
| 14 |
+
spec = response.json()
|
| 15 |
+
|
| 16 |
+
print("📋 OpenAPI 规范分析")
|
| 17 |
+
print("=" * 50)
|
| 18 |
+
|
| 19 |
+
# 查找模型相关的信息
|
| 20 |
+
def find_model_info(obj, path=""):
|
| 21 |
+
models_found = []
|
| 22 |
+
|
| 23 |
+
if isinstance(obj, dict):
|
| 24 |
+
for key, value in obj.items():
|
| 25 |
+
current_path = f"{path}.{key}" if path else key
|
| 26 |
+
|
| 27 |
+
if "model" in key.lower() or "claude" in key.lower() or "anthropic" in key.lower():
|
| 28 |
+
models_found.append((current_path, value))
|
| 29 |
+
|
| 30 |
+
models_found.extend(find_model_info(value, current_path))
|
| 31 |
+
|
| 32 |
+
elif isinstance(obj, list):
|
| 33 |
+
for i, item in enumerate(obj):
|
| 34 |
+
models_found.extend(find_model_info(item, f"{path}[{i}]"))
|
| 35 |
+
|
| 36 |
+
return models_found
|
| 37 |
+
|
| 38 |
+
model_info = find_model_info(spec)
|
| 39 |
+
|
| 40 |
+
if model_info:
|
| 41 |
+
print("🔍 发现模型相关信息:")
|
| 42 |
+
for path, value in model_info[:10]: # 只显示前10个
|
| 43 |
+
print(f" {path}: {value}")
|
| 44 |
+
else:
|
| 45 |
+
print("❌ 未在 OpenAPI 规范中发现模型信息")
|
| 46 |
+
|
| 47 |
+
# 检查 schemas
|
| 48 |
+
if "components" in spec and "schemas" in spec["components"]:
|
| 49 |
+
schemas = spec["components"]["schemas"]
|
| 50 |
+
print(f"\n📝 发现 {len(schemas)} 个 schema:")
|
| 51 |
+
for schema_name in schemas.keys():
|
| 52 |
+
print(f" • {schema_name}")
|
| 53 |
+
|
| 54 |
+
# 保存完整规范
|
| 55 |
+
with open("openapi_spec.json", "w", encoding="utf-8") as f:
|
| 56 |
+
json.dump(spec, f, ensure_ascii=False, indent=2)
|
| 57 |
+
print(f"\n📁 完整 OpenAPI 规范已保存到: openapi_spec.json")
|
| 58 |
+
|
| 59 |
+
else:
|
| 60 |
+
print(f"❌ 获取 OpenAPI 规范失败: {response.status_code}")
|
| 61 |
+
|
| 62 |
+
except Exception as e:
|
| 63 |
+
print(f"❌ 检查 OpenAPI 规范异常: {e}")
|
| 64 |
+
|
| 65 |
+
def check_docs_page():
|
| 66 |
+
"""检查文档页面"""
|
| 67 |
+
try:
|
| 68 |
+
response = requests.get("http://localhost:8000/docs", timeout=10)
|
| 69 |
+
if response.status_code == 200:
|
| 70 |
+
print("📖 /docs 页面可访问")
|
| 71 |
+
print("建议在浏览器中访问 http://localhost:8000/docs 查看完整文档")
|
| 72 |
+
else:
|
| 73 |
+
print(f"❌ /docs 页面不可访问: {response.status_code}")
|
| 74 |
+
except Exception as e:
|
| 75 |
+
print(f"❌ 检查 /docs 页面异常: {e}")
|
| 76 |
+
|
| 77 |
+
if __name__ == "__main__":
|
| 78 |
+
check_openapi_spec()
|
| 79 |
+
check_docs_page()
|
discover_models.py
ADDED
|
@@ -0,0 +1,256 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""
|
| 3 |
+
尝试获取 Amazon Q API 支持的所有模型
|
| 4 |
+
"""
|
| 5 |
+
|
| 6 |
+
import requests
|
| 7 |
+
import json
|
| 8 |
+
import re
|
| 9 |
+
from typing import List, Dict, Optional
|
| 10 |
+
|
| 11 |
+
BASE_URL = "http://localhost:8000"
|
| 12 |
+
|
| 13 |
+
def try_models_endpoint():
|
| 14 |
+
"""尝试调用 /v1/models 端点(如果存在)"""
|
| 15 |
+
try:
|
| 16 |
+
response = requests.get(f"{BASE_URL}/v1/models", timeout=10)
|
| 17 |
+
if response.status_code == 200:
|
| 18 |
+
data = response.json()
|
| 19 |
+
print("✅ 发现 /v1/models 端点")
|
| 20 |
+
return data
|
| 21 |
+
else:
|
| 22 |
+
print(f"❌ /v1/models 端点返回: {response.status_code}")
|
| 23 |
+
return None
|
| 24 |
+
except Exception as e:
|
| 25 |
+
print(f"❌ /v1/models 端点异常: {e}")
|
| 26 |
+
return None
|
| 27 |
+
|
| 28 |
+
def extract_model_from_error(error_text: str) -> List[str]:
|
| 29 |
+
"""从错误信息中提取可能的模型名称"""
|
| 30 |
+
models = []
|
| 31 |
+
|
| 32 |
+
# 常见的模型名称模式
|
| 33 |
+
patterns = [
|
| 34 |
+
r'claude-[\w\.-]+',
|
| 35 |
+
r'anthropic\.[\w\.-]+',
|
| 36 |
+
r'model\s+["\']?([a-zA-Z0-9_\.-]+)["\']?',
|
| 37 |
+
r'available\s+models?[:\s]+([^\n\r]+)',
|
| 38 |
+
r'supported\s+models?[:\s]+([^\n\r]+)',
|
| 39 |
+
]
|
| 40 |
+
|
| 41 |
+
for pattern in patterns:
|
| 42 |
+
matches = re.findall(pattern, error_text, re.IGNORECASE)
|
| 43 |
+
models.extend(matches)
|
| 44 |
+
|
| 45 |
+
return list(set(models)) # 去重
|
| 46 |
+
|
| 47 |
+
def try_common_amazon_q_models() -> List[str]:
|
| 48 |
+
"""尝试 Amazon Q 可能支持的其他模型名称"""
|
| 49 |
+
# 基于 AWS Bedrock 和 Amazon Q 的常见模型命名
|
| 50 |
+
amazon_q_models = [
|
| 51 |
+
# Claude 模型 (AWS Bedrock 格式)
|
| 52 |
+
"anthropic.claude-v2:1",
|
| 53 |
+
"anthropic.claude-v2",
|
| 54 |
+
"anthropic.claude-instant-v1",
|
| 55 |
+
"anthropic.claude-3-sonnet-20240229-v1:0",
|
| 56 |
+
"anthropic.claude-3-sonnet-20240229-v1",
|
| 57 |
+
"anthropic.claude-3-haiku-20240307-v1:0",
|
| 58 |
+
"anthropic.claude-3-haiku-20240307-v1",
|
| 59 |
+
"anthropic.claude-3-opus-20240229-v1:0",
|
| 60 |
+
"anthropic.claude-3-opus-20240229-v1",
|
| 61 |
+
|
| 62 |
+
# Amazon Q 特定模型
|
| 63 |
+
"amazon.q",
|
| 64 |
+
"amazon.q-turbo",
|
| 65 |
+
"amazon.q-pro",
|
| 66 |
+
"amazon.q-max",
|
| 67 |
+
"q.amazon",
|
| 68 |
+
"q-turbo.amazon",
|
| 69 |
+
"q-pro.amazon",
|
| 70 |
+
"q-max.amazon",
|
| 71 |
+
|
| 72 |
+
# 其他可能的命名
|
| 73 |
+
"claude",
|
| 74 |
+
"claude-v2",
|
| 75 |
+
"claude-instant",
|
| 76 |
+
"claude-3-sonnet",
|
| 77 |
+
"claude-3-haiku",
|
| 78 |
+
"claude-3-opus",
|
| 79 |
+
"sonnet",
|
| 80 |
+
"haiku",
|
| 81 |
+
"opus",
|
| 82 |
+
|
| 83 |
+
# 通用模型名
|
| 84 |
+
"default",
|
| 85 |
+
"base",
|
| 86 |
+
"latest",
|
| 87 |
+
"text-davinci-003", # 测试是否支持OpenAI模型名
|
| 88 |
+
"gpt-3.5-turbo",
|
| 89 |
+
"gpt-4",
|
| 90 |
+
]
|
| 91 |
+
|
| 92 |
+
return amazon_q_models
|
| 93 |
+
|
| 94 |
+
def test_model_with_details(model_name: str) -> Dict[str, any]:
|
| 95 |
+
"""详细测试单个模型"""
|
| 96 |
+
url = f"{BASE_URL}/v1/chat/completions"
|
| 97 |
+
|
| 98 |
+
payload = {
|
| 99 |
+
"model": model_name,
|
| 100 |
+
"messages": [
|
| 101 |
+
{"role": "user", "content": "test"}
|
| 102 |
+
],
|
| 103 |
+
"stream": False,
|
| 104 |
+
"max_tokens": 5
|
| 105 |
+
}
|
| 106 |
+
|
| 107 |
+
try:
|
| 108 |
+
response = requests.post(url, json=payload, timeout=15)
|
| 109 |
+
|
| 110 |
+
result = {
|
| 111 |
+
"model": model_name,
|
| 112 |
+
"status_code": response.status_code,
|
| 113 |
+
"available": response.status_code == 200,
|
| 114 |
+
"error": None,
|
| 115 |
+
"error_details": None
|
| 116 |
+
}
|
| 117 |
+
|
| 118 |
+
if response.status_code != 200:
|
| 119 |
+
result["error"] = response.text[:300]
|
| 120 |
+
# 尝试从错误中提取模型信息
|
| 121 |
+
extracted_models = extract_model_from_error(response.text)
|
| 122 |
+
if extracted_models:
|
| 123 |
+
result["extracted_models"] = extracted_models
|
| 124 |
+
|
| 125 |
+
return result
|
| 126 |
+
|
| 127 |
+
except Exception as e:
|
| 128 |
+
return {
|
| 129 |
+
"model": model_name,
|
| 130 |
+
"status_code": None,
|
| 131 |
+
"available": False,
|
| 132 |
+
"error": str(e),
|
| 133 |
+
"error_details": None
|
| 134 |
+
}
|
| 135 |
+
|
| 136 |
+
def comprehensive_model_search():
|
| 137 |
+
"""全面搜索可用模型"""
|
| 138 |
+
print("🔍 全面搜索 Amazon Q API 支持的模型")
|
| 139 |
+
print("=" * 60)
|
| 140 |
+
|
| 141 |
+
# 1. 尝试标准 models 端点
|
| 142 |
+
print("\n1️⃣ 尝试标准 /v1/models 端点...")
|
| 143 |
+
models_data = try_models_endpoint()
|
| 144 |
+
if models_data:
|
| 145 |
+
print("发现模型列表:")
|
| 146 |
+
if isinstance(models_data, dict) and "data" in models_data:
|
| 147 |
+
for model in models_data["data"]:
|
| 148 |
+
print(f" • {model.get('id', 'unknown')}")
|
| 149 |
+
elif isinstance(models_data, list):
|
| 150 |
+
for model in models_data:
|
| 151 |
+
if isinstance(model, dict):
|
| 152 |
+
print(f" • {model.get('id', model.get('model', 'unknown'))}")
|
| 153 |
+
else:
|
| 154 |
+
print(f" • {model}")
|
| 155 |
+
return models_data
|
| 156 |
+
|
| 157 |
+
# 2. 测试更多模型名称
|
| 158 |
+
print("\n2️⃣ 测试扩展的模型名称列表...")
|
| 159 |
+
additional_models = try_common_amazon_q_models()
|
| 160 |
+
|
| 161 |
+
print(f"测试 {len(additional_models)} 个额外的模型名称...")
|
| 162 |
+
|
| 163 |
+
available_models = []
|
| 164 |
+
error_models = []
|
| 165 |
+
extracted_from_errors = set()
|
| 166 |
+
|
| 167 |
+
for i, model in enumerate(additional_models, 1):
|
| 168 |
+
print(f"[{i}/{len(additional_models)}] {model}...", end=" ")
|
| 169 |
+
|
| 170 |
+
result = test_model_with_details(model)
|
| 171 |
+
|
| 172 |
+
if result["available"]:
|
| 173 |
+
print("✅")
|
| 174 |
+
available_models.append(model)
|
| 175 |
+
else:
|
| 176 |
+
print("❌")
|
| 177 |
+
error_models.append((model, result["error"]))
|
| 178 |
+
|
| 179 |
+
# 从错误中提取模型信息
|
| 180 |
+
if "extracted_models" in result:
|
| 181 |
+
extracted_from_errors.update(result["extracted_models"])
|
| 182 |
+
|
| 183 |
+
# 避免请求过快
|
| 184 |
+
import time
|
| 185 |
+
time.sleep(0.3)
|
| 186 |
+
|
| 187 |
+
# 3. 输出结果
|
| 188 |
+
print("\n" + "=" * 60)
|
| 189 |
+
print("📊 搜索结果")
|
| 190 |
+
print("=" * 60)
|
| 191 |
+
|
| 192 |
+
if available_models:
|
| 193 |
+
print(f"\n✅ 发现可用模型 ({len(available_models)} 个):")
|
| 194 |
+
for model in available_models:
|
| 195 |
+
print(f" • {model}")
|
| 196 |
+
else:
|
| 197 |
+
print("\n❌ 没有发现新的可用模型")
|
| 198 |
+
|
| 199 |
+
if extracted_from_errors:
|
| 200 |
+
print(f"\n🔍 从错误信息中提取的可能模型 ({len(extracted_from_errors)} 个):")
|
| 201 |
+
for model in sorted(extracted_from_errors):
|
| 202 |
+
print(f" • {model}")
|
| 203 |
+
|
| 204 |
+
# 4. 保存结果
|
| 205 |
+
search_results = {
|
| 206 |
+
"available_models": available_models,
|
| 207 |
+
"error_models": [{"model": m, "error": e} for m, e in error_models[:10]], # 只保存前10个错误
|
| 208 |
+
"extracted_from_errors": list(extracted_from_errors),
|
| 209 |
+
"timestamp": str(time.time())
|
| 210 |
+
}
|
| 211 |
+
|
| 212 |
+
with open("model_search_results.json", "w", encoding="utf-8") as f:
|
| 213 |
+
json.dump(search_results, f, ensure_ascii=False, indent=2)
|
| 214 |
+
|
| 215 |
+
print(f"\n📁 详细结果已保存到: model_search_results.json")
|
| 216 |
+
|
| 217 |
+
return search_results
|
| 218 |
+
|
| 219 |
+
def inspect_api_info():
|
| 220 |
+
"""检查API的其他信息端点"""
|
| 221 |
+
endpoints_to_try = [
|
| 222 |
+
"/",
|
| 223 |
+
"/docs",
|
| 224 |
+
"/openapi.json",
|
| 225 |
+
"/info",
|
| 226 |
+
"/v1",
|
| 227 |
+
"/status",
|
| 228 |
+
"/health"
|
| 229 |
+
]
|
| 230 |
+
|
| 231 |
+
print("\n🔍 检查API信息端点...")
|
| 232 |
+
|
| 233 |
+
for endpoint in endpoints_to_try:
|
| 234 |
+
try:
|
| 235 |
+
response = requests.get(f"{BASE_URL}{endpoint}", timeout=5)
|
| 236 |
+
if response.status_code == 200:
|
| 237 |
+
print(f"✅ {endpoint} - 可访问")
|
| 238 |
+
# 检查是否包含模型信息
|
| 239 |
+
content = response.text.lower()
|
| 240 |
+
if any(keyword in content for keyword in ["model", "claude", "anthropic"]):
|
| 241 |
+
print(f" 📄 可能包含模型相关信息")
|
| 242 |
+
else:
|
| 243 |
+
print(f"❌ {endpoint} - {response.status_code}")
|
| 244 |
+
except:
|
| 245 |
+
print(f"❌ {endpoint} - 连接失败")
|
| 246 |
+
|
| 247 |
+
if __name__ == "__main__":
|
| 248 |
+
import time
|
| 249 |
+
|
| 250 |
+
# 检查API信息端点
|
| 251 |
+
inspect_api_info()
|
| 252 |
+
|
| 253 |
+
# 全面模型搜索
|
| 254 |
+
comprehensive_model_search()
|
| 255 |
+
|
| 256 |
+
print("\n✨ 搜索完成!")
|
model_search_results.json
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"available_models": [],
|
| 3 |
+
"error_models": [
|
| 4 |
+
{
|
| 5 |
+
"model": "anthropic.claude-v2:1",
|
| 6 |
+
"error": "Internal Server Error"
|
| 7 |
+
},
|
| 8 |
+
{
|
| 9 |
+
"model": "anthropic.claude-v2",
|
| 10 |
+
"error": "Internal Server Error"
|
| 11 |
+
},
|
| 12 |
+
{
|
| 13 |
+
"model": "anthropic.claude-instant-v1",
|
| 14 |
+
"error": "Internal Server Error"
|
| 15 |
+
},
|
| 16 |
+
{
|
| 17 |
+
"model": "anthropic.claude-3-sonnet-20240229-v1:0",
|
| 18 |
+
"error": "Internal Server Error"
|
| 19 |
+
},
|
| 20 |
+
{
|
| 21 |
+
"model": "anthropic.claude-3-sonnet-20240229-v1",
|
| 22 |
+
"error": "Internal Server Error"
|
| 23 |
+
},
|
| 24 |
+
{
|
| 25 |
+
"model": "anthropic.claude-3-haiku-20240307-v1:0",
|
| 26 |
+
"error": "Internal Server Error"
|
| 27 |
+
},
|
| 28 |
+
{
|
| 29 |
+
"model": "anthropic.claude-3-haiku-20240307-v1",
|
| 30 |
+
"error": "Internal Server Error"
|
| 31 |
+
},
|
| 32 |
+
{
|
| 33 |
+
"model": "anthropic.claude-3-opus-20240229-v1:0",
|
| 34 |
+
"error": "Internal Server Error"
|
| 35 |
+
},
|
| 36 |
+
{
|
| 37 |
+
"model": "anthropic.claude-3-opus-20240229-v1",
|
| 38 |
+
"error": "Internal Server Error"
|
| 39 |
+
},
|
| 40 |
+
{
|
| 41 |
+
"model": "amazon.q",
|
| 42 |
+
"error": "Internal Server Error"
|
| 43 |
+
}
|
| 44 |
+
],
|
| 45 |
+
"extracted_from_errors": [],
|
| 46 |
+
"timestamp": "1763807315.45737"
|
| 47 |
+
}
|
openapi_spec.json
ADDED
|
@@ -0,0 +1,699 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"openapi": "3.1.0",
|
| 3 |
+
"info": {
|
| 4 |
+
"title": "v2 OpenAI-compatible Server (Amazon Q Backend)",
|
| 5 |
+
"version": "0.1.0"
|
| 6 |
+
},
|
| 7 |
+
"paths": {
|
| 8 |
+
"/v1/chat/completions": {
|
| 9 |
+
"post": {
|
| 10 |
+
"summary": "Chat Completions",
|
| 11 |
+
"description": "OpenAI-compatible chat endpoint.\n - stream default False\n - messages will be converted into \"{role}:\n{content}\" and injected into template\n - account is chosen randomly among enabled accounts (API key is for authorization only)",
|
| 12 |
+
"operationId": "chat_completions_v1_chat_completions_post",
|
| 13 |
+
"parameters": [
|
| 14 |
+
{
|
| 15 |
+
"name": "authorization",
|
| 16 |
+
"in": "header",
|
| 17 |
+
"required": false,
|
| 18 |
+
"schema": {
|
| 19 |
+
"anyOf": [
|
| 20 |
+
{
|
| 21 |
+
"type": "string"
|
| 22 |
+
},
|
| 23 |
+
{
|
| 24 |
+
"type": "null"
|
| 25 |
+
}
|
| 26 |
+
],
|
| 27 |
+
"title": "Authorization"
|
| 28 |
+
}
|
| 29 |
+
}
|
| 30 |
+
],
|
| 31 |
+
"requestBody": {
|
| 32 |
+
"required": true,
|
| 33 |
+
"content": {
|
| 34 |
+
"application/json": {
|
| 35 |
+
"schema": {
|
| 36 |
+
"$ref": "#/components/schemas/ChatCompletionRequest"
|
| 37 |
+
}
|
| 38 |
+
}
|
| 39 |
+
}
|
| 40 |
+
},
|
| 41 |
+
"responses": {
|
| 42 |
+
"200": {
|
| 43 |
+
"description": "Successful Response",
|
| 44 |
+
"content": {
|
| 45 |
+
"application/json": {
|
| 46 |
+
"schema": {}
|
| 47 |
+
}
|
| 48 |
+
}
|
| 49 |
+
},
|
| 50 |
+
"422": {
|
| 51 |
+
"description": "Validation Error",
|
| 52 |
+
"content": {
|
| 53 |
+
"application/json": {
|
| 54 |
+
"schema": {
|
| 55 |
+
"$ref": "#/components/schemas/HTTPValidationError"
|
| 56 |
+
}
|
| 57 |
+
}
|
| 58 |
+
}
|
| 59 |
+
}
|
| 60 |
+
}
|
| 61 |
+
}
|
| 62 |
+
},
|
| 63 |
+
"/v2/auth/start": {
|
| 64 |
+
"post": {
|
| 65 |
+
"summary": "Auth Start",
|
| 66 |
+
"description": "Start device authorization and return verification URL for user login.\nSession lifetime capped at 5 minutes on claim.",
|
| 67 |
+
"operationId": "auth_start_v2_auth_start_post",
|
| 68 |
+
"requestBody": {
|
| 69 |
+
"content": {
|
| 70 |
+
"application/json": {
|
| 71 |
+
"schema": {
|
| 72 |
+
"$ref": "#/components/schemas/AuthStartBody"
|
| 73 |
+
}
|
| 74 |
+
}
|
| 75 |
+
},
|
| 76 |
+
"required": true
|
| 77 |
+
},
|
| 78 |
+
"responses": {
|
| 79 |
+
"200": {
|
| 80 |
+
"description": "Successful Response",
|
| 81 |
+
"content": {
|
| 82 |
+
"application/json": {
|
| 83 |
+
"schema": {}
|
| 84 |
+
}
|
| 85 |
+
}
|
| 86 |
+
},
|
| 87 |
+
"422": {
|
| 88 |
+
"description": "Validation Error",
|
| 89 |
+
"content": {
|
| 90 |
+
"application/json": {
|
| 91 |
+
"schema": {
|
| 92 |
+
"$ref": "#/components/schemas/HTTPValidationError"
|
| 93 |
+
}
|
| 94 |
+
}
|
| 95 |
+
}
|
| 96 |
+
}
|
| 97 |
+
}
|
| 98 |
+
}
|
| 99 |
+
},
|
| 100 |
+
"/v2/auth/status/{auth_id}": {
|
| 101 |
+
"get": {
|
| 102 |
+
"summary": "Auth Status",
|
| 103 |
+
"operationId": "auth_status_v2_auth_status__auth_id__get",
|
| 104 |
+
"parameters": [
|
| 105 |
+
{
|
| 106 |
+
"name": "auth_id",
|
| 107 |
+
"in": "path",
|
| 108 |
+
"required": true,
|
| 109 |
+
"schema": {
|
| 110 |
+
"type": "string",
|
| 111 |
+
"title": "Auth Id"
|
| 112 |
+
}
|
| 113 |
+
}
|
| 114 |
+
],
|
| 115 |
+
"responses": {
|
| 116 |
+
"200": {
|
| 117 |
+
"description": "Successful Response",
|
| 118 |
+
"content": {
|
| 119 |
+
"application/json": {
|
| 120 |
+
"schema": {}
|
| 121 |
+
}
|
| 122 |
+
}
|
| 123 |
+
},
|
| 124 |
+
"422": {
|
| 125 |
+
"description": "Validation Error",
|
| 126 |
+
"content": {
|
| 127 |
+
"application/json": {
|
| 128 |
+
"schema": {
|
| 129 |
+
"$ref": "#/components/schemas/HTTPValidationError"
|
| 130 |
+
}
|
| 131 |
+
}
|
| 132 |
+
}
|
| 133 |
+
}
|
| 134 |
+
}
|
| 135 |
+
}
|
| 136 |
+
},
|
| 137 |
+
"/v2/auth/claim/{auth_id}": {
|
| 138 |
+
"post": {
|
| 139 |
+
"summary": "Auth Claim",
|
| 140 |
+
"description": "Block up to 5 minutes to exchange the device code for tokens after user completed login.\nOn success, creates an enabled account and returns it.",
|
| 141 |
+
"operationId": "auth_claim_v2_auth_claim__auth_id__post",
|
| 142 |
+
"parameters": [
|
| 143 |
+
{
|
| 144 |
+
"name": "auth_id",
|
| 145 |
+
"in": "path",
|
| 146 |
+
"required": true,
|
| 147 |
+
"schema": {
|
| 148 |
+
"type": "string",
|
| 149 |
+
"title": "Auth Id"
|
| 150 |
+
}
|
| 151 |
+
}
|
| 152 |
+
],
|
| 153 |
+
"responses": {
|
| 154 |
+
"200": {
|
| 155 |
+
"description": "Successful Response",
|
| 156 |
+
"content": {
|
| 157 |
+
"application/json": {
|
| 158 |
+
"schema": {}
|
| 159 |
+
}
|
| 160 |
+
}
|
| 161 |
+
},
|
| 162 |
+
"422": {
|
| 163 |
+
"description": "Validation Error",
|
| 164 |
+
"content": {
|
| 165 |
+
"application/json": {
|
| 166 |
+
"schema": {
|
| 167 |
+
"$ref": "#/components/schemas/HTTPValidationError"
|
| 168 |
+
}
|
| 169 |
+
}
|
| 170 |
+
}
|
| 171 |
+
}
|
| 172 |
+
}
|
| 173 |
+
}
|
| 174 |
+
},
|
| 175 |
+
"/v2/accounts": {
|
| 176 |
+
"get": {
|
| 177 |
+
"summary": "List Accounts",
|
| 178 |
+
"operationId": "list_accounts_v2_accounts_get",
|
| 179 |
+
"responses": {
|
| 180 |
+
"200": {
|
| 181 |
+
"description": "Successful Response",
|
| 182 |
+
"content": {
|
| 183 |
+
"application/json": {
|
| 184 |
+
"schema": {}
|
| 185 |
+
}
|
| 186 |
+
}
|
| 187 |
+
}
|
| 188 |
+
}
|
| 189 |
+
},
|
| 190 |
+
"post": {
|
| 191 |
+
"summary": "Create Account",
|
| 192 |
+
"operationId": "create_account_v2_accounts_post",
|
| 193 |
+
"requestBody": {
|
| 194 |
+
"content": {
|
| 195 |
+
"application/json": {
|
| 196 |
+
"schema": {
|
| 197 |
+
"$ref": "#/components/schemas/AccountCreate"
|
| 198 |
+
}
|
| 199 |
+
}
|
| 200 |
+
},
|
| 201 |
+
"required": true
|
| 202 |
+
},
|
| 203 |
+
"responses": {
|
| 204 |
+
"200": {
|
| 205 |
+
"description": "Successful Response",
|
| 206 |
+
"content": {
|
| 207 |
+
"application/json": {
|
| 208 |
+
"schema": {}
|
| 209 |
+
}
|
| 210 |
+
}
|
| 211 |
+
},
|
| 212 |
+
"422": {
|
| 213 |
+
"description": "Validation Error",
|
| 214 |
+
"content": {
|
| 215 |
+
"application/json": {
|
| 216 |
+
"schema": {
|
| 217 |
+
"$ref": "#/components/schemas/HTTPValidationError"
|
| 218 |
+
}
|
| 219 |
+
}
|
| 220 |
+
}
|
| 221 |
+
}
|
| 222 |
+
}
|
| 223 |
+
}
|
| 224 |
+
},
|
| 225 |
+
"/v2/accounts/{account_id}": {
|
| 226 |
+
"get": {
|
| 227 |
+
"summary": "Get Account Detail",
|
| 228 |
+
"operationId": "get_account_detail_v2_accounts__account_id__get",
|
| 229 |
+
"parameters": [
|
| 230 |
+
{
|
| 231 |
+
"name": "account_id",
|
| 232 |
+
"in": "path",
|
| 233 |
+
"required": true,
|
| 234 |
+
"schema": {
|
| 235 |
+
"type": "string",
|
| 236 |
+
"title": "Account Id"
|
| 237 |
+
}
|
| 238 |
+
}
|
| 239 |
+
],
|
| 240 |
+
"responses": {
|
| 241 |
+
"200": {
|
| 242 |
+
"description": "Successful Response",
|
| 243 |
+
"content": {
|
| 244 |
+
"application/json": {
|
| 245 |
+
"schema": {}
|
| 246 |
+
}
|
| 247 |
+
}
|
| 248 |
+
},
|
| 249 |
+
"422": {
|
| 250 |
+
"description": "Validation Error",
|
| 251 |
+
"content": {
|
| 252 |
+
"application/json": {
|
| 253 |
+
"schema": {
|
| 254 |
+
"$ref": "#/components/schemas/HTTPValidationError"
|
| 255 |
+
}
|
| 256 |
+
}
|
| 257 |
+
}
|
| 258 |
+
}
|
| 259 |
+
}
|
| 260 |
+
},
|
| 261 |
+
"delete": {
|
| 262 |
+
"summary": "Delete Account",
|
| 263 |
+
"operationId": "delete_account_v2_accounts__account_id__delete",
|
| 264 |
+
"parameters": [
|
| 265 |
+
{
|
| 266 |
+
"name": "account_id",
|
| 267 |
+
"in": "path",
|
| 268 |
+
"required": true,
|
| 269 |
+
"schema": {
|
| 270 |
+
"type": "string",
|
| 271 |
+
"title": "Account Id"
|
| 272 |
+
}
|
| 273 |
+
}
|
| 274 |
+
],
|
| 275 |
+
"responses": {
|
| 276 |
+
"200": {
|
| 277 |
+
"description": "Successful Response",
|
| 278 |
+
"content": {
|
| 279 |
+
"application/json": {
|
| 280 |
+
"schema": {}
|
| 281 |
+
}
|
| 282 |
+
}
|
| 283 |
+
},
|
| 284 |
+
"422": {
|
| 285 |
+
"description": "Validation Error",
|
| 286 |
+
"content": {
|
| 287 |
+
"application/json": {
|
| 288 |
+
"schema": {
|
| 289 |
+
"$ref": "#/components/schemas/HTTPValidationError"
|
| 290 |
+
}
|
| 291 |
+
}
|
| 292 |
+
}
|
| 293 |
+
}
|
| 294 |
+
}
|
| 295 |
+
},
|
| 296 |
+
"patch": {
|
| 297 |
+
"summary": "Update Account",
|
| 298 |
+
"operationId": "update_account_v2_accounts__account_id__patch",
|
| 299 |
+
"parameters": [
|
| 300 |
+
{
|
| 301 |
+
"name": "account_id",
|
| 302 |
+
"in": "path",
|
| 303 |
+
"required": true,
|
| 304 |
+
"schema": {
|
| 305 |
+
"type": "string",
|
| 306 |
+
"title": "Account Id"
|
| 307 |
+
}
|
| 308 |
+
}
|
| 309 |
+
],
|
| 310 |
+
"requestBody": {
|
| 311 |
+
"required": true,
|
| 312 |
+
"content": {
|
| 313 |
+
"application/json": {
|
| 314 |
+
"schema": {
|
| 315 |
+
"$ref": "#/components/schemas/AccountUpdate"
|
| 316 |
+
}
|
| 317 |
+
}
|
| 318 |
+
}
|
| 319 |
+
},
|
| 320 |
+
"responses": {
|
| 321 |
+
"200": {
|
| 322 |
+
"description": "Successful Response",
|
| 323 |
+
"content": {
|
| 324 |
+
"application/json": {
|
| 325 |
+
"schema": {}
|
| 326 |
+
}
|
| 327 |
+
}
|
| 328 |
+
},
|
| 329 |
+
"422": {
|
| 330 |
+
"description": "Validation Error",
|
| 331 |
+
"content": {
|
| 332 |
+
"application/json": {
|
| 333 |
+
"schema": {
|
| 334 |
+
"$ref": "#/components/schemas/HTTPValidationError"
|
| 335 |
+
}
|
| 336 |
+
}
|
| 337 |
+
}
|
| 338 |
+
}
|
| 339 |
+
}
|
| 340 |
+
}
|
| 341 |
+
},
|
| 342 |
+
"/v2/accounts/{account_id}/refresh": {
|
| 343 |
+
"post": {
|
| 344 |
+
"summary": "Manual Refresh",
|
| 345 |
+
"operationId": "manual_refresh_v2_accounts__account_id__refresh_post",
|
| 346 |
+
"parameters": [
|
| 347 |
+
{
|
| 348 |
+
"name": "account_id",
|
| 349 |
+
"in": "path",
|
| 350 |
+
"required": true,
|
| 351 |
+
"schema": {
|
| 352 |
+
"type": "string",
|
| 353 |
+
"title": "Account Id"
|
| 354 |
+
}
|
| 355 |
+
}
|
| 356 |
+
],
|
| 357 |
+
"responses": {
|
| 358 |
+
"200": {
|
| 359 |
+
"description": "Successful Response",
|
| 360 |
+
"content": {
|
| 361 |
+
"application/json": {
|
| 362 |
+
"schema": {}
|
| 363 |
+
}
|
| 364 |
+
}
|
| 365 |
+
},
|
| 366 |
+
"422": {
|
| 367 |
+
"description": "Validation Error",
|
| 368 |
+
"content": {
|
| 369 |
+
"application/json": {
|
| 370 |
+
"schema": {
|
| 371 |
+
"$ref": "#/components/schemas/HTTPValidationError"
|
| 372 |
+
}
|
| 373 |
+
}
|
| 374 |
+
}
|
| 375 |
+
}
|
| 376 |
+
}
|
| 377 |
+
}
|
| 378 |
+
},
|
| 379 |
+
"/": {
|
| 380 |
+
"get": {
|
| 381 |
+
"summary": "Index",
|
| 382 |
+
"operationId": "index__get",
|
| 383 |
+
"responses": {
|
| 384 |
+
"200": {
|
| 385 |
+
"description": "Successful Response"
|
| 386 |
+
}
|
| 387 |
+
}
|
| 388 |
+
}
|
| 389 |
+
},
|
| 390 |
+
"/healthz": {
|
| 391 |
+
"get": {
|
| 392 |
+
"summary": "Health",
|
| 393 |
+
"operationId": "health_healthz_get",
|
| 394 |
+
"responses": {
|
| 395 |
+
"200": {
|
| 396 |
+
"description": "Successful Response",
|
| 397 |
+
"content": {
|
| 398 |
+
"application/json": {
|
| 399 |
+
"schema": {}
|
| 400 |
+
}
|
| 401 |
+
}
|
| 402 |
+
}
|
| 403 |
+
}
|
| 404 |
+
}
|
| 405 |
+
}
|
| 406 |
+
},
|
| 407 |
+
"components": {
|
| 408 |
+
"schemas": {
|
| 409 |
+
"AccountCreate": {
|
| 410 |
+
"properties": {
|
| 411 |
+
"label": {
|
| 412 |
+
"anyOf": [
|
| 413 |
+
{
|
| 414 |
+
"type": "string"
|
| 415 |
+
},
|
| 416 |
+
{
|
| 417 |
+
"type": "null"
|
| 418 |
+
}
|
| 419 |
+
],
|
| 420 |
+
"title": "Label"
|
| 421 |
+
},
|
| 422 |
+
"clientId": {
|
| 423 |
+
"type": "string",
|
| 424 |
+
"title": "Clientid"
|
| 425 |
+
},
|
| 426 |
+
"clientSecret": {
|
| 427 |
+
"type": "string",
|
| 428 |
+
"title": "Clientsecret"
|
| 429 |
+
},
|
| 430 |
+
"refreshToken": {
|
| 431 |
+
"anyOf": [
|
| 432 |
+
{
|
| 433 |
+
"type": "string"
|
| 434 |
+
},
|
| 435 |
+
{
|
| 436 |
+
"type": "null"
|
| 437 |
+
}
|
| 438 |
+
],
|
| 439 |
+
"title": "Refreshtoken"
|
| 440 |
+
},
|
| 441 |
+
"accessToken": {
|
| 442 |
+
"anyOf": [
|
| 443 |
+
{
|
| 444 |
+
"type": "string"
|
| 445 |
+
},
|
| 446 |
+
{
|
| 447 |
+
"type": "null"
|
| 448 |
+
}
|
| 449 |
+
],
|
| 450 |
+
"title": "Accesstoken"
|
| 451 |
+
},
|
| 452 |
+
"other": {
|
| 453 |
+
"anyOf": [
|
| 454 |
+
{
|
| 455 |
+
"type": "object"
|
| 456 |
+
},
|
| 457 |
+
{
|
| 458 |
+
"type": "null"
|
| 459 |
+
}
|
| 460 |
+
],
|
| 461 |
+
"title": "Other"
|
| 462 |
+
},
|
| 463 |
+
"enabled": {
|
| 464 |
+
"anyOf": [
|
| 465 |
+
{
|
| 466 |
+
"type": "boolean"
|
| 467 |
+
},
|
| 468 |
+
{
|
| 469 |
+
"type": "null"
|
| 470 |
+
}
|
| 471 |
+
],
|
| 472 |
+
"title": "Enabled",
|
| 473 |
+
"default": true
|
| 474 |
+
}
|
| 475 |
+
},
|
| 476 |
+
"type": "object",
|
| 477 |
+
"required": [
|
| 478 |
+
"clientId",
|
| 479 |
+
"clientSecret"
|
| 480 |
+
],
|
| 481 |
+
"title": "AccountCreate"
|
| 482 |
+
},
|
| 483 |
+
"AccountUpdate": {
|
| 484 |
+
"properties": {
|
| 485 |
+
"label": {
|
| 486 |
+
"anyOf": [
|
| 487 |
+
{
|
| 488 |
+
"type": "string"
|
| 489 |
+
},
|
| 490 |
+
{
|
| 491 |
+
"type": "null"
|
| 492 |
+
}
|
| 493 |
+
],
|
| 494 |
+
"title": "Label"
|
| 495 |
+
},
|
| 496 |
+
"clientId": {
|
| 497 |
+
"anyOf": [
|
| 498 |
+
{
|
| 499 |
+
"type": "string"
|
| 500 |
+
},
|
| 501 |
+
{
|
| 502 |
+
"type": "null"
|
| 503 |
+
}
|
| 504 |
+
],
|
| 505 |
+
"title": "Clientid"
|
| 506 |
+
},
|
| 507 |
+
"clientSecret": {
|
| 508 |
+
"anyOf": [
|
| 509 |
+
{
|
| 510 |
+
"type": "string"
|
| 511 |
+
},
|
| 512 |
+
{
|
| 513 |
+
"type": "null"
|
| 514 |
+
}
|
| 515 |
+
],
|
| 516 |
+
"title": "Clientsecret"
|
| 517 |
+
},
|
| 518 |
+
"refreshToken": {
|
| 519 |
+
"anyOf": [
|
| 520 |
+
{
|
| 521 |
+
"type": "string"
|
| 522 |
+
},
|
| 523 |
+
{
|
| 524 |
+
"type": "null"
|
| 525 |
+
}
|
| 526 |
+
],
|
| 527 |
+
"title": "Refreshtoken"
|
| 528 |
+
},
|
| 529 |
+
"accessToken": {
|
| 530 |
+
"anyOf": [
|
| 531 |
+
{
|
| 532 |
+
"type": "string"
|
| 533 |
+
},
|
| 534 |
+
{
|
| 535 |
+
"type": "null"
|
| 536 |
+
}
|
| 537 |
+
],
|
| 538 |
+
"title": "Accesstoken"
|
| 539 |
+
},
|
| 540 |
+
"other": {
|
| 541 |
+
"anyOf": [
|
| 542 |
+
{
|
| 543 |
+
"type": "object"
|
| 544 |
+
},
|
| 545 |
+
{
|
| 546 |
+
"type": "null"
|
| 547 |
+
}
|
| 548 |
+
],
|
| 549 |
+
"title": "Other"
|
| 550 |
+
},
|
| 551 |
+
"enabled": {
|
| 552 |
+
"anyOf": [
|
| 553 |
+
{
|
| 554 |
+
"type": "boolean"
|
| 555 |
+
},
|
| 556 |
+
{
|
| 557 |
+
"type": "null"
|
| 558 |
+
}
|
| 559 |
+
],
|
| 560 |
+
"title": "Enabled"
|
| 561 |
+
}
|
| 562 |
+
},
|
| 563 |
+
"type": "object",
|
| 564 |
+
"title": "AccountUpdate"
|
| 565 |
+
},
|
| 566 |
+
"AuthStartBody": {
|
| 567 |
+
"properties": {
|
| 568 |
+
"label": {
|
| 569 |
+
"anyOf": [
|
| 570 |
+
{
|
| 571 |
+
"type": "string"
|
| 572 |
+
},
|
| 573 |
+
{
|
| 574 |
+
"type": "null"
|
| 575 |
+
}
|
| 576 |
+
],
|
| 577 |
+
"title": "Label"
|
| 578 |
+
},
|
| 579 |
+
"enabled": {
|
| 580 |
+
"anyOf": [
|
| 581 |
+
{
|
| 582 |
+
"type": "boolean"
|
| 583 |
+
},
|
| 584 |
+
{
|
| 585 |
+
"type": "null"
|
| 586 |
+
}
|
| 587 |
+
],
|
| 588 |
+
"title": "Enabled",
|
| 589 |
+
"default": true
|
| 590 |
+
}
|
| 591 |
+
},
|
| 592 |
+
"type": "object",
|
| 593 |
+
"title": "AuthStartBody"
|
| 594 |
+
},
|
| 595 |
+
"ChatCompletionRequest": {
|
| 596 |
+
"properties": {
|
| 597 |
+
"model": {
|
| 598 |
+
"anyOf": [
|
| 599 |
+
{
|
| 600 |
+
"type": "string"
|
| 601 |
+
},
|
| 602 |
+
{
|
| 603 |
+
"type": "null"
|
| 604 |
+
}
|
| 605 |
+
],
|
| 606 |
+
"title": "Model"
|
| 607 |
+
},
|
| 608 |
+
"messages": {
|
| 609 |
+
"items": {
|
| 610 |
+
"$ref": "#/components/schemas/ChatMessage"
|
| 611 |
+
},
|
| 612 |
+
"type": "array",
|
| 613 |
+
"title": "Messages"
|
| 614 |
+
},
|
| 615 |
+
"stream": {
|
| 616 |
+
"anyOf": [
|
| 617 |
+
{
|
| 618 |
+
"type": "boolean"
|
| 619 |
+
},
|
| 620 |
+
{
|
| 621 |
+
"type": "null"
|
| 622 |
+
}
|
| 623 |
+
],
|
| 624 |
+
"title": "Stream",
|
| 625 |
+
"default": false
|
| 626 |
+
}
|
| 627 |
+
},
|
| 628 |
+
"type": "object",
|
| 629 |
+
"required": [
|
| 630 |
+
"messages"
|
| 631 |
+
],
|
| 632 |
+
"title": "ChatCompletionRequest"
|
| 633 |
+
},
|
| 634 |
+
"ChatMessage": {
|
| 635 |
+
"properties": {
|
| 636 |
+
"role": {
|
| 637 |
+
"type": "string",
|
| 638 |
+
"title": "Role"
|
| 639 |
+
},
|
| 640 |
+
"content": {
|
| 641 |
+
"title": "Content"
|
| 642 |
+
}
|
| 643 |
+
},
|
| 644 |
+
"type": "object",
|
| 645 |
+
"required": [
|
| 646 |
+
"role",
|
| 647 |
+
"content"
|
| 648 |
+
],
|
| 649 |
+
"title": "ChatMessage"
|
| 650 |
+
},
|
| 651 |
+
"HTTPValidationError": {
|
| 652 |
+
"properties": {
|
| 653 |
+
"detail": {
|
| 654 |
+
"items": {
|
| 655 |
+
"$ref": "#/components/schemas/ValidationError"
|
| 656 |
+
},
|
| 657 |
+
"type": "array",
|
| 658 |
+
"title": "Detail"
|
| 659 |
+
}
|
| 660 |
+
},
|
| 661 |
+
"type": "object",
|
| 662 |
+
"title": "HTTPValidationError"
|
| 663 |
+
},
|
| 664 |
+
"ValidationError": {
|
| 665 |
+
"properties": {
|
| 666 |
+
"loc": {
|
| 667 |
+
"items": {
|
| 668 |
+
"anyOf": [
|
| 669 |
+
{
|
| 670 |
+
"type": "string"
|
| 671 |
+
},
|
| 672 |
+
{
|
| 673 |
+
"type": "integer"
|
| 674 |
+
}
|
| 675 |
+
]
|
| 676 |
+
},
|
| 677 |
+
"type": "array",
|
| 678 |
+
"title": "Location"
|
| 679 |
+
},
|
| 680 |
+
"msg": {
|
| 681 |
+
"type": "string",
|
| 682 |
+
"title": "Message"
|
| 683 |
+
},
|
| 684 |
+
"type": {
|
| 685 |
+
"type": "string",
|
| 686 |
+
"title": "Error Type"
|
| 687 |
+
}
|
| 688 |
+
},
|
| 689 |
+
"type": "object",
|
| 690 |
+
"required": [
|
| 691 |
+
"loc",
|
| 692 |
+
"msg",
|
| 693 |
+
"type"
|
| 694 |
+
],
|
| 695 |
+
"title": "ValidationError"
|
| 696 |
+
}
|
| 697 |
+
}
|
| 698 |
+
}
|
| 699 |
+
}
|
query_amazon_models.py
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""
|
| 3 |
+
直接查询 Amazon Q 服务来获取支持的模型
|
| 4 |
+
"""
|
| 5 |
+
|
| 6 |
+
import requests
|
| 7 |
+
import json
|
| 8 |
+
import time
|
| 9 |
+
from replicate import send_chat_request
|
| 10 |
+
|
| 11 |
+
def get_available_models_from_amazon_q():
|
| 12 |
+
"""尝试通过特殊查询获取 Amazon Q 支持的模型"""
|
| 13 |
+
|
| 14 |
+
# 尝试不同的查询方式来获取模型信息
|
| 15 |
+
test_queries = [
|
| 16 |
+
"你支持哪些模型?",
|
| 17 |
+
"有哪些可用的模型?",
|
| 18 |
+
"列出所有支持的模型名称",
|
| 19 |
+
"What models are available?",
|
| 20 |
+
"List all supported models",
|
| 21 |
+
"Show model options",
|
| 22 |
+
"model list",
|
| 23 |
+
"models",
|
| 24 |
+
"help"
|
| 25 |
+
]
|
| 26 |
+
|
| 27 |
+
print("🔍 通过查询尝试获取 Amazon Q 支持的模型信息")
|
| 28 |
+
print("=" * 60)
|
| 29 |
+
|
| 30 |
+
# 这里需要一个有效的 access token,我们先尝试从现有账号获取
|
| 31 |
+
try:
|
| 32 |
+
# 检查是否有可用账号
|
| 33 |
+
accounts_response = requests.get("http://localhost:8000/v2/accounts", timeout=10)
|
| 34 |
+
if accounts_response.status_code != 200:
|
| 35 |
+
print("❌ 无法获取账号信息")
|
| 36 |
+
return
|
| 37 |
+
|
| 38 |
+
accounts = accounts_response.json()
|
| 39 |
+
enabled_accounts = [acc for acc in accounts if acc.get("enabled", False)]
|
| 40 |
+
|
| 41 |
+
if not enabled_accounts:
|
| 42 |
+
print("❌ 没有可用的账号")
|
| 43 |
+
return
|
| 44 |
+
|
| 45 |
+
account = enabled_accounts[0]
|
| 46 |
+
access_token = account.get("accessToken")
|
| 47 |
+
|
| 48 |
+
if not access_token:
|
| 49 |
+
# 尝试刷新 token
|
| 50 |
+
print("🔄 刷新 access token...")
|
| 51 |
+
refresh_response = requests.post(f"http://localhost:8000/v2/accounts/{account['id']}/refresh", timeout=10)
|
| 52 |
+
if refresh_response.status_code == 200:
|
| 53 |
+
updated_account = refresh_response.json()
|
| 54 |
+
access_token = updated_account.get("accessToken")
|
| 55 |
+
|
| 56 |
+
if not access_token:
|
| 57 |
+
print("❌ 无法获取 access token")
|
| 58 |
+
return
|
| 59 |
+
|
| 60 |
+
print(f"✅ 获取到 access token,开始查询...")
|
| 61 |
+
|
| 62 |
+
# 对每个查询进行测试
|
| 63 |
+
for i, query in enumerate(test_queries, 1):
|
| 64 |
+
print(f"\n[{i}/{len(test_queries)}] 查询: {query}")
|
| 65 |
+
print("-" * 40)
|
| 66 |
+
|
| 67 |
+
try:
|
| 68 |
+
text, _, tracker = send_chat_request(
|
| 69 |
+
access_token,
|
| 70 |
+
[{"role": "user", "content": query}],
|
| 71 |
+
model=None, # 不指定模型,使用默认
|
| 72 |
+
stream=False,
|
| 73 |
+
timeout=(10, 30)
|
| 74 |
+
)
|
| 75 |
+
|
| 76 |
+
if text:
|
| 77 |
+
print(f"响应: {text[:200]}...")
|
| 78 |
+
|
| 79 |
+
# 检查响应中是否包含模型信息
|
| 80 |
+
model_keywords = ["model", "claude", "anthropic", "sonnet", "haiku", "opus"]
|
| 81 |
+
found_models = []
|
| 82 |
+
|
| 83 |
+
for keyword in model_keywords:
|
| 84 |
+
if keyword.lower() in text.lower():
|
| 85 |
+
found_models.append(keyword)
|
| 86 |
+
|
| 87 |
+
if found_models:
|
| 88 |
+
print(f"🔍 发现模型相关关键词: {', '.join(found_models)}")
|
| 89 |
+
else:
|
| 90 |
+
print("❌ 无响应")
|
| 91 |
+
|
| 92 |
+
except Exception as e:
|
| 93 |
+
print(f"❌ 查询失败: {e}")
|
| 94 |
+
|
| 95 |
+
time.sleep(1) # 避免请求过快
|
| 96 |
+
|
| 97 |
+
except Exception as e:
|
| 98 |
+
print(f"❌ 获取模型信息失败: {e}")
|
| 99 |
+
|
| 100 |
+
def test_model_variations():
|
| 101 |
+
"""测试模型名称的变体"""
|
| 102 |
+
# 基于已知可用的 claude-sonnet-4,测试可能的变体
|
| 103 |
+
variations = [
|
| 104 |
+
"claude-sonnet-4",
|
| 105 |
+
"Claude-Sonnet-4",
|
| 106 |
+
"CLAUDE-SONNET-4",
|
| 107 |
+
"sonnet-4",
|
| 108 |
+
"claude-4-sonnet",
|
| 109 |
+
"claude-4",
|
| 110 |
+
"sonnet4",
|
| 111 |
+
"anthropic-sonnet-4",
|
| 112 |
+
"anthropic-claude-sonnet-4",
|
| 113 |
+
]
|
| 114 |
+
|
| 115 |
+
print("\n🧪 测试模型名称变体")
|
| 116 |
+
print("=" * 40)
|
| 117 |
+
|
| 118 |
+
for model in variations:
|
| 119 |
+
try:
|
| 120 |
+
text, _, tracker = send_chat_request(
|
| 121 |
+
"dummy_token", # 这里会被替换为真实 token
|
| 122 |
+
[{"role": "user", "content": "test"}],
|
| 123 |
+
model=model,
|
| 124 |
+
stream=False,
|
| 125 |
+
timeout=(5, 15)
|
| 126 |
+
)
|
| 127 |
+
|
| 128 |
+
if text:
|
| 129 |
+
print(f"✅ {model} - 可用")
|
| 130 |
+
else:
|
| 131 |
+
print(f"❌ {model} - 不可用")
|
| 132 |
+
|
| 133 |
+
except Exception as e:
|
| 134 |
+
print(f"❌ {model} - 错误: {str(e)[:50]}")
|
| 135 |
+
|
| 136 |
+
time.sleep(0.5)
|
| 137 |
+
|
| 138 |
+
if __name__ == "__main__":
|
| 139 |
+
get_available_models_from_amazon_q()
|
| 140 |
+
# test_model_variations() # 暂时不运行,因为需要有效token
|
quick_test.py
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""
|
| 3 |
+
简单的 Amazon Q API 测试脚本
|
| 4 |
+
"""
|
| 5 |
+
|
| 6 |
+
import requests
|
| 7 |
+
import json
|
| 8 |
+
|
| 9 |
+
def test_api():
|
| 10 |
+
"""测试 API 基本功能"""
|
| 11 |
+
url = "http://localhost:8000/v1/chat/completions"
|
| 12 |
+
|
| 13 |
+
payload = {
|
| 14 |
+
"model": "claude-sonnet-4",
|
| 15 |
+
"messages": [
|
| 16 |
+
{"role": "user", "content": "你好,请简单介绍一下你自己"}
|
| 17 |
+
],
|
| 18 |
+
"stream": False
|
| 19 |
+
}
|
| 20 |
+
|
| 21 |
+
try:
|
| 22 |
+
response = requests.post(url, json=payload, timeout=30)
|
| 23 |
+
|
| 24 |
+
if response.status_code == 200:
|
| 25 |
+
result = response.json()
|
| 26 |
+
content = result.get("choices", [{}])[0].get("message", {}).get("content", "")
|
| 27 |
+
print("✅ API 测试成功!")
|
| 28 |
+
print(f"响应内容: {content}")
|
| 29 |
+
return True
|
| 30 |
+
else:
|
| 31 |
+
print(f"❌ API 测试失败: {response.status_code}")
|
| 32 |
+
print(f"错误信息: {response.text}")
|
| 33 |
+
return False
|
| 34 |
+
|
| 35 |
+
except Exception as e:
|
| 36 |
+
print(f"❌ 请求异常: {e}")
|
| 37 |
+
return False
|
| 38 |
+
|
| 39 |
+
def test_streaming():
|
| 40 |
+
"""测试流式响应"""
|
| 41 |
+
url = "http://localhost:8000/v1/chat/completions"
|
| 42 |
+
|
| 43 |
+
payload = {
|
| 44 |
+
"model": "claude-sonnet-4",
|
| 45 |
+
"messages": [
|
| 46 |
+
{"role": "user", "content": "请用一句话介绍人工智能"}
|
| 47 |
+
],
|
| 48 |
+
"stream": True
|
| 49 |
+
}
|
| 50 |
+
|
| 51 |
+
try:
|
| 52 |
+
response = requests.post(url, json=payload, stream=True, timeout=30)
|
| 53 |
+
|
| 54 |
+
if response.status_code == 200:
|
| 55 |
+
print("✅ 流式测试成功!")
|
| 56 |
+
print("流式响应:")
|
| 57 |
+
for line in response.iter_lines():
|
| 58 |
+
if line:
|
| 59 |
+
line_str = line.decode('utf-8')
|
| 60 |
+
if line_str.startswith('data: ') and line_str != 'data: [DONE]':
|
| 61 |
+
data = json.loads(line_str[6:])
|
| 62 |
+
content = data.get("choices", [{}])[0].get("delta", {}).get("content", "")
|
| 63 |
+
if content:
|
| 64 |
+
print(content, end='', flush=True)
|
| 65 |
+
print() # 换行
|
| 66 |
+
return True
|
| 67 |
+
else:
|
| 68 |
+
print(f"❌ 流式测试失败: {response.status_code}")
|
| 69 |
+
return False
|
| 70 |
+
|
| 71 |
+
except Exception as e:
|
| 72 |
+
print(f"❌ 流式请求异常: {e}")
|
| 73 |
+
return False
|
| 74 |
+
|
| 75 |
+
if __name__ == "__main__":
|
| 76 |
+
print("🧪 Amazon Q API 快速测试")
|
| 77 |
+
print("=" * 40)
|
| 78 |
+
|
| 79 |
+
# 测试基本功能
|
| 80 |
+
print("1. 测试基本对话功能...")
|
| 81 |
+
test_api()
|
| 82 |
+
|
| 83 |
+
print("\n2. 测试流式响应...")
|
| 84 |
+
test_streaming()
|
| 85 |
+
|
| 86 |
+
print("\n✨ 测试完成!")
|
test_models.py
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""
|
| 3 |
+
测试 Amazon Q API 可用模型的脚本
|
| 4 |
+
"""
|
| 5 |
+
|
| 6 |
+
import requests
|
| 7 |
+
import json
|
| 8 |
+
import time
|
| 9 |
+
from typing import List, Dict, Optional
|
| 10 |
+
|
| 11 |
+
# API 配置
|
| 12 |
+
BASE_URL = "http://localhost:8000"
|
| 13 |
+
API_KEY = "" # 根据你的 .env 配置设置,如果为空则使用开发模式
|
| 14 |
+
|
| 15 |
+
# 常见的 Claude 模型列表(基于 Amazon Q 可能支持的模型)
|
| 16 |
+
TEST_MODELS = [
|
| 17 |
+
"claude-sonnet-4",
|
| 18 |
+
"claude-sonnet-3.5",
|
| 19 |
+
"claude-haiku-3.5",
|
| 20 |
+
"claude-opus-3",
|
| 21 |
+
"claude-sonnet-3",
|
| 22 |
+
"claude-haiku-3",
|
| 23 |
+
"claude-instant-1.2",
|
| 24 |
+
"anthropic.claude-3-sonnet-20240229-v1:0",
|
| 25 |
+
"anthropic.claude-3-haiku-20240307-v1:0",
|
| 26 |
+
"anthropic.claude-3-opus-20240229-v1:0",
|
| 27 |
+
]
|
| 28 |
+
|
| 29 |
+
def test_model(model_name: str, api_key: str = "") -> Dict[str, any]:
|
| 30 |
+
"""测试单个模型是否可用"""
|
| 31 |
+
url = f"{BASE_URL}/v1/chat/completions"
|
| 32 |
+
|
| 33 |
+
headers = {
|
| 34 |
+
"Content-Type": "application/json",
|
| 35 |
+
}
|
| 36 |
+
|
| 37 |
+
if api_key:
|
| 38 |
+
headers["Authorization"] = f"Bearer {api_key}"
|
| 39 |
+
|
| 40 |
+
payload = {
|
| 41 |
+
"model": model_name,
|
| 42 |
+
"messages": [
|
| 43 |
+
{"role": "user", "content": "请简单回复:你好"}
|
| 44 |
+
],
|
| 45 |
+
"stream": False,
|
| 46 |
+
"max_tokens": 10
|
| 47 |
+
}
|
| 48 |
+
|
| 49 |
+
try:
|
| 50 |
+
response = requests.post(url, headers=headers, json=payload, timeout=30)
|
| 51 |
+
|
| 52 |
+
result = {
|
| 53 |
+
"model": model_name,
|
| 54 |
+
"status_code": response.status_code,
|
| 55 |
+
"available": response.status_code == 200,
|
| 56 |
+
"error": None,
|
| 57 |
+
"response_preview": None
|
| 58 |
+
}
|
| 59 |
+
|
| 60 |
+
if response.status_code == 200:
|
| 61 |
+
try:
|
| 62 |
+
data = response.json()
|
| 63 |
+
content = data.get("choices", [{}])[0].get("message", {}).get("content", "")
|
| 64 |
+
result["response_preview"] = content[:100] # 只显示前100个字符
|
| 65 |
+
except:
|
| 66 |
+
result["response_preview"] = "解析响应失败"
|
| 67 |
+
else:
|
| 68 |
+
result["error"] = response.text[:200] # 只显示前200个字符的错误信息
|
| 69 |
+
|
| 70 |
+
except requests.exceptions.Timeout:
|
| 71 |
+
result = {
|
| 72 |
+
"model": model_name,
|
| 73 |
+
"status_code": None,
|
| 74 |
+
"available": False,
|
| 75 |
+
"error": "请求超时",
|
| 76 |
+
"response_preview": None
|
| 77 |
+
}
|
| 78 |
+
except Exception as e:
|
| 79 |
+
result = {
|
| 80 |
+
"model": model_name,
|
| 81 |
+
"status_code": None,
|
| 82 |
+
"available": False,
|
| 83 |
+
"error": str(e)[:200],
|
| 84 |
+
"response_preview": None
|
| 85 |
+
}
|
| 86 |
+
|
| 87 |
+
return result
|
| 88 |
+
|
| 89 |
+
def check_api_health() -> bool:
|
| 90 |
+
"""检查 API 服务是否健康"""
|
| 91 |
+
try:
|
| 92 |
+
response = requests.get(f"{BASE_URL}/healthz", timeout=10)
|
| 93 |
+
return response.status_code == 200
|
| 94 |
+
except:
|
| 95 |
+
return False
|
| 96 |
+
|
| 97 |
+
def check_accounts() -> bool:
|
| 98 |
+
"""检查是否有可用账号"""
|
| 99 |
+
try:
|
| 100 |
+
headers = {"Authorization": f"Bearer {API_KEY}"} if API_KEY else {}
|
| 101 |
+
response = requests.get(f"{BASE_URL}/v2/accounts", headers=headers, timeout=10)
|
| 102 |
+
if response.status_code == 200:
|
| 103 |
+
accounts = response.json()
|
| 104 |
+
enabled_accounts = [acc for acc in accounts if acc.get("enabled", False)]
|
| 105 |
+
return len(enabled_accounts) > 0
|
| 106 |
+
return False
|
| 107 |
+
except:
|
| 108 |
+
return False
|
| 109 |
+
|
| 110 |
+
def main():
|
| 111 |
+
"""主函数"""
|
| 112 |
+
print("🔍 Amazon Q API 模型测试脚本")
|
| 113 |
+
print("=" * 50)
|
| 114 |
+
|
| 115 |
+
# 检查 API 服务状态
|
| 116 |
+
print("📡 检查 API 服务状态...")
|
| 117 |
+
if not check_api_health():
|
| 118 |
+
print("❌ API 服务不可用,请确保服务正在运行在 http://localhost:8000")
|
| 119 |
+
return
|
| 120 |
+
|
| 121 |
+
print("✅ API 服务正常")
|
| 122 |
+
|
| 123 |
+
# 检查账号状态
|
| 124 |
+
print("👤 检查可用账号...")
|
| 125 |
+
if not check_accounts():
|
| 126 |
+
print("❌ 没有可用的账号,请先添加并启用 Amazon Q 账号")
|
| 127 |
+
return
|
| 128 |
+
|
| 129 |
+
print("✅ 发现可用账号")
|
| 130 |
+
|
| 131 |
+
# 测试模型
|
| 132 |
+
print(f"\n🧪 开始测试 {len(TEST_MODELS)} 个模型...")
|
| 133 |
+
print("-" * 80)
|
| 134 |
+
|
| 135 |
+
available_models = []
|
| 136 |
+
failed_models = []
|
| 137 |
+
|
| 138 |
+
for i, model in enumerate(TEST_MODELS, 1):
|
| 139 |
+
print(f"[{i}/{len(TEST_MODELS)}] 测试: {model}...", end=" ")
|
| 140 |
+
|
| 141 |
+
result = test_model(model, API_KEY)
|
| 142 |
+
|
| 143 |
+
if result["available"]:
|
| 144 |
+
print("✅ 可用")
|
| 145 |
+
available_models.append(model)
|
| 146 |
+
if result["response_preview"]:
|
| 147 |
+
print(f" 响应预览: {result['response_preview']}")
|
| 148 |
+
else:
|
| 149 |
+
print("❌ 不可用")
|
| 150 |
+
failed_models.append((model, result["error"]))
|
| 151 |
+
|
| 152 |
+
# 避免请求过于频繁
|
| 153 |
+
time.sleep(0.5)
|
| 154 |
+
|
| 155 |
+
# 输出结果总结
|
| 156 |
+
print("\n" + "=" * 80)
|
| 157 |
+
print("📊 测试结果总结")
|
| 158 |
+
print("=" * 80)
|
| 159 |
+
|
| 160 |
+
if available_models:
|
| 161 |
+
print(f"\n✅ 可用模型 ({len(available_models)} 个):")
|
| 162 |
+
for model in available_models:
|
| 163 |
+
print(f" • {model}")
|
| 164 |
+
else:
|
| 165 |
+
print("\n❌ 没有发现可用的模型")
|
| 166 |
+
|
| 167 |
+
if failed_models:
|
| 168 |
+
print(f"\n❌ 不可用模型 ({len(failed_models)} 个):")
|
| 169 |
+
for model, error in failed_models[:5]: # 只显示前5个错误
|
| 170 |
+
print(f" • {model}: {error}")
|
| 171 |
+
if len(failed_models) > 5:
|
| 172 |
+
print(f" ... 还有 {len(failed_models) - 5} 个模型不可用")
|
| 173 |
+
|
| 174 |
+
# 生成配置建议
|
| 175 |
+
if available_models:
|
| 176 |
+
print(f"\n💡 建议配置:")
|
| 177 |
+
print(f"推荐使用: {available_models[0]}")
|
| 178 |
+
print(f"在代码中使用: model = \"{available_models[0]}\"")
|
| 179 |
+
|
| 180 |
+
# 保存可用模型到文件
|
| 181 |
+
with open("available_models.txt", "w", encoding="utf-8") as f:
|
| 182 |
+
f.write("可用模型列表:\n")
|
| 183 |
+
for model in available_models:
|
| 184 |
+
f.write(f"{model}\n")
|
| 185 |
+
print(f"📁 可用模型已保存到: available_models.txt")
|
| 186 |
+
|
| 187 |
+
if __name__ == "__main__":
|
| 188 |
+
main()
|