vanna 0.7.9__py3-none-any.whl → 2.0.0rc1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- vanna/__init__.py +167 -395
- vanna/agents/__init__.py +7 -0
- vanna/capabilities/__init__.py +17 -0
- vanna/capabilities/agent_memory/__init__.py +21 -0
- vanna/capabilities/agent_memory/base.py +103 -0
- vanna/capabilities/agent_memory/models.py +53 -0
- vanna/capabilities/file_system/__init__.py +14 -0
- vanna/capabilities/file_system/base.py +71 -0
- vanna/capabilities/file_system/models.py +25 -0
- vanna/capabilities/sql_runner/__init__.py +13 -0
- vanna/capabilities/sql_runner/base.py +37 -0
- vanna/capabilities/sql_runner/models.py +13 -0
- vanna/components/__init__.py +92 -0
- vanna/components/base.py +11 -0
- vanna/components/rich/__init__.py +83 -0
- vanna/components/rich/containers/__init__.py +7 -0
- vanna/components/rich/containers/card.py +20 -0
- vanna/components/rich/data/__init__.py +9 -0
- vanna/components/rich/data/chart.py +17 -0
- vanna/components/rich/data/dataframe.py +93 -0
- vanna/components/rich/feedback/__init__.py +21 -0
- vanna/components/rich/feedback/badge.py +16 -0
- vanna/components/rich/feedback/icon_text.py +14 -0
- vanna/components/rich/feedback/log_viewer.py +41 -0
- vanna/components/rich/feedback/notification.py +19 -0
- vanna/components/rich/feedback/progress.py +37 -0
- vanna/components/rich/feedback/status_card.py +28 -0
- vanna/components/rich/feedback/status_indicator.py +14 -0
- vanna/components/rich/interactive/__init__.py +21 -0
- vanna/components/rich/interactive/button.py +95 -0
- vanna/components/rich/interactive/task_list.py +58 -0
- vanna/components/rich/interactive/ui_state.py +93 -0
- vanna/components/rich/specialized/__init__.py +7 -0
- vanna/components/rich/specialized/artifact.py +20 -0
- vanna/components/rich/text.py +16 -0
- vanna/components/simple/__init__.py +15 -0
- vanna/components/simple/image.py +15 -0
- vanna/components/simple/link.py +15 -0
- vanna/components/simple/text.py +11 -0
- vanna/core/__init__.py +193 -0
- vanna/core/_compat.py +19 -0
- vanna/core/agent/__init__.py +10 -0
- vanna/core/agent/agent.py +1407 -0
- vanna/core/agent/config.py +123 -0
- vanna/core/audit/__init__.py +28 -0
- vanna/core/audit/base.py +299 -0
- vanna/core/audit/models.py +131 -0
- vanna/core/component_manager.py +329 -0
- vanna/core/components.py +53 -0
- vanna/core/enhancer/__init__.py +11 -0
- vanna/core/enhancer/base.py +94 -0
- vanna/core/enhancer/default.py +118 -0
- vanna/core/enricher/__init__.py +10 -0
- vanna/core/enricher/base.py +59 -0
- vanna/core/errors.py +47 -0
- vanna/core/evaluation/__init__.py +81 -0
- vanna/core/evaluation/base.py +186 -0
- vanna/core/evaluation/dataset.py +254 -0
- vanna/core/evaluation/evaluators.py +376 -0
- vanna/core/evaluation/report.py +289 -0
- vanna/core/evaluation/runner.py +313 -0
- vanna/core/filter/__init__.py +10 -0
- vanna/core/filter/base.py +67 -0
- vanna/core/lifecycle/__init__.py +10 -0
- vanna/core/lifecycle/base.py +83 -0
- vanna/core/llm/__init__.py +16 -0
- vanna/core/llm/base.py +40 -0
- vanna/core/llm/models.py +61 -0
- vanna/core/middleware/__init__.py +10 -0
- vanna/core/middleware/base.py +69 -0
- vanna/core/observability/__init__.py +11 -0
- vanna/core/observability/base.py +88 -0
- vanna/core/observability/models.py +47 -0
- vanna/core/recovery/__init__.py +11 -0
- vanna/core/recovery/base.py +84 -0
- vanna/core/recovery/models.py +32 -0
- vanna/core/registry.py +278 -0
- vanna/core/rich_component.py +156 -0
- vanna/core/simple_component.py +27 -0
- vanna/core/storage/__init__.py +14 -0
- vanna/core/storage/base.py +46 -0
- vanna/core/storage/models.py +46 -0
- vanna/core/system_prompt/__init__.py +13 -0
- vanna/core/system_prompt/base.py +36 -0
- vanna/core/system_prompt/default.py +157 -0
- vanna/core/tool/__init__.py +18 -0
- vanna/core/tool/base.py +70 -0
- vanna/core/tool/models.py +84 -0
- vanna/core/user/__init__.py +17 -0
- vanna/core/user/base.py +29 -0
- vanna/core/user/models.py +25 -0
- vanna/core/user/request_context.py +70 -0
- vanna/core/user/resolver.py +42 -0
- vanna/core/validation.py +164 -0
- vanna/core/workflow/__init__.py +12 -0
- vanna/core/workflow/base.py +254 -0
- vanna/core/workflow/default.py +789 -0
- vanna/examples/__init__.py +1 -0
- vanna/examples/__main__.py +44 -0
- vanna/examples/anthropic_quickstart.py +80 -0
- vanna/examples/artifact_example.py +293 -0
- vanna/examples/claude_sqlite_example.py +236 -0
- vanna/examples/coding_agent_example.py +300 -0
- vanna/examples/custom_system_prompt_example.py +174 -0
- vanna/examples/default_workflow_handler_example.py +208 -0
- vanna/examples/email_auth_example.py +340 -0
- vanna/examples/evaluation_example.py +269 -0
- vanna/examples/extensibility_example.py +262 -0
- vanna/examples/minimal_example.py +67 -0
- vanna/examples/mock_auth_example.py +227 -0
- vanna/examples/mock_custom_tool.py +311 -0
- vanna/examples/mock_quickstart.py +79 -0
- vanna/examples/mock_quota_example.py +145 -0
- vanna/examples/mock_rich_components_demo.py +396 -0
- vanna/examples/mock_sqlite_example.py +223 -0
- vanna/examples/openai_quickstart.py +83 -0
- vanna/examples/primitive_components_demo.py +305 -0
- vanna/examples/quota_lifecycle_example.py +139 -0
- vanna/examples/visualization_example.py +251 -0
- vanna/integrations/__init__.py +17 -0
- vanna/integrations/anthropic/__init__.py +9 -0
- vanna/integrations/anthropic/llm.py +270 -0
- vanna/integrations/azureopenai/__init__.py +9 -0
- vanna/integrations/azureopenai/llm.py +329 -0
- vanna/integrations/azuresearch/__init__.py +7 -0
- vanna/integrations/azuresearch/agent_memory.py +413 -0
- vanna/integrations/bigquery/__init__.py +5 -0
- vanna/integrations/bigquery/sql_runner.py +81 -0
- vanna/integrations/chromadb/__init__.py +104 -0
- vanna/integrations/chromadb/agent_memory.py +416 -0
- vanna/integrations/clickhouse/__init__.py +5 -0
- vanna/integrations/clickhouse/sql_runner.py +82 -0
- vanna/integrations/duckdb/__init__.py +5 -0
- vanna/integrations/duckdb/sql_runner.py +65 -0
- vanna/integrations/faiss/__init__.py +7 -0
- vanna/integrations/faiss/agent_memory.py +431 -0
- vanna/integrations/google/__init__.py +9 -0
- vanna/integrations/google/gemini.py +370 -0
- vanna/integrations/hive/__init__.py +5 -0
- vanna/integrations/hive/sql_runner.py +87 -0
- vanna/integrations/local/__init__.py +17 -0
- vanna/integrations/local/agent_memory/__init__.py +7 -0
- vanna/integrations/local/agent_memory/in_memory.py +285 -0
- vanna/integrations/local/audit.py +59 -0
- vanna/integrations/local/file_system.py +242 -0
- vanna/integrations/local/file_system_conversation_store.py +255 -0
- vanna/integrations/local/storage.py +62 -0
- vanna/integrations/marqo/__init__.py +7 -0
- vanna/integrations/marqo/agent_memory.py +354 -0
- vanna/integrations/milvus/__init__.py +7 -0
- vanna/integrations/milvus/agent_memory.py +458 -0
- vanna/integrations/mock/__init__.py +9 -0
- vanna/integrations/mock/llm.py +65 -0
- vanna/integrations/mssql/__init__.py +5 -0
- vanna/integrations/mssql/sql_runner.py +66 -0
- vanna/integrations/mysql/__init__.py +5 -0
- vanna/integrations/mysql/sql_runner.py +92 -0
- vanna/integrations/ollama/__init__.py +7 -0
- vanna/integrations/ollama/llm.py +252 -0
- vanna/integrations/openai/__init__.py +10 -0
- vanna/integrations/openai/llm.py +267 -0
- vanna/integrations/openai/responses.py +163 -0
- vanna/integrations/opensearch/__init__.py +7 -0
- vanna/integrations/opensearch/agent_memory.py +411 -0
- vanna/integrations/oracle/__init__.py +5 -0
- vanna/integrations/oracle/sql_runner.py +75 -0
- vanna/integrations/pinecone/__init__.py +7 -0
- vanna/integrations/pinecone/agent_memory.py +329 -0
- vanna/integrations/plotly/__init__.py +5 -0
- vanna/integrations/plotly/chart_generator.py +313 -0
- vanna/integrations/postgres/__init__.py +9 -0
- vanna/integrations/postgres/sql_runner.py +112 -0
- vanna/integrations/premium/agent_memory/__init__.py +7 -0
- vanna/integrations/premium/agent_memory/premium.py +186 -0
- vanna/integrations/presto/__init__.py +5 -0
- vanna/integrations/presto/sql_runner.py +107 -0
- vanna/integrations/qdrant/__init__.py +7 -0
- vanna/integrations/qdrant/agent_memory.py +439 -0
- vanna/integrations/snowflake/__init__.py +5 -0
- vanna/integrations/snowflake/sql_runner.py +147 -0
- vanna/integrations/sqlite/__init__.py +9 -0
- vanna/integrations/sqlite/sql_runner.py +65 -0
- vanna/integrations/weaviate/__init__.py +7 -0
- vanna/integrations/weaviate/agent_memory.py +428 -0
- vanna/{ZhipuAI → legacy/ZhipuAI}/ZhipuAI_embeddings.py +11 -11
- vanna/legacy/__init__.py +403 -0
- vanna/legacy/adapter.py +463 -0
- vanna/{advanced → legacy/advanced}/__init__.py +3 -1
- vanna/{anthropic → legacy/anthropic}/anthropic_chat.py +9 -7
- vanna/{azuresearch → legacy/azuresearch}/azuresearch_vector.py +79 -41
- vanna/{base → legacy/base}/base.py +224 -217
- vanna/legacy/bedrock/__init__.py +1 -0
- vanna/{bedrock → legacy/bedrock}/bedrock_converse.py +13 -12
- vanna/{chromadb → legacy/chromadb}/chromadb_vector.py +3 -1
- vanna/legacy/cohere/__init__.py +2 -0
- vanna/{cohere → legacy/cohere}/cohere_chat.py +19 -14
- vanna/{cohere → legacy/cohere}/cohere_embeddings.py +25 -19
- vanna/{deepseek → legacy/deepseek}/deepseek_chat.py +5 -6
- vanna/legacy/faiss/__init__.py +1 -0
- vanna/{faiss → legacy/faiss}/faiss.py +113 -59
- vanna/{flask → legacy/flask}/__init__.py +84 -43
- vanna/{flask → legacy/flask}/assets.py +5 -5
- vanna/{flask → legacy/flask}/auth.py +5 -4
- vanna/{google → legacy/google}/bigquery_vector.py +75 -42
- vanna/{google → legacy/google}/gemini_chat.py +7 -3
- vanna/{hf → legacy/hf}/hf.py +0 -1
- vanna/{milvus → legacy/milvus}/milvus_vector.py +58 -35
- vanna/{mock → legacy/mock}/llm.py +0 -1
- vanna/legacy/mock/vectordb.py +67 -0
- vanna/legacy/ollama/ollama.py +110 -0
- vanna/{openai → legacy/openai}/openai_chat.py +2 -6
- vanna/legacy/opensearch/opensearch_vector.py +369 -0
- vanna/legacy/opensearch/opensearch_vector_semantic.py +200 -0
- vanna/legacy/oracle/oracle_vector.py +584 -0
- vanna/{pgvector → legacy/pgvector}/pgvector.py +42 -13
- vanna/{qdrant → legacy/qdrant}/qdrant.py +2 -6
- vanna/legacy/qianfan/Qianfan_Chat.py +170 -0
- vanna/legacy/qianfan/Qianfan_embeddings.py +36 -0
- vanna/legacy/qianwen/QianwenAI_chat.py +132 -0
- vanna/{remote.py → legacy/remote.py} +28 -26
- vanna/{utils.py → legacy/utils.py} +6 -11
- vanna/{vannadb → legacy/vannadb}/vannadb_vector.py +115 -46
- vanna/{vllm → legacy/vllm}/vllm.py +5 -6
- vanna/{weaviate → legacy/weaviate}/weaviate_vector.py +59 -40
- vanna/{xinference → legacy/xinference}/xinference.py +6 -6
- vanna/py.typed +0 -0
- vanna/servers/__init__.py +16 -0
- vanna/servers/__main__.py +8 -0
- vanna/servers/base/__init__.py +18 -0
- vanna/servers/base/chat_handler.py +65 -0
- vanna/servers/base/models.py +111 -0
- vanna/servers/base/rich_chat_handler.py +141 -0
- vanna/servers/base/templates.py +331 -0
- vanna/servers/cli/__init__.py +7 -0
- vanna/servers/cli/server_runner.py +204 -0
- vanna/servers/fastapi/__init__.py +7 -0
- vanna/servers/fastapi/app.py +163 -0
- vanna/servers/fastapi/routes.py +183 -0
- vanna/servers/flask/__init__.py +7 -0
- vanna/servers/flask/app.py +132 -0
- vanna/servers/flask/routes.py +137 -0
- vanna/tools/__init__.py +41 -0
- vanna/tools/agent_memory.py +322 -0
- vanna/tools/file_system.py +879 -0
- vanna/tools/python.py +222 -0
- vanna/tools/run_sql.py +165 -0
- vanna/tools/visualize_data.py +195 -0
- vanna/utils/__init__.py +0 -0
- vanna/web_components/__init__.py +44 -0
- vanna-2.0.0rc1.dist-info/METADATA +868 -0
- vanna-2.0.0rc1.dist-info/RECORD +289 -0
- vanna-2.0.0rc1.dist-info/entry_points.txt +3 -0
- vanna/bedrock/__init__.py +0 -1
- vanna/cohere/__init__.py +0 -2
- vanna/faiss/__init__.py +0 -1
- vanna/mock/vectordb.py +0 -55
- vanna/ollama/ollama.py +0 -103
- vanna/opensearch/opensearch_vector.py +0 -392
- vanna/opensearch/opensearch_vector_semantic.py +0 -175
- vanna/oracle/oracle_vector.py +0 -585
- vanna/qianfan/Qianfan_Chat.py +0 -165
- vanna/qianfan/Qianfan_embeddings.py +0 -36
- vanna/qianwen/QianwenAI_chat.py +0 -133
- vanna-0.7.9.dist-info/METADATA +0 -408
- vanna-0.7.9.dist-info/RECORD +0 -79
- /vanna/{ZhipuAI → legacy/ZhipuAI}/ZhipuAI_Chat.py +0 -0
- /vanna/{ZhipuAI → legacy/ZhipuAI}/__init__.py +0 -0
- /vanna/{anthropic → legacy/anthropic}/__init__.py +0 -0
- /vanna/{azuresearch → legacy/azuresearch}/__init__.py +0 -0
- /vanna/{base → legacy/base}/__init__.py +0 -0
- /vanna/{chromadb → legacy/chromadb}/__init__.py +0 -0
- /vanna/{deepseek → legacy/deepseek}/__init__.py +0 -0
- /vanna/{exceptions → legacy/exceptions}/__init__.py +0 -0
- /vanna/{google → legacy/google}/__init__.py +0 -0
- /vanna/{hf → legacy/hf}/__init__.py +0 -0
- /vanna/{local.py → legacy/local.py} +0 -0
- /vanna/{marqo → legacy/marqo}/__init__.py +0 -0
- /vanna/{marqo → legacy/marqo}/marqo.py +0 -0
- /vanna/{milvus → legacy/milvus}/__init__.py +0 -0
- /vanna/{mistral → legacy/mistral}/__init__.py +0 -0
- /vanna/{mistral → legacy/mistral}/mistral.py +0 -0
- /vanna/{mock → legacy/mock}/__init__.py +0 -0
- /vanna/{mock → legacy/mock}/embedding.py +0 -0
- /vanna/{ollama → legacy/ollama}/__init__.py +0 -0
- /vanna/{openai → legacy/openai}/__init__.py +0 -0
- /vanna/{openai → legacy/openai}/openai_embeddings.py +0 -0
- /vanna/{opensearch → legacy/opensearch}/__init__.py +0 -0
- /vanna/{oracle → legacy/oracle}/__init__.py +0 -0
- /vanna/{pgvector → legacy/pgvector}/__init__.py +0 -0
- /vanna/{pinecone → legacy/pinecone}/__init__.py +0 -0
- /vanna/{pinecone → legacy/pinecone}/pinecone_vector.py +0 -0
- /vanna/{qdrant → legacy/qdrant}/__init__.py +0 -0
- /vanna/{qianfan → legacy/qianfan}/__init__.py +0 -0
- /vanna/{qianwen → legacy/qianwen}/QianwenAI_embeddings.py +0 -0
- /vanna/{qianwen → legacy/qianwen}/__init__.py +0 -0
- /vanna/{types → legacy/types}/__init__.py +0 -0
- /vanna/{vannadb → legacy/vannadb}/__init__.py +0 -0
- /vanna/{vllm → legacy/vllm}/__init__.py +0 -0
- /vanna/{weaviate → legacy/weaviate}/__init__.py +0 -0
- /vanna/{xinference → legacy/xinference}/__init__.py +0 -0
- {vanna-0.7.9.dist-info → vanna-2.0.0rc1.dist-info}/WHEEL +0 -0
- {vanna-0.7.9.dist-info → vanna-2.0.0rc1.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Request and response models for server endpoints.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import time
|
|
6
|
+
import uuid
|
|
7
|
+
from typing import Any, Dict, List, Optional, Union
|
|
8
|
+
|
|
9
|
+
from pydantic import BaseModel, Field
|
|
10
|
+
|
|
11
|
+
from ...components import UiComponent, RichComponent
|
|
12
|
+
from ...core.component_manager import ComponentUpdate
|
|
13
|
+
from ...core.user.request_context import RequestContext
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class ChatRequest(BaseModel):
|
|
17
|
+
"""Request model for chat endpoints."""
|
|
18
|
+
|
|
19
|
+
message: str = Field(description="User message")
|
|
20
|
+
conversation_id: Optional[str] = Field(default=None, description="Conversation ID")
|
|
21
|
+
request_id: Optional[str] = Field(
|
|
22
|
+
default=None, description="Request ID for tracing"
|
|
23
|
+
)
|
|
24
|
+
request_context: RequestContext = Field(
|
|
25
|
+
default_factory=RequestContext,
|
|
26
|
+
description="Request context for user resolution",
|
|
27
|
+
)
|
|
28
|
+
metadata: Dict[str, Any] = Field(
|
|
29
|
+
default_factory=dict, description="Additional metadata"
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class ChatStreamChunk(BaseModel):
|
|
34
|
+
"""Single chunk in a streaming chat response."""
|
|
35
|
+
|
|
36
|
+
rich: Dict[str, Any] = Field(description="Rich component data for advanced UIs")
|
|
37
|
+
simple: Optional[Dict[str, Any]] = Field(
|
|
38
|
+
default=None, description="Simple component data for basic UIs"
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
# Stream metadata
|
|
42
|
+
conversation_id: str = Field(description="Conversation ID")
|
|
43
|
+
request_id: str = Field(description="Request ID")
|
|
44
|
+
timestamp: float = Field(default_factory=time.time, description="Timestamp")
|
|
45
|
+
|
|
46
|
+
@classmethod
|
|
47
|
+
def from_component(
|
|
48
|
+
cls,
|
|
49
|
+
component: Union[UiComponent, RichComponent],
|
|
50
|
+
conversation_id: str,
|
|
51
|
+
request_id: str,
|
|
52
|
+
) -> "ChatStreamChunk":
|
|
53
|
+
"""Create chunk from UI component or rich component."""
|
|
54
|
+
|
|
55
|
+
if isinstance(component, UiComponent):
|
|
56
|
+
# Full UiComponent with both rich and simple
|
|
57
|
+
rich_data = component.rich_component.serialize_for_frontend()
|
|
58
|
+
simple_data = None
|
|
59
|
+
if component.simple_component:
|
|
60
|
+
simple_data = component.simple_component.serialize_for_frontend()
|
|
61
|
+
|
|
62
|
+
return cls(
|
|
63
|
+
rich=rich_data,
|
|
64
|
+
simple=simple_data,
|
|
65
|
+
conversation_id=conversation_id,
|
|
66
|
+
request_id=request_id,
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
# Rich component only (no simple fallback)
|
|
70
|
+
rich_data = component.serialize_for_frontend()
|
|
71
|
+
return cls(
|
|
72
|
+
rich=rich_data,
|
|
73
|
+
simple=None,
|
|
74
|
+
conversation_id=conversation_id,
|
|
75
|
+
request_id=request_id,
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
@classmethod
|
|
79
|
+
def from_component_update(
|
|
80
|
+
cls, update: ComponentUpdate, conversation_id: str, request_id: str
|
|
81
|
+
) -> "ChatStreamChunk":
|
|
82
|
+
"""Create chunk from component update."""
|
|
83
|
+
update_payload = update.serialize_for_frontend()
|
|
84
|
+
return cls(
|
|
85
|
+
rich=update_payload,
|
|
86
|
+
simple=None, # Component updates don't have simple representations
|
|
87
|
+
conversation_id=conversation_id,
|
|
88
|
+
request_id=request_id,
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
class ChatResponse(BaseModel):
|
|
93
|
+
"""Complete chat response for polling endpoints."""
|
|
94
|
+
|
|
95
|
+
chunks: List[ChatStreamChunk] = Field(description="Response chunks")
|
|
96
|
+
conversation_id: str = Field(description="Conversation ID")
|
|
97
|
+
request_id: str = Field(description="Request ID")
|
|
98
|
+
total_chunks: int = Field(description="Total number of chunks")
|
|
99
|
+
|
|
100
|
+
@classmethod
|
|
101
|
+
def from_chunks(cls, chunks: List[ChatStreamChunk]) -> "ChatResponse":
|
|
102
|
+
"""Create response from chunks."""
|
|
103
|
+
if not chunks:
|
|
104
|
+
return cls(chunks=[], conversation_id="", request_id="", total_chunks=0)
|
|
105
|
+
|
|
106
|
+
return cls(
|
|
107
|
+
chunks=chunks,
|
|
108
|
+
conversation_id=chunks[0].conversation_id,
|
|
109
|
+
request_id=chunks[0].request_id,
|
|
110
|
+
total_chunks=len(chunks),
|
|
111
|
+
)
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# """
|
|
2
|
+
# Rich component-aware chat handling logic.
|
|
3
|
+
# """
|
|
4
|
+
|
|
5
|
+
# import uuid
|
|
6
|
+
# from typing import AsyncGenerator, Callable, List, Optional, Union
|
|
7
|
+
|
|
8
|
+
# from ...core import Agent, User
|
|
9
|
+
# from ...core.rich_components import RichComponent
|
|
10
|
+
# from ...core.component_manager import ComponentManager, ComponentUpdate
|
|
11
|
+
# from .models import ChatRequest, ChatResponse, ChatStreamChunk
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
# class RichChatHandler:
|
|
15
|
+
# """Rich component-aware chat handling logic."""
|
|
16
|
+
|
|
17
|
+
# def __init__(
|
|
18
|
+
# self,
|
|
19
|
+
# agent: Agent,
|
|
20
|
+
# default_user_factory: Optional[Callable[[Optional[str]], User]] = None,
|
|
21
|
+
# ):
|
|
22
|
+
# """Initialize rich chat handler.
|
|
23
|
+
|
|
24
|
+
# Args:
|
|
25
|
+
# agent: The agent to handle chat requests
|
|
26
|
+
# default_user_factory: Function to create default user from user_id
|
|
27
|
+
# """
|
|
28
|
+
# self.agent = agent
|
|
29
|
+
# self.default_user_factory = default_user_factory or self._create_default_user
|
|
30
|
+
# self.component_managers: dict[str, ComponentManager] = {} # Per conversation
|
|
31
|
+
|
|
32
|
+
# async def handle_stream(
|
|
33
|
+
# self, request: ChatRequest
|
|
34
|
+
# ) -> AsyncGenerator[ChatStreamChunk, None]:
|
|
35
|
+
# """Stream chat responses with rich component support.
|
|
36
|
+
|
|
37
|
+
# Args:
|
|
38
|
+
# request: Chat request
|
|
39
|
+
|
|
40
|
+
# Yields:
|
|
41
|
+
# Chat stream chunks including rich component updates
|
|
42
|
+
# """
|
|
43
|
+
# user = self._resolve_user(request.user_id)
|
|
44
|
+
# conversation_id = request.conversation_id or self._generate_conversation_id()
|
|
45
|
+
# request_id = request.request_id or str(uuid.uuid4())
|
|
46
|
+
|
|
47
|
+
# # Get or create component manager for this conversation
|
|
48
|
+
# if conversation_id not in self.component_managers:
|
|
49
|
+
# self.component_managers[conversation_id] = ComponentManager()
|
|
50
|
+
|
|
51
|
+
# component_manager = self.component_managers[conversation_id]
|
|
52
|
+
|
|
53
|
+
# async for component in self.agent.send_message(
|
|
54
|
+
# conversation_id=conversation_id,
|
|
55
|
+
# user=user,
|
|
56
|
+
# message=request.message,
|
|
57
|
+
# request_id=request_id,
|
|
58
|
+
# ):
|
|
59
|
+
# if isinstance(component, RichComponent):
|
|
60
|
+
# # Handle rich component through manager
|
|
61
|
+
# update = component_manager.emit(component)
|
|
62
|
+
# yield ChatStreamChunk.from_component_update(update, conversation_id, request_id)
|
|
63
|
+
# else:
|
|
64
|
+
# # Handle legacy components
|
|
65
|
+
# yield ChatStreamChunk.from_component(component, conversation_id, request_id)
|
|
66
|
+
|
|
67
|
+
# async def handle_poll(self, request: ChatRequest) -> ChatResponse:
|
|
68
|
+
# """Handle polling request with rich component support.
|
|
69
|
+
|
|
70
|
+
# Args:
|
|
71
|
+
# request: Chat request
|
|
72
|
+
|
|
73
|
+
# Returns:
|
|
74
|
+
# Complete chat response with all components
|
|
75
|
+
# """
|
|
76
|
+
# chunks: List[ChatStreamChunk] = []
|
|
77
|
+
|
|
78
|
+
# async for chunk in self.handle_stream(request):
|
|
79
|
+
# chunks.append(chunk)
|
|
80
|
+
|
|
81
|
+
# return ChatResponse.from_chunks(chunks)
|
|
82
|
+
|
|
83
|
+
# def get_component_manager(self, conversation_id: str) -> Optional[ComponentManager]:
|
|
84
|
+
# """Get the component manager for a conversation."""
|
|
85
|
+
# return self.component_managers.get(conversation_id)
|
|
86
|
+
|
|
87
|
+
# def get_component(self, conversation_id: str, component_id: str) -> Optional[RichComponent]:
|
|
88
|
+
# """Get a specific component from a conversation."""
|
|
89
|
+
# manager = self.get_component_manager(conversation_id)
|
|
90
|
+
# return manager.get_component(component_id) if manager else None
|
|
91
|
+
|
|
92
|
+
# def get_all_components(self, conversation_id: str) -> List[RichComponent]:
|
|
93
|
+
# """Get all components in a conversation."""
|
|
94
|
+
# manager = self.get_component_manager(conversation_id)
|
|
95
|
+
# return manager.get_all_components() if manager else []
|
|
96
|
+
|
|
97
|
+
# def update_component(
|
|
98
|
+
# self,
|
|
99
|
+
# conversation_id: str,
|
|
100
|
+
# component_id: str,
|
|
101
|
+
# **updates
|
|
102
|
+
# ) -> Optional[ComponentUpdate]:
|
|
103
|
+
# """Update a component in a conversation."""
|
|
104
|
+
# manager = self.get_component_manager(conversation_id)
|
|
105
|
+
# return manager.update_component(component_id, **updates) if manager else None
|
|
106
|
+
|
|
107
|
+
# def remove_component(
|
|
108
|
+
# self,
|
|
109
|
+
# conversation_id: str,
|
|
110
|
+
# component_id: str
|
|
111
|
+
# ) -> Optional[ComponentUpdate]:
|
|
112
|
+
# """Remove a component from a conversation."""
|
|
113
|
+
# manager = self.get_component_manager(conversation_id)
|
|
114
|
+
# return manager.remove_component(component_id) if manager else None
|
|
115
|
+
|
|
116
|
+
# def clear_conversation_components(self, conversation_id: str):
|
|
117
|
+
# """Clear all components for a conversation."""
|
|
118
|
+
# if conversation_id in self.component_managers:
|
|
119
|
+
# del self.component_managers[conversation_id]
|
|
120
|
+
|
|
121
|
+
# def _resolve_user(self, user_id: Optional[str]) -> User:
|
|
122
|
+
# """Resolve user from ID or create default."""
|
|
123
|
+
# if user_id:
|
|
124
|
+
# # In a real implementation, you'd fetch from a user store
|
|
125
|
+
# return User(id=user_id, username=f"user_{user_id}", email="", permissions=[])
|
|
126
|
+
|
|
127
|
+
# return self.default_user_factory(user_id)
|
|
128
|
+
|
|
129
|
+
# def _create_default_user(self, user_id: Optional[str]) -> User:
|
|
130
|
+
# """Create a default user."""
|
|
131
|
+
# user_id = user_id or "anonymous"
|
|
132
|
+
# return User(
|
|
133
|
+
# id=user_id,
|
|
134
|
+
# username=f"user_{user_id}",
|
|
135
|
+
# email="",
|
|
136
|
+
# permissions=[]
|
|
137
|
+
# )
|
|
138
|
+
|
|
139
|
+
# def _generate_conversation_id(self) -> str:
|
|
140
|
+
# """Generate a new conversation ID."""
|
|
141
|
+
# return str(uuid.uuid4())
|
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
"""
|
|
2
|
+
HTML templates for Vanna Agents servers.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from typing import Optional
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def get_vanna_component_script(
|
|
9
|
+
dev_mode: bool = False,
|
|
10
|
+
static_path: str = "/static",
|
|
11
|
+
cdn_url: str = "https://img.vanna.ai/vanna-components.js",
|
|
12
|
+
) -> str:
|
|
13
|
+
"""Get the script tag for loading Vanna web components.
|
|
14
|
+
|
|
15
|
+
Args:
|
|
16
|
+
dev_mode: If True, load from local static files
|
|
17
|
+
static_path: Path to static assets in dev mode
|
|
18
|
+
cdn_url: CDN URL for production
|
|
19
|
+
|
|
20
|
+
Returns:
|
|
21
|
+
HTML script tag for loading components
|
|
22
|
+
"""
|
|
23
|
+
if dev_mode:
|
|
24
|
+
return (
|
|
25
|
+
f'<script type="module" src="{static_path}/vanna-components.js"></script>'
|
|
26
|
+
)
|
|
27
|
+
else:
|
|
28
|
+
return f'<script type="module" src="{cdn_url}"></script>'
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def get_index_html(
|
|
32
|
+
dev_mode: bool = False,
|
|
33
|
+
static_path: str = "/static",
|
|
34
|
+
cdn_url: str = "https://img.vanna.ai/vanna-components.js",
|
|
35
|
+
api_base_url: str = "",
|
|
36
|
+
) -> str:
|
|
37
|
+
"""Generate index HTML with configurable component loading.
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
dev_mode: If True, load components from local static files
|
|
41
|
+
static_path: Path to static assets in dev mode
|
|
42
|
+
cdn_url: CDN URL for production components
|
|
43
|
+
api_base_url: Base URL for API endpoints
|
|
44
|
+
|
|
45
|
+
Returns:
|
|
46
|
+
Complete HTML page as string
|
|
47
|
+
"""
|
|
48
|
+
component_script = get_vanna_component_script(dev_mode, static_path, cdn_url)
|
|
49
|
+
|
|
50
|
+
return f"""<!DOCTYPE html>
|
|
51
|
+
<html lang="en">
|
|
52
|
+
<head>
|
|
53
|
+
<meta charset="UTF-8">
|
|
54
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
55
|
+
<title>Vanna Agents Chat</title>
|
|
56
|
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
57
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
58
|
+
<link href="https://fonts.googleapis.com/css2?family=Roboto+Slab:wght@400;500;600;700&family=Space+Grotesk:wght@300;400;500;600;700&family=Space+Mono:wght@400;700&display=swap" rel="stylesheet">
|
|
59
|
+
<script src="https://cdn.tailwindcss.com"></script>
|
|
60
|
+
<script>
|
|
61
|
+
tailwind.config = {{
|
|
62
|
+
theme: {{
|
|
63
|
+
extend: {{
|
|
64
|
+
colors: {{
|
|
65
|
+
'vanna-navy': '#023d60',
|
|
66
|
+
'vanna-cream': '#e7e1cf',
|
|
67
|
+
'vanna-teal': '#15a8a8',
|
|
68
|
+
'vanna-orange': '#fe5d26',
|
|
69
|
+
'vanna-magenta': '#bf1363',
|
|
70
|
+
}},
|
|
71
|
+
fontFamily: {{
|
|
72
|
+
'sans': ['Space Grotesk', 'ui-sans-serif', 'system-ui'],
|
|
73
|
+
'serif': ['Roboto Slab', 'ui-serif', 'Georgia'],
|
|
74
|
+
'mono': ['Space Mono', 'ui-monospace', 'monospace'],
|
|
75
|
+
}}
|
|
76
|
+
}}
|
|
77
|
+
}}
|
|
78
|
+
}}
|
|
79
|
+
</script>
|
|
80
|
+
<style>
|
|
81
|
+
body {{
|
|
82
|
+
background: linear-gradient(to bottom, #e7e1cf, #ffffff, #e7e1cf);
|
|
83
|
+
min-height: 100vh;
|
|
84
|
+
position: relative;
|
|
85
|
+
overflow-x: hidden;
|
|
86
|
+
}}
|
|
87
|
+
|
|
88
|
+
/* Background decorations matching landing page */
|
|
89
|
+
body::before {{
|
|
90
|
+
content: '';
|
|
91
|
+
position: fixed;
|
|
92
|
+
inset: 0;
|
|
93
|
+
pointer-events: none;
|
|
94
|
+
z-index: 0;
|
|
95
|
+
/* Radial gradients with brand colors */
|
|
96
|
+
background:
|
|
97
|
+
radial-gradient(circle at top left, rgba(21, 168, 168, 0.12), transparent 60%),
|
|
98
|
+
radial-gradient(circle at bottom right, rgba(254, 93, 38, 0.08), transparent 65%);
|
|
99
|
+
}}
|
|
100
|
+
|
|
101
|
+
body::after {{
|
|
102
|
+
content: '';
|
|
103
|
+
position: fixed;
|
|
104
|
+
inset: 0;
|
|
105
|
+
pointer-events: none;
|
|
106
|
+
z-index: 0;
|
|
107
|
+
/* Dot pattern with retro computing aesthetic */
|
|
108
|
+
background-image: radial-gradient(circle at 2px 2px, rgba(2, 61, 96, 0.3) 1px, transparent 0);
|
|
109
|
+
background-size: 32px 32px;
|
|
110
|
+
/* Grid overlay */
|
|
111
|
+
background-image:
|
|
112
|
+
radial-gradient(circle at 2px 2px, rgba(2, 61, 96, 0.3) 1px, transparent 0),
|
|
113
|
+
linear-gradient(rgba(2, 61, 96, 0.1) 1px, transparent 1px),
|
|
114
|
+
linear-gradient(90deg, rgba(2, 61, 96, 0.1) 1px, transparent 1px);
|
|
115
|
+
background-size: 32px 32px, 100px 100px, 100px 100px;
|
|
116
|
+
}}
|
|
117
|
+
|
|
118
|
+
/* Ensure content is above background */
|
|
119
|
+
body > * {{
|
|
120
|
+
position: relative;
|
|
121
|
+
z-index: 1;
|
|
122
|
+
}}
|
|
123
|
+
|
|
124
|
+
vanna-chat {{
|
|
125
|
+
width: 100%;
|
|
126
|
+
height: 100%;
|
|
127
|
+
display: block;
|
|
128
|
+
}}
|
|
129
|
+
</style>
|
|
130
|
+
{component_script}
|
|
131
|
+
</head>
|
|
132
|
+
<body>
|
|
133
|
+
<div class="max-w-6xl mx-auto p-5">
|
|
134
|
+
<!-- Header -->
|
|
135
|
+
<div class="text-center mb-8">
|
|
136
|
+
<h1 class="text-4xl font-bold text-vanna-navy mb-2 font-serif">Vanna Agents</h1>
|
|
137
|
+
<p class="text-lg font-mono font-bold text-vanna-teal mb-4">DATA-FIRST AGENTS</p>
|
|
138
|
+
<p class="text-slate-600 mb-4">Interactive AI Assistant powered by Vanna Agents Framework</p>
|
|
139
|
+
<a href="javascript:window.location='view-source:'+window.location.href" class="inline-flex items-center gap-2 px-4 py-2 bg-vanna-teal text-white text-sm font-medium rounded-lg hover:bg-vanna-navy transition">
|
|
140
|
+
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
141
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4"/>
|
|
142
|
+
</svg>
|
|
143
|
+
View Page Source
|
|
144
|
+
</a>
|
|
145
|
+
</div>
|
|
146
|
+
|
|
147
|
+
{(' <div class="bg-vanna-orange/10 border border-vanna-orange/30 rounded-lg p-3 mb-5 text-vanna-orange text-sm font-medium">📦 Development Mode: Loading components from local assets</div>' if dev_mode else "")}
|
|
148
|
+
|
|
149
|
+
<!-- Login Form -->
|
|
150
|
+
<div id="loginContainer" class="max-w-md mx-auto mb-10 bg-white p-8 rounded-xl shadow-lg border border-vanna-teal/30">
|
|
151
|
+
<div class="text-center mb-6">
|
|
152
|
+
<h2 class="text-2xl font-semibold text-vanna-navy mb-2 font-serif">Login to Continue</h2>
|
|
153
|
+
<p class="text-sm text-slate-600">Select your email to access the chat</p>
|
|
154
|
+
</div>
|
|
155
|
+
|
|
156
|
+
<div class="mb-5">
|
|
157
|
+
<label for="emailInput" class="block mb-2 text-sm font-medium text-vanna-navy">Email Address</label>
|
|
158
|
+
<select
|
|
159
|
+
id="emailInput"
|
|
160
|
+
class="w-full px-4 py-3 text-sm border border-vanna-teal/30 rounded-lg focus:outline-none focus:ring-2 focus:ring-vanna-teal focus:border-transparent bg-white"
|
|
161
|
+
>
|
|
162
|
+
<option value="">Select an email...</option>
|
|
163
|
+
<option value="admin@example.com">admin@example.com</option>
|
|
164
|
+
<option value="user@example.com">user@example.com</option>
|
|
165
|
+
</select>
|
|
166
|
+
</div>
|
|
167
|
+
|
|
168
|
+
<button id="loginButton" class="w-full px-4 py-3 bg-vanna-teal text-white text-sm font-medium rounded-lg hover:bg-vanna-navy focus:outline-none focus:ring-2 focus:ring-vanna-teal focus:ring-offset-2 transition disabled:bg-gray-400 disabled:cursor-not-allowed">
|
|
169
|
+
Continue
|
|
170
|
+
</button>
|
|
171
|
+
|
|
172
|
+
<div class="mt-5 p-3 bg-vanna-teal/10 border-l-4 border-vanna-teal rounded text-xs text-vanna-navy leading-relaxed">
|
|
173
|
+
<strong>Demo Mode:</strong> This is a frontend-only authentication demo.
|
|
174
|
+
Your email will be stored as a cookie and automatically sent with all API requests.
|
|
175
|
+
</div>
|
|
176
|
+
</div>
|
|
177
|
+
|
|
178
|
+
<!-- Logged In Status (hidden by default) -->
|
|
179
|
+
<div id="loggedInStatus" class="hidden text-center p-4 bg-vanna-teal/10 border border-vanna-teal/30 rounded-lg mb-5">
|
|
180
|
+
Logged in as <span id="loggedInEmail" class="font-semibold text-vanna-navy"></span>
|
|
181
|
+
<br>
|
|
182
|
+
<button id="logoutButton" class="mt-2 px-3 py-1.5 bg-vanna-navy text-white text-xs rounded hover:bg-vanna-teal transition">
|
|
183
|
+
Logout
|
|
184
|
+
</button>
|
|
185
|
+
</div>
|
|
186
|
+
|
|
187
|
+
<!-- Chat Container (hidden by default) -->
|
|
188
|
+
<div id="chatSections" class="hidden">
|
|
189
|
+
<div class="bg-white rounded-xl shadow-lg h-[600px] overflow-hidden border border-vanna-teal/30">
|
|
190
|
+
<vanna-chat
|
|
191
|
+
api-base="{api_base_url}"
|
|
192
|
+
sse-endpoint="{api_base_url}/api/vanna/v2/chat_sse"
|
|
193
|
+
ws-endpoint="{api_base_url}/api/vanna/v2/chat_websocket"
|
|
194
|
+
poll-endpoint="{api_base_url}/api/vanna/v2/chat_poll">
|
|
195
|
+
</vanna-chat>
|
|
196
|
+
</div>
|
|
197
|
+
|
|
198
|
+
<div class="mt-8 p-5 bg-white rounded-lg shadow border border-vanna-teal/30">
|
|
199
|
+
<h3 class="text-lg font-semibold text-vanna-navy mb-3 font-serif">API Endpoints</h3>
|
|
200
|
+
<ul class="space-y-2">
|
|
201
|
+
<li class="p-2 bg-vanna-cream/50 rounded font-mono text-sm">
|
|
202
|
+
<span class="font-bold text-vanna-teal mr-2">POST</span>{api_base_url}/api/vanna/v2/chat_sse - Server-Sent Events streaming
|
|
203
|
+
</li>
|
|
204
|
+
<li class="p-2 bg-vanna-cream/50 rounded font-mono text-sm">
|
|
205
|
+
<span class="font-bold text-vanna-teal mr-2">WS</span>{api_base_url}/api/vanna/v2/chat_websocket - WebSocket real-time chat
|
|
206
|
+
</li>
|
|
207
|
+
<li class="p-2 bg-vanna-cream/50 rounded font-mono text-sm">
|
|
208
|
+
<span class="font-bold text-vanna-teal mr-2">POST</span>{api_base_url}/api/vanna/v2/chat_poll - Request/response polling
|
|
209
|
+
</li>
|
|
210
|
+
<li class="p-2 bg-vanna-cream/50 rounded font-mono text-sm">
|
|
211
|
+
<span class="font-bold text-vanna-teal mr-2">GET</span>{api_base_url}/health - Health check
|
|
212
|
+
</li>
|
|
213
|
+
</ul>
|
|
214
|
+
</div>
|
|
215
|
+
</div>
|
|
216
|
+
</div>
|
|
217
|
+
|
|
218
|
+
<script>
|
|
219
|
+
// Cookie helpers
|
|
220
|
+
const getCookie = (name) => {{
|
|
221
|
+
const value = `; ${{document.cookie}}`;
|
|
222
|
+
const parts = value.split(`; ${{name}}=`);
|
|
223
|
+
return parts.length === 2 ? parts.pop().split(';').shift() : null;
|
|
224
|
+
}};
|
|
225
|
+
|
|
226
|
+
const setCookie = (name, value) => {{
|
|
227
|
+
const expires = new Date(Date.now() + 365 * 864e5).toUTCString();
|
|
228
|
+
document.cookie = `${{name}}=${{value}}; expires=${{expires}}; path=/; SameSite=Lax`;
|
|
229
|
+
}};
|
|
230
|
+
|
|
231
|
+
const deleteCookie = (name) => {{
|
|
232
|
+
document.cookie = `${{name}}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;`;
|
|
233
|
+
}};
|
|
234
|
+
|
|
235
|
+
// Login/Logout
|
|
236
|
+
document.addEventListener('DOMContentLoaded', () => {{
|
|
237
|
+
const email = getCookie('vanna_email');
|
|
238
|
+
|
|
239
|
+
// Check if already logged in
|
|
240
|
+
if (email) {{
|
|
241
|
+
loginContainer.classList.add('hidden');
|
|
242
|
+
loggedInStatus.classList.remove('hidden');
|
|
243
|
+
chatSections.classList.remove('hidden');
|
|
244
|
+
loggedInEmail.textContent = email;
|
|
245
|
+
}}
|
|
246
|
+
|
|
247
|
+
// Login button
|
|
248
|
+
loginButton.addEventListener('click', () => {{
|
|
249
|
+
const email = emailInput.value.trim();
|
|
250
|
+
if (!email) {{
|
|
251
|
+
alert('Please select an email address');
|
|
252
|
+
return;
|
|
253
|
+
}}
|
|
254
|
+
setCookie('vanna_email', email);
|
|
255
|
+
loginContainer.classList.add('hidden');
|
|
256
|
+
loggedInStatus.classList.remove('hidden');
|
|
257
|
+
chatSections.classList.remove('hidden');
|
|
258
|
+
loggedInEmail.textContent = email;
|
|
259
|
+
}});
|
|
260
|
+
|
|
261
|
+
// Logout button
|
|
262
|
+
logoutButton.addEventListener('click', () => {{
|
|
263
|
+
deleteCookie('vanna_email');
|
|
264
|
+
loginContainer.classList.remove('hidden');
|
|
265
|
+
loggedInStatus.classList.add('hidden');
|
|
266
|
+
chatSections.classList.add('hidden');
|
|
267
|
+
emailInput.value = '';
|
|
268
|
+
}});
|
|
269
|
+
|
|
270
|
+
// Enter key
|
|
271
|
+
emailInput.addEventListener('keypress', (e) => {{
|
|
272
|
+
if (e.key === 'Enter') loginButton.click();
|
|
273
|
+
}});
|
|
274
|
+
}});
|
|
275
|
+
</script>
|
|
276
|
+
|
|
277
|
+
<script>
|
|
278
|
+
// Artifact demo event listener
|
|
279
|
+
document.addEventListener('DOMContentLoaded', () => {{
|
|
280
|
+
const vannaChat = document.querySelector('vanna-chat');
|
|
281
|
+
|
|
282
|
+
if (vannaChat) {{
|
|
283
|
+
// Add artifact event listener to demonstrate external rendering
|
|
284
|
+
vannaChat.addEventListener('artifact-opened', (event) => {{
|
|
285
|
+
const {{ artifactId, type, title, trigger }} = event.detail;
|
|
286
|
+
|
|
287
|
+
console.log('🎨 Artifact Event:', {{ artifactId, type, title, trigger }});
|
|
288
|
+
|
|
289
|
+
// For demo: open all artifacts externally
|
|
290
|
+
setTimeout(() => {{
|
|
291
|
+
const newWindow = window.open('', '_blank', 'width=900,height=700');
|
|
292
|
+
if (newWindow) {{
|
|
293
|
+
newWindow.document.write(event.detail.getStandaloneHTML());
|
|
294
|
+
newWindow.document.close();
|
|
295
|
+
newWindow.document.title = title || 'Vanna Artifact';
|
|
296
|
+
console.log(`📱 Opened ${{title}} in new window`);
|
|
297
|
+
}}
|
|
298
|
+
}}, 100);
|
|
299
|
+
|
|
300
|
+
// Prevent default in-chat rendering
|
|
301
|
+
event.detail.preventDefault();
|
|
302
|
+
console.log('✋ Showing placeholder in chat instead of full artifact');
|
|
303
|
+
}});
|
|
304
|
+
|
|
305
|
+
console.log('🎯 Artifact demo mode: All artifacts will open externally');
|
|
306
|
+
}}
|
|
307
|
+
}});
|
|
308
|
+
|
|
309
|
+
// Fallback if web component doesn't load
|
|
310
|
+
if (!customElements.get('vanna-chat')) {{
|
|
311
|
+
setTimeout(() => {{
|
|
312
|
+
if (!customElements.get('vanna-chat')) {{
|
|
313
|
+
document.querySelector('vanna-chat').innerHTML = `
|
|
314
|
+
<div class="p-10 text-center text-gray-600">
|
|
315
|
+
<h3 class="text-xl font-semibold mb-2">Vanna Chat Component</h3>
|
|
316
|
+
<p class="mb-2">Web component failed to load. Please check your connection.</p>
|
|
317
|
+
<p class="text-sm text-gray-400">
|
|
318
|
+
{("Loading from: local static assets" if dev_mode else f"Loading from: {cdn_url}")}
|
|
319
|
+
</p>
|
|
320
|
+
</div>
|
|
321
|
+
`;
|
|
322
|
+
}}
|
|
323
|
+
}}, 2000);
|
|
324
|
+
}}
|
|
325
|
+
</script>
|
|
326
|
+
</body>
|
|
327
|
+
</html>"""
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
# Backward compatibility - default production HTML
|
|
331
|
+
INDEX_HTML = get_index_html()
|