mirror of
https://github.com/run-llama/create-llama.git
synced 2026-07-01 21:04:08 -04:00
feat: show document artifact after generating report (#658)
* feat: show document artifact after generating report
* keep chat message content as it is
* use artifactEvent from server
* add deep research example
* bump chat-ui for new editor
* import editor css
* hide warning for workflowEvent<{}>() in eject mode
* fix format
* use CL for better testing
* generate artifact after streaming report in Python
* bump chat-ui to support citations
* use isinstance to check stream
* fix document editor spacing
* Create tame-wolves-obey.md
* add sources to document artifact
* add sources to document artifact in python
* type cast
* no need score
* fix lint
* move handle stream logic to server
* refactor: use chunk.text and chunk.raw
* bump chat-ui 0.5.6 to fix citations
* update changset
* fix lock
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
---
|
||||
"create-llama": patch
|
||||
"@llamaindex/server": patch
|
||||
"@create-llama/llama-index-server": patch
|
||||
---
|
||||
|
||||
feat: show document artifact after generating report
|
||||
+37
-3
@@ -1,7 +1,7 @@
|
||||
import logging
|
||||
import os
|
||||
import uuid
|
||||
from typing import List, Literal, Optional
|
||||
from typing import List, Literal, Optional, AsyncGenerator
|
||||
|
||||
from app.index import get_index
|
||||
from llama_index.core.base.llms.types import (
|
||||
@@ -23,7 +23,18 @@ from llama_index.core.workflow import (
|
||||
Workflow,
|
||||
step,
|
||||
)
|
||||
from llama_index.server.api.models import ChatRequest, SourceNodesEvent, UIEvent
|
||||
from llama_index.server.api.models import (
|
||||
ArtifactEvent,
|
||||
ArtifactType,
|
||||
ChatRequest,
|
||||
SourceNodesEvent,
|
||||
UIEvent,
|
||||
Artifact,
|
||||
DocumentArtifactData,
|
||||
DocumentArtifactSource,
|
||||
)
|
||||
import time
|
||||
from llama_index.server.utils.stream import write_response_to_stream
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
logger = logging.getLogger("uvicorn")
|
||||
@@ -365,8 +376,31 @@ class DeepResearchWorkflow(Workflow):
|
||||
user_request=self.user_request,
|
||||
stream=self.stream,
|
||||
)
|
||||
|
||||
final_response = await write_response_to_stream(res, ctx)
|
||||
|
||||
ctx.write_event_to_stream(
|
||||
ArtifactEvent(
|
||||
data=Artifact(
|
||||
type=ArtifactType.DOCUMENT,
|
||||
created_at=int(time.time()),
|
||||
data=DocumentArtifactData(
|
||||
title="DeepResearch Report",
|
||||
content=final_response,
|
||||
type="markdown",
|
||||
sources=[
|
||||
DocumentArtifactSource(
|
||||
id=node.id_,
|
||||
)
|
||||
for node in self.context_nodes
|
||||
],
|
||||
),
|
||||
),
|
||||
)
|
||||
)
|
||||
|
||||
return StopEvent(
|
||||
result=res,
|
||||
result="",
|
||||
)
|
||||
|
||||
|
||||
|
||||
+21
-1
@@ -1,4 +1,4 @@
|
||||
import { toSourceEvent } from "@llamaindex/server";
|
||||
import { artifactEvent, toSourceEvent } from "@llamaindex/server";
|
||||
import {
|
||||
agentStreamEvent,
|
||||
createStatefulMiddleware,
|
||||
@@ -339,6 +339,26 @@ export function getWorkflow(index: VectorStoreIndex | LlamaCloudIndex) {
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
// Open the generated report in Canvas
|
||||
sendEvent(
|
||||
artifactEvent.with({
|
||||
type: "artifact",
|
||||
data: {
|
||||
type: "document",
|
||||
created_at: Date.now(),
|
||||
data: {
|
||||
title: "DeepResearch Report",
|
||||
content: response,
|
||||
type: "markdown",
|
||||
sources: state.contextNodes.map((node) => ({
|
||||
id: node.node.id_,
|
||||
})),
|
||||
},
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
return stopAgentEvent.with({
|
||||
result: response,
|
||||
});
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import type { Metadata } from "next";
|
||||
import { Inter } from "next/font/google";
|
||||
|
||||
import "@llamaindex/chat-ui/styles/editor.css";
|
||||
import "@llamaindex/chat-ui/styles/markdown.css";
|
||||
import "@llamaindex/chat-ui/styles/pdf.css";
|
||||
import "./globals.css";
|
||||
|
||||
@@ -18,6 +18,7 @@ const eslintConfig = [
|
||||
"react-hooks/exhaustive-deps": "off",
|
||||
"@next/next/no-img-element": "off",
|
||||
"@next/next/no-assign-module-variable": "off",
|
||||
"@typescript-eslint/no-empty-object-type": "off",
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
@@ -110,6 +110,7 @@ export type DocumentArtifactData = {
|
||||
title: string;
|
||||
content: string;
|
||||
type: string; // markdown, html,...
|
||||
sources?: { id: string }[]; // sources that are used to render citation numbers in the document
|
||||
};
|
||||
|
||||
export type CodeArtifact = Artifact<CodeArtifactData> & {
|
||||
|
||||
@@ -4,6 +4,7 @@ from llama_index.server.models.artifacts import (
|
||||
ArtifactType,
|
||||
CodeArtifactData,
|
||||
DocumentArtifactData,
|
||||
DocumentArtifactSource,
|
||||
)
|
||||
from llama_index.server.models.chat import ChatAPIMessage, ChatRequest
|
||||
from llama_index.server.models.hitl import HumanInputEvent, HumanResponseEvent
|
||||
@@ -20,6 +21,7 @@ __all__ = [
|
||||
"ArtifactEvent",
|
||||
"ArtifactType",
|
||||
"DocumentArtifactData",
|
||||
"DocumentArtifactSource",
|
||||
"CodeArtifactData",
|
||||
"ChatAPIMessage",
|
||||
"ChatRequest",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import logging
|
||||
from enum import Enum
|
||||
from typing import Literal, Optional, Union
|
||||
from typing import List, Literal, Optional, Union
|
||||
|
||||
from llama_index.core.workflow.events import Event
|
||||
from llama_index.server.models.chat import ChatAPIMessage
|
||||
@@ -21,10 +21,16 @@ class CodeArtifactData(BaseModel):
|
||||
language: str
|
||||
|
||||
|
||||
class DocumentArtifactSource(BaseModel):
|
||||
id: str
|
||||
# we can add more fields here
|
||||
|
||||
|
||||
class DocumentArtifactData(BaseModel):
|
||||
title: str
|
||||
content: str
|
||||
type: Literal["markdown", "html"]
|
||||
sources: Optional[List[DocumentArtifactSource]] = None
|
||||
|
||||
|
||||
class Artifact(BaseModel):
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
from typing import AsyncGenerator, Union
|
||||
from llama_index.core.base.llms.types import (
|
||||
CompletionResponse,
|
||||
CompletionResponseAsyncGen,
|
||||
)
|
||||
from llama_index.core.workflow import Context
|
||||
from llama_index.core.agent.workflow.workflow_events import AgentStream
|
||||
|
||||
|
||||
async def write_response_to_stream(
|
||||
res: Union[CompletionResponse, CompletionResponseAsyncGen],
|
||||
ctx: Context,
|
||||
current_agent_name: str = "assistant",
|
||||
) -> str:
|
||||
"""
|
||||
Handle both streaming and non-streaming LLM responses.
|
||||
|
||||
Args:
|
||||
res: The LLM response (either streaming or non-streaming)
|
||||
ctx: The workflow context for writing events to stream
|
||||
current_agent_name: The name of the current agent (default: "assistant")
|
||||
|
||||
Returns:
|
||||
The final response text as a string
|
||||
"""
|
||||
final_response = ""
|
||||
|
||||
if isinstance(res, AsyncGenerator):
|
||||
# Handle streaming response (CompletionResponseAsyncGen)
|
||||
async for chunk in res:
|
||||
ctx.write_event_to_stream(
|
||||
AgentStream(
|
||||
delta=chunk.delta or "",
|
||||
response=final_response,
|
||||
current_agent_name=current_agent_name,
|
||||
tool_calls=[],
|
||||
raw=chunk.raw or "",
|
||||
)
|
||||
)
|
||||
final_response = chunk.text
|
||||
else:
|
||||
# Handle non-streaming response (CompletionResponse)
|
||||
final_response = res.text
|
||||
|
||||
return final_response
|
||||
Reference in New Issue
Block a user