Spaces:
Running
Running
export flow button
Browse files
README.md
CHANGED
|
@@ -5,6 +5,7 @@ colorFrom: yellow
|
|
| 5 |
colorTo: yellow
|
| 6 |
sdk: docker
|
| 7 |
short_description: Compare the best text-to-generation models on Hugging Face
|
|
|
|
| 8 |
pinned: true
|
| 9 |
app_port: 3000
|
| 10 |
license: mit
|
|
|
|
| 5 |
colorTo: yellow
|
| 6 |
sdk: docker
|
| 7 |
short_description: Compare the best text-to-generation models on Hugging Face
|
| 8 |
+
failure_strategy: rollback
|
| 9 |
pinned: true
|
| 10 |
app_port: 3000
|
| 11 |
license: mit
|
src/lib/components/chat/Assistant.svelte
CHANGED
|
@@ -184,10 +184,14 @@
|
|
| 184 |
<span class="inline-flex items-center gap-1 rounded-full bg-muted py-0.5 pr-2 pl-1">
|
| 185 |
<img
|
| 186 |
src={`https://huggingface.co/api/avatars/${inferenceProvider}`}
|
| 187 |
-
alt={
|
|
|
|
|
|
|
| 188 |
class="size-4 rounded-full"
|
| 189 |
/>
|
| 190 |
-
{
|
|
|
|
|
|
|
| 191 |
</span>
|
| 192 |
provider
|
| 193 |
</span>
|
|
|
|
| 184 |
<span class="inline-flex items-center gap-1 rounded-full bg-muted py-0.5 pr-2 pl-1">
|
| 185 |
<img
|
| 186 |
src={`https://huggingface.co/api/avatars/${inferenceProvider}`}
|
| 187 |
+
alt={(nodeData.current?.data.inferenceProvider as string) ??
|
| 188 |
+
inferenceProvider ??
|
| 189 |
+
provider}
|
| 190 |
class="size-4 rounded-full"
|
| 191 |
/>
|
| 192 |
+
{(nodeData.current?.data.inferenceProvider as string) ??
|
| 193 |
+
inferenceProvider ??
|
| 194 |
+
provider}
|
| 195 |
</span>
|
| 196 |
provider
|
| 197 |
</span>
|
src/lib/components/flow/actions/PanelFlowActions.svelte
CHANGED
|
@@ -4,8 +4,9 @@
|
|
| 4 |
|
| 5 |
import { Button } from '$lib/components/ui/button';
|
| 6 |
import { breakpointsState } from '$lib/state/breakpoints.svelte';
|
|
|
|
| 7 |
|
| 8 |
-
const { getNodes } = useSvelteFlow();
|
| 9 |
let showPanelFlowActions = $derived(getNodes().length > 1);
|
| 10 |
|
| 11 |
function handleReset() {
|
|
@@ -18,11 +19,10 @@
|
|
| 18 |
function handleExport() {
|
| 19 |
const ok = confirm('Are you sure you want to export the flow?');
|
| 20 |
if (ok) {
|
| 21 |
-
const
|
| 22 |
-
const
|
| 23 |
-
const
|
| 24 |
-
|
| 25 |
-
window.open(flowUrl, '_blank');
|
| 26 |
}
|
| 27 |
}
|
| 28 |
</script>
|
|
@@ -43,7 +43,7 @@
|
|
| 43 |
Clear flow
|
| 44 |
{/if}
|
| 45 |
</Button>
|
| 46 |
-
<
|
| 47 |
variant="outline"
|
| 48 |
size={breakpointsState.isMobile ? 'icon-sm' : 'default'}
|
| 49 |
class=""
|
|
@@ -53,6 +53,6 @@
|
|
| 53 |
{#if !breakpointsState.isMobile}
|
| 54 |
Export flow
|
| 55 |
{/if}
|
| 56 |
-
</Button>
|
| 57 |
</Panel>
|
| 58 |
{/if}
|
|
|
|
| 4 |
|
| 5 |
import { Button } from '$lib/components/ui/button';
|
| 6 |
import { breakpointsState } from '$lib/state/breakpoints.svelte';
|
| 7 |
+
import { mapNodesExport } from '$lib/helpers/map-nodes-export';
|
| 8 |
|
| 9 |
+
const { getNodes, getEdges } = useSvelteFlow();
|
| 10 |
let showPanelFlowActions = $derived(getNodes().length > 1);
|
| 11 |
|
| 12 |
function handleReset() {
|
|
|
|
| 19 |
function handleExport() {
|
| 20 |
const ok = confirm('Are you sure you want to export the flow?');
|
| 21 |
if (ok) {
|
| 22 |
+
const exported = mapNodesExport(getNodes(), getEdges());
|
| 23 |
+
const blob = new Blob([JSON.stringify(exported, null, 2)], { type: 'application/json' });
|
| 24 |
+
const url = URL.createObjectURL(blob);
|
| 25 |
+
window.open(url, '_blank');
|
|
|
|
| 26 |
}
|
| 27 |
}
|
| 28 |
</script>
|
|
|
|
| 43 |
Clear flow
|
| 44 |
{/if}
|
| 45 |
</Button>
|
| 46 |
+
<Button
|
| 47 |
variant="outline"
|
| 48 |
size={breakpointsState.isMobile ? 'icon-sm' : 'default'}
|
| 49 |
class=""
|
|
|
|
| 53 |
{#if !breakpointsState.isMobile}
|
| 54 |
Export flow
|
| 55 |
{/if}
|
| 56 |
+
</Button>
|
| 57 |
</Panel>
|
| 58 |
{/if}
|
src/lib/components/model/SettingsModel.svelte
CHANGED
|
@@ -252,7 +252,7 @@
|
|
| 252 |
alt={providerName}
|
| 253 |
class="size-4 rounded"
|
| 254 |
/>
|
| 255 |
-
{
|
| 256 |
</div>
|
| 257 |
{#if formatPricingPerToken(provider.pricing)}
|
| 258 |
<span class="text-xs text-muted-foreground">
|
|
|
|
| 252 |
alt={providerName}
|
| 253 |
class="size-4 rounded"
|
| 254 |
/>
|
| 255 |
+
{provider.provider}
|
| 256 |
</div>
|
| 257 |
{#if formatPricingPerToken(provider.pricing)}
|
| 258 |
<span class="text-xs text-muted-foreground">
|
src/lib/helpers/map-nodes-export.ts
CHANGED
|
@@ -1,13 +1,31 @@
|
|
| 1 |
-
import type { Node } from '@xyflow/svelte';
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 12 |
});
|
|
|
|
|
|
|
| 13 |
}
|
|
|
|
| 1 |
+
import type { Node, Edge } from '@xyflow/svelte';
|
| 2 |
+
import type { ChatMessage } from './types';
|
| 3 |
+
|
| 4 |
+
export function mapNodesExport(
|
| 5 |
+
nodes: Node[],
|
| 6 |
+
edges: Edge[]
|
| 7 |
+
): Record<string, ChatMessage[]> {
|
| 8 |
+
const outgoing = new Map<string, number>();
|
| 9 |
+
|
| 10 |
+
for (const node of nodes) {
|
| 11 |
+
outgoing.set(node.id, 0);
|
| 12 |
+
}
|
| 13 |
+
for (const edge of edges) {
|
| 14 |
+
outgoing.set(edge.source, (outgoing.get(edge.source) ?? 0) + 1);
|
| 15 |
+
}
|
| 16 |
+
|
| 17 |
+
// Each leaf user node (no outgoing edges) = one exported flow.
|
| 18 |
+
// This covers both fully disconnected flows and edit branches within the same tree.
|
| 19 |
+
const leafUserNodes = nodes.filter(
|
| 20 |
+
(n) =>
|
| 21 |
+
(n.type === 'user' || n.type === 'user-follow-up') && (outgoing.get(n.id) ?? 0) === 0
|
| 22 |
+
);
|
| 23 |
+
|
| 24 |
+
const result: Record<string, ChatMessage[]> = {};
|
| 25 |
+
|
| 26 |
+
leafUserNodes.forEach((node, index) => {
|
| 27 |
+
result[String(index + 1)] = (node.data.messages as ChatMessage[]) ?? [];
|
| 28 |
});
|
| 29 |
+
|
| 30 |
+
return result;
|
| 31 |
}
|