Spaces:
Sleeping
Sleeping
Sun Jun 8 12:09:47 CST 2025
Browse files- .clinerules +166 -0
- .gitignore +3 -0
- Dockerfile +16 -0
- app.py +191 -0
- key_selector.py +15 -0
- memory-bank/activeContext.md +25 -0
- memory-bank/productContext.md +22 -0
- memory-bank/progress.md +31 -0
- memory-bank/projectbrief.md +26 -0
- memory-bank/systemPatterns.md +32 -0
- memory-bank/techContext.md +26 -0
- push.sh +3 -0
- requirements.txt +3 -0
.clinerules
ADDED
@@ -0,0 +1,166 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# 自定义指令
|
2 |
+
CUSTOM_INSTRUCTIONS = """
|
3 |
+
# 基本配置
|
4 |
+
env_tool(虚拟环境管理工具): conda
|
5 |
+
env_name(虚拟环境名称): api-proxy
|
6 |
+
env_activate_cmd(激活虚拟环境命令): conda activate {env_tool}
|
7 |
+
|
8 |
+
# 角色
|
9 |
+
你是一个基于python开发工程师
|
10 |
+
|
11 |
+
# 项目要求
|
12 |
+
- 使用 fastapi 开发一个实现多种 api 代理转发的工具
|
13 |
+
|
14 |
+
# 知识参考
|
15 |
+
当你需要查询相关源码时,请访问下面的链接:
|
16 |
+
|
17 |
+
---
|
18 |
+
|
19 |
+
# 虚拟环境要求
|
20 |
+
- 虚拟环境工具:{env_tool}
|
21 |
+
- 使用名为{env_name}的虚拟环境,如果没有则创建,如果有则运行下面的命令行:{env_activate_cmd}
|
22 |
+
|
23 |
+
# 项目管理
|
24 |
+
- 使用 Memory Bank作为项目管理工具
|
25 |
+
- 用户可以到当前目录下通过指令进行任务管理
|
26 |
+
- Memory Bank 中使用中文记录的项目信息
|
27 |
+
|
28 |
+
# 交流
|
29 |
+
- 如非特别指明,必须使用中文进行交流
|
30 |
+
- 如果需求不明确时,必须找用户进行需求调研,调研时,一次只提问一个问题
|
31 |
+
|
32 |
+
"""
|
33 |
+
# 自动批准规则
|
34 |
+
AUTO_APPROVE = true
|
35 |
+
|
36 |
+
|
37 |
+
---
|
38 |
+
description: Describes Cline's Memory Bank system, its structure, and workflows for maintaining project knowledge across sessions.
|
39 |
+
author: https://github.com/nickbaumann98
|
40 |
+
version: 1.0
|
41 |
+
tags: ["memory-bank", "knowledge-base", "core-behavior", "documentation-protocol"]
|
42 |
+
globs: ["memory-bank/**/*.md", "*"]
|
43 |
+
---
|
44 |
+
# Cline's Memory Bank
|
45 |
+
|
46 |
+
I am Cline, an expert software engineer with a unique characteristic: my memory resets completely between sessions. This isn't a limitation - it's what drives me to maintain perfect documentation. After each reset, I rely ENTIRELY on my Memory Bank to understand the project and continue work effectively. I MUST read ALL memory bank files at the start of EVERY task - this is not optional.
|
47 |
+
|
48 |
+
## Memory Bank Structure
|
49 |
+
|
50 |
+
The Memory Bank consists of core files and optional context files, all in Markdown format. Files build upon each other in a clear hierarchy:
|
51 |
+
|
52 |
+
```mermaid
|
53 |
+
flowchart TD
|
54 |
+
PB[projectbrief.md] --> PC[productContext.md]
|
55 |
+
PB --> SP[systemPatterns.md]
|
56 |
+
PB --> TC[techContext.md]
|
57 |
+
|
58 |
+
PC --> AC[activeContext.md]
|
59 |
+
SP --> AC
|
60 |
+
TC --> AC
|
61 |
+
|
62 |
+
AC --> P[progress.md]
|
63 |
+
```
|
64 |
+
|
65 |
+
### Core Files (Required)
|
66 |
+
1. `projectbrief.md`
|
67 |
+
- Foundation document that shapes all other files
|
68 |
+
- Created at project start if it doesn't exist
|
69 |
+
- Defines core requirements and goals
|
70 |
+
- Source of truth for project scope
|
71 |
+
|
72 |
+
2. `productContext.md`
|
73 |
+
- Why this project exists
|
74 |
+
- Problems it solves
|
75 |
+
- How it should work
|
76 |
+
- User experience goals
|
77 |
+
|
78 |
+
3. `activeContext.md`
|
79 |
+
- Current work focus
|
80 |
+
- Recent changes
|
81 |
+
- Next steps
|
82 |
+
- Active decisions and considerations
|
83 |
+
- Important patterns and preferences
|
84 |
+
- Learnings and project insights
|
85 |
+
|
86 |
+
4. `systemPatterns.md`
|
87 |
+
- System architecture
|
88 |
+
- Key technical decisions
|
89 |
+
- Design patterns in use
|
90 |
+
- Component relationships
|
91 |
+
- Critical implementation paths
|
92 |
+
|
93 |
+
5. `techContext.md`
|
94 |
+
- Technologies used
|
95 |
+
- Development setup
|
96 |
+
- Technical constraints
|
97 |
+
- Dependencies
|
98 |
+
- Tool usage patterns
|
99 |
+
|
100 |
+
6. `progress.md`
|
101 |
+
- What works
|
102 |
+
- What's left to build
|
103 |
+
- Current status
|
104 |
+
- Known issues
|
105 |
+
- Evolution of project decisions
|
106 |
+
|
107 |
+
### Additional Context
|
108 |
+
Create additional files/folders within memory-bank/ when they help organize:
|
109 |
+
- Complex feature documentation
|
110 |
+
- Integration specifications
|
111 |
+
- API documentation
|
112 |
+
- Testing strategies
|
113 |
+
- Deployment procedures
|
114 |
+
|
115 |
+
## Core Workflows
|
116 |
+
|
117 |
+
### Plan Mode
|
118 |
+
```mermaid
|
119 |
+
flowchart TD
|
120 |
+
Start[Start] --> ReadFiles[Read Memory Bank]
|
121 |
+
ReadFiles --> CheckFiles{Files Complete?}
|
122 |
+
|
123 |
+
CheckFiles -->|No| Plan[Create Plan]
|
124 |
+
Plan --> Document[Document in Chat]
|
125 |
+
|
126 |
+
CheckFiles -->|Yes| Verify[Verify Context]
|
127 |
+
Verify --> Strategy[Develop Strategy]
|
128 |
+
Strategy --> Present[Present Approach]
|
129 |
+
```
|
130 |
+
|
131 |
+
### Act Mode
|
132 |
+
```mermaid
|
133 |
+
flowchart TD
|
134 |
+
Start[Start] --> Context[Check Memory Bank]
|
135 |
+
Context --> Update[Update Documentation]
|
136 |
+
Update --> Execute[Execute Task]
|
137 |
+
Execute --> Document[Document Changes]
|
138 |
+
```
|
139 |
+
|
140 |
+
## Documentation Updates
|
141 |
+
|
142 |
+
Memory Bank updates occur when:
|
143 |
+
1. Discovering new project patterns
|
144 |
+
2. After implementing significant changes
|
145 |
+
3. When user requests with **update memory bank** (MUST review ALL files)
|
146 |
+
4. When context needs clarification
|
147 |
+
|
148 |
+
```mermaid
|
149 |
+
flowchart TD
|
150 |
+
Start[Update Process]
|
151 |
+
|
152 |
+
subgraph Process
|
153 |
+
P1[Review ALL Files]
|
154 |
+
P2[Document Current State]
|
155 |
+
P3[Clarify Next Steps]
|
156 |
+
P4[Document Insights & Patterns]
|
157 |
+
|
158 |
+
P1 --> P2 --> P3 --> P4
|
159 |
+
end
|
160 |
+
|
161 |
+
Start --> Process
|
162 |
+
```
|
163 |
+
|
164 |
+
Note: When triggered by **update memory bank**, I MUST review every memory bank file, even if some don't require updates. Focus particularly on activeContext.md and progress.md as they track current state.
|
165 |
+
|
166 |
+
REMEMBER: After every memory reset, I begin completely fresh. The Memory Bank is my only link to previous work. It must be maintained with precision and clarity, as my effectiveness depends entirely on its accuracy.
|
.gitignore
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
**/__pycache__/
|
2 |
+
README.md
|
3 |
+
.env
|
Dockerfile
ADDED
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Read the doc: https://huggingface.co/docs/hub/spaces-sdks-docker
|
2 |
+
# you will also find guides on how best to write your Dockerfile
|
3 |
+
|
4 |
+
FROM python:3.9
|
5 |
+
|
6 |
+
RUN useradd -m -u 1000 user
|
7 |
+
USER user
|
8 |
+
ENV PATH="/home/user/.local/bin:$PATH"
|
9 |
+
|
10 |
+
WORKDIR /app
|
11 |
+
|
12 |
+
COPY --chown=user ./requirements.txt requirements.txt
|
13 |
+
RUN pip install --no-cache-dir --upgrade -r requirements.txt
|
14 |
+
|
15 |
+
COPY --chown=user . /app
|
16 |
+
CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]
|
app.py
ADDED
@@ -0,0 +1,191 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from fastapi import FastAPI, Request, HTTPException, Response
|
2 |
+
from fastapi.responses import StreamingResponse
|
3 |
+
import httpx
|
4 |
+
import logging
|
5 |
+
import os, json
|
6 |
+
import re # 用于URL路径处理
|
7 |
+
from pprint import pprint
|
8 |
+
from key_selector import KeySelector
|
9 |
+
|
10 |
+
def get_target_url(url: str) -> str:
|
11 |
+
"""将url参数变了转换为合法的目标url;from http/ or https/ to http:// or https://"""
|
12 |
+
url = re.sub(r"^http/", "http://", url)
|
13 |
+
url = re.sub(r"^https/", "https://", url)
|
14 |
+
return url
|
15 |
+
|
16 |
+
app = FastAPI()
|
17 |
+
|
18 |
+
# 配置日志
|
19 |
+
logging.basicConfig(level=logging.INFO)
|
20 |
+
logger = logging.getLogger("uvicorn.error")
|
21 |
+
|
22 |
+
# 从环境变量获取配置
|
23 |
+
# UPSTREAM_HOST = os.getenv("UPSTREAM_HOST", "http://127.0.0.1") # 必须包含端口号
|
24 |
+
# AUTH_TOKEN = os.getenv("AUTH_TOKEN", "YIG8ANC8q2QxFV_Gf8qwkPdBj2EpsqGqlfc3qvSdg7ksVkZcokOUtQn43XGK0NK3UUdBlIkYzNWefco_Wu4RcKnB0kpNgtZ2nTeqNum0i3fTUEhEcWSlJtT8FQgRK7bi") # 安全认证令牌
|
25 |
+
X_Goog_Api_Key = os.getenv("X_Goog_Api_Key", "")
|
26 |
+
|
27 |
+
@app.get("/")
|
28 |
+
async def read_root():
|
29 |
+
return {"message": "FastAPI Proxy is running"}
|
30 |
+
|
31 |
+
@app.post("/v25/{path:path}")
|
32 |
+
async def proxy(request: Request, path: str):
|
33 |
+
# 添加流式请求判断逻辑
|
34 |
+
is_streaming = ":streamGenerateContent" in path.lower()
|
35 |
+
print(f"path: {path}")
|
36 |
+
# path = "https/generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent"
|
37 |
+
# target_url = "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent"
|
38 |
+
target_url = get_target_url(path)
|
39 |
+
# target_url = f"{target_url}?key={X_Goog_Api_Key}"
|
40 |
+
print(f"target_url: {target_url}")
|
41 |
+
method = request.method
|
42 |
+
headers = {k: v for k, v in request.headers.items()
|
43 |
+
# if k.lower() not in ["host", "connection", "Postman-Token", "content-length"]}
|
44 |
+
if k.lower() not in ["host", "content-length"]}
|
45 |
+
|
46 |
+
key_selector = KeySelector()
|
47 |
+
# print('apikey',key_selector.get_api_key()['key_value'])
|
48 |
+
|
49 |
+
headers["X-Goog-Api-Key"] = key_selector.get_api_key()['key_value']
|
50 |
+
# print(key_selector.api_key_info.key_value)
|
51 |
+
# headers["host"] = "generativelanguage.googleapis.com"
|
52 |
+
|
53 |
+
try:
|
54 |
+
# 关键修复:禁用KeepAlive防止连接冲突
|
55 |
+
transport = httpx.AsyncHTTPTransport(retries=3, http1=True)
|
56 |
+
|
57 |
+
async with httpx.AsyncClient(
|
58 |
+
transport=transport,
|
59 |
+
timeout=httpx.Timeout(300.0, connect=30.0)
|
60 |
+
) as client:
|
61 |
+
# 处理请求体
|
62 |
+
req_content = await request.body()
|
63 |
+
print(f"Request headers: {headers}")
|
64 |
+
# print(f"req_content: {req_content}")
|
65 |
+
# req_content_str = req_content.decode('utf-8') # 假设内容是 UTF-8 编码
|
66 |
+
# print(f"req_content_str: {req_content_str}")
|
67 |
+
print(f'target_url: {target_url}')
|
68 |
+
print(f'method: {method}')
|
69 |
+
# 发送请求到上游服务
|
70 |
+
response = await client.request(
|
71 |
+
method=method,
|
72 |
+
url=target_url,
|
73 |
+
headers=headers,
|
74 |
+
content=req_content,
|
75 |
+
follow_redirects=True # 自动处理重定向
|
76 |
+
)
|
77 |
+
|
78 |
+
if is_streaming:
|
79 |
+
# 流式响应处理
|
80 |
+
async def stream_generator():
|
81 |
+
try:
|
82 |
+
async for chunk in response.aiter_bytes():
|
83 |
+
yield chunk
|
84 |
+
except Exception as e:
|
85 |
+
logger.error(f"Stream interrupted: {str(e)}")
|
86 |
+
yield json.dumps({"error": "流中断"}).encode()
|
87 |
+
|
88 |
+
# 移除冲突头部
|
89 |
+
headers = dict(response.headers)
|
90 |
+
headers.pop("Content-Length", None)
|
91 |
+
|
92 |
+
return StreamingResponse(
|
93 |
+
content=stream_generator(),
|
94 |
+
status_code=response.status_code,
|
95 |
+
headers=headers,
|
96 |
+
media_type="application/x-ndjson" # Gemini流式格式
|
97 |
+
)
|
98 |
+
else:
|
99 |
+
|
100 |
+
print(f"response.status_code: {response.status_code}")
|
101 |
+
print(f"response.text: {response.text}")
|
102 |
+
# 解析 JSON 字符串
|
103 |
+
try:
|
104 |
+
data = json.loads(response.text)
|
105 |
+
# 格式化输出 JSON 数据
|
106 |
+
formatted_json = json.dumps(data, ensure_ascii=False, indent=4)
|
107 |
+
print('formatted_json')
|
108 |
+
print(formatted_json)
|
109 |
+
# return formatted_json
|
110 |
+
return Response(
|
111 |
+
content=formatted_json,
|
112 |
+
media_type="application/json"
|
113 |
+
)
|
114 |
+
except json.JSONDecodeError as e:
|
115 |
+
print(f"Error decoding JSON: {e}")
|
116 |
+
|
117 |
+
|
118 |
+
# # 详细记录错误响应
|
119 |
+
# if response.status_code >= 400:
|
120 |
+
# error_detail = response.text[:1000] # 增加错误详情长度
|
121 |
+
# logger.error(f"Upstream error {response.status_code}: {error_detail}")
|
122 |
+
# # 可选:记录完整响应到文件
|
123 |
+
# # with open("error.log", "a") as f:
|
124 |
+
# # f.write(f"\n--- {target_url} ---\n{response.text}\n")
|
125 |
+
|
126 |
+
# # 流式传输响应
|
127 |
+
# return StreamingResponse(
|
128 |
+
# content=response.aiter_bytes(),
|
129 |
+
# status_code=response.status_code,
|
130 |
+
# headers=dict(response.headers)
|
131 |
+
# )
|
132 |
+
|
133 |
+
except httpx.ConnectError as e:
|
134 |
+
logger.error(f"Connection failed to {target_url}: {e}")
|
135 |
+
raise HTTPException(502, f"无法连接到上游服务: {target_url}") # Modified error message
|
136 |
+
except httpx.ReadTimeout as e:
|
137 |
+
logger.error(f"Timeout: {e}")
|
138 |
+
raise HTTPException(504, "上游服务响应超时")
|
139 |
+
except httpx.HTTPError as e: # 捕获所有HTTP异常
|
140 |
+
print('111111111111111111111')
|
141 |
+
|
142 |
+
try:
|
143 |
+
# 安全地获取异常信息
|
144 |
+
error_type = type(e).__name__
|
145 |
+
|
146 |
+
# 尝试获取状态码(如果存在)
|
147 |
+
status_code = getattr(e, 'response', None) and e.response.status_code
|
148 |
+
|
149 |
+
# 安全地获取错误详情
|
150 |
+
error_detail = ""
|
151 |
+
try:
|
152 |
+
# 尝试获取文本响应(限制长度)
|
153 |
+
if hasattr(e, 'response') and e.response:
|
154 |
+
error_detail = e.response.text[:500] # 只取前500个字符
|
155 |
+
except Exception as ex:
|
156 |
+
error_detail = f"无法获取错误详情: {type(ex).__name__}"
|
157 |
+
|
158 |
+
# 安全地记录日志
|
159 |
+
logger.error(
|
160 |
+
"HTTP代理错误 | "
|
161 |
+
f"类型: {error_type} | "
|
162 |
+
f"状态码: {status_code or 'N/A'} | "
|
163 |
+
f"目标URL: {target_url} | "
|
164 |
+
f"详情: {error_detail[:200]}" # 日志中只记录前200字符
|
165 |
+
)
|
166 |
+
|
167 |
+
# 打印到控制台以便调试
|
168 |
+
print(f"111111111111111111111 - HTTP代理错误: {error_type}")
|
169 |
+
print(f"目标URL: {target_url}")
|
170 |
+
print(f"状态码: {status_code or 'N/A'}")
|
171 |
+
print(f"错误详情: {error_detail[:500]}")
|
172 |
+
|
173 |
+
except Exception as ex:
|
174 |
+
# 如果记录日志本身出错,使用最安全的方式记录
|
175 |
+
logger.error(f"记录HTTP错误时发生异常: {type(ex).__name__}")
|
176 |
+
print(f"严重错误: 记录HTTP错误时发生异常: {ex}")
|
177 |
+
|
178 |
+
# 返回用户友好的错误响应
|
179 |
+
raise HTTPException(
|
180 |
+
status_code=502,
|
181 |
+
detail=f"网关服务错误: {error_type} (上游状态: {status_code or '未知'})"
|
182 |
+
)
|
183 |
+
|
184 |
+
|
185 |
+
print('111111111111111111111')
|
186 |
+
# logger.error(f"HTTP error: {str(e)}")
|
187 |
+
|
188 |
+
raise HTTPException(502, f"网关错误: {str(e)}")
|
189 |
+
except Exception as e:
|
190 |
+
logger.exception("Unexpected proxy error")
|
191 |
+
raise HTTPException(500, f"内部服务器错误: {str(e)}")
|
key_selector.py
ADDED
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
from dotenv import load_dotenv
|
3 |
+
load_dotenv()
|
4 |
+
|
5 |
+
class KeySelector():
|
6 |
+
def __init__(self):
|
7 |
+
pass
|
8 |
+
|
9 |
+
def get_api_key(self):
|
10 |
+
api_key_info = {
|
11 |
+
"key_at": "at_headers",
|
12 |
+
"key_name": "X_Goog_Api_Key",
|
13 |
+
"key_value": os.getenv("X_Goog_Api_Key", "")
|
14 |
+
}
|
15 |
+
return api_key_info
|
memory-bank/activeContext.md
ADDED
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# 当前背景 (Active Context)
|
2 |
+
|
3 |
+
## 当前工作重点
|
4 |
+
初始化项目记忆库。
|
5 |
+
|
6 |
+
## 最近的变更
|
7 |
+
- 创建了 `projectbrief.md` 文件,定义了项目的核心目标和范围。
|
8 |
+
- 创建了 `productContext.md` 文件,描述了项目的目的、解决的问题和用户体验目标。
|
9 |
+
- 创建了 `systemPatterns.md` 文件,概述了系统架构、设计模式和关键组件。
|
10 |
+
- 创建了 `techContext.md` 文件,记录了使用的技术、开发环境设置和技术约束。
|
11 |
+
|
12 |
+
## 下一步计划
|
13 |
+
- 创建 `progress.md` 文件,记录项目的当前状态、已完成和待完成的工作。
|
14 |
+
- 根据项目需求,开始实现 FastAPI 应用的核心代理转发逻辑。
|
15 |
+
- 定义和实现代理规则的配置加载机制。
|
16 |
+
- 集成 HTTP 客户端库 (`httpx`) 进行后端请求转发。
|
17 |
+
|
18 |
+
## 重要的模式和偏好
|
19 |
+
- 优先使用异步编程。
|
20 |
+
- 保持代码简洁和模块化。
|
21 |
+
- 遵循 FastAPI 的最佳实践。
|
22 |
+
|
23 |
+
## 学习和项目洞察
|
24 |
+
- 项目处于初期阶段,主要任务是搭建基本框架和配置。
|
25 |
+
- 需要仔细设计配置文件的结构,以便于灵活地添加和管理代理规则。
|
memory-bank/productContext.md
ADDED
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# 产品背景 (Product Context)
|
2 |
+
|
3 |
+
## 项目目的
|
4 |
+
本项目旨在开发一个灵活的 API 代理转发工具,以解决在微服务架构或集成不同第三方服务时遇到的跨域、认证、请求/响应格式不一致等问题。通过集中管理 API 访问,简化客户端与多个后端服务之间的交互。
|
5 |
+
|
6 |
+
## 解决的问题
|
7 |
+
- **跨域问题**: 允许客户端通过单一来源访问不同域的 API。
|
8 |
+
- **API 集成**: 简化集成多个内部或外部 API 的过程。
|
9 |
+
- **请求/响应转换**: 提供一个中心点来标准化或修改请求和响应数据。
|
10 |
+
- **配置管理**: 集中管理所有代理目标的配置。
|
11 |
+
|
12 |
+
## 用户体验目标
|
13 |
+
- **开发者**: 易于配置和扩展新的代理规则。
|
14 |
+
- **系统管理员**: 易于部署和管理。
|
15 |
+
- **最终用户**: 无感知地通过代理访问后端服务。
|
16 |
+
|
17 |
+
## 功能愿景
|
18 |
+
- 支持基于路径、请求方法等多种匹配规则进行转发。
|
19 |
+
- 支持请求头、请求体、查询参数的修改。
|
20 |
+
- 支持响应头、响应体的修改。
|
21 |
+
- 易于集成认证和授权机制(未来可能)。
|
22 |
+
- 提供基本的日志记录功能。
|
memory-bank/progress.md
ADDED
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# 项目进度 (Progress)
|
2 |
+
|
3 |
+
## 当前状态
|
4 |
+
项目记忆库已初始化。核心记忆文件(projectbrief.md, productContext.md, systemPatterns.md, techContext.md, activeContext.md)已创建。
|
5 |
+
|
6 |
+
## 已完成的工作
|
7 |
+
- 创建了 Memory Bank 目录。
|
8 |
+
- 创建并填充了以下记忆文件:
|
9 |
+
- `projectbrief.md`
|
10 |
+
- `productContext.md`
|
11 |
+
- `systemPatterns.md`
|
12 |
+
- `techContext.md`
|
13 |
+
- `activeContext.md`
|
14 |
+
|
15 |
+
## 待完成的工作
|
16 |
+
- 实现 FastAPI 应用的核心代理转发逻辑。
|
17 |
+
- 设计和实现代理规则的配置加载机制。
|
18 |
+
- 集成 `httpx` 库进行后端请求转发。
|
19 |
+
- 添加基本的日志记录功能。
|
20 |
+
- 根据需求实现请求/响应转换功能。
|
21 |
+
- 编写单元测试和集成测试。
|
22 |
+
- 完善 Dockerfile。
|
23 |
+
- 编写详细的 README.md 文档。
|
24 |
+
|
25 |
+
## 已知问题
|
26 |
+
- 暂无已知问题。
|
27 |
+
|
28 |
+
## 项目决策演变
|
29 |
+
- 决定使用 FastAPI 作为后端框架,因为它提供了高性能和易于使用的异步支持。
|
30 |
+
- 决定使用 `httpx` 作为 HTTP 客户端,因为它支持异步请求。
|
31 |
+
- 决定使用配置文件来管理代理规则,以提高灵活性。
|
memory-bank/projectbrief.md
ADDED
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# 项目简报 (Project Brief)
|
2 |
+
|
3 |
+
## 项目名称
|
4 |
+
API 代理转发工具
|
5 |
+
|
6 |
+
## 核心目标
|
7 |
+
使用 FastAPI 开发一个实现多种 API 代理转发的工具。
|
8 |
+
|
9 |
+
## 主要需求
|
10 |
+
- 能够接收来自客户端的请求。
|
11 |
+
- 根据配置将请求转发到不同的后端 API。
|
12 |
+
- 处理请求和响应的转换(如果需要)。
|
13 |
+
- 支持多种 API 的代理。
|
14 |
+
|
15 |
+
## 范围
|
16 |
+
本项目专注于构建核心的代理转发功能。
|
17 |
+
|
18 |
+
## 非范围
|
19 |
+
- 高级安全功能(如认证、授权)除非明确要求。
|
20 |
+
- 复杂的负载均衡策略除非明确要求。
|
21 |
+
- 详细的监控和日志分析除非明确要求。
|
22 |
+
|
23 |
+
## 成功标准
|
24 |
+
- 能够成功代理转发至少两种不同的 API 请求。
|
25 |
+
- 代码结构清晰,易于扩展新的代理目标。
|
26 |
+
- 满足基本的性能要求。
|
memory-bank/systemPatterns.md
ADDED
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# 系统模式 (System Patterns)
|
2 |
+
|
3 |
+
## 架构概述
|
4 |
+
本项目将采用基于 FastAPI 的微服务架构。核心是一个 FastAPI 应用,负责接收所有进来的请求,并根据配置将请求转发到相应的后端服务。
|
5 |
+
|
6 |
+
```mermaid
|
7 |
+
graph LR
|
8 |
+
Client --> Proxy[FastAPI Proxy]
|
9 |
+
Proxy --> BackendA[Backend Service A]
|
10 |
+
Proxy --> BackendB[Backend Service B]
|
11 |
+
Proxy --> BackendC[Backend Service C]
|
12 |
+
```
|
13 |
+
|
14 |
+
## 设计模式
|
15 |
+
- **API Gateway Pattern**: FastAPI 应用充当 API 网关,作为客户端访问后端服务的单一入口点。
|
16 |
+
- **Configuration Pattern**: 代理规则将通过配置文件进行管理,以便于修改和扩展。
|
17 |
+
- **Middleware Pattern**: 利用 FastAPI 的中间件功能处理请求和响应的通用逻辑(如日志、认证等)。
|
18 |
+
|
19 |
+
## 关键组件
|
20 |
+
- **FastAPI Application**: 核心应用,处理路由和请求转发。
|
21 |
+
- **Configuration Loader**: 负责加载和解析代理规则配置文件。
|
22 |
+
- **HTTP Client**: 用于向后端服务发起请求(例如使用 `httpx` 库)。
|
23 |
+
- **Request/Response Transformer (Optional)**: 根据配置修改请求和响应。
|
24 |
+
|
25 |
+
## 数据流
|
26 |
+
1. 客户端发起请求到 FastAPI Proxy。
|
27 |
+
2. FastAPI Proxy 接收请求。
|
28 |
+
3. Configuration Loader 解析配置,查找匹配的代理规则。
|
29 |
+
4. 如果找到匹配规则,HTTP Client 根据规则向后端服务发起请求。
|
30 |
+
5. 后端服务返回响应。
|
31 |
+
6. Request/Response Transformer (如果存在) 修改响应。
|
32 |
+
7. FastAPI Proxy 将响应返回给客户端。
|
memory-bank/techContext.md
ADDED
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# 技术背景 (Tech Context)
|
2 |
+
|
3 |
+
## 使用的技术
|
4 |
+
- **后端框架**: FastAPI (Python)
|
5 |
+
- **异步 HTTP 客户端**: httpx
|
6 |
+
- **配置管理**: 可能使用 `python-dotenv` 或其他配置库来加载配置文件。
|
7 |
+
- **依赖管理**: pip 和 requirements.txt
|
8 |
+
- **容器化**: Docker
|
9 |
+
|
10 |
+
## 开发环境设置
|
11 |
+
1. 克隆仓库。
|
12 |
+
2. 创建并激活 Conda 虚拟环境 (`conda create -n api-proxy python=3.9` 或使用现有环境,然后 `conda activate api-proxy`)。
|
13 |
+
3. 安装依赖 (`pip install -r requirements.txt`)。
|
14 |
+
4. 运行应用 (`uvicorn app:app --reload`)。
|
15 |
+
|
16 |
+
## 技术约束
|
17 |
+
- 需要 Python 3.7+。
|
18 |
+
- 依赖于 FastAPI 和 httpx 库。
|
19 |
+
|
20 |
+
## 依赖关系
|
21 |
+
- `requirements.txt` 文件列出了所有必要的 Python 依赖。
|
22 |
+
|
23 |
+
## 工具使用模式
|
24 |
+
- 使用 `uvicorn` 作为 ASGI 服务器运行 FastAPI 应用。
|
25 |
+
- 使用 `pip` 管理 Python 包。
|
26 |
+
- 使用 Docker 构建和运行容器。
|
push.sh
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
git add .
|
2 |
+
git commit -m "$(date)"
|
3 |
+
git push
|
requirements.txt
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
fastapi
|
2 |
+
uvicorn[standard]
|
3 |
+
httpx
|