gyc12 commited on
Commit
73bad29
·
verified ·
1 Parent(s): 21888fa

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +136 -0
app.py ADDED
@@ -0,0 +1,136 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Poe Documentation: https://creator.poe.com/docs/server-bots-functional-guides
2
+ # OpenAI Documentation: https://platform.openai.com/docs/api-reference/chat/create
3
+
4
+ # Get Environment Variables
5
+ import os
6
+
7
+ DEFAULT_MODEL = os.getenv("BOT", default="GPT-4o")
8
+ LISTEN_PORT = int(os.getenv("PORT", default=10000))
9
+ BASE_URL = os.getenv("BASE", default="https://api.poe.com/bot/")
10
+
11
+ # Proxy Server
12
+ import uvicorn
13
+ import json
14
+
15
+ from fastapi import FastAPI, Request, Header
16
+ from fastapi.middleware.cors import CORSMiddleware
17
+ from fastapi.responses import StreamingResponse
18
+ from typing import Any, AsyncGenerator
19
+ from fastapi_poe.types import ProtocolMessage
20
+ from fastapi_poe.client import get_bot_response
21
+ from fastapi.middleware.cors import CORSMiddleware
22
+
23
+ app = FastAPI()
24
+
25
+ app.add_middleware(
26
+ CORSMiddleware,
27
+ allow_origins=["*"], # Allow all origins
28
+ allow_credentials=True,
29
+ allow_methods=["*"],
30
+ allow_headers=["*"],
31
+ )
32
+
33
+
34
+ def openai_format_messages_to_poe_format(openai_format_messages: list) -> list:
35
+ """Convert OpenAI formatted messages to POE formatted messages."""
36
+ poe_format_messages = [
37
+ # Convert 'assistant' to 'bot' or we get an error
38
+ ProtocolMessage(
39
+ role=msg["role"].lower().replace("assistant", "bot"),
40
+ content=msg["content"],
41
+ temperature=msg.get("temperature", 0.5),
42
+ )
43
+ for msg in openai_format_messages
44
+ ]
45
+ return poe_format_messages
46
+
47
+
48
+ async def get_poe_bot_stream_partials(
49
+ api_key: str, poe_format_messages: list, bot_name: str
50
+ ) -> AsyncGenerator[str, None]:
51
+ async for partial in get_bot_response(
52
+ messages=poe_format_messages,
53
+ bot_name=bot_name,
54
+ api_key=api_key,
55
+ base_url=BASE_URL,
56
+ skip_system_prompt=False,
57
+ ):
58
+ yield partial.text
59
+
60
+
61
+ # by @OvO
62
+ async def adaptive_streamer(
63
+ poe_bot_stream_partials_generator, is_sse_enabled=False
64
+ ) -> AsyncGenerator[str, Any]:
65
+
66
+ STREAM_PREFIX = 'data:{"id":"chatcmpl-1","object":"chat.completion.chunk","created":1,"model":"a","choices":[{"index":0,"delta":{"content":'
67
+ STREAM_SUFFIX = "}}]}\n\n"
68
+
69
+ ENDING_CHUNK = 'data: {"id":"chatcmpl-123","object":"chat.completion.chunk","created":1694268190,"model":"gpt-4","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}\n\ndata: [DONE]\n\n'
70
+
71
+ NON_STREAM_PREFIX = '{"id":"chatcmpl-123","object":"chat.completion","created":1694268190,"model":"gpt-4","choices":[{"index":0,"message":{"role":"assistant","content":"'
72
+ NON_STREAM_SUFFIX = '"},"logprobs":null,"finish_reason":"stop"}],"usage":{"prompt_tokens":0,"completion_tokens":0,"total_tokens":0},"system_fingerprint":"abc"}\n\n'
73
+
74
+ if is_sse_enabled:
75
+ chat_prefix, chat_suffix = STREAM_PREFIX, STREAM_SUFFIX
76
+ _json_dumps = lambda data: json.dumps(data)
77
+ else:
78
+ chat_prefix, chat_suffix = "", ""
79
+ _json_dumps = lambda data: json.dumps(data)[1:-1]
80
+ yield NON_STREAM_PREFIX
81
+
82
+ async for partial in poe_bot_stream_partials_generator:
83
+ try:
84
+ yield chat_prefix
85
+ yield _json_dumps(partial)
86
+ yield chat_suffix
87
+ except:
88
+ continue
89
+
90
+ if is_sse_enabled:
91
+ yield ENDING_CHUNK
92
+ else:
93
+ yield NON_STREAM_SUFFIX
94
+
95
+ return
96
+
97
+
98
+ @app.post("/v1/chat/completions")
99
+ async def chat_completions(
100
+ request: Request, authorization: str = Header(None)
101
+ ) -> StreamingResponse:
102
+
103
+ # Assuming the header follows the standard format: "Bearer $API_KEY"
104
+ api_key = authorization.split(" ")[1]
105
+ body = await request.json()
106
+
107
+ # Extract bot_name (model) and messages from the request body
108
+ bot_name = body.get("model", DEFAULT_MODEL)
109
+ openai_format_messages = body.get("messages", [])
110
+ is_stream = body.get("stream", False)
111
+
112
+ # Convert OpenAI formatted messages to POE formatted messages
113
+ poe_format_messages = openai_format_messages_to_poe_format(openai_format_messages)
114
+
115
+ # Get poe bot response
116
+ poe_bot_stream_partials_generator = get_poe_bot_stream_partials(
117
+ api_key, poe_format_messages, bot_name
118
+ )
119
+
120
+ return StreamingResponse(
121
+ adaptive_streamer(poe_bot_stream_partials_generator, is_stream),
122
+ media_type=(
123
+ ("text/event-stream" if is_stream else "application/json")
124
+ + ";charset=UTF-8"
125
+ ),
126
+ )
127
+
128
+
129
+ if __name__ == "__main__":
130
+ try:
131
+ import uvloop
132
+ except ImportError:
133
+ uvloop = None
134
+ if uvloop:
135
+ uvloop.install()
136
+ uvicorn.run(app, host="0.0.0.0", port=LISTEN_PORT)