mirror of
https://gitee.com/wanwujie/deer-flow
synced 2026-04-19 12:24:46 +08:00
merge: upstream/experimental with citations feature
- Merge upstream changes including image search, tooltips, and UI improvements - Keep citations feature with inline hover cards - Resolve conflict in message-list-item.tsx: use upstream img max-width (90%) while preserving citations logic - Maintain file upload improvements with citations support Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -25,6 +25,7 @@ dependencies = [
|
|||||||
"tavily-python>=0.7.17",
|
"tavily-python>=0.7.17",
|
||||||
"firecrawl-py>=1.15.0",
|
"firecrawl-py>=1.15.0",
|
||||||
"uvicorn[standard]>=0.34.0",
|
"uvicorn[standard]>=0.34.0",
|
||||||
|
"ddgs>=9.10.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[dependency-groups]
|
[dependency-groups]
|
||||||
|
|||||||
@@ -158,6 +158,7 @@ The key AI trends for 2026 include enhanced reasoning capabilities, multimodal i
|
|||||||
- Progressive Loading: Load resources incrementally as referenced in skills
|
- Progressive Loading: Load resources incrementally as referenced in skills
|
||||||
- Output Files: Final deliverables must be in `/mnt/user-data/outputs`
|
- Output Files: Final deliverables must be in `/mnt/user-data/outputs`
|
||||||
- Clarity: Be direct and helpful, avoid unnecessary meta-commentary
|
- Clarity: Be direct and helpful, avoid unnecessary meta-commentary
|
||||||
|
- Including Images and Mermaid: Images and Mermaid diagrams are always welcomed in the Markdown format, and you're encouraged to use `\n\n` or "```mermaid" to display images in response or Markdown files
|
||||||
- Multi-task: Better utilize parallel tool calling to call multiple tools at one time for better performance
|
- Multi-task: Better utilize parallel tool calling to call multiple tools at one time for better performance
|
||||||
- Language Consistency: Keep using the same language as user's
|
- Language Consistency: Keep using the same language as user's
|
||||||
- Always Respond: Your thinking is internal. You MUST always provide a visible response to the user after thinking.
|
- Always Respond: Your thinking is internal. You MUST always provide a visible response to the user after thinking.
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ from typing import override
|
|||||||
|
|
||||||
from langchain.agents import AgentState
|
from langchain.agents import AgentState
|
||||||
from langchain.agents.middleware import AgentMiddleware
|
from langchain.agents.middleware import AgentMiddleware
|
||||||
from langchain_core.messages import AIMessage, ToolMessage
|
from langchain_core.messages import ToolMessage
|
||||||
from langgraph.graph import END
|
from langgraph.graph import END
|
||||||
from langgraph.prebuilt.tool_node import ToolCallRequest
|
from langgraph.prebuilt.tool_node import ToolCallRequest
|
||||||
from langgraph.types import Command
|
from langgraph.types import Command
|
||||||
@@ -118,17 +118,13 @@ class ClarificationMiddleware(AgentMiddleware[ClarificationMiddlewareState]):
|
|||||||
name="ask_clarification",
|
name="ask_clarification",
|
||||||
)
|
)
|
||||||
|
|
||||||
ai_response_message = AIMessage(content=formatted_message)
|
|
||||||
|
|
||||||
# Return a Command that:
|
# Return a Command that:
|
||||||
# 1. Adds the formatted tool message (keeping the AI message intact)
|
# 1. Adds the formatted tool message
|
||||||
# 2. Interrupts execution by going to __end__
|
# 2. Interrupts execution by going to __end__
|
||||||
# Note: We don't modify the AI message to preserve all fields (reasoning_content, tool_calls, etc.)
|
# Note: We don't add an extra AIMessage here - the frontend will detect
|
||||||
# This is especially important for thinking mode where reasoning_content is required
|
# and display ask_clarification tool messages directly
|
||||||
|
|
||||||
# Return Command to add the tool message and interrupt
|
|
||||||
return Command(
|
return Command(
|
||||||
update={"messages": [tool_message, ai_response_message]},
|
update={"messages": [tool_message]},
|
||||||
goto=END,
|
goto=END,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
3
backend/src/community/image_search/__init__.py
Normal file
3
backend/src/community/image_search/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
from .tools import image_search_tool
|
||||||
|
|
||||||
|
__all__ = ["image_search_tool"]
|
||||||
139
backend/src/community/image_search/tools.py
Normal file
139
backend/src/community/image_search/tools.py
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
"""
|
||||||
|
Image Search Tool - Search images using DuckDuckGo for reference in image generation.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import json
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from langchain.tools import tool
|
||||||
|
|
||||||
|
from src.config import get_app_config
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def _search_images(
|
||||||
|
query: str,
|
||||||
|
max_results: int = 5,
|
||||||
|
region: str = "wt-wt",
|
||||||
|
safesearch: str = "moderate",
|
||||||
|
size: str | None = None,
|
||||||
|
color: str | None = None,
|
||||||
|
type_image: str | None = None,
|
||||||
|
layout: str | None = None,
|
||||||
|
license_image: str | None = None,
|
||||||
|
) -> list[dict]:
|
||||||
|
"""
|
||||||
|
Execute image search using DuckDuckGo.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
query: Search keywords
|
||||||
|
max_results: Maximum number of results
|
||||||
|
region: Search region
|
||||||
|
safesearch: Safe search level
|
||||||
|
size: Image size (Small/Medium/Large/Wallpaper)
|
||||||
|
color: Color filter
|
||||||
|
type_image: Image type (photo/clipart/gif/transparent/line)
|
||||||
|
layout: Layout (Square/Tall/Wide)
|
||||||
|
license_image: License filter
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
List of search results
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
from ddgs import DDGS
|
||||||
|
except ImportError:
|
||||||
|
logger.error("ddgs library not installed. Run: pip install ddgs")
|
||||||
|
return []
|
||||||
|
|
||||||
|
ddgs = DDGS()
|
||||||
|
|
||||||
|
try:
|
||||||
|
kwargs = {
|
||||||
|
"region": region,
|
||||||
|
"safesearch": safesearch,
|
||||||
|
"max_results": max_results,
|
||||||
|
}
|
||||||
|
|
||||||
|
if size:
|
||||||
|
kwargs["size"] = size
|
||||||
|
if color:
|
||||||
|
kwargs["color"] = color
|
||||||
|
if type_image:
|
||||||
|
kwargs["type_image"] = type_image
|
||||||
|
if layout:
|
||||||
|
kwargs["layout"] = layout
|
||||||
|
if license_image:
|
||||||
|
kwargs["license_image"] = license_image
|
||||||
|
|
||||||
|
results = ddgs.images(query, **kwargs)
|
||||||
|
return list(results) if results else []
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Failed to search images: {e}")
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
@tool("image_search", parse_docstring=True)
|
||||||
|
def image_search_tool(
|
||||||
|
query: str,
|
||||||
|
max_results: int = 5,
|
||||||
|
size: str | None = None,
|
||||||
|
type_image: str | None = None,
|
||||||
|
layout: str | None = None,
|
||||||
|
) -> str:
|
||||||
|
"""Search for images online. Use this tool BEFORE image generation to find reference images for characters, portraits, objects, scenes, or any content requiring visual accuracy.
|
||||||
|
|
||||||
|
**When to use:**
|
||||||
|
- Before generating character/portrait images: search for similar poses, expressions, styles
|
||||||
|
- Before generating specific objects/products: search for accurate visual references
|
||||||
|
- Before generating scenes/locations: search for architectural or environmental references
|
||||||
|
- Before generating fashion/clothing: search for style and detail references
|
||||||
|
|
||||||
|
The returned image URLs can be used as reference images in image generation to significantly improve quality.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
query: Search keywords describing the images you want to find. Be specific for better results (e.g., "Japanese woman street photography 1990s" instead of just "woman").
|
||||||
|
max_results: Maximum number of images to return. Default is 5.
|
||||||
|
size: Image size filter. Options: "Small", "Medium", "Large", "Wallpaper". Use "Large" for reference images.
|
||||||
|
type_image: Image type filter. Options: "photo", "clipart", "gif", "transparent", "line". Use "photo" for realistic references.
|
||||||
|
layout: Layout filter. Options: "Square", "Tall", "Wide". Choose based on your generation needs.
|
||||||
|
"""
|
||||||
|
config = get_app_config().get_tool_config("image_search")
|
||||||
|
|
||||||
|
# Override max_results from config if set
|
||||||
|
if config is not None and "max_results" in config.model_extra:
|
||||||
|
max_results = config.model_extra.get("max_results", max_results)
|
||||||
|
|
||||||
|
results = _search_images(
|
||||||
|
query=query,
|
||||||
|
max_results=max_results,
|
||||||
|
size=size,
|
||||||
|
type_image=type_image,
|
||||||
|
layout=layout,
|
||||||
|
)
|
||||||
|
|
||||||
|
if not results:
|
||||||
|
return json.dumps({"error": "No images found", "query": query}, ensure_ascii=False)
|
||||||
|
|
||||||
|
normalized_results = [
|
||||||
|
{
|
||||||
|
"title": r.get("title", ""),
|
||||||
|
"image_url": r.get("image", ""),
|
||||||
|
"thumbnail_url": r.get("thumbnail", ""),
|
||||||
|
"source_url": r.get("url", ""),
|
||||||
|
"source": r.get("source", ""),
|
||||||
|
"width": r.get("width"),
|
||||||
|
"height": r.get("height"),
|
||||||
|
}
|
||||||
|
for r in results
|
||||||
|
]
|
||||||
|
|
||||||
|
output = {
|
||||||
|
"query": query,
|
||||||
|
"total_results": len(normalized_results),
|
||||||
|
"results": normalized_results,
|
||||||
|
"usage_hint": "Use the 'image_url' values as reference images in image generation. Download them first if needed.",
|
||||||
|
}
|
||||||
|
|
||||||
|
return json.dumps(output, indent=2, ensure_ascii=False)
|
||||||
@@ -55,8 +55,7 @@ class SandboxConfig(BaseModel):
|
|||||||
)
|
)
|
||||||
environment: dict[str, str] = Field(
|
environment: dict[str, str] = Field(
|
||||||
default_factory=dict,
|
default_factory=dict,
|
||||||
description="Environment variables to inject into the sandbox container. "
|
description="Environment variables to inject into the sandbox container. Values starting with $ will be resolved from host environment variables.",
|
||||||
"Values starting with $ will be resolved from host environment variables.",
|
|
||||||
)
|
)
|
||||||
|
|
||||||
model_config = ConfigDict(extra="allow")
|
model_config = ConfigDict(extra="allow")
|
||||||
|
|||||||
@@ -71,9 +71,7 @@ async def get_mcp_configuration() -> McpConfigResponse:
|
|||||||
"""
|
"""
|
||||||
config = get_extensions_config()
|
config = get_extensions_config()
|
||||||
|
|
||||||
return McpConfigResponse(
|
return McpConfigResponse(mcp_servers={name: McpServerConfigResponse(**server.model_dump()) for name, server in config.mcp_servers.items()})
|
||||||
mcp_servers={name: McpServerConfigResponse(**server.model_dump()) for name, server in config.mcp_servers.items()}
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@router.put(
|
@router.put(
|
||||||
@@ -143,9 +141,7 @@ async def update_mcp_configuration(request: McpConfigUpdateRequest) -> McpConfig
|
|||||||
|
|
||||||
# Reload the configuration and update the global cache
|
# Reload the configuration and update the global cache
|
||||||
reloaded_config = reload_extensions_config()
|
reloaded_config = reload_extensions_config()
|
||||||
return McpConfigResponse(
|
return McpConfigResponse(mcp_servers={name: McpServerConfigResponse(**server.model_dump()) for name, server in reloaded_config.mcp_servers.items()})
|
||||||
mcp_servers={name: McpServerConfigResponse(**server.model_dump()) for name, server in reloaded_config.mcp_servers.items()}
|
|
||||||
)
|
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Failed to update MCP configuration: {e}", exc_info=True)
|
logger.error(f"Failed to update MCP configuration: {e}", exc_info=True)
|
||||||
|
|||||||
@@ -48,20 +48,14 @@ class PatchedChatDeepSeek(ChatDeepSeek):
|
|||||||
# Iterate through both and match by position
|
# Iterate through both and match by position
|
||||||
if len(payload_messages) == len(original_messages):
|
if len(payload_messages) == len(original_messages):
|
||||||
for payload_msg, orig_msg in zip(payload_messages, original_messages):
|
for payload_msg, orig_msg in zip(payload_messages, original_messages):
|
||||||
if (
|
if payload_msg.get("role") == "assistant" and isinstance(orig_msg, AIMessage):
|
||||||
payload_msg.get("role") == "assistant"
|
|
||||||
and isinstance(orig_msg, AIMessage)
|
|
||||||
):
|
|
||||||
reasoning_content = orig_msg.additional_kwargs.get("reasoning_content")
|
reasoning_content = orig_msg.additional_kwargs.get("reasoning_content")
|
||||||
if reasoning_content is not None:
|
if reasoning_content is not None:
|
||||||
payload_msg["reasoning_content"] = reasoning_content
|
payload_msg["reasoning_content"] = reasoning_content
|
||||||
else:
|
else:
|
||||||
# Fallback: match by counting assistant messages
|
# Fallback: match by counting assistant messages
|
||||||
ai_messages = [m for m in original_messages if isinstance(m, AIMessage)]
|
ai_messages = [m for m in original_messages if isinstance(m, AIMessage)]
|
||||||
assistant_payloads = [
|
assistant_payloads = [(i, m) for i, m in enumerate(payload_messages) if m.get("role") == "assistant"]
|
||||||
(i, m) for i, m in enumerate(payload_messages)
|
|
||||||
if m.get("role") == "assistant"
|
|
||||||
]
|
|
||||||
|
|
||||||
for (idx, payload_msg), ai_msg in zip(assistant_payloads, ai_messages):
|
for (idx, payload_msg), ai_msg in zip(assistant_payloads, ai_messages):
|
||||||
reasoning_content = ai_msg.additional_kwargs.get("reasoning_content")
|
reasoning_content = ai_msg.additional_kwargs.get("reasoning_content")
|
||||||
|
|||||||
137
backend/uv.lock
generated
137
backend/uv.lock
generated
@@ -1,5 +1,5 @@
|
|||||||
version = 1
|
version = 1
|
||||||
revision = 2
|
revision = 3
|
||||||
requires-python = ">=3.12"
|
requires-python = ">=3.12"
|
||||||
resolution-markers = [
|
resolution-markers = [
|
||||||
"python_full_version >= '3.14' and sys_platform == 'win32'",
|
"python_full_version >= '3.14' and sys_platform == 'win32'",
|
||||||
@@ -295,6 +295,60 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/95/c1/84fc6811122f54b20de2e5afb312ee07a3a47a328755587d1e505475239b/blockbuster-1.5.26-py3-none-any.whl", hash = "sha256:f8e53fb2dd4b6c6ec2f04907ddbd063ca7cd1ef587d24448ef4e50e81e3a79bb", size = 13226, upload-time = "2025-12-05T10:43:48.778Z" },
|
{ url = "https://files.pythonhosted.org/packages/95/c1/84fc6811122f54b20de2e5afb312ee07a3a47a328755587d1e505475239b/blockbuster-1.5.26-py3-none-any.whl", hash = "sha256:f8e53fb2dd4b6c6ec2f04907ddbd063ca7cd1ef587d24448ef4e50e81e3a79bb", size = 13226, upload-time = "2025-12-05T10:43:48.778Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "brotli"
|
||||||
|
version = "1.2.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/f7/16/c92ca344d646e71a43b8bb353f0a6490d7f6e06210f8554c8f874e454285/brotli-1.2.0.tar.gz", hash = "sha256:e310f77e41941c13340a95976fe66a8a95b01e783d430eeaf7a2f87e0a57dd0a", size = 7388632, upload-time = "2025-11-05T18:39:42.86Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/11/ee/b0a11ab2315c69bb9b45a2aaed022499c9c24a205c3a49c3513b541a7967/brotli-1.2.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:35d382625778834a7f3061b15423919aa03e4f5da34ac8e02c074e4b75ab4f84", size = 861543, upload-time = "2025-11-05T18:38:24.183Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e1/2f/29c1459513cd35828e25531ebfcbf3e92a5e49f560b1777a9af7203eb46e/brotli-1.2.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7a61c06b334bd99bc5ae84f1eeb36bfe01400264b3c352f968c6e30a10f9d08b", size = 444288, upload-time = "2025-11-05T18:38:25.139Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3d/6f/feba03130d5fceadfa3a1bb102cb14650798c848b1df2a808356f939bb16/brotli-1.2.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:acec55bb7c90f1dfc476126f9711a8e81c9af7fb617409a9ee2953115343f08d", size = 1528071, upload-time = "2025-11-05T18:38:26.081Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2b/38/f3abb554eee089bd15471057ba85f47e53a44a462cfce265d9bf7088eb09/brotli-1.2.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:260d3692396e1895c5034f204f0db022c056f9e2ac841593a4cf9426e2a3faca", size = 1626913, upload-time = "2025-11-05T18:38:27.284Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/03/a7/03aa61fbc3c5cbf99b44d158665f9b0dd3d8059be16c460208d9e385c837/brotli-1.2.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:072e7624b1fc4d601036ab3f4f27942ef772887e876beff0301d261210bca97f", size = 1419762, upload-time = "2025-11-05T18:38:28.295Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/21/1b/0374a89ee27d152a5069c356c96b93afd1b94eae83f1e004b57eb6ce2f10/brotli-1.2.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:adedc4a67e15327dfdd04884873c6d5a01d3e3b6f61406f99b1ed4865a2f6d28", size = 1484494, upload-time = "2025-11-05T18:38:29.29Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/cf/57/69d4fe84a67aef4f524dcd075c6eee868d7850e85bf01d778a857d8dbe0a/brotli-1.2.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:7a47ce5c2288702e09dc22a44d0ee6152f2c7eda97b3c8482d826a1f3cfc7da7", size = 1593302, upload-time = "2025-11-05T18:38:30.639Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d5/3b/39e13ce78a8e9a621c5df3aeb5fd181fcc8caba8c48a194cd629771f6828/brotli-1.2.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:af43b8711a8264bb4e7d6d9a6d004c3a2019c04c01127a868709ec29962b6036", size = 1487913, upload-time = "2025-11-05T18:38:31.618Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/62/28/4d00cb9bd76a6357a66fcd54b4b6d70288385584063f4b07884c1e7286ac/brotli-1.2.0-cp312-cp312-win32.whl", hash = "sha256:e99befa0b48f3cd293dafeacdd0d191804d105d279e0b387a32054c1180f3161", size = 334362, upload-time = "2025-11-05T18:38:32.939Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/1c/4e/bc1dcac9498859d5e353c9b153627a3752868a9d5f05ce8dedd81a2354ab/brotli-1.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:b35c13ce241abdd44cb8ca70683f20c0c079728a36a996297adb5334adfc1c44", size = 369115, upload-time = "2025-11-05T18:38:33.765Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/6c/d4/4ad5432ac98c73096159d9ce7ffeb82d151c2ac84adcc6168e476bb54674/brotli-1.2.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:9e5825ba2c9998375530504578fd4d5d1059d09621a02065d1b6bfc41a8e05ab", size = 861523, upload-time = "2025-11-05T18:38:34.67Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/91/9f/9cc5bd03ee68a85dc4bc89114f7067c056a3c14b3d95f171918c088bf88d/brotli-1.2.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0cf8c3b8ba93d496b2fae778039e2f5ecc7cff99df84df337ca31d8f2252896c", size = 444289, upload-time = "2025-11-05T18:38:35.6Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2e/b6/fe84227c56a865d16a6614e2c4722864b380cb14b13f3e6bef441e73a85a/brotli-1.2.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c8565e3cdc1808b1a34714b553b262c5de5fbda202285782173ec137fd13709f", size = 1528076, upload-time = "2025-11-05T18:38:36.639Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/55/de/de4ae0aaca06c790371cf6e7ee93a024f6b4bb0568727da8c3de112e726c/brotli-1.2.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:26e8d3ecb0ee458a9804f47f21b74845cc823fd1bb19f02272be70774f56e2a6", size = 1626880, upload-time = "2025-11-05T18:38:37.623Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5f/16/a1b22cbea436642e071adcaf8d4b350a2ad02f5e0ad0da879a1be16188a0/brotli-1.2.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:67a91c5187e1eec76a61625c77a6c8c785650f5b576ca732bd33ef58b0dff49c", size = 1419737, upload-time = "2025-11-05T18:38:38.729Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/46/63/c968a97cbb3bdbf7f974ef5a6ab467a2879b82afbc5ffb65b8acbb744f95/brotli-1.2.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4ecdb3b6dc36e6d6e14d3a1bdc6c1057c8cbf80db04031d566eb6080ce283a48", size = 1484440, upload-time = "2025-11-05T18:38:39.916Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/06/9d/102c67ea5c9fc171f423e8399e585dabea29b5bc79b05572891e70013cdd/brotli-1.2.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3e1b35d56856f3ed326b140d3c6d9db91740f22e14b06e840fe4bb1923439a18", size = 1593313, upload-time = "2025-11-05T18:38:41.24Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9e/4a/9526d14fa6b87bc827ba1755a8440e214ff90de03095cacd78a64abe2b7d/brotli-1.2.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:54a50a9dad16b32136b2241ddea9e4df159b41247b2ce6aac0b3276a66a8f1e5", size = 1487945, upload-time = "2025-11-05T18:38:42.277Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5b/e8/3fe1ffed70cbef83c5236166acaed7bb9c766509b157854c80e2f766b38c/brotli-1.2.0-cp313-cp313-win32.whl", hash = "sha256:1b1d6a4efedd53671c793be6dd760fcf2107da3a52331ad9ea429edf0902f27a", size = 334368, upload-time = "2025-11-05T18:38:43.345Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ff/91/e739587be970a113b37b821eae8097aac5a48e5f0eca438c22e4c7dd8648/brotli-1.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:b63daa43d82f0cdabf98dee215b375b4058cce72871fd07934f179885aad16e8", size = 369116, upload-time = "2025-11-05T18:38:44.609Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/17/e1/298c2ddf786bb7347a1cd71d63a347a79e5712a7c0cba9e3c3458ebd976f/brotli-1.2.0-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:6c12dad5cd04530323e723787ff762bac749a7b256a5bece32b2243dd5c27b21", size = 863080, upload-time = "2025-11-05T18:38:45.503Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/84/0c/aac98e286ba66868b2b3b50338ffbd85a35c7122e9531a73a37a29763d38/brotli-1.2.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:3219bd9e69868e57183316ee19c84e03e8f8b5a1d1f2667e1aa8c2f91cb061ac", size = 445453, upload-time = "2025-11-05T18:38:46.433Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ec/f1/0ca1f3f99ae300372635ab3fe2f7a79fa335fee3d874fa7f9e68575e0e62/brotli-1.2.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:963a08f3bebd8b75ac57661045402da15991468a621f014be54e50f53a58d19e", size = 1528168, upload-time = "2025-11-05T18:38:47.371Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d6/a6/2ebfc8f766d46df8d3e65b880a2e220732395e6d7dc312c1e1244b0f074a/brotli-1.2.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9322b9f8656782414b37e6af884146869d46ab85158201d82bab9abbcb971dc7", size = 1627098, upload-time = "2025-11-05T18:38:48.385Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f3/2f/0976d5b097ff8a22163b10617f76b2557f15f0f39d6a0fe1f02b1a53e92b/brotli-1.2.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cf9cba6f5b78a2071ec6fb1e7bd39acf35071d90a81231d67e92d637776a6a63", size = 1419861, upload-time = "2025-11-05T18:38:49.372Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9c/97/d76df7176a2ce7616ff94c1fb72d307c9a30d2189fe877f3dd99af00ea5a/brotli-1.2.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7547369c4392b47d30a3467fe8c3330b4f2e0f7730e45e3103d7d636678a808b", size = 1484594, upload-time = "2025-11-05T18:38:50.655Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d3/93/14cf0b1216f43df5609f5b272050b0abd219e0b54ea80b47cef9867b45e7/brotli-1.2.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:fc1530af5c3c275b8524f2e24841cbe2599d74462455e9bae5109e9ff42e9361", size = 1593455, upload-time = "2025-11-05T18:38:51.624Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b3/73/3183c9e41ca755713bdf2cc1d0810df742c09484e2e1ddd693bee53877c1/brotli-1.2.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d2d085ded05278d1c7f65560aae97b3160aeb2ea2c0b3e26204856beccb60888", size = 1488164, upload-time = "2025-11-05T18:38:53.079Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/64/6a/0c78d8f3a582859236482fd9fa86a65a60328a00983006bcf6d83b7b2253/brotli-1.2.0-cp314-cp314-win32.whl", hash = "sha256:832c115a020e463c2f67664560449a7bea26b0c1fdd690352addad6d0a08714d", size = 339280, upload-time = "2025-11-05T18:38:54.02Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f5/10/56978295c14794b2c12007b07f3e41ba26acda9257457d7085b0bb3bb90c/brotli-1.2.0-cp314-cp314-win_amd64.whl", hash = "sha256:e7c0af964e0b4e3412a0ebf341ea26ec767fa0b4cf81abb5e897c9338b5ad6a3", size = 375639, upload-time = "2025-11-05T18:38:55.67Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "brotlicffi"
|
||||||
|
version = "1.2.0.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "cffi" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/84/85/57c314a6b35336efbbdc13e5fc9ae13f6b60a0647cfa7c1221178ac6d8ae/brotlicffi-1.2.0.0.tar.gz", hash = "sha256:34345d8d1f9d534fcac2249e57a4c3c8801a33c9942ff9f8574f67a175e17adb", size = 476682, upload-time = "2025-11-21T18:17:57.334Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e4/df/a72b284d8c7bef0ed5756b41c2eb7d0219a1dd6ac6762f1c7bdbc31ef3af/brotlicffi-1.2.0.0-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:9458d08a7ccde8e3c0afedbf2c70a8263227a68dea5ab13590593f4c0a4fd5f4", size = 432340, upload-time = "2025-11-21T18:17:42.277Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/74/2b/cc55a2d1d6fb4f5d458fba44a3d3f91fb4320aa14145799fd3a996af0686/brotlicffi-1.2.0.0-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:84e3d0020cf1bd8b8131f4a07819edee9f283721566fe044a20ec792ca8fd8b7", size = 1534002, upload-time = "2025-11-21T18:17:43.746Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e4/9c/d51486bf366fc7d6735f0e46b5b96ca58dc005b250263525a1eea3cd5d21/brotlicffi-1.2.0.0-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:33cfb408d0cff64cd50bef268c0fed397c46fbb53944aa37264148614a62e990", size = 1536547, upload-time = "2025-11-21T18:17:45.729Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/1b/37/293a9a0a7caf17e6e657668bebb92dfe730305999fe8c0e2703b8888789c/brotlicffi-1.2.0.0-cp38-abi3-win32.whl", hash = "sha256:23e5c912fdc6fd37143203820230374d24babd078fc054e18070a647118158f6", size = 343085, upload-time = "2025-11-21T18:17:48.887Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/07/6b/6e92009df3b8b7272f85a0992b306b61c34b7ea1c4776643746e61c380ac/brotlicffi-1.2.0.0-cp38-abi3-win_amd64.whl", hash = "sha256:f139a7cdfe4ae7859513067b736eb44d19fae1186f9e99370092f6915216451b", size = 378586, upload-time = "2025-11-21T18:17:50.531Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "certifi"
|
name = "certifi"
|
||||||
version = "2026.1.4"
|
version = "2026.1.4"
|
||||||
@@ -525,12 +579,29 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/e8/cb/2da4cc83f5edb9c3257d09e1e7ab7b23f049c7962cae8d842bbef0a9cec9/cryptography-46.0.3-cp38-abi3-win_arm64.whl", hash = "sha256:d89c3468de4cdc4f08a57e214384d0471911a3830fcdaf7a8cc587e42a866372", size = 2918740, upload-time = "2025-10-15T23:18:12.277Z" },
|
{ url = "https://files.pythonhosted.org/packages/e8/cb/2da4cc83f5edb9c3257d09e1e7ab7b23f049c7962cae8d842bbef0a9cec9/cryptography-46.0.3-cp38-abi3-win_arm64.whl", hash = "sha256:d89c3468de4cdc4f08a57e214384d0471911a3830fcdaf7a8cc587e42a866372", size = 2918740, upload-time = "2025-10-15T23:18:12.277Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ddgs"
|
||||||
|
version = "9.10.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "click" },
|
||||||
|
{ name = "fake-useragent" },
|
||||||
|
{ name = "httpx", extra = ["brotli", "http2", "socks"] },
|
||||||
|
{ name = "lxml" },
|
||||||
|
{ name = "primp" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/07/76/8dc0323d1577037abad7a679f8af150ebb73a94995d3012de71a8898e6e6/ddgs-9.10.0.tar.gz", hash = "sha256:d9381ff75bdf1ad6691d3d1dc2be12be190d1d32ecd24f1002c492143c52c34f", size = 31491, upload-time = "2025-12-17T23:30:15.021Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b5/0e/d4b7d6a8df5074cf67bc14adead39955b0bf847c947ff6cad0bb527887f4/ddgs-9.10.0-py3-none-any.whl", hash = "sha256:81233d79309836eb03e7df2a0d2697adc83c47c342713132c0ba618f1f2c6eee", size = 40311, upload-time = "2025-12-17T23:30:13.606Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "deer-flow"
|
name = "deer-flow"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = { virtual = "." }
|
source = { virtual = "." }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "agent-sandbox" },
|
{ name = "agent-sandbox" },
|
||||||
|
{ name = "ddgs" },
|
||||||
{ name = "dotenv" },
|
{ name = "dotenv" },
|
||||||
{ name = "fastapi" },
|
{ name = "fastapi" },
|
||||||
{ name = "firecrawl-py" },
|
{ name = "firecrawl-py" },
|
||||||
@@ -561,6 +632,7 @@ dev = [
|
|||||||
[package.metadata]
|
[package.metadata]
|
||||||
requires-dist = [
|
requires-dist = [
|
||||||
{ name = "agent-sandbox", specifier = ">=0.0.19" },
|
{ name = "agent-sandbox", specifier = ">=0.0.19" },
|
||||||
|
{ name = "ddgs", specifier = ">=9.10.0" },
|
||||||
{ name = "dotenv", specifier = ">=0.9.9" },
|
{ name = "dotenv", specifier = ">=0.9.9" },
|
||||||
{ name = "fastapi", specifier = ">=0.115.0" },
|
{ name = "fastapi", specifier = ">=0.115.0" },
|
||||||
{ name = "firecrawl-py", specifier = ">=1.15.0" },
|
{ name = "firecrawl-py", specifier = ">=1.15.0" },
|
||||||
@@ -626,6 +698,15 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/c1/8b/5fe2cc11fee489817272089c4203e679c63b570a5aaeb18d852ae3cbba6a/et_xmlfile-2.0.0-py3-none-any.whl", hash = "sha256:7a91720bc756843502c3b7504c77b8fe44217c85c537d85037f0f536151b2caa", size = 18059, upload-time = "2024-10-25T17:25:39.051Z" },
|
{ url = "https://files.pythonhosted.org/packages/c1/8b/5fe2cc11fee489817272089c4203e679c63b570a5aaeb18d852ae3cbba6a/et_xmlfile-2.0.0-py3-none-any.whl", hash = "sha256:7a91720bc756843502c3b7504c77b8fe44217c85c537d85037f0f536151b2caa", size = 18059, upload-time = "2024-10-25T17:25:39.051Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fake-useragent"
|
||||||
|
version = "2.2.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/41/43/948d10bf42735709edb5ae51e23297d034086f17fc7279fef385a7acb473/fake_useragent-2.2.0.tar.gz", hash = "sha256:4e6ab6571e40cc086d788523cf9e018f618d07f9050f822ff409a4dfe17c16b2", size = 158898, upload-time = "2025-04-14T15:32:19.238Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/51/37/b3ea9cd5558ff4cb51957caca2193981c6b0ff30bd0d2630ac62505d99d0/fake_useragent-2.2.0-py3-none-any.whl", hash = "sha256:67f35ca4d847b0d298187443aaf020413746e56acd985a611908c73dba2daa24", size = 161695, upload-time = "2025-04-14T15:32:17.732Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fastapi"
|
name = "fastapi"
|
||||||
version = "0.128.0"
|
version = "0.128.0"
|
||||||
@@ -880,6 +961,28 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" },
|
{ url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "h2"
|
||||||
|
version = "4.3.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "hpack" },
|
||||||
|
{ name = "hyperframe" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/1d/17/afa56379f94ad0fe8defd37d6eb3f89a25404ffc71d4d848893d270325fc/h2-4.3.0.tar.gz", hash = "sha256:6c59efe4323fa18b47a632221a1888bd7fde6249819beda254aeca909f221bf1", size = 2152026, upload-time = "2025-08-23T18:12:19.778Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/69/b2/119f6e6dcbd96f9069ce9a2665e0146588dc9f88f29549711853645e736a/h2-4.3.0-py3-none-any.whl", hash = "sha256:c438f029a25f7945c69e0ccf0fb951dc3f73a5f6412981daee861431b70e2bdd", size = 61779, upload-time = "2025-08-23T18:12:17.779Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hpack"
|
||||||
|
version = "4.1.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/2c/48/71de9ed269fdae9c8057e5a4c0aa7402e8bb16f2c6e90b3aa53327b113f8/hpack-4.1.0.tar.gz", hash = "sha256:ec5eca154f7056aa06f196a557655c5b009b382873ac8d1e66e79e87535f1dca", size = 51276, upload-time = "2025-01-22T21:44:58.347Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/07/c6/80c95b1b2b94682a72cbdbfb85b81ae2daffa4291fbfa1b1464502ede10d/hpack-4.1.0-py3-none-any.whl", hash = "sha256:157ac792668d995c657d93111f46b4535ed114f0c9c8d672271bbec7eae1b496", size = 34357, upload-time = "2025-01-22T21:44:56.92Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "html5lib"
|
name = "html5lib"
|
||||||
version = "1.1"
|
version = "1.1"
|
||||||
@@ -951,6 +1054,13 @@ wheels = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[package.optional-dependencies]
|
[package.optional-dependencies]
|
||||||
|
brotli = [
|
||||||
|
{ name = "brotli", marker = "platform_python_implementation == 'CPython'" },
|
||||||
|
{ name = "brotlicffi", marker = "platform_python_implementation != 'CPython'" },
|
||||||
|
]
|
||||||
|
http2 = [
|
||||||
|
{ name = "h2" },
|
||||||
|
]
|
||||||
socks = [
|
socks = [
|
||||||
{ name = "socksio" },
|
{ name = "socksio" },
|
||||||
]
|
]
|
||||||
@@ -976,6 +1086,15 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/f0/0f/310fb31e39e2d734ccaa2c0fb981ee41f7bd5056ce9bc29b2248bd569169/humanfriendly-10.0-py2.py3-none-any.whl", hash = "sha256:1697e1a8a8f550fd43c2865cd84542fc175a61dcb779b6fee18cf6b6ccba1477", size = 86794, upload-time = "2021-09-17T21:40:39.897Z" },
|
{ url = "https://files.pythonhosted.org/packages/f0/0f/310fb31e39e2d734ccaa2c0fb981ee41f7bd5056ce9bc29b2248bd569169/humanfriendly-10.0-py2.py3-none-any.whl", hash = "sha256:1697e1a8a8f550fd43c2865cd84542fc175a61dcb779b6fee18cf6b6ccba1477", size = 86794, upload-time = "2021-09-17T21:40:39.897Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hyperframe"
|
||||||
|
version = "6.1.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/02/e7/94f8232d4a74cc99514c13a9f995811485a6903d48e5d952771ef6322e30/hyperframe-6.1.0.tar.gz", hash = "sha256:f630908a00854a7adeabd6382b43923a4c4cd4b821fcb527e6ab9e15382a3b08", size = 26566, upload-time = "2025-01-22T21:41:49.302Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/48/30/47d0bf6072f7252e6521f3447ccfa40b421b6824517f82854703d0f5a98b/hyperframe-6.1.0-py3-none-any.whl", hash = "sha256:b03380493a519fce58ea5af42e4a42317bf9bd425596f7a0835ffce80f1a42e5", size = 13007, upload-time = "2025-01-22T21:41:47.295Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "idna"
|
name = "idna"
|
||||||
version = "3.11"
|
version = "3.11"
|
||||||
@@ -2181,6 +2300,22 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" },
|
{ url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "primp"
|
||||||
|
version = "0.15.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/56/0b/a87556189da4de1fc6360ca1aa05e8335509633f836cdd06dd17f0743300/primp-0.15.0.tar.gz", hash = "sha256:1af8ea4b15f57571ff7fc5e282a82c5eb69bc695e19b8ddeeda324397965b30a", size = 113022, upload-time = "2025-04-17T11:41:05.315Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f5/5a/146ac964b99ea7657ad67eb66f770be6577dfe9200cb28f9a95baffd6c3f/primp-0.15.0-cp38-abi3-macosx_10_12_x86_64.whl", hash = "sha256:1b281f4ca41a0c6612d4c6e68b96e28acfe786d226a427cd944baa8d7acd644f", size = 3178914, upload-time = "2025-04-17T11:40:59.558Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/bc/8a/cc2321e32db3ce64d6e32950d5bcbea01861db97bfb20b5394affc45b387/primp-0.15.0-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:489cbab55cd793ceb8f90bb7423c6ea64ebb53208ffcf7a044138e3c66d77299", size = 2955079, upload-time = "2025-04-17T11:40:57.398Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c3/7b/cbd5d999a07ff2a21465975d4eb477ae6f69765e8fe8c9087dab250180d8/primp-0.15.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c18b45c23f94016215f62d2334552224236217aaeb716871ce0e4dcfa08eb161", size = 3281018, upload-time = "2025-04-17T11:40:55.308Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/1b/6e/a6221c612e61303aec2bcac3f0a02e8b67aee8c0db7bdc174aeb8010f975/primp-0.15.0-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:e985a9cba2e3f96a323722e5440aa9eccaac3178e74b884778e926b5249df080", size = 3255229, upload-time = "2025-04-17T11:40:47.811Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3b/54/bfeef5aca613dc660a69d0760a26c6b8747d8fdb5a7f20cb2cee53c9862f/primp-0.15.0-cp38-abi3-manylinux_2_34_armv7l.whl", hash = "sha256:6b84a6ffa083e34668ff0037221d399c24d939b5629cd38223af860de9e17a83", size = 3014522, upload-time = "2025-04-17T11:40:50.191Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ac/96/84078e09f16a1dad208f2fe0f8a81be2cf36e024675b0f9eec0c2f6e2182/primp-0.15.0-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:592f6079646bdf5abbbfc3b0a28dac8de943f8907a250ce09398cda5eaebd260", size = 3418567, upload-time = "2025-04-17T11:41:01.595Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/6c/80/8a7a9587d3eb85be3d0b64319f2f690c90eb7953e3f73a9ddd9e46c8dc42/primp-0.15.0-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:5a728e5a05f37db6189eb413d22c78bd143fa59dd6a8a26dacd43332b3971fe8", size = 3606279, upload-time = "2025-04-17T11:41:03.61Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0c/dd/f0183ed0145e58cf9d286c1b2c14f63ccee987a4ff79ac85acc31b5d86bd/primp-0.15.0-cp38-abi3-win_amd64.whl", hash = "sha256:aeb6bd20b06dfc92cfe4436939c18de88a58c640752cf7f30d9e4ae893cdec32", size = 3149967, upload-time = "2025-04-17T11:41:07.067Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "propcache"
|
name = "propcache"
|
||||||
version = "0.4.1"
|
version = "0.4.1"
|
||||||
|
|||||||
@@ -100,6 +100,13 @@ tools:
|
|||||||
use: src.community.jina_ai.tools:web_fetch_tool
|
use: src.community.jina_ai.tools:web_fetch_tool
|
||||||
timeout: 10
|
timeout: 10
|
||||||
|
|
||||||
|
# Image search tool (uses DuckDuckGo)
|
||||||
|
# Use this to find reference images before image generation
|
||||||
|
- name: image_search
|
||||||
|
group: web
|
||||||
|
use: src.community.image_search.tools:image_search_tool
|
||||||
|
max_results: 5
|
||||||
|
|
||||||
# File operations tools
|
# File operations tools
|
||||||
- name: ls
|
- name: ls
|
||||||
group: file:read
|
group: file:read
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ import { cn } from "@/lib/utils";
|
|||||||
|
|
||||||
import { useArtifacts } from "../artifacts";
|
import { useArtifacts } from "../artifacts";
|
||||||
import { FlipDisplay } from "../flip-display";
|
import { FlipDisplay } from "../flip-display";
|
||||||
|
import { Tooltip } from "../tooltip";
|
||||||
|
|
||||||
export function MessageGroup({
|
export function MessageGroup({
|
||||||
className,
|
className,
|
||||||
@@ -217,6 +218,48 @@ function ToolCall({
|
|||||||
)}
|
)}
|
||||||
</ChainOfThoughtStep>
|
</ChainOfThoughtStep>
|
||||||
);
|
);
|
||||||
|
} else if (name === "image_search") {
|
||||||
|
let label: React.ReactNode = t.toolCalls.searchForRelatedImages;
|
||||||
|
if (typeof args.query === "string") {
|
||||||
|
label = t.toolCalls.searchForRelatedImagesFor(args.query);
|
||||||
|
}
|
||||||
|
const results = (
|
||||||
|
result as {
|
||||||
|
results: {
|
||||||
|
source_url: string;
|
||||||
|
thumbnail_url: string;
|
||||||
|
image_url: string;
|
||||||
|
title: string;
|
||||||
|
}[];
|
||||||
|
}
|
||||||
|
)?.results;
|
||||||
|
return (
|
||||||
|
<ChainOfThoughtStep key={id} label={label} icon={SearchIcon}>
|
||||||
|
{Array.isArray(results) && (
|
||||||
|
<ChainOfThoughtSearchResults>
|
||||||
|
{Array.isArray(results) &&
|
||||||
|
results.map((item) => (
|
||||||
|
<Tooltip key={item.image_url} content={item.title}>
|
||||||
|
<a
|
||||||
|
className="size-24 overflow-hidden rounded-lg object-cover"
|
||||||
|
href={item.source_url}
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
className="size-24 object-cover"
|
||||||
|
src={item.thumbnail_url}
|
||||||
|
alt={item.title}
|
||||||
|
width={100}
|
||||||
|
height={100}
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
</Tooltip>
|
||||||
|
))}
|
||||||
|
</ChainOfThoughtSearchResults>
|
||||||
|
)}
|
||||||
|
</ChainOfThoughtStep>
|
||||||
|
);
|
||||||
} else if (name === "web_fetch") {
|
} else if (name === "web_fetch") {
|
||||||
const url = (args as { url: string })?.url;
|
const url = (args as { url: string })?.url;
|
||||||
let title = url;
|
let title = url;
|
||||||
|
|||||||
@@ -243,7 +243,7 @@ function MessageContent_({
|
|||||||
if (typeof src !== "string") {
|
if (typeof src !== "string") {
|
||||||
return (
|
return (
|
||||||
<img
|
<img
|
||||||
className="max-w-full overflow-hidden rounded-lg"
|
className="max-w-[90%] overflow-hidden rounded-lg"
|
||||||
src={src}
|
src={src}
|
||||||
alt={alt}
|
alt={alt}
|
||||||
/>
|
/>
|
||||||
@@ -256,7 +256,7 @@ function MessageContent_({
|
|||||||
return (
|
return (
|
||||||
<a href={url} target="_blank" rel="noopener noreferrer">
|
<a href={url} target="_blank" rel="noopener noreferrer">
|
||||||
<img
|
<img
|
||||||
className="max-w-full overflow-hidden rounded-lg"
|
className="max-w-[90%] overflow-hidden rounded-lg"
|
||||||
src={url}
|
src={url}
|
||||||
alt={alt}
|
alt={alt}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -53,6 +53,17 @@ export function MessageList({
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if (group.type === "assistant:clarification") {
|
||||||
|
const message = group.messages[0];
|
||||||
|
if (message && hasContent(message)) {
|
||||||
|
return (
|
||||||
|
<MessageResponse key={group.id} rehypePlugins={rehypePlugins}>
|
||||||
|
{extractContentFromMessage(message)}
|
||||||
|
</MessageResponse>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
if (group.type === "assistant:present-files") {
|
if (group.type === "assistant:present-files") {
|
||||||
const files: string[] = [];
|
const files: string[] = [];
|
||||||
for (const message of group.messages) {
|
for (const message of group.messages) {
|
||||||
|
|||||||
@@ -106,6 +106,9 @@ export const enUS: Translations = {
|
|||||||
needYourHelp: "Need your help",
|
needYourHelp: "Need your help",
|
||||||
useTool: (toolName: string) => `Use "${toolName}" tool`,
|
useTool: (toolName: string) => `Use "${toolName}" tool`,
|
||||||
searchForRelatedInfo: "Search for related information",
|
searchForRelatedInfo: "Search for related information",
|
||||||
|
searchForRelatedImages: "Search for related images",
|
||||||
|
searchForRelatedImagesFor: (query: string) =>
|
||||||
|
`Search for related images for "${query}"`,
|
||||||
searchOnWebFor: (query: string) => `Search on the web for "${query}"`,
|
searchOnWebFor: (query: string) => `Search on the web for "${query}"`,
|
||||||
viewWebPage: "View web page",
|
viewWebPage: "View web page",
|
||||||
listFolder: "List folder",
|
listFolder: "List folder",
|
||||||
|
|||||||
@@ -101,6 +101,8 @@ export interface Translations {
|
|||||||
needYourHelp: string;
|
needYourHelp: string;
|
||||||
useTool: (toolName: string) => string;
|
useTool: (toolName: string) => string;
|
||||||
searchForRelatedInfo: string;
|
searchForRelatedInfo: string;
|
||||||
|
searchForRelatedImages: string;
|
||||||
|
searchForRelatedImagesFor: (query: string) => string;
|
||||||
searchOnWebFor: (query: string) => string;
|
searchOnWebFor: (query: string) => string;
|
||||||
viewWebPage: string;
|
viewWebPage: string;
|
||||||
listFolder: string;
|
listFolder: string;
|
||||||
|
|||||||
@@ -104,6 +104,8 @@ export const zhCN: Translations = {
|
|||||||
needYourHelp: "需要你的协助",
|
needYourHelp: "需要你的协助",
|
||||||
useTool: (toolName: string) => `使用 “${toolName}” 工具`,
|
useTool: (toolName: string) => `使用 “${toolName}” 工具`,
|
||||||
searchForRelatedInfo: "搜索相关信息",
|
searchForRelatedInfo: "搜索相关信息",
|
||||||
|
searchForRelatedImages: "搜索相关图片",
|
||||||
|
searchForRelatedImagesFor: (query: string) => `搜索相关图片 “${query}”`,
|
||||||
searchOnWebFor: (query: string) => `在网络上搜索 “${query}”`,
|
searchOnWebFor: (query: string) => `在网络上搜索 “${query}”`,
|
||||||
viewWebPage: "查看网页",
|
viewWebPage: "查看网页",
|
||||||
listFolder: "列出文件夹",
|
listFolder: "列出文件夹",
|
||||||
|
|||||||
@@ -14,11 +14,14 @@ interface AssistantMessageGroup extends GenericMessageGroup<"assistant"> {}
|
|||||||
|
|
||||||
interface AssistantPresentFilesGroup extends GenericMessageGroup<"assistant:present-files"> {}
|
interface AssistantPresentFilesGroup extends GenericMessageGroup<"assistant:present-files"> {}
|
||||||
|
|
||||||
|
interface AssistantClarificationGroup extends GenericMessageGroup<"assistant:clarification"> {}
|
||||||
|
|
||||||
type MessageGroup =
|
type MessageGroup =
|
||||||
| HumanMessageGroup
|
| HumanMessageGroup
|
||||||
| AssistantProcessingGroup
|
| AssistantProcessingGroup
|
||||||
| AssistantMessageGroup
|
| AssistantMessageGroup
|
||||||
| AssistantPresentFilesGroup;
|
| AssistantPresentFilesGroup
|
||||||
|
| AssistantClarificationGroup;
|
||||||
|
|
||||||
export function groupMessages<T>(
|
export function groupMessages<T>(
|
||||||
messages: Message[],
|
messages: Message[],
|
||||||
@@ -38,10 +41,28 @@ export function groupMessages<T>(
|
|||||||
messages: [message],
|
messages: [message],
|
||||||
});
|
});
|
||||||
} else if (message.type === "tool") {
|
} else if (message.type === "tool") {
|
||||||
if (
|
// Check if this is a clarification tool message
|
||||||
|
if (isClarificationToolMessage(message)) {
|
||||||
|
// Add to processing group if available (to maintain tool call association)
|
||||||
|
if (
|
||||||
|
lastGroup &&
|
||||||
|
lastGroup.type !== "human" &&
|
||||||
|
lastGroup.type !== "assistant" &&
|
||||||
|
lastGroup.type !== "assistant:clarification"
|
||||||
|
) {
|
||||||
|
lastGroup.messages.push(message);
|
||||||
|
}
|
||||||
|
// Also create a separate clarification group for prominent display
|
||||||
|
groups.push({
|
||||||
|
id: message.id,
|
||||||
|
type: "assistant:clarification",
|
||||||
|
messages: [message],
|
||||||
|
});
|
||||||
|
} else if (
|
||||||
lastGroup &&
|
lastGroup &&
|
||||||
lastGroup.type !== "human" &&
|
lastGroup.type !== "human" &&
|
||||||
lastGroup.type !== "assistant"
|
lastGroup.type !== "assistant" &&
|
||||||
|
lastGroup.type !== "assistant:clarification"
|
||||||
) {
|
) {
|
||||||
lastGroup.messages.push(message);
|
lastGroup.messages.push(message);
|
||||||
} else {
|
} else {
|
||||||
@@ -186,10 +207,15 @@ export function hasToolCalls(message: Message) {
|
|||||||
|
|
||||||
export function hasPresentFiles(message: Message) {
|
export function hasPresentFiles(message: Message) {
|
||||||
return (
|
return (
|
||||||
message.type === "ai" && message.tool_calls?.[0]?.name === "present_files"
|
message.type === "ai" &&
|
||||||
|
message.tool_calls?.some((toolCall) => toolCall.name === "present_files")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isClarificationToolMessage(message: Message) {
|
||||||
|
return message.type === "tool" && message.name === "ask_clarification";
|
||||||
|
}
|
||||||
|
|
||||||
export function extractPresentFilesFromMessage(message: Message) {
|
export function extractPresentFilesFromMessage(message: Message) {
|
||||||
if (message.type !== "ai" || !hasPresentFiles(message)) {
|
if (message.type !== "ai" || !hasPresentFiles(message)) {
|
||||||
return [];
|
return [];
|
||||||
|
|||||||
169
skills/public/deep-research/SKILL.md
Normal file
169
skills/public/deep-research/SKILL.md
Normal file
@@ -0,0 +1,169 @@
|
|||||||
|
---
|
||||||
|
name: deep-research
|
||||||
|
description: Use this skill BEFORE any content generation task (PPT, design, articles, images, videos, reports). Provides a systematic methodology for conducting thorough, multi-angle web research to gather comprehensive information.
|
||||||
|
---
|
||||||
|
|
||||||
|
# Deep Research Skill
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
This skill provides a systematic methodology for conducting thorough web research. **Load this skill BEFORE starting any content generation task** to ensure you gather sufficient information from multiple angles, depths, and sources.
|
||||||
|
|
||||||
|
## When to Use This Skill
|
||||||
|
|
||||||
|
**Always load this skill first when the task involves creating:**
|
||||||
|
- Presentations (PPT/slides)
|
||||||
|
- Frontend designs or UI mockups
|
||||||
|
- Articles, reports, or documentation
|
||||||
|
- Videos or multimedia content
|
||||||
|
- Any content that requires real-world information, examples, or current data
|
||||||
|
|
||||||
|
## Core Principle
|
||||||
|
|
||||||
|
**Never generate content based solely on general knowledge.** The quality of your output directly depends on the quality and quantity of research conducted beforehand. A single search query is NEVER enough.
|
||||||
|
|
||||||
|
## Research Methodology
|
||||||
|
|
||||||
|
### Phase 1: Broad Exploration
|
||||||
|
|
||||||
|
Start with broad searches to understand the landscape:
|
||||||
|
|
||||||
|
1. **Initial Survey**: Search for the main topic to understand the overall context
|
||||||
|
2. **Identify Dimensions**: From initial results, identify key subtopics, themes, angles, or aspects that need deeper exploration
|
||||||
|
3. **Map the Territory**: Note different perspectives, stakeholders, or viewpoints that exist
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```
|
||||||
|
Topic: "AI in healthcare"
|
||||||
|
Initial searches:
|
||||||
|
- "AI healthcare applications 2024"
|
||||||
|
- "artificial intelligence medical diagnosis"
|
||||||
|
- "healthcare AI market trends"
|
||||||
|
|
||||||
|
Identified dimensions:
|
||||||
|
- Diagnostic AI (radiology, pathology)
|
||||||
|
- Treatment recommendation systems
|
||||||
|
- Administrative automation
|
||||||
|
- Patient monitoring
|
||||||
|
- Regulatory landscape
|
||||||
|
- Ethical considerations
|
||||||
|
```
|
||||||
|
|
||||||
|
### Phase 2: Deep Dive
|
||||||
|
|
||||||
|
For each important dimension identified, conduct targeted research:
|
||||||
|
|
||||||
|
1. **Specific Queries**: Search with precise keywords for each subtopic
|
||||||
|
2. **Multiple Phrasings**: Try different keyword combinations and phrasings
|
||||||
|
3. **Fetch Full Content**: Use `web_fetch` to read important sources in full, not just snippets
|
||||||
|
4. **Follow References**: When sources mention other important resources, search for those too
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```
|
||||||
|
Dimension: "Diagnostic AI in radiology"
|
||||||
|
Targeted searches:
|
||||||
|
- "AI radiology FDA approved systems"
|
||||||
|
- "chest X-ray AI detection accuracy"
|
||||||
|
- "radiology AI clinical trials results"
|
||||||
|
|
||||||
|
Then fetch and read:
|
||||||
|
- Key research papers or summaries
|
||||||
|
- Industry reports
|
||||||
|
- Real-world case studies
|
||||||
|
```
|
||||||
|
|
||||||
|
### Phase 3: Diversity & Validation
|
||||||
|
|
||||||
|
Ensure comprehensive coverage by seeking diverse information types:
|
||||||
|
|
||||||
|
| Information Type | Purpose | Example Searches |
|
||||||
|
|-----------------|---------|------------------|
|
||||||
|
| **Facts & Data** | Concrete evidence | "statistics", "data", "numbers", "market size" |
|
||||||
|
| **Examples & Cases** | Real-world applications | "case study", "example", "implementation" |
|
||||||
|
| **Expert Opinions** | Authority perspectives | "expert analysis", "interview", "commentary" |
|
||||||
|
| **Trends & Predictions** | Future direction | "trends 2024", "forecast", "future of" |
|
||||||
|
| **Comparisons** | Context and alternatives | "vs", "comparison", "alternatives" |
|
||||||
|
| **Challenges & Criticisms** | Balanced view | "challenges", "limitations", "criticism" |
|
||||||
|
|
||||||
|
### Phase 4: Synthesis Check
|
||||||
|
|
||||||
|
Before proceeding to content generation, verify:
|
||||||
|
|
||||||
|
- [ ] Have I searched from at least 3-5 different angles?
|
||||||
|
- [ ] Have I fetched and read the most important sources in full?
|
||||||
|
- [ ] Do I have concrete data, examples, and expert perspectives?
|
||||||
|
- [ ] Have I explored both positive aspects and challenges/limitations?
|
||||||
|
- [ ] Is my information current and from authoritative sources?
|
||||||
|
|
||||||
|
**If any answer is NO, continue researching before generating content.**
|
||||||
|
|
||||||
|
## Search Strategy Tips
|
||||||
|
|
||||||
|
### Effective Query Patterns
|
||||||
|
|
||||||
|
```
|
||||||
|
# Be specific with context
|
||||||
|
❌ "AI trends"
|
||||||
|
✅ "enterprise AI adoption trends 2024"
|
||||||
|
|
||||||
|
# Include authoritative source hints
|
||||||
|
"[topic] research paper"
|
||||||
|
"[topic] McKinsey report"
|
||||||
|
"[topic] industry analysis"
|
||||||
|
|
||||||
|
# Search for specific content types
|
||||||
|
"[topic] case study"
|
||||||
|
"[topic] statistics"
|
||||||
|
"[topic] expert interview"
|
||||||
|
|
||||||
|
# Use temporal qualifiers
|
||||||
|
"[topic] 2024"
|
||||||
|
"[topic] latest"
|
||||||
|
"[topic] recent developments"
|
||||||
|
```
|
||||||
|
|
||||||
|
### When to Use web_fetch
|
||||||
|
|
||||||
|
Use `web_fetch` to read full content when:
|
||||||
|
- A search result looks highly relevant and authoritative
|
||||||
|
- You need detailed information beyond the snippet
|
||||||
|
- The source contains data, case studies, or expert analysis
|
||||||
|
- You want to understand the full context of a finding
|
||||||
|
|
||||||
|
### Iterative Refinement
|
||||||
|
|
||||||
|
Research is iterative. After initial searches:
|
||||||
|
1. Review what you've learned
|
||||||
|
2. Identify gaps in your understanding
|
||||||
|
3. Formulate new, more targeted queries
|
||||||
|
4. Repeat until you have comprehensive coverage
|
||||||
|
|
||||||
|
## Quality Bar
|
||||||
|
|
||||||
|
Your research is sufficient when you can confidently answer:
|
||||||
|
- What are the key facts and data points?
|
||||||
|
- What are 2-3 concrete real-world examples?
|
||||||
|
- What do experts say about this topic?
|
||||||
|
- What are the current trends and future directions?
|
||||||
|
- What are the challenges or limitations?
|
||||||
|
- What makes this topic relevant or important now?
|
||||||
|
|
||||||
|
## Common Mistakes to Avoid
|
||||||
|
|
||||||
|
- ❌ Stopping after 1-2 searches
|
||||||
|
- ❌ Relying on search snippets without reading full sources
|
||||||
|
- ❌ Searching only one aspect of a multi-faceted topic
|
||||||
|
- ❌ Ignoring contradicting viewpoints or challenges
|
||||||
|
- ❌ Using outdated information when current data exists
|
||||||
|
- ❌ Starting content generation before research is complete
|
||||||
|
|
||||||
|
## Output
|
||||||
|
|
||||||
|
After completing research, you should have:
|
||||||
|
1. A comprehensive understanding of the topic from multiple angles
|
||||||
|
2. Specific facts, data points, and statistics
|
||||||
|
3. Real-world examples and case studies
|
||||||
|
4. Expert perspectives and authoritative sources
|
||||||
|
5. Current trends and relevant context
|
||||||
|
|
||||||
|
**Only then proceed to content generation**, using the gathered information to create high-quality, well-informed content.
|
||||||
@@ -158,6 +158,26 @@ After generation:
|
|||||||
- Provide brief description of the generation result
|
- Provide brief description of the generation result
|
||||||
- Offer to iterate if adjustments needed
|
- Offer to iterate if adjustments needed
|
||||||
|
|
||||||
|
## Tips: Enhancing Generation with Reference Images
|
||||||
|
|
||||||
|
For scenarios where visual accuracy is critical, **use the `image_search` tool first** to find reference images before generation.
|
||||||
|
|
||||||
|
**Recommended scenarios for using image_search tool:**
|
||||||
|
- **Character/Portrait Generation**: Search for similar poses, expressions, or styles to guide facial features and body proportions
|
||||||
|
- **Specific Objects or Products**: Find reference images of real objects to ensure accurate representation
|
||||||
|
- **Architectural or Environmental Scenes**: Search for location references to capture authentic details
|
||||||
|
- **Fashion and Clothing**: Find style references to ensure accurate garment details and styling
|
||||||
|
|
||||||
|
**Example workflow:**
|
||||||
|
1. Call the `image_search` tool to find suitable reference images:
|
||||||
|
```
|
||||||
|
image_search(query="Japanese woman street photography 1990s", size="Large")
|
||||||
|
```
|
||||||
|
2. Download the returned image URLs to local files
|
||||||
|
3. Use the downloaded images as `--reference-images` parameter in the generation script
|
||||||
|
|
||||||
|
This approach significantly improves generation quality by providing the model with concrete visual guidance rather than relying solely on text descriptions.
|
||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
- Always use English for prompts regardless of user's language
|
- Always use English for prompts regardless of user's language
|
||||||
|
|||||||
@@ -23,11 +23,14 @@ Choose one of the following styles when creating the presentation plan:
|
|||||||
|
|
||||||
| Style | Description | Best For |
|
| Style | Description | Best For |
|
||||||
|-------|-------------|----------|
|
|-------|-------------|----------|
|
||||||
| **business** | Professional corporate look with clean lines, navy/blue tones, structured layouts, subtle gradients | Corporate reports, business proposals, quarterly reviews |
|
| **glassmorphism** | Frosted glass panels with blur effects, floating translucent cards, vibrant gradient backgrounds, depth through layering | Tech products, AI/SaaS demos, futuristic pitches |
|
||||||
| **academic** | Scholarly and formal, serif fonts aesthetic, muted colors, data-focused layouts, whitespace emphasis | Research presentations, lectures, thesis defense |
|
| **dark-premium** | Rich black backgrounds (#0a0a0a), luminous accent colors, subtle glow effects, luxury brand aesthetic | Premium products, executive presentations, high-end brands |
|
||||||
| **minimal** | Ultra-clean with maximum whitespace, single accent color, simple geometric shapes, focus on content | Product launches, tech demos, modern startups |
|
| **gradient-modern** | Bold mesh gradients, fluid color transitions, contemporary typography, vibrant yet sophisticated | Startups, creative agencies, brand launches |
|
||||||
|
| **neo-brutalist** | Raw bold typography, high contrast, intentional "ugly" aesthetic, anti-design as design, Memphis-inspired | Edgy brands, Gen-Z targeting, disruptive startups |
|
||||||
|
| **3d-isometric** | Clean isometric illustrations, floating 3D elements, soft shadows, tech-forward aesthetic | Tech explainers, product features, SaaS presentations |
|
||||||
|
| **editorial** | Magazine-quality layouts, sophisticated typography hierarchy, dramatic photography, Vogue/Bloomberg aesthetic | Annual reports, luxury brands, thought leadership |
|
||||||
|
| **minimal-swiss** | Grid-based precision, Helvetica-inspired typography, bold use of negative space, timeless modernism | Architecture, design firms, premium consulting |
|
||||||
| **keynote** | Apple-inspired aesthetic with bold typography, dramatic imagery, high contrast, cinematic feel | Keynotes, product reveals, inspirational talks |
|
| **keynote** | Apple-inspired aesthetic with bold typography, dramatic imagery, high contrast, cinematic feel | Keynotes, product reveals, inspirational talks |
|
||||||
| **creative** | Bold colors, artistic layouts, unique compositions, expressive visuals, unconventional designs | Creative pitches, design portfolios, artistic presentations |
|
|
||||||
|
|
||||||
## Workflow
|
## Workflow
|
||||||
|
|
||||||
@@ -159,59 +162,61 @@ Parameters:
|
|||||||
[!NOTE]
|
[!NOTE]
|
||||||
Do NOT read the python file, just call it with the parameters.
|
Do NOT read the python file, just call it with the parameters.
|
||||||
|
|
||||||
## Complete Example: Apple Keynote Style
|
## Complete Example: Glassmorphism Style (最现代前卫)
|
||||||
|
|
||||||
User request: "Create a keynote-style presentation about the future of AI in healthcare"
|
User request: "Create a presentation about AI product launch"
|
||||||
|
|
||||||
### Step 1: Create presentation plan
|
### Step 1: Create presentation plan
|
||||||
|
|
||||||
Create `/mnt/user-data/workspace/ai-healthcare-plan.json`:
|
Create `/mnt/user-data/workspace/ai-product-plan.json`:
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"title": "The Future of AI in Healthcare",
|
"title": "Introducing Nova AI",
|
||||||
"style": "keynote",
|
"style": "glassmorphism",
|
||||||
"style_guidelines": {
|
"style_guidelines": {
|
||||||
"color_palette": "Deep black or dark gray backgrounds, crisp white text, electric blue accent color for highlights",
|
"color_palette": "Vibrant purple-to-cyan gradient background (#667eea→#00d4ff), frosted glass panels with 15-20% white opacity, electric accents",
|
||||||
"typography": "San Francisco or Helvetica Neue inspired, bold headlines 72pt+, light body text, extreme size contrast",
|
"typography": "SF Pro Display style, bold 700 weight white titles with subtle text-shadow, clean 400 weight body text, excellent contrast on glass",
|
||||||
"imagery": "Cinematic photography, dramatic lighting, shallow depth of field, human-centered tech imagery",
|
"imagery": "Abstract 3D glass spheres, floating translucent geometric shapes, soft luminous orbs, depth through layered transparency",
|
||||||
"layout": "Single focal point per slide, asymmetric balance, 60%+ negative space, no bullet points visible"
|
"layout": "Centered frosted glass cards with 32px rounded corners, 48-64px padding, floating above gradient, layered depth with soft shadows",
|
||||||
|
"effects": "Backdrop blur 20-40px on glass panels, subtle white border glow, soft colored shadows matching gradient, light refraction effects",
|
||||||
|
"visual_language": "Apple Vision Pro / visionOS aesthetic, premium depth through transparency, futuristic yet approachable, 2024 design trends"
|
||||||
},
|
},
|
||||||
"aspect_ratio": "16:9",
|
"aspect_ratio": "16:9",
|
||||||
"slides": [
|
"slides": [
|
||||||
{
|
{
|
||||||
"slide_number": 1,
|
"slide_number": 1,
|
||||||
"type": "title",
|
"type": "title",
|
||||||
"title": "The Future of AI in Healthcare",
|
"title": "Introducing Nova AI",
|
||||||
"subtitle": "Transforming Patient Care",
|
"subtitle": "Intelligence, Reimagined",
|
||||||
"visual_description": "Dark cinematic background with subtle blue light rays. Large bold white title centered. Subtle medical imagery (heartbeat line, DNA helix) as abstract light trails. Apple keynote aesthetic with dramatic lighting."
|
"visual_description": "Stunning gradient background flowing from deep purple (#667eea) through magenta to cyan (#00d4ff). Center: large frosted glass panel with strong backdrop blur, containing bold white title 'Introducing Nova AI' and lighter subtitle. Floating 3D glass spheres and abstract shapes around the card creating depth. Soft glow emanating from behind the glass panel. Premium visionOS aesthetic. The glass card has subtle white border (1px rgba 255,255,255,0.3) and soft purple-tinted shadow."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"slide_number": 2,
|
"slide_number": 2,
|
||||||
"type": "content",
|
"type": "content",
|
||||||
"title": "Diagnosis Revolution",
|
"title": "Why Nova?",
|
||||||
"key_points": ["AI detects diseases earlier", "98% accuracy in imaging", "Saves countless lives"],
|
"key_points": ["10x faster processing", "Human-like understanding", "Enterprise-grade security"],
|
||||||
"visual_description": "Split composition: left side shows a doctor viewing a holographic medical scan, right side has the title in large white text. Dark background with blue accent lighting on the hologram. Cinematic, dramatic."
|
"visual_description": "Same purple-cyan gradient background. Left side: floating frosted glass card with title 'Why Nova?' in bold white, three key points below with subtle glass pill badges. Right side: abstract 3D visualization of neural network as interconnected glass nodes with soft glow. Floating translucent geometric shapes (icosahedrons, tori) adding depth. Consistent glassmorphism aesthetic with previous slide."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"slide_number": 3,
|
"slide_number": 3,
|
||||||
"type": "content",
|
"type": "content",
|
||||||
"title": "Personalized Medicine",
|
"title": "How It Works",
|
||||||
"key_points": ["Treatment tailored to your DNA", "Predictive health insights", "AI-powered drug discovery"],
|
"key_points": ["Natural language input", "Multi-modal processing", "Instant insights"],
|
||||||
"visual_description": "Abstract DNA double helix rendered in glowing blue light against deep black. Title overlaid in bold white. Futuristic yet human. Shallow depth of field effect."
|
"visual_description": "Gradient background consistent with previous slides. Central composition: three stacked frosted glass cards at slight angles showing the workflow steps, connected by soft glowing lines. Each card has an abstract icon. Floating glass orbs and light particles around the composition. Title 'How It Works' in bold white at top. Depth created through card layering and transparency."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"slide_number": 4,
|
"slide_number": 4,
|
||||||
"type": "content",
|
"type": "content",
|
||||||
"title": "Always There For You",
|
"title": "Built for Scale",
|
||||||
"key_points": ["24/7 AI health monitoring", "Early warning systems", "Peace of mind"],
|
"key_points": ["1M+ concurrent users", "99.99% uptime", "Global infrastructure"],
|
||||||
"visual_description": "Warm scene of a smartwatch on a wrist displaying health metrics, soft bokeh background of a family moment. Emotional, human-centered. Title in white, positioned to not overlap the main image."
|
"visual_description": "Same gradient background. Asymmetric layout: right side features large frosted glass panel with metrics displayed in bold typography. Left side: abstract 3D globe made of glass panels and connection lines, representing global scale. Floating data visualization elements as small glass cards with numbers. Soft ambient glow throughout. Premium tech aesthetic."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"slide_number": 5,
|
"slide_number": 5,
|
||||||
"type": "conclusion",
|
"type": "conclusion",
|
||||||
"title": "The Future is Now",
|
"title": "The Future Starts Now",
|
||||||
"subtitle": "",
|
"subtitle": "Join the waitlist",
|
||||||
"visual_description": "Powerful closing image: silhouette of a healthcare worker against a sunrise/dawn sky with subtle tech elements. Hopeful, inspiring. Large bold title. Minimal, impactful."
|
"visual_description": "Dramatic finale slide. Gradient background with slightly increased vibrancy. Central frosted glass card with bold title 'The Future Starts Now' and call-to-action subtitle. Behind the card: burst of soft light rays and floating glass particles creating celebration effect. Multiple layered glass shapes creating depth. The most visually impactful slide while maintaining style consistency."
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -223,108 +228,183 @@ Read `/mnt/skills/public/image-generation/SKILL.md` to understand how to generat
|
|||||||
|
|
||||||
### Step 3: Generate slide images sequentially with reference chaining
|
### Step 3: Generate slide images sequentially with reference chaining
|
||||||
|
|
||||||
**Slide 1 - Title (establishes the style):**
|
**Slide 1 - Title (establishes the visual language):**
|
||||||
|
|
||||||
Create `/mnt/user-data/workspace/ai-healthcare-slide-01.json`:
|
Create `/mnt/user-data/workspace/nova-slide-01.json`:
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"prompt": "Professional presentation title slide in Apple Keynote style. Deep black background with subtle blue light rays emanating from center. Large bold white sans-serif title 'The Future of AI in Healthcare' centered, subtitle 'Transforming Patient Care' below in lighter weight. Abstract medical elements (heartbeat line, DNA helix) as subtle glowing blue light trails. Cinematic dramatic lighting. Premium tech aesthetic. 16:9 aspect ratio presentation slide.",
|
"prompt": "Ultra-premium presentation title slide with glassmorphism design. Background: smooth flowing gradient from deep purple (#667eea) through magenta (#f093fb) to cyan (#00d4ff), soft and vibrant. Center: large frosted glass panel with strong backdrop blur effect, rounded corners 32px, containing bold white sans-serif title 'Introducing Nova AI' (72pt, SF Pro Display style, font-weight 700) with subtle text shadow, subtitle 'Intelligence, Reimagined' below in lighter weight. The glass panel has subtle white border (1px rgba 255,255,255,0.25) and soft purple-tinted drop shadow. Floating around the card: 3D glass spheres with refraction, translucent geometric shapes (icosahedrons, abstract blobs), creating depth and dimension. Soft luminous glow emanating from behind the glass panel. Small floating particles of light. Apple Vision Pro / visionOS UI aesthetic. Professional presentation slide, 16:9 aspect ratio. Hyper-modern, premium tech product launch feel.",
|
||||||
"style": "Apple Keynote presentation, premium tech aesthetic, cinematic dramatic lighting, WWDC style",
|
"style": "Glassmorphism, visionOS aesthetic, Apple Vision Pro UI style, premium tech, 2024 design trends",
|
||||||
"composition": "Centered title, 60% negative space, subtle background imagery, clear text hierarchy",
|
"composition": "Centered glass card as focal point, floating 3D elements creating depth at edges, 40% negative space, clear visual hierarchy",
|
||||||
"lighting": "Dramatic rim lighting, subtle blue accent glow, dark moody atmosphere",
|
"lighting": "Soft ambient glow from gradient, light refraction through glass elements, subtle rim lighting on 3D shapes",
|
||||||
"color_palette": "Deep black background (#0a0a0a), pure white text (#ffffff), electric blue accent (#0071e3)"
|
"color_palette": "Purple gradient #667eea, magenta #f093fb, cyan #00d4ff, frosted white rgba(255,255,255,0.15), pure white text #ffffff",
|
||||||
|
"effects": "Backdrop blur on glass panels, soft drop shadows with color tint, light refraction, subtle noise texture on glass, floating particles"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
python /mnt/skills/public/image-generation/scripts/generate.py \
|
python /mnt/skills/public/image-generation/scripts/generate.py \
|
||||||
--prompt-file /mnt/user-data/workspace/ai-healthcare-slide-01.json \
|
--prompt-file /mnt/user-data/workspace/nova-slide-01.json \
|
||||||
--output-file /mnt/user-data/outputs/ai-healthcare-slide-01.jpg \
|
--output-file /mnt/user-data/outputs/nova-slide-01.jpg \
|
||||||
--aspect-ratio 16:9
|
--aspect-ratio 16:9
|
||||||
```
|
```
|
||||||
|
|
||||||
**Slide 2 - Content (references slide 1):**
|
**Slide 2 - Content (MUST reference slide 1 for consistency):**
|
||||||
|
|
||||||
Create `/mnt/user-data/workspace/ai-healthcare-slide-02.json`:
|
Create `/mnt/user-data/workspace/nova-slide-02.json`:
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"prompt": "Presentation slide continuing the exact visual style from the reference image. Same dark background, same typography style, same blue accent color. Title 'Diagnosis Revolution' in bold white on the right. Left side shows a doctor viewing a holographic medical brain scan with blue glow. Maintain the cinematic Apple Keynote aesthetic from reference. Dark premium tech look.",
|
"prompt": "Presentation slide continuing EXACT visual style from reference image. SAME purple-to-cyan gradient background, SAME glassmorphism aesthetic, SAME typography style. Left side: frosted glass card with backdrop blur containing title 'Why Nova?' in bold white (matching reference font style), three feature points as subtle glass pill badges below. Right side: abstract 3D neural network visualization made of interconnected glass nodes with soft cyan glow, floating in space. Floating translucent geometric shapes (matching style from reference) adding depth. The frosted glass has identical treatment: white border, purple-tinted shadow, same blur intensity. CRITICAL: This slide must look like it belongs in the exact same presentation as the reference image - same colors, same glass treatment, same overall aesthetic.",
|
||||||
"style": "Match reference image style exactly - Apple Keynote, dark cinematic, premium",
|
"style": "MATCH REFERENCE EXACTLY - Glassmorphism, visionOS aesthetic, same visual language",
|
||||||
"composition": "Asymmetric split layout, imagery left, text right, consistent with reference aesthetic",
|
"composition": "Asymmetric split: glass card left (40%), 3D visualization right (40%), breathing room between elements",
|
||||||
"color_palette": "Exactly match the reference image colors - deep black, white text, blue accents",
|
"color_palette": "EXACTLY match reference: purple #667eea, cyan #00d4ff gradient, same frosted white treatment, same text white",
|
||||||
"consistency_note": "Must appear as part of the same presentation as the reference image"
|
"consistency_note": "CRITICAL: Must be visually identical in style to reference image. Same gradient colors, same glass blur intensity, same shadow treatment, same typography weight and style. Viewer should immediately recognize this as the same presentation."
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
python /mnt/skills/public/image-generation/scripts/generate.py \
|
python /mnt/skills/public/image-generation/scripts/generate.py \
|
||||||
--prompt-file /mnt/user-data/workspace/ai-healthcare-slide-02.json \
|
--prompt-file /mnt/user-data/workspace/nova-slide-02.json \
|
||||||
--reference-images /mnt/user-data/outputs/ai-healthcare-slide-01.jpg \
|
--reference-images /mnt/user-data/outputs/nova-slide-01.jpg \
|
||||||
--output-file /mnt/user-data/outputs/ai-healthcare-slide-02.jpg \
|
--output-file /mnt/user-data/outputs/nova-slide-02.jpg \
|
||||||
--aspect-ratio 16:9
|
--aspect-ratio 16:9
|
||||||
```
|
```
|
||||||
|
|
||||||
**Continue for slides 3-5, each referencing the previous slide...**
|
**Slides 3-5: Continue the same pattern, each referencing the previous slide**
|
||||||
|
|
||||||
|
Key consistency rules for subsequent slides:
|
||||||
|
- Always include "continuing EXACT visual style from reference image" in prompt
|
||||||
|
- Specify "SAME gradient background", "SAME glass treatment", "SAME typography"
|
||||||
|
- Include `consistency_note` emphasizing style matching
|
||||||
|
- Reference the immediately previous slide image
|
||||||
|
|
||||||
### Step 4: Compose final PPT
|
### Step 4: Compose final PPT
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
python /mnt/skills/public/ppt-generation/scripts/generate.py \
|
python /mnt/skills/public/ppt-generation/scripts/generate.py \
|
||||||
--plan-file /mnt/user-data/workspace/ai-healthcare-plan.json \
|
--plan-file /mnt/user-data/workspace/nova-plan.json \
|
||||||
--slide-images /mnt/user-data/outputs/ai-healthcare-slide-01.jpg /mnt/user-data/outputs/ai-healthcare-slide-02.jpg /mnt/user-data/outputs/ai-healthcare-slide-03.jpg /mnt/user-data/outputs/ai-healthcare-slide-04.jpg /mnt/user-data/outputs/ai-healthcare-slide-05.jpg \
|
--slide-images /mnt/user-data/outputs/nova-slide-01.jpg /mnt/user-data/outputs/nova-slide-02.jpg /mnt/user-data/outputs/nova-slide-03.jpg /mnt/user-data/outputs/nova-slide-04.jpg /mnt/user-data/outputs/nova-slide-05.jpg \
|
||||||
--output-file /mnt/user-data/outputs/ai-healthcare-presentation.pptx
|
--output-file /mnt/user-data/outputs/nova-presentation.pptx
|
||||||
```
|
```
|
||||||
|
|
||||||
## Style-Specific Guidelines
|
## Style-Specific Guidelines
|
||||||
|
|
||||||
### Business Style
|
### Glassmorphism Style (推荐 - 最现代前卫)
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"style": "business",
|
"style": "glassmorphism",
|
||||||
"style_guidelines": {
|
"style_guidelines": {
|
||||||
"color_palette": "Navy blue (#1a365d), white, light gray backgrounds, subtle gold accents",
|
"color_palette": "Vibrant gradient backgrounds (purple #667eea to pink #f093fb, or cyan #4facfe to blue #00f2fe), frosted white panels with 20% opacity, accent colors that pop against the gradient",
|
||||||
"typography": "Clean sans-serif (Arial, Calibri style), professional hierarchy, 44pt titles",
|
"typography": "SF Pro Display or Inter font style, bold 600-700 weight titles, clean 400 weight body, white text with subtle drop shadow for readability on glass",
|
||||||
"imagery": "Professional photography, office environments, handshakes, charts, clean iconography",
|
"imagery": "Abstract 3D shapes floating in space, soft blurred orbs, geometric primitives with glass material, depth through overlapping translucent layers",
|
||||||
"layout": "Grid-based, structured, clear sections, subtle divider lines, company branding space"
|
"layout": "Floating card panels with backdrop-blur effect, generous padding (48-64px), rounded corners (24-32px radius), layered depth with subtle shadows",
|
||||||
|
"effects": "Frosted glass blur (backdrop-filter: blur 20px), subtle white border (1px rgba 255,255,255,0.2), soft glow behind panels, floating elements with drop shadows",
|
||||||
|
"visual_language": "Premium tech aesthetic like Apple Vision Pro UI, depth through transparency, light refracting through glass surfaces"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Academic Style
|
### Dark Premium Style
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"style": "academic",
|
"style": "dark-premium",
|
||||||
"style_guidelines": {
|
"style_guidelines": {
|
||||||
"color_palette": "White/cream backgrounds, dark navy text, burgundy or forest green accents",
|
"color_palette": "Deep black base (#0a0a0a to #121212), luminous accent color (electric blue #00d4ff, neon purple #bf5af2, or gold #ffd700), subtle gray gradients for depth (#1a1a1a to #0a0a0a)",
|
||||||
"typography": "Serif fonts (Times, Georgia style) for scholarly feel, clear hierarchy for citations",
|
"typography": "Elegant sans-serif (Neue Haas Grotesk or Suisse Int'l style), dramatic size contrast (72pt+ headlines, 18pt body), letter-spacing -0.02em for headlines, pure white (#ffffff) text",
|
||||||
"imagery": "Diagrams, charts, scholarly imagery, books, research settings, data visualizations",
|
"imagery": "Dramatic studio lighting, rim lights and edge glow, cinematic product shots, abstract light trails, premium material textures (brushed metal, matte surfaces)",
|
||||||
"layout": "Traditional layouts, room for references, structured content areas, institution logo space"
|
"layout": "Generous negative space (60%+), asymmetric balance, content anchored to grid but with breathing room, single focal point per slide",
|
||||||
|
"effects": "Subtle ambient glow behind key elements, light bloom effects, grain texture overlay (2-3% opacity), vignette on edges",
|
||||||
|
"visual_language": "Luxury tech brand aesthetic (Bang & Olufsen, Porsche Design), sophistication through restraint, every element intentional"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Minimal Style
|
### Gradient Modern Style
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"style": "minimal",
|
"style": "gradient-modern",
|
||||||
"style_guidelines": {
|
"style_guidelines": {
|
||||||
"color_palette": "Pure white background, black text, single accent color (e.g., coral, teal)",
|
"color_palette": "Bold mesh gradients (Stripe/Linear style: purple-pink-orange #7c3aed→#ec4899→#f97316, or cool tones: cyan-blue-purple #06b6d4→#3b82f6→#8b5cf6), white or dark text depending on background intensity",
|
||||||
"typography": "Thin modern sans-serif, generous letter-spacing, one font weight for body",
|
"typography": "Modern geometric sans-serif (Satoshi, General Sans, or Clash Display style), variable font weights, oversized bold headlines (80pt+), comfortable body text (20pt)",
|
||||||
"imagery": "Simple line illustrations, geometric shapes, isolated objects, vast whitespace",
|
"imagery": "Abstract fluid shapes, morphing gradients, 3D rendered abstract objects, soft organic forms, floating geometric primitives",
|
||||||
"layout": "Maximum whitespace (70%+), single element focus, extreme simplicity"
|
"layout": "Dynamic asymmetric compositions, overlapping elements with blend modes, text integrated with gradient flows, full-bleed backgrounds",
|
||||||
|
"effects": "Smooth gradient transitions, subtle noise texture (3-5% for depth), soft shadows with color tint matching gradient, motion blur suggesting movement",
|
||||||
|
"visual_language": "Contemporary SaaS aesthetic (Stripe, Linear, Vercel), energetic yet professional, forward-thinking tech vibes"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Creative Style
|
### Neo-Brutalist Style
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"style": "creative",
|
"style": "neo-brutalist",
|
||||||
"style_guidelines": {
|
"style_guidelines": {
|
||||||
"color_palette": "Bold vibrant colors, gradients, unexpected color combinations, high saturation",
|
"color_palette": "High contrast primaries: stark black, pure white, with bold accent (hot pink #ff0080, electric yellow #ffff00, or raw red #ff0000), optional: Memphis-inspired pastels as secondary",
|
||||||
"typography": "Mix of display and body fonts, creative text arrangements, variable sizes",
|
"typography": "Ultra-bold condensed type (Impact, Druk, or Bebas Neue style), UPPERCASE headlines, extreme size contrast, intentionally tight or overlapping letter-spacing",
|
||||||
"imagery": "Artistic photography, illustrations, collage elements, textures, hand-drawn elements",
|
"imagery": "Raw unfiltered photography, intentional visual noise, halftone patterns, cut-out collage aesthetic, hand-drawn elements, stickers and stamps",
|
||||||
"layout": "Breaking the grid, overlapping elements, dynamic compositions, visual storytelling"
|
"layout": "Broken grid, overlapping elements, thick black borders (4-8px), visible structure, anti-whitespace (dense but organized chaos)",
|
||||||
|
"effects": "Hard shadows (no blur, offset 8-12px), pixelation accents, scan lines, CRT screen effects, intentional 'mistakes'",
|
||||||
|
"visual_language": "Anti-corporate rebellion, DIY zine aesthetic meets digital, raw authenticity, memorable through boldness"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3D Isometric Style
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"style": "3d-isometric",
|
||||||
|
"style_guidelines": {
|
||||||
|
"color_palette": "Soft contemporary palette: muted purples (#8b5cf6), teals (#14b8a6), warm corals (#fb7185), with cream or light gray backgrounds (#fafafa), consistent saturation across elements",
|
||||||
|
"typography": "Friendly geometric sans-serif (Circular, Gilroy, or Quicksand style), medium weight headlines, excellent readability, comfortable 24pt body text",
|
||||||
|
"imagery": "Clean isometric 3D illustrations, consistent 30° isometric angle, soft clay-render aesthetic, floating platforms and devices, cute simplified objects",
|
||||||
|
"layout": "Central isometric scene as hero, text balanced around 3D elements, clear visual hierarchy, comfortable margins (64px+)",
|
||||||
|
"effects": "Soft drop shadows (20px blur, 30% opacity), ambient occlusion on 3D objects, subtle gradients on surfaces, consistent light source (top-left)",
|
||||||
|
"visual_language": "Friendly tech illustration (Slack, Notion, Asana style), approachable complexity, clarity through simplification"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Editorial Style
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"style": "editorial",
|
||||||
|
"style_guidelines": {
|
||||||
|
"color_palette": "Sophisticated neutrals: off-white (#f5f5f0), charcoal (#2d2d2d), with single accent color (burgundy #7c2d12, forest #14532d, or navy #1e3a5f), occasional full-color photography",
|
||||||
|
"typography": "Refined serif for headlines (Playfair Display, Freight, or Editorial New style), clean sans-serif for body (Söhne, Graphik), dramatic size hierarchy (96pt headlines, 16pt body), generous line-height 1.6",
|
||||||
|
"imagery": "Magazine-quality photography, dramatic crops, full-bleed images, portraits with intentional negative space, editorial lighting (Vogue, Bloomberg Businessweek style)",
|
||||||
|
"layout": "Sophisticated grid system (12-column), intentional asymmetry, pull quotes as design elements, text wrapping around images, elegant margins",
|
||||||
|
"effects": "Minimal effects - let photography and typography shine, subtle image treatments (slight desaturation, film grain), elegant borders and rules",
|
||||||
|
"visual_language": "High-end magazine aesthetic, intellectual sophistication, content elevated through design restraint"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Minimal Swiss Style
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"style": "minimal-swiss",
|
||||||
|
"style_guidelines": {
|
||||||
|
"color_palette": "Pure white (#ffffff) or off-white (#fafaf9) backgrounds, true black (#000000) text, single bold accent (Swiss red #ff0000, Klein blue #002fa7, or signal yellow #ffcc00)",
|
||||||
|
"typography": "Helvetica Neue or Aktiv Grotesk, strict type scale (12/16/24/48/96), medium weight for body, bold for emphasis only, flush-left ragged-right alignment",
|
||||||
|
"imagery": "Objective photography, geometric shapes, clean iconography, mathematical precision, intentional empty space as compositional element",
|
||||||
|
"layout": "Strict grid adherence (baseline grid visible in spirit), modular compositions, generous whitespace (40%+ of slide), content aligned to invisible grid lines",
|
||||||
|
"effects": "None - purity of form, no shadows, no gradients, no decorative elements, occasional single hairline rules",
|
||||||
|
"visual_language": "International Typographic Style, form follows function, timeless modernism, Dieter Rams-inspired restraint"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Keynote Style (Apple风格)
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"style": "keynote",
|
||||||
|
"style_guidelines": {
|
||||||
|
"color_palette": "Deep blacks (#000000 to #1d1d1f), pure white text, signature blue (#0071e3) or gradient accents (purple-pink for creative, blue-teal for tech)",
|
||||||
|
"typography": "San Francisco Pro Display, extreme weight contrast (bold 80pt+ titles, light 24pt body), negative letter-spacing on headlines (-0.03em), optical alignment",
|
||||||
|
"imagery": "Cinematic photography, shallow depth of field, dramatic lighting (rim lights, spot lighting), product hero shots with reflections, full-bleed imagery",
|
||||||
|
"layout": "Maximum negative space, single powerful image or statement per slide, content centered or dramatically offset, no clutter",
|
||||||
|
"effects": "Subtle gradient overlays, light bloom and glow on key elements, reflection on surfaces, smooth gradient backgrounds",
|
||||||
|
"visual_language": "Apple WWDC keynote aesthetic, confidence through simplicity, every pixel considered, theatrical presentation"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -341,10 +421,42 @@ After generation:
|
|||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
|
### Critical Quality Guidelines
|
||||||
|
|
||||||
|
**Prompt Engineering for Professional Results:**
|
||||||
- Always use English for image prompts regardless of user's language
|
- Always use English for image prompts regardless of user's language
|
||||||
- **Generate slides sequentially** - each slide must reference the previous one for consistency
|
- Be EXTREMELY specific about visual details - vague prompts produce generic results
|
||||||
|
- Include exact hex color codes (e.g., #667eea not "purple")
|
||||||
|
- Specify typography details: font weight (400/700), size hierarchy, letter-spacing
|
||||||
|
- Describe effects precisely: "backdrop blur 20px", "drop shadow 8px blur 30% opacity"
|
||||||
|
- Reference real design systems: "visionOS aesthetic", "Stripe website style", "Bloomberg Businessweek layout"
|
||||||
|
|
||||||
|
**Visual Consistency (Most Important):**
|
||||||
|
- **Generate slides sequentially** - each slide MUST reference the previous one
|
||||||
- The first slide is critical - it establishes the visual language for the entire presentation
|
- The first slide is critical - it establishes the visual language for the entire presentation
|
||||||
- Include style_guidelines in the prompt for every slide to maintain consistency
|
- In every subsequent slide prompt, explicitly state: "continuing EXACT visual style from reference image"
|
||||||
- The image-generation skill is a dependency - ensure it's available
|
- Use SAME, EXACT, MATCH keywords emphatically in prompts to enforce consistency
|
||||||
- If a slide looks inconsistent, regenerate it with stronger reference to the previous slide
|
- Include a `consistency_note` field in every JSON prompt after slide 1
|
||||||
- For best results, be very specific about matching colors, typography, and mood in prompts
|
- If a slide looks inconsistent, regenerate it with STRONGER reference emphasis
|
||||||
|
|
||||||
|
**Design Principles for Modern Aesthetics:**
|
||||||
|
- Embrace negative space - 40-60% empty space creates premium feel
|
||||||
|
- Limit elements per slide - one focal point, one message
|
||||||
|
- Use depth through layering (shadows, transparency, z-depth)
|
||||||
|
- Typography hierarchy: massive headlines (72pt+), comfortable body (18-24pt)
|
||||||
|
- Color restraint: one primary palette, 1-2 accent colors maximum
|
||||||
|
|
||||||
|
**Common Mistakes to Avoid:**
|
||||||
|
- ❌ Generic prompts like "professional slide" - be specific
|
||||||
|
- ❌ Too many elements/text per slide - cluttered = unprofessional
|
||||||
|
- ❌ Inconsistent colors between slides - always reference previous slide
|
||||||
|
- ❌ Skipping the reference image parameter - this breaks visual consistency
|
||||||
|
- ❌ Using different design styles within one presentation
|
||||||
|
|
||||||
|
**Recommended Styles for Different Contexts:**
|
||||||
|
- Tech product launch → `glassmorphism` or `gradient-modern`
|
||||||
|
- Luxury/premium brand → `dark-premium` or `editorial`
|
||||||
|
- Startup pitch → `gradient-modern` or `minimal-swiss`
|
||||||
|
- Executive presentation → `dark-premium` or `keynote`
|
||||||
|
- Creative agency → `neo-brutalist` or `gradient-modern`
|
||||||
|
- Data/analytics → `minimal-swiss` or `3d-isometric`
|
||||||
|
|||||||
Reference in New Issue
Block a user