Shyamnath's picture
Push UI dashboard and deployment files
c40c75a
raw
history blame
8.59 kB
import React, { useState } from 'react';
import { Button, Select, Tabs, message } from 'antd';
import { CopyOutlined } from '@ant-design/icons';
import { Title } from '@tremor/react';
import { transformRequestCall } from './networking';
interface TransformRequestPanelProps {
accessToken: string | null;
}
interface TransformResponse {
raw_request_api_base: string;
raw_request_body: Record<string, any>;
raw_request_headers: Record<string, string>;
}
const TransformRequestPanel: React.FC<TransformRequestPanelProps> = ({ accessToken }) => {
const [originalRequestJSON, setOriginalRequestJSON] = useState(`{
"model": "openai/gpt-4o",
"messages": [
{
"role": "system",
"content": "You are a helpful assistant."
},
{
"role": "user",
"content": "Explain quantum computing in simple terms"
}
],
"temperature": 0.7,
"max_tokens": 500,
"stream": true
}`);
const [transformedResponse, setTransformedResponse] = useState('');
const [isLoading, setIsLoading] = useState(false);
// Function to format curl command from API response parts
const formatCurlCommand = (apiBase: string, requestBody: Record<string, any>, requestHeaders: Record<string, string>) => {
// Format the request body as nicely indented JSON with 2 spaces
const formattedBody = JSON.stringify(requestBody, null, 2)
// Add additional indentation for the entire body
.split('\n')
.map(line => ` ${line}`)
.join('\n');
// Build headers string with consistent indentation
const headerString = Object.entries(requestHeaders)
.map(([key, value]) => `-H '${key}: ${value}'`)
.join(' \\\n ');
// Build the curl command with consistent indentation
return `curl -X POST \\
${apiBase} \\
${headerString ? `${headerString} \\\n ` : ''}-H 'Content-Type: application/json' \\
-d '{
${formattedBody}
}'`;
};
// Function to handle the transform request
const handleTransform = async () => {
setIsLoading(true);
try {
// Parse the JSON from the textarea
let requestBody;
try {
requestBody = JSON.parse(originalRequestJSON);
} catch (e) {
message.error('Invalid JSON in request body');
setIsLoading(false);
return;
}
// Create the request payload
const payload = {
call_type: "completion",
request_body: requestBody
};
// Make the API call using fetch
if (!accessToken) {
message.error('No access token found');
setIsLoading(false);
return;
}
const data = await transformRequestCall(accessToken, payload);
// Check if the response has the expected fields
if (data.raw_request_api_base && data.raw_request_body) {
// Format the curl command with the separate parts
const formattedCurl = formatCurlCommand(
data.raw_request_api_base,
data.raw_request_body,
data.raw_request_headers || {}
);
// Update state with the formatted curl command
setTransformedResponse(formattedCurl);
message.success('Request transformed successfully');
} else {
// Handle the case where the API returns a different format
// Try to extract the parts from a string response if needed
const rawText = typeof data === 'string' ? data : JSON.stringify(data);
setTransformedResponse(rawText);
message.info('Transformed request received in unexpected format');
}
} catch (err) {
console.error('Error transforming request:', err);
message.error('Failed to transform request');
} finally {
setIsLoading(false);
}
};
// Add this handler function near your other handlers
const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
if ((e.metaKey || e.ctrlKey) && e.key === 'Enter') {
e.preventDefault(); // Prevent default behavior
handleTransform();
}
};
return (
<div className="w-full m-2" style={{ overflow: 'hidden' }}>
<Title>Playground</Title>
<p className="text-sm text-gray-500">See how LiteLLM transforms your request for the specified provider.</p>
<div style={{
display: 'flex',
gap: '16px',
width: '100%',
minWidth: 0,
overflow: 'hidden'
}} className="mt-4">
{/* Original Request Panel */}
<div style={{
flex: '1 1 50%',
display: 'flex',
flexDirection: 'column',
border: '1px solid #e8e8e8',
borderRadius: '8px',
padding: '24px',
overflow: 'hidden',
maxHeight: '600px',
minWidth: 0
}}>
<div style={{ marginBottom: '24px' }}>
<h2 style={{ fontSize: '24px', fontWeight: 'bold', margin: '0 0 4px 0' }}>Original Request</h2>
<p style={{ color: '#666', margin: 0 }}>The request you would send to LiteLLM /chat/completions endpoint.</p>
</div>
<textarea
style={{
flex: '1 1 auto',
width: '100%',
minHeight: '240px',
padding: '16px',
border: '1px solid #e8e8e8',
borderRadius: '6px',
fontFamily: 'monospace',
fontSize: '14px',
resize: 'none',
marginBottom: '24px',
overflow: 'auto'
}}
value={originalRequestJSON}
onChange={(e) => setOriginalRequestJSON(e.target.value)}
onKeyDown={handleKeyDown}
placeholder="Press Cmd/Ctrl + Enter to transform"
/>
<div style={{
display: 'flex',
justifyContent: 'flex-end',
marginTop: 'auto'
}}>
<Button
type="primary"
style={{
backgroundColor: '#000',
display: 'flex',
alignItems: 'center',
gap: '8px'
}}
onClick={handleTransform}
loading={isLoading}
>
<span>Transform</span>
<span></span>
</Button>
</div>
</div>
{/* Transformed Request Panel */}
<div style={{
flex: '1 1 50%',
display: 'flex',
flexDirection: 'column',
border: '1px solid #e8e8e8',
borderRadius: '8px',
padding: '24px',
overflow: 'hidden',
maxHeight: '800px',
minWidth: 0
}}>
<div style={{ marginBottom: '24px' }}>
<h2 style={{ fontSize: '24px', fontWeight: 'bold', margin: '0 0 4px 0' }}>Transformed Request</h2>
<p style={{ color: '#666', margin: 0 }}>How LiteLLM transforms your request for the specified provider.</p>
<br/>
<p style={{ color: '#666', margin: 0 }} className="text-xs">Note: Sensitive headers are not shown.</p>
</div>
<div style={{
position: 'relative',
backgroundColor: '#f5f5f5',
borderRadius: '6px',
flex: '1 1 auto',
display: 'flex',
flexDirection: 'column',
overflow: 'hidden'
}}>
<pre
style={{
padding: '16px',
fontFamily: 'monospace',
fontSize: '14px',
margin: 0,
overflow: 'auto',
flex: '1 1 auto'
}}
>
{transformedResponse || `curl -X POST \\
https://api.openai.com/v1/chat/completions \\
-H 'Authorization: Bearer sk-xxx' \\
-H 'Content-Type: application/json' \\
-d '{
"model": "gpt-4",
"messages": [
{
"role": "system",
"content": "You are a helpful assistant."
}
],
"temperature": 0.7
}'`}
</pre>
<Button
type="text"
icon={<CopyOutlined />}
style={{
position: 'absolute',
right: '8px',
top: '8px'
}}
size="small"
onClick={() => {
navigator.clipboard.writeText(transformedResponse || '');
message.success('Copied to clipboard');
}}
/>
</div>
</div>
</div>
<div className="mt-4 text-right w-full">
<p className="text-sm text-gray-500">Found an error? File an issue <a href="https://github.com/BerriAI/litellm/issues" target="_blank" rel="noopener noreferrer">here</a>.</p>
</div>
</div>
);
};
export default TransformRequestPanel;