Skip to content

Commit

Permalink
added azure openai
Browse files Browse the repository at this point in the history
  • Loading branch information
GQAdonis committed Dec 22, 2024
1 parent 8b58c7a commit 51b4a43
Show file tree
Hide file tree
Showing 14 changed files with 329 additions and 102 deletions.
52 changes: 45 additions & 7 deletions app/components/chat/Chat.client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,12 @@ export function Chat() {
<ToastContainer
closeButton={({ closeToast }) => {
return (
<button className="Toastify__close-button" onClick={closeToast}>
<button
type="button"
aria-label="Close notification"
className="Toastify__close-button"
onClick={closeToast}
>
<div className="i-ph:x text-lg" />
</button>
);
Expand Down Expand Up @@ -139,19 +144,52 @@ export const ChatImpl = memo(
promptId,
},
sendExtraMessageFields: true,
onError: (error) => {
headers: {
Accept: 'text/event-stream',
},
onError: async (error: Error & { response?: Response }) => {
logger.error('Request failed\n\n', error);
toast.error(
'There was an error processing your request: ' + (error.message ? error.message : 'No details were returned'),
);

let errorMessage = 'An unknown error occurred';

try {
if (error.response) {
const response = (await error.response.json()) as {
error?: string;
details?: string;
provider?: string;
model?: string;
};

if (response?.error) {
errorMessage = response.error;

if (response.details) {
logger.error('Error details:', response.details);
}

if (response.provider) {
logger.error('Provider:', response.provider);
}

if (response.model) {
logger.error('Model:', response.model);
}
}
}
} catch (e) {
logger.error('Error parsing error response:', e);
errorMessage = error.message || 'An unknown error occurred';
}

toast.error(errorMessage);
stop();
},
onFinish: (message, response) => {
const usage = response.usage;

if (usage) {
console.log('Token usage:', usage);

// You can now use the usage data as needed
}

logger.debug('Finished streaming');
Expand Down
4 changes: 4 additions & 0 deletions app/components/chat/Messages.client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ export const Messages = React.forwardRef<HTMLDivElement, MessagesProps>((props:
{messageId && (
<WithTooltip tooltip="Revert to this message">
<button
type="button"
aria-label="Revert to this message"
onClick={() => handleRewind(messageId)}
key="i-ph:arrow-u-up-left"
className={classNames(
Expand All @@ -88,6 +90,8 @@ export const Messages = React.forwardRef<HTMLDivElement, MessagesProps>((props:

<WithTooltip tooltip="Fork chat from this message">
<button
type="button"
aria-label="Fork chat from this message"
onClick={() => handleFork(messageId)}
key="i-ph:git-fork"
className={classNames(
Expand Down
2 changes: 2 additions & 0 deletions app/components/chat/ModelSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ export const ModelSelector = ({
return (
<div className="mb-2 flex gap-2 flex-col sm:flex-row">
<select
aria-label="Select AI Provider"
value={provider?.name ?? ''}
onChange={(e) => {
const newProvider = providerList.find((p: ProviderInfo) => p.name === e.target.value);
Expand All @@ -79,6 +80,7 @@ export const ModelSelector = ({
))}
</select>
<select
aria-label="Select AI Model"
key={provider?.name}
value={model}
onChange={(e) => setModel?.(e.target.value)}
Expand Down
4 changes: 4 additions & 0 deletions app/components/chat/chatExportAndImport/ImportButtons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,15 @@ import { ImportFolderButton } from '~/components/chat/ImportFolderButton';
export function ImportButtons(importChat: ((description: string, messages: Message[]) => Promise<void>) | undefined) {
return (
<div className="flex flex-col items-center justify-center w-auto">
<label htmlFor="chat-import" className="sr-only">
Import chat file
</label>
<input
type="file"
id="chat-import"
className="hidden"
accept=".json"
aria-label="Import chat file"
onChange={async (e) => {
const file = e.target.files?.[0];

Expand Down
12 changes: 10 additions & 2 deletions app/components/settings/connections/ConnectionsTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -95,20 +95,28 @@ export default function ConnectionsTab() {
<h3 className="text-lg font-medium text-bolt-elements-textPrimary mb-4">GitHub Connection</h3>
<div className="flex mb-4">
<div className="flex-1 mr-2">
<label className="block text-sm text-bolt-elements-textSecondary mb-1">GitHub Username:</label>
<label htmlFor="github-username" className="block text-sm text-bolt-elements-textSecondary mb-1">
GitHub Username:
</label>
<input
id="github-username"
type="text"
value={githubUsername}
placeholder="Enter GitHub username"
onChange={(e) => setGithubUsername(e.target.value)}
disabled={isVerifying}
className="w-full bg-white dark:bg-bolt-elements-background-depth-4 relative px-2 py-1.5 rounded-md focus:outline-none placeholder-bolt-elements-textTertiary text-bolt-elements-textPrimary dark:text-bolt-elements-textPrimary border border-bolt-elements-borderColor disabled:opacity-50"
/>
</div>
<div className="flex-1">
<label className="block text-sm text-bolt-elements-textSecondary mb-1">Personal Access Token:</label>
<label htmlFor="github-token" className="block text-sm text-bolt-elements-textSecondary mb-1">
Personal Access Token:
</label>
<input
id="github-token"
type="password"
value={githubToken}
placeholder="Enter personal access token"
onChange={(e) => setGithubToken(e.target.value)}
disabled={isVerifying}
className="w-full bg-white dark:bg-bolt-elements-background-depth-4 relative px-2 py-1.5 rounded-md focus:outline-none placeholder-bolt-elements-textTertiary text-bolt-elements-textPrimary dark:text-bolt-elements-textPrimary border border-bolt-elements-borderColor disabled:opacity-50"
Expand Down
8 changes: 8 additions & 0 deletions app/components/sidebar/HistoryItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,14 @@ export function HistoryItem({ item, onDelete, onDuplicate, exportChat }: History

const renderDescriptionForm = (
<form onSubmit={handleSubmit} className="flex-1 flex items-center">
<label htmlFor="chat-description" className="sr-only">
Edit chat description
</label>
<input
id="chat-description"
type="text"
placeholder="Enter chat description"
aria-label="Edit chat description"
className="flex-1 bg-bolt-elements-background-depth-1 text-bolt-elements-textPrimary rounded px-2 mr-2"
autoFocus
value={currentDescription}
Expand All @@ -37,6 +43,7 @@ export function HistoryItem({ item, onDelete, onDuplicate, exportChat }: History
/>
<button
type="submit"
aria-label="Save description"
className="i-ph:check scale-110 hover:text-bolt-elements-item-contentAccent"
onMouseDown={handleSubmit}
/>
Expand Down Expand Up @@ -125,6 +132,7 @@ const ChatActionButton = forwardRef(
<button
ref={ref}
type="button"
aria-label={toolTipContent}
className={`scale-110 mr-2 hover:text-bolt-elements-item-contentAccent ${icon} ${className ? className : ''}`}
onClick={onClick}
/>
Expand Down
104 changes: 55 additions & 49 deletions app/lib/.server/llm/stream-text.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,63 +153,69 @@ export async function streamText(props: {
}) {
const { messages, env: serverEnv, options, apiKeys, files, providerSettings, promptId } = props;

// console.log({serverEnv});
try {
let currentModel = DEFAULT_MODEL;
let currentProvider = DEFAULT_PROVIDER.name;
const MODEL_LIST = await getModelList({ apiKeys, providerSettings, serverEnv: serverEnv as any });
const processedMessages = messages.map((message) => {
if (message.role === 'user') {
const { model, provider, content } = extractPropertiesFromMessage(message);

if (MODEL_LIST.find((m) => m.name === model)) {
currentModel = model;
}

let currentModel = DEFAULT_MODEL;
let currentProvider = DEFAULT_PROVIDER.name;
const MODEL_LIST = await getModelList({ apiKeys, providerSettings, serverEnv: serverEnv as any });
const processedMessages = messages.map((message) => {
if (message.role === 'user') {
const { model, provider, content } = extractPropertiesFromMessage(message);
currentProvider = provider;

if (MODEL_LIST.find((m) => m.name === model)) {
currentModel = model;
return { ...message, content };
} else if (message.role == 'assistant') {
const content = message.content;
return { ...message, content };
}

currentProvider = provider;

return { ...message, content };
} else if (message.role == 'assistant') {
const content = message.content;

// content = simplifyBoltActions(content);

return { ...message, content };
}

return message;
});
return message;
});

const modelDetails = MODEL_LIST.find((m) => m.name === currentModel);
const modelDetails = MODEL_LIST.find((m) => m.name === currentModel);
const dynamicMaxTokens = modelDetails && modelDetails.maxTokenAllowed ? modelDetails.maxTokenAllowed : MAX_TOKENS;
const provider = PROVIDER_LIST.find((p) => p.name === currentProvider) || DEFAULT_PROVIDER;

const dynamicMaxTokens = modelDetails && modelDetails.maxTokenAllowed ? modelDetails.maxTokenAllowed : MAX_TOKENS;
let systemPrompt =
PromptLibrary.getPropmtFromLibrary(promptId || 'default', {
cwd: WORK_DIR,
allowedHtmlElements: allowedHTMLElements,
modificationTagName: MODIFICATIONS_TAG_NAME,
}) ?? getSystemPrompt();

const provider = PROVIDER_LIST.find((p) => p.name === currentProvider) || DEFAULT_PROVIDER;
let codeContext = '';

let systemPrompt =
PromptLibrary.getPropmtFromLibrary(promptId || 'default', {
cwd: WORK_DIR,
allowedHtmlElements: allowedHTMLElements,
modificationTagName: MODIFICATIONS_TAG_NAME,
}) ?? getSystemPrompt();
let codeContext = '';
if (files) {
codeContext = createFilesContext(files);
codeContext = '';
systemPrompt = `${systemPrompt}\n\n ${codeContext}`;
}

if (files) {
codeContext = createFilesContext(files);
codeContext = '';
systemPrompt = `${systemPrompt}\n\n ${codeContext}`;
try {
const modelInstance = provider.getModelInstance({
model: currentModel,
serverEnv,
apiKeys,
providerSettings,
});

return _streamText({
model: modelInstance,
system: systemPrompt,
maxTokens: dynamicMaxTokens,
messages: convertToCoreMessages(processedMessages as any),
...options,
});
} catch (error) {
console.error('Error creating model instance:', error);
throw error instanceof Error ? error : new Error(String(error));
}
} catch (error) {
console.error('Error in streamText:', error);
throw error instanceof Error ? error : new Error(String(error));
}

return _streamText({
model: provider.getModelInstance({
model: currentModel,
serverEnv,
apiKeys,
providerSettings,
}),
system: systemPrompt,
maxTokens: dynamicMaxTokens,
messages: convertToCoreMessages(processedMessages as any),
...options,
});
}
37 changes: 33 additions & 4 deletions app/lib/.server/llm/switchable-stream.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,12 @@ export default class SwitchableStream extends TransformStream {

this._currentReader = newStream.getReader();

this._pumpStream();
try {
await this._pumpStream();
} catch (error) {
console.error('Error switching stream source:', error);
throw error instanceof Error ? error : new Error(String(error));
}

this._switches++;
}
Expand All @@ -44,11 +49,35 @@ export default class SwitchableStream extends TransformStream {
break;
}

this._controller.enqueue(value);
// Handle different types of chunks that might come from different providers
if (value instanceof Uint8Array) {
// Handle binary data
this._controller.enqueue(value);
} else if (typeof value === 'string') {
// Handle string data
this._controller.enqueue(new TextEncoder().encode(value));
} else if (value && typeof value === 'object') {
// Handle structured data (like from Azure OpenAI)
try {
const chunk = JSON.stringify(value);
this._controller.enqueue(new TextEncoder().encode(chunk + '\n'));
} catch (e) {
console.error('Error stringifying chunk:', e);
this._controller.enqueue(new TextEncoder().encode(String(value)));
}
} else {
// Handle any other type by converting to string
this._controller.enqueue(new TextEncoder().encode(String(value)));
}
}
} catch (error) {
console.log(error);
this._controller.error(error);
console.error('Error pumping stream:', error);

if (this._controller) {
this._controller.error(error instanceof Error ? error : new Error(String(error)));
}

throw error instanceof Error ? error : new Error(String(error));
}
}

Expand Down
2 changes: 2 additions & 0 deletions app/lib/modules/llm/registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import OllamaProvider from './providers/ollama';
import OpenRouterProvider from './providers/open-router';
import OpenAILikeProvider from './providers/openai-like';
import OpenAIProvider from './providers/openai';
import AzureOpenAIProvider from './providers/azure-openai';
import PerplexityProvider from './providers/perplexity';
import TogetherProvider from './providers/together';
import XAIProvider from './providers/xai';
Expand All @@ -24,6 +25,7 @@ export {
MistralProvider,
OllamaProvider,
OpenAIProvider,
AzureOpenAIProvider,
OpenRouterProvider,
OpenAILikeProvider,
PerplexityProvider,
Expand Down
Loading

0 comments on commit 51b4a43

Please sign in to comment.