Skip to content

Commit abd0c00

Browse files
committed
Fix PR 133 merge integration issues
1 parent 55431c9 commit abd0c00

19 files changed

Lines changed: 113 additions & 284 deletions

cat.jpg

-7.63 KB
Binary file not shown.

cat_watercolor.jpg

-866 KB
Binary file not shown.

docker-compose.yml

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,12 @@ services:
44
flow2api:
55
image: ghcr.io/thesmallhancat/flow2api:latest
66
container_name: flow2api
7-
network_mode: host
7+
ports:
8+
- "38000:8000"
89
volumes:
910
- ./data:/app/data
1011
- ./tmp:/app/tmp
1112
- ./config/setting.toml:/app/config/setting.toml
12-
- ./src/services/proxy_manager.py:/app/src/services/proxy_manager.py
13-
- ./src/services/flow_client.py:/app/src/services/flow_client.py
14-
- ./src/api/admin.py:/app/src/api/admin.py
1513
environment:
1614
- PYTHONUNBUFFERED=1
1715
restart: unless-stopped

extension/background.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ let heartbeatInterval = null;
44

55
const DEFAULT_SETTINGS = {
66
serverUrl: "ws://127.0.0.1:8000/captcha_ws",
7+
apiKey: "",
78
routeKey: "",
89
clientLabel: ""
910
};
@@ -13,6 +14,7 @@ function getSettings() {
1314
chrome.storage.local.get(DEFAULT_SETTINGS, (stored) => {
1415
resolve({
1516
serverUrl: (stored.serverUrl || DEFAULT_SETTINGS.serverUrl).trim(),
17+
apiKey: (stored.apiKey || "").trim(),
1618
routeKey: (stored.routeKey || "").trim(),
1719
clientLabel: (stored.clientLabel || "").trim()
1820
});
@@ -74,6 +76,9 @@ async function connectWS() {
7476

7577
const settings = await getSettings();
7678
const url = new URL(settings.serverUrl || DEFAULT_SETTINGS.serverUrl);
79+
if (settings.apiKey) {
80+
url.searchParams.set("key", settings.apiKey);
81+
}
7782
if (settings.routeKey) {
7883
url.searchParams.set("route_key", settings.routeKey);
7984
}
@@ -227,7 +232,7 @@ async function handleGetToken(data) {
227232

228233
chrome.storage.onChanged.addListener((changes, areaName) => {
229234
if (areaName !== "local") return;
230-
if (changes.routeKey || changes.serverUrl || changes.clientLabel) {
235+
if (changes.routeKey || changes.serverUrl || changes.apiKey || changes.clientLabel) {
231236
console.log("[Flow2API] Extension settings changed, reconnecting WebSocket...");
232237
closeSocket();
233238
connectWS();

extension/manifest 2.json

Lines changed: 0 additions & 18 deletions
This file was deleted.

extension/manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
"scripting"
1010
],
1111
"host_permissions": [
12-
"<all_urls>"
12+
"https://labs.google/*"
1313
],
1414
"background": {
1515
"service_worker": "background.js"

extension/options 2.js

Lines changed: 0 additions & 47 deletions
This file was deleted.

extension/options.html

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,9 +87,12 @@ <h1>Flow2API Captcha Worker</h1>
8787
<label for="serverUrl">WebSocket URL</label>
8888
<input id="serverUrl" type="text" placeholder="ws://127.0.0.1:8000/captcha_ws">
8989

90+
<label for="apiKey">Flow2API API Key</label>
91+
<input id="apiKey" type="password" placeholder="管理后台里的 API Key">
92+
9093
<button id="saveBtn" type="button">保存</button>
9194
<div class="status" id="status"></div>
92-
<div class="hint">管理台 token 里填写同样的 <code>Route Key</code>,比如 9223 对 9223。</div>
95+
<div class="hint">管理台 token 里填写同样的 <code>Route Key</code>,比如 9223 对 9223。后端会使用 API Key 校验 WebSocket 连接。</div>
9396
</div>
9497
</div>
9598
<script src="options.js"></script>

extension/options.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
const DEFAULT_SETTINGS = {
22
serverUrl: "ws://127.0.0.1:8000/captcha_ws",
3+
apiKey: "",
34
routeKey: "",
45
clientLabel: ""
56
};
@@ -9,6 +10,7 @@ const $ = (id) => document.getElementById(id);
910
function normalizeSettings(values) {
1011
return {
1112
serverUrl: (values.serverUrl || DEFAULT_SETTINGS.serverUrl).trim(),
13+
apiKey: (values.apiKey || "").trim(),
1214
routeKey: (values.routeKey || "").trim(),
1315
clientLabel: (values.clientLabel || "").trim()
1416
};
@@ -33,6 +35,7 @@ function loadSettings() {
3335
chrome.storage.local.get(DEFAULT_SETTINGS, (stored) => {
3436
const settings = normalizeSettings(stored);
3537
$("serverUrl").value = settings.serverUrl;
38+
$("apiKey").value = settings.apiKey;
3639
$("routeKey").value = settings.routeKey;
3740
$("clientLabel").value = settings.clientLabel;
3841
});
@@ -41,6 +44,7 @@ function loadSettings() {
4144
function saveSettings() {
4245
const settings = normalizeSettings({
4346
serverUrl: $("serverUrl").value,
47+
apiKey: $("apiKey").value,
4448
routeKey: $("routeKey").value,
4549
clientLabel: $("clientLabel").value
4650
});
@@ -49,6 +53,10 @@ function saveSettings() {
4953
setStatus("WebSocket URL 必须以 ws:// 或 wss:// 开头。", true);
5054
return;
5155
}
56+
if (!settings.apiKey) {
57+
setStatus("请填写 Flow2API API Key。", true);
58+
return;
59+
}
5260

5361
chrome.storage.local.set(settings, () => {
5462
if (chrome.runtime.lastError) {

src/api/routes.py

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@
99
from urllib.parse import urlparse
1010

1111
from curl_cffi.requests import AsyncSession
12-
from fastapi import APIRouter, Depends, HTTPException, Query, WebSocket, WebSocketDisconnect
12+
from fastapi import APIRouter, Depends, HTTPException, Query, Request, WebSocket, WebSocketDisconnect
1313
from fastapi.responses import JSONResponse, StreamingResponse
1414

15-
from ..core.auth import verify_api_key_flexible
15+
from ..core.auth import AuthManager, verify_api_key_flexible
1616
from ..core.logger import debug_logger
1717
from ..core.model_resolver import get_base_model_aliases, resolve_model_name
1818
from ..core.models import (
@@ -23,7 +23,6 @@
2323
)
2424
from ..services.generation_handler import MODEL_CONFIG, GenerationHandler
2525
from ..services.browser_captcha_extension import ExtensionCaptchaService
26-
from fastapi import WebSocket, WebSocketDisconnect
2726

2827
router = APIRouter()
2928

@@ -486,6 +485,7 @@ async def _collect_non_stream_result(
486485
model: str,
487486
prompt: str,
488487
images: List[bytes],
488+
base_url_override: Optional[str] = None,
489489
video_media_id: Optional[str] = None,
490490
) -> str:
491491
handler = _ensure_generation_handler()
@@ -495,6 +495,7 @@ async def _collect_non_stream_result(
495495
prompt=prompt,
496496
images=images if images else None,
497497
stream=False,
498+
base_url_override=base_url_override,
498499
video_media_id=video_media_id,
499500
):
500501
result = chunk
@@ -723,6 +724,7 @@ async def _iterate_openai_stream(
723724
prompt=normalized.prompt,
724725
images=normalized.images if normalized.images else None,
725726
stream=True,
727+
base_url_override=base_url_override,
726728
video_media_id=normalized.video_media_id,
727729
):
728730
if chunk.startswith("data: "):
@@ -746,6 +748,7 @@ async def _iterate_gemini_stream(
746748
prompt=normalized.prompt,
747749
images=normalized.images if normalized.images else None,
748750
stream=True,
751+
base_url_override=base_url_override,
749752
video_media_id=normalized.video_media_id,
750753
):
751754
if chunk.startswith("data: "):
@@ -874,6 +877,7 @@ async def create_chat_completion(
874877
normalized.model,
875878
normalized.prompt,
876879
normalized.images,
880+
base_url_override=request_base_url,
877881
video_media_id=normalized.video_media_id,
878882
)
879883
)
@@ -907,7 +911,8 @@ async def generate_content(
907911
normalized.model,
908912
normalized.prompt,
909913
normalized.images,
910-
request_base_url,
914+
base_url_override=request_base_url,
915+
video_media_id=normalized.video_media_id,
911916
)
912917
)
913918
)
@@ -970,6 +975,20 @@ async def stream_generate_content(
970975
@router.websocket("/captcha_ws")
971976
async def captcha_websocket_endpoint(websocket: WebSocket):
972977
from ..core.logger import debug_logger
978+
api_key = (
979+
websocket.query_params.get("key")
980+
or websocket.query_params.get("api_key")
981+
or websocket.headers.get("x-goog-api-key")
982+
or ""
983+
).strip()
984+
authorization = (websocket.headers.get("authorization") or "").strip()
985+
if authorization.lower().startswith("bearer "):
986+
api_key = authorization[7:].strip()
987+
988+
if not api_key or not AuthManager.verify_api_key(api_key):
989+
await websocket.close(code=1008)
990+
return
991+
973992
service = await ExtensionCaptchaService.get_instance()
974993
await service.connect(websocket)
975994
try:

0 commit comments

Comments
 (0)