Spaces:
Running
Running
add gpt-5 with poe
Browse files
app.py
CHANGED
@@ -587,9 +587,10 @@ def get_inference_client(model_id, provider="auto"):
|
|
587 |
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
|
588 |
)
|
589 |
elif model_id == "gpt-5":
|
590 |
-
# Use OpenAI client for GPT-5 model
|
591 |
return OpenAI(
|
592 |
-
api_key=os.getenv("
|
|
|
593 |
)
|
594 |
elif model_id == "step-3":
|
595 |
# Use StepFun API client for Step-3 model
|
@@ -699,10 +700,24 @@ def remove_code_block(text):
|
|
699 |
# Remove a leading language marker line (e.g., 'python') if present
|
700 |
if extracted.split('\n', 1)[0].strip().lower() in ['python', 'html', 'css', 'javascript', 'json', 'c', 'cpp', 'markdown', 'latex', 'jinja2', 'typescript', 'yaml', 'dockerfile', 'shell', 'r', 'sql', 'sql-mssql', 'sql-mysql', 'sql-mariadb', 'sql-sqlite', 'sql-cassandra', 'sql-plSQL', 'sql-hive', 'sql-pgsql', 'sql-gql', 'sql-gpsql', 'sql-sparksql', 'sql-esper']:
|
701 |
return extracted.split('\n', 1)[1] if '\n' in extracted else ''
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
702 |
return extracted
|
703 |
# If no code block is found, check if the entire text is HTML
|
704 |
-
|
705 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
706 |
# Special handling for python: remove python marker
|
707 |
if text.strip().startswith('```python'):
|
708 |
return text.strip()[9:-3].strip()
|
@@ -712,6 +727,13 @@ def remove_code_block(text):
|
|
712 |
return lines[1] if len(lines) > 1 else ''
|
713 |
return text.strip()
|
714 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
715 |
def parse_transformers_js_output(text):
|
716 |
"""Parse transformers.js output and extract the three files (index.html, index.js, style.css)"""
|
717 |
files = {
|
@@ -2500,13 +2522,13 @@ This will help me create a better design for you."""
|
|
2500 |
)
|
2501 |
|
2502 |
else:
|
2503 |
-
#
|
2504 |
if _current_model["id"] == "gpt-5":
|
2505 |
completion = client.chat.completions.create(
|
2506 |
-
model=
|
2507 |
messages=messages,
|
2508 |
stream=True,
|
2509 |
-
|
2510 |
)
|
2511 |
else:
|
2512 |
completion = client.chat.completions.create(
|
@@ -2516,6 +2538,9 @@ This will help me create a better design for you."""
|
|
2516 |
max_tokens=16384
|
2517 |
)
|
2518 |
content = ""
|
|
|
|
|
|
|
2519 |
for chunk in completion:
|
2520 |
# Handle different response formats for Mistral vs others
|
2521 |
chunk_content = None
|
@@ -2540,7 +2565,42 @@ This will help me create a better design for you."""
|
|
2540 |
chunk_content = chunk.choices[0].delta.content
|
2541 |
|
2542 |
if chunk_content:
|
2543 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2544 |
search_status = " (with web search)" if enable_search and tavily_client else ""
|
2545 |
|
2546 |
# Handle transformers.js output differently
|
|
|
587 |
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
|
588 |
)
|
589 |
elif model_id == "gpt-5":
|
590 |
+
# Use Poe (OpenAI-compatible) client for GPT-5 model
|
591 |
return OpenAI(
|
592 |
+
api_key=os.getenv("POE_API_KEY"),
|
593 |
+
base_url="https://api.poe.com/v1"
|
594 |
)
|
595 |
elif model_id == "step-3":
|
596 |
# Use StepFun API client for Step-3 model
|
|
|
700 |
# Remove a leading language marker line (e.g., 'python') if present
|
701 |
if extracted.split('\n', 1)[0].strip().lower() in ['python', 'html', 'css', 'javascript', 'json', 'c', 'cpp', 'markdown', 'latex', 'jinja2', 'typescript', 'yaml', 'dockerfile', 'shell', 'r', 'sql', 'sql-mssql', 'sql-mysql', 'sql-mariadb', 'sql-sqlite', 'sql-cassandra', 'sql-plSQL', 'sql-hive', 'sql-pgsql', 'sql-gql', 'sql-gpsql', 'sql-sparksql', 'sql-esper']:
|
702 |
return extracted.split('\n', 1)[1] if '\n' in extracted else ''
|
703 |
+
# If HTML markup starts later in the block (e.g., Poe injected preface), trim to first HTML root
|
704 |
+
html_root_idx = None
|
705 |
+
for tag in ['<!DOCTYPE html', '<html']:
|
706 |
+
idx = extracted.find(tag)
|
707 |
+
if idx != -1:
|
708 |
+
html_root_idx = idx if html_root_idx is None else min(html_root_idx, idx)
|
709 |
+
if html_root_idx is not None and html_root_idx > 0:
|
710 |
+
return extracted[html_root_idx:].strip()
|
711 |
return extracted
|
712 |
# If no code block is found, check if the entire text is HTML
|
713 |
+
stripped = text.strip()
|
714 |
+
if stripped.startswith('<!DOCTYPE html>') or stripped.startswith('<html') or stripped.startswith('<'):
|
715 |
+
# If HTML root appears later (e.g., Poe preface), trim to first HTML root
|
716 |
+
for tag in ['<!DOCTYPE html', '<html']:
|
717 |
+
idx = stripped.find(tag)
|
718 |
+
if idx > 0:
|
719 |
+
return stripped[idx:].strip()
|
720 |
+
return stripped
|
721 |
# Special handling for python: remove python marker
|
722 |
if text.strip().startswith('```python'):
|
723 |
return text.strip()[9:-3].strip()
|
|
|
727 |
return lines[1] if len(lines) > 1 else ''
|
728 |
return text.strip()
|
729 |
|
730 |
+
def strip_placeholder_thinking(text: str) -> str:
|
731 |
+
"""Remove placeholder 'Thinking...' status lines from streamed text."""
|
732 |
+
if not text:
|
733 |
+
return text
|
734 |
+
# Matches lines like: "Thinking..." or "Thinking... (12s elapsed)"
|
735 |
+
return re.sub(r"(?mi)^[\t ]*Thinking\.\.\.(?:\s*\(\d+s elapsed\))?[\t ]*$\n?", "", text)
|
736 |
+
|
737 |
def parse_transformers_js_output(text):
|
738 |
"""Parse transformers.js output and extract the three files (index.html, index.js, style.css)"""
|
739 |
files = {
|
|
|
2522 |
)
|
2523 |
|
2524 |
else:
|
2525 |
+
# Poe expects model id "GPT-5" and uses max_tokens
|
2526 |
if _current_model["id"] == "gpt-5":
|
2527 |
completion = client.chat.completions.create(
|
2528 |
+
model="GPT-5",
|
2529 |
messages=messages,
|
2530 |
stream=True,
|
2531 |
+
max_tokens=16384
|
2532 |
)
|
2533 |
else:
|
2534 |
completion = client.chat.completions.create(
|
|
|
2538 |
max_tokens=16384
|
2539 |
)
|
2540 |
content = ""
|
2541 |
+
# For Poe/GPT-5, maintain a simple code-fence state machine to only accumulate code
|
2542 |
+
poe_inside_code_block = False
|
2543 |
+
poe_partial_buffer = ""
|
2544 |
for chunk in completion:
|
2545 |
# Handle different response formats for Mistral vs others
|
2546 |
chunk_content = None
|
|
|
2565 |
chunk_content = chunk.choices[0].delta.content
|
2566 |
|
2567 |
if chunk_content:
|
2568 |
+
if _current_model["id"] == "gpt-5":
|
2569 |
+
# Filter placeholders
|
2570 |
+
incoming = strip_placeholder_thinking(chunk_content)
|
2571 |
+
# Process code fences incrementally, only keep content inside fences
|
2572 |
+
s = poe_partial_buffer + incoming
|
2573 |
+
append_text = ""
|
2574 |
+
i = 0
|
2575 |
+
# Find all triple backticks positions
|
2576 |
+
for m in re.finditer(r"```", s):
|
2577 |
+
if not poe_inside_code_block:
|
2578 |
+
# Opening fence. Require a newline to confirm full opener so we can skip optional language line
|
2579 |
+
nl = s.find("\n", m.end())
|
2580 |
+
if nl == -1:
|
2581 |
+
# Incomplete opener; buffer from this fence and wait for more
|
2582 |
+
poe_partial_buffer = s[m.start():]
|
2583 |
+
s = None
|
2584 |
+
break
|
2585 |
+
# Enter code, skip past newline after optional language token
|
2586 |
+
poe_inside_code_block = True
|
2587 |
+
i = nl + 1
|
2588 |
+
else:
|
2589 |
+
# Closing fence, append content inside and exit code
|
2590 |
+
append_text += s[i:m.start()]
|
2591 |
+
poe_inside_code_block = False
|
2592 |
+
i = m.end()
|
2593 |
+
if s is not None:
|
2594 |
+
if poe_inside_code_block:
|
2595 |
+
append_text += s[i:]
|
2596 |
+
poe_partial_buffer = ""
|
2597 |
+
else:
|
2598 |
+
poe_partial_buffer = s[i:]
|
2599 |
+
if append_text:
|
2600 |
+
content += append_text
|
2601 |
+
else:
|
2602 |
+
# Append content, filtering out placeholder thinking lines
|
2603 |
+
content += strip_placeholder_thinking(chunk_content)
|
2604 |
search_status = " (with web search)" if enable_search and tavily_client else ""
|
2605 |
|
2606 |
# Handle transformers.js output differently
|