Skip to content

Commit

Permalink
feat(prompts): add code snippets using the phoenix-clients (#6441)
Browse files Browse the repository at this point in the history
* cleanup

* cleanup

* cleanup

* cleanup

* cleanup

* cleanup
  • Loading branch information
mikeldking committed Feb 19, 2025
1 parent 10d6361 commit 3fd8296
Show file tree
Hide file tree
Showing 11 changed files with 360 additions and 113 deletions.
36 changes: 23 additions & 13 deletions app/src/components/code/PythonBlock.tsx
Original file line number Diff line number Diff line change
@@ -1,35 +1,45 @@
import React from "react";
import React, { useMemo } from "react";
import { python } from "@codemirror/lang-python";
import { nord } from "@uiw/codemirror-theme-nord";
import CodeMirror, { ReactCodeMirrorProps } from "@uiw/react-codemirror";
import CodeMirror, {
BasicSetupOptions,
ReactCodeMirrorProps,
} from "@uiw/react-codemirror";

import { useTheme } from "@phoenix/contexts";

import { readOnlyCodeMirrorCSS } from "./styles";

type PythonBlockProps = Omit<
ReactCodeMirrorProps,
"theme" | "extensions" | "editable" | "basicSetup"
>;
"theme" | "extensions" | "editable"
> & {
basicSetup?: BasicSetupOptions;
};

export function PythonBlock(props: PythonBlockProps) {
const { theme } = useTheme();
const codeMirrorTheme = theme === "light" ? undefined : nord;
const { basicSetup: propsBasicSetup = {} } = props;
const basicSetup = useMemo(() => {
return {
lineNumbers: false,
foldGutter: true,
bracketMatching: true,
syntaxHighlighting: true,
highlightActiveLine: false,
highlightActiveLineGutter: false,
...(propsBasicSetup as object),
};
}, [propsBasicSetup]);

return (
<CodeMirror
value={props.value}
extensions={[python()]}
editable={false}
theme={codeMirrorTheme}
{...props}
basicSetup={{
lineNumbers: false,
foldGutter: true,
bracketMatching: true,
syntaxHighlighting: true,
highlightActiveLine: false,
highlightActiveLineGutter: false,
}}
basicSetup={basicSetup}
css={readOnlyCodeMirrorCSS}
/>
);
Expand Down
35 changes: 23 additions & 12 deletions app/src/components/code/TypeScriptBlock.tsx
Original file line number Diff line number Diff line change
@@ -1,35 +1,46 @@
import React from "react";
import React, { useMemo } from "react";
import { javascript } from "@codemirror/lang-javascript";
import { nord } from "@uiw/codemirror-theme-nord";
import CodeMirror, { ReactCodeMirrorProps } from "@uiw/react-codemirror";
import CodeMirror, {
BasicSetupOptions,
ReactCodeMirrorProps,
} from "@uiw/react-codemirror";

import { useTheme } from "@phoenix/contexts";

import { readOnlyCodeMirrorCSS } from "./styles";

type TypeScriptBlockProps = Omit<
ReactCodeMirrorProps,
"theme" | "extensions" | "editable" | "basicSetup"
>;
"theme" | "extensions" | "editable"
> & {
basicSetup?: BasicSetupOptions;
};

export function TypeScriptBlock(props: TypeScriptBlockProps) {
const { theme } = useTheme();
const codeMirrorTheme = theme === "light" ? undefined : nord;
const { basicSetup: propsBasicSetup } = props;

const basicSetup = useMemo(() => {
return {
lineNumbers: false,
foldGutter: true,
bracketMatching: true,
syntaxHighlighting: true,
highlightActiveLine: false,
highlightActiveLineGutter: false,
...(propsBasicSetup as object),
};
}, [propsBasicSetup]);
return (
<CodeMirror
value={props.value}
extensions={[javascript({ typescript: true })]}
editable={false}
theme={codeMirrorTheme}
{...props}
basicSetup={{
lineNumbers: false,
foldGutter: true,
bracketMatching: true,
syntaxHighlighting: true,
highlightActiveLine: false,
highlightActiveLineGutter: false,
}}
basicSetup={basicSetup}
css={readOnlyCodeMirrorCSS}
/>
);
Expand Down
105 changes: 81 additions & 24 deletions app/src/pages/prompt/PromptCodeExportCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,13 @@ import {
PythonBlock,
TypeScriptBlock,
} from "@phoenix/components/code";
import { assertUnreachable } from "@phoenix/typeUtils";

import { PromptCodeExportCard__main$key } from "./__generated__/PromptCodeExportCard__main.graphql";
import { mapPromptToSnippet } from "./promptCodeSnippets";
import {
mapPromptToClientSnippet,
mapPromptToSDKSnippet,
} from "./promptCodeSnippets";

export function PromptCodeExportCard({
promptVersion,
Expand All @@ -33,6 +37,7 @@ export function PromptCodeExportCard({
const data = useFragment<PromptCodeExportCard__main$key>(
graphql`
fragment PromptCodeExportCard__main on PromptVersion {
id
invocationParameters
modelName
modelProvider
Expand Down Expand Up @@ -84,23 +89,13 @@ export function PromptCodeExportCard({
`,
promptVersion
);
const snippet = useMemo(
() => mapPromptToSnippet({ promptVersion: data, language }),
const sdkSnippet = useMemo(
() => mapPromptToSDKSnippet({ promptVersion: data, language }),
[data, language]
);
if (!snippet) {
return (
<Card title="Code" variant="compact" bodyStyle={{ padding: 0 }}>
<View padding="size-100">
<Flex justifyContent="center" alignItems="center">
<Text color="text-300">
No code snippet available for this prompt
</Text>
</Flex>
</View>
</Card>
);
}
const clientSnippet = useMemo(() => {
return mapPromptToClientSnippet({ promptVersion: data, language });
}, [data, language]);
return (
<Card
title="Code"
Expand All @@ -109,24 +104,86 @@ export function PromptCodeExportCard({
extra={
<Flex gap="size-100" alignItems="center">
<CodeLanguageRadioGroup language={language} onChange={setLanguage} />
<CopyToClipboardButton text={snippet} />
</Flex>
}
>
<DisclosureGroup defaultExpandedKeys={["snippet"]}>
<Disclosure id="snippet">
<DisclosureTrigger>Code</DisclosureTrigger>
<DisclosureGroup defaultExpandedKeys={["sdk-inline", "client"]}>
<Disclosure id="sdk-inline">
<DisclosureTrigger arrowPosition="start">
<Flex
direction="row"
justifyContent="space-between"
alignItems="center"
gap="size-100"
width="100%"
>
<Text>SDK Inline</Text>
{sdkSnippet ? <CopyToClipboardButton text={sdkSnippet} /> : null}
</Flex>
</DisclosureTrigger>
<DisclosurePanel>
<View padding="size-100">
{language === "Python" ? (
<PythonBlock value={snippet} />
) : language === "TypeScript" ? (
<TypeScriptBlock value={snippet} />
{sdkSnippet == null ? (
<View width="100%" padding="size-200">
<Text color="text-300">
No code snippet available for this prompt
</Text>
</View>
) : (
<CodeBlock language={language} value={sdkSnippet} />
)}
</View>
</DisclosurePanel>
</Disclosure>
<Disclosure id="client">
<DisclosureTrigger arrowPosition="start">
<Flex
direction="row"
justifyContent="space-between"
alignItems="center"
width="100%"
gap="size-100"
>
<Text>Using the Client</Text>
{clientSnippet ? (
<CopyToClipboardButton text={clientSnippet} />
) : null}
</Flex>
</DisclosureTrigger>
<DisclosurePanel>
<View padding="size-100">
{clientSnippet == null ? (
<View width="100%" padding="size-200">
<Text color="text-300">
No client code snippet available for this prompt
</Text>
</View>
) : (
<CodeBlock language={language} value={clientSnippet} />
)}
</View>
</DisclosurePanel>
</Disclosure>
</DisclosureGroup>
</Card>
);
}

function CodeBlock({
language,
value,
}: {
language: CodeLanguage;
value: string;
}) {
switch (language) {
case "Python":
return <PythonBlock value={value} basicSetup={{ lineNumbers: true }} />;
case "TypeScript":
return (
<TypeScriptBlock value={value} basicSetup={{ lineNumbers: true }} />
);
default:
assertUnreachable(language);
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 3fd8296

Please sign in to comment.