atrokhym commited on
Commit
fe3ea80
·
1 Parent(s): 4b236e9

changing based on PR review

Browse files
app/components/chat/BaseChat.tsx CHANGED
@@ -35,7 +35,7 @@ const ModelSelector = ({ model, setModel, provider, setProvider, modelList, prov
35
  <select
36
  value={provider?.name}
37
  onChange={(e) => {
38
- setProvider(providerList.find(p => p.name === e.target.value));
39
  const firstModel = [...modelList].find((m) => m.provider == e.target.value);
40
  setModel(firstModel ? firstModel.name : '');
41
  }}
@@ -51,7 +51,7 @@ const ModelSelector = ({ model, setModel, provider, setProvider, modelList, prov
51
  key={provider?.name}
52
  value={model}
53
  onChange={(e) => setModel(e.target.value)}
54
- style={{ maxWidth: "70%" }}
55
  className="flex-1 p-2 rounded-lg border border-bolt-elements-borderColor bg-bolt-elements-prompt-background text-bolt-elements-textPrimary focus:outline-none focus:ring-2 focus:ring-bolt-elements-focus transition-all"
56
  >
57
  {[...modelList]
@@ -93,32 +93,34 @@ interface BaseChatProps {
93
  setImageDataList?: (dataList: string[]) => void;
94
  }
95
  export const BaseChat = React.forwardRef<HTMLDivElement, BaseChatProps>(
96
- ({
97
- textareaRef,
98
- messageRef,
99
- scrollRef,
100
- showChat,
101
- chatStarted = false,
102
- isStreaming = false,
103
- model,
104
- setModel,
105
- provider,
106
- setProvider,
107
- input = '',
108
- enhancingPrompt,
109
- handleInputChange,
110
- promptEnhanced,
111
- enhancePrompt,
112
- sendMessage,
113
- handleStop,
114
- uploadedFiles,
115
- setUploadedFiles,
116
- imageDataList,
117
- setImageDataList,
118
- messages,
119
- children, // Add this
120
- }, ref) => {
121
- console.log(provider);
 
 
122
  const TEXTAREA_MAX_HEIGHT = chatStarted ? 400 : 200;
123
  const [apiKeys, setApiKeys] = useState<Record<string, string>>({});
124
  const [modelList, setModelList] = useState(MODEL_LIST);
@@ -139,7 +141,7 @@ export const BaseChat = React.forwardRef<HTMLDivElement, BaseChatProps>(
139
  Cookies.remove('apiKeys');
140
  }
141
 
142
- initializeModelList().then(modelList => {
143
  setModelList(modelList);
144
  });
145
  }, []);
@@ -239,12 +241,13 @@ export const BaseChat = React.forwardRef<HTMLDivElement, BaseChatProps>(
239
  setProvider={setProvider}
240
  providerList={PROVIDER_LIST}
241
  />
242
- {provider &&
243
  <APIKeyManager
244
  provider={provider}
245
  apiKey={apiKeys[provider.name] || ''}
246
  setApiKey={(key) => updateApiKey(provider.name, key)}
247
- />}
 
248
 
249
  <FilePreview
250
  files={uploadedFiles}
@@ -309,7 +312,7 @@ export const BaseChat = React.forwardRef<HTMLDivElement, BaseChatProps>(
309
  className="transition-all"
310
  onClick={() => handleFileUpload()}
311
  >
312
- <div className="i-ph:upload text-xl"></div>
313
  </IconButton>
314
 
315
  <IconButton
@@ -374,6 +377,3 @@ export const BaseChat = React.forwardRef<HTMLDivElement, BaseChatProps>(
374
  );
375
  },
376
  );
377
-
378
-
379
-
 
35
  <select
36
  value={provider?.name}
37
  onChange={(e) => {
38
+ setProvider(providerList.find((p) => p.name === e.target.value));
39
  const firstModel = [...modelList].find((m) => m.provider == e.target.value);
40
  setModel(firstModel ? firstModel.name : '');
41
  }}
 
51
  key={provider?.name}
52
  value={model}
53
  onChange={(e) => setModel(e.target.value)}
54
+ style={{ maxWidth: '70%' }}
55
  className="flex-1 p-2 rounded-lg border border-bolt-elements-borderColor bg-bolt-elements-prompt-background text-bolt-elements-textPrimary focus:outline-none focus:ring-2 focus:ring-bolt-elements-focus transition-all"
56
  >
57
  {[...modelList]
 
93
  setImageDataList?: (dataList: string[]) => void;
94
  }
95
  export const BaseChat = React.forwardRef<HTMLDivElement, BaseChatProps>(
96
+ (
97
+ {
98
+ textareaRef,
99
+ messageRef,
100
+ scrollRef,
101
+ showChat = true,
102
+ chatStarted = false,
103
+ isStreaming = false,
104
+ model,
105
+ setModel,
106
+ provider,
107
+ setProvider,
108
+ input = '',
109
+ enhancingPrompt,
110
+ handleInputChange,
111
+ promptEnhanced,
112
+ enhancePrompt,
113
+ sendMessage,
114
+ handleStop,
115
+ uploadedFiles,
116
+ setUploadedFiles,
117
+ imageDataList,
118
+ setImageDataList,
119
+ messages,
120
+ children, // Add this
121
+ },
122
+ ref,
123
+ ) => {
124
  const TEXTAREA_MAX_HEIGHT = chatStarted ? 400 : 200;
125
  const [apiKeys, setApiKeys] = useState<Record<string, string>>({});
126
  const [modelList, setModelList] = useState(MODEL_LIST);
 
141
  Cookies.remove('apiKeys');
142
  }
143
 
144
+ initializeModelList().then((modelList) => {
145
  setModelList(modelList);
146
  });
147
  }, []);
 
241
  setProvider={setProvider}
242
  providerList={PROVIDER_LIST}
243
  />
244
+ {provider && (
245
  <APIKeyManager
246
  provider={provider}
247
  apiKey={apiKeys[provider.name] || ''}
248
  setApiKey={(key) => updateApiKey(provider.name, key)}
249
+ />
250
+ )}
251
 
252
  <FilePreview
253
  files={uploadedFiles}
 
312
  className="transition-all"
313
  onClick={() => handleFileUpload()}
314
  >
315
+ <div className="i-ph:paperclip text-xl"></div>
316
  </IconButton>
317
 
318
  <IconButton
 
377
  );
378
  },
379
  );
 
 
 
app/components/chat/FilePreview.tsx CHANGED
@@ -1,23 +1,22 @@
1
- // FilePreview.tsx
2
  import React from 'react';
3
- import { X } from 'lucide-react';
4
 
 
5
  interface FilePreviewProps {
6
  files: File[];
7
- imageDataList: string[]; // or imagePreviews: string[]
8
  onRemove: (index: number) => void;
9
  }
10
 
11
  const FilePreview: React.FC<FilePreviewProps> = ({ files, imageDataList, onRemove }) => {
12
  if (!files || files.length === 0) {
13
- return null; // Or render a placeholder if desired
14
  }
15
 
16
  return (
17
- <div className="flex flex-row overflow-x-auto"> {/* Add horizontal scrolling if needed */}
18
  {files.map((file, index) => (
19
  <div key={file.name + file.size} className="mr-2 relative">
20
- {/* Display image preview or file icon */}
21
  {imageDataList[index] && (
22
  <div className="relative">
23
  <img src={imageDataList[index]} alt={file.name} className="max-h-20" />
@@ -26,7 +25,7 @@ const FilePreview: React.FC<FilePreviewProps> = ({ files, imageDataList, onRemov
26
  className="absolute -top-2 -right-2 z-10 bg-white rounded-full p-1 shadow-md hover:bg-gray-100"
27
  >
28
  <div className="bg-black rounded-full p-1">
29
- <X className="w-3 h-3 text-gray-400" strokeWidth={2.5} />
30
  </div>
31
  </button>
32
  </div>
 
1
+ // Remove the lucide-react import
2
  import React from 'react';
 
3
 
4
+ // Rest of the interface remains the same
5
  interface FilePreviewProps {
6
  files: File[];
7
+ imageDataList: string[];
8
  onRemove: (index: number) => void;
9
  }
10
 
11
  const FilePreview: React.FC<FilePreviewProps> = ({ files, imageDataList, onRemove }) => {
12
  if (!files || files.length === 0) {
13
+ return null;
14
  }
15
 
16
  return (
17
+ <div className="flex flex-row overflow-x-auto">
18
  {files.map((file, index) => (
19
  <div key={file.name + file.size} className="mr-2 relative">
 
20
  {imageDataList[index] && (
21
  <div className="relative">
22
  <img src={imageDataList[index]} alt={file.name} className="max-h-20" />
 
25
  className="absolute -top-2 -right-2 z-10 bg-white rounded-full p-1 shadow-md hover:bg-gray-100"
26
  >
27
  <div className="bg-black rounded-full p-1">
28
+ <div className="i-ph:x w-3 h-3 text-gray-400" />
29
  </div>
30
  </button>
31
  </div>
app/components/chat/UserMessage.tsx CHANGED
@@ -21,9 +21,6 @@ export function UserMessage({ content }: UserMessageProps) {
21
  );
22
  }
23
 
24
- // function sanitizeUserMessage(content: string) {
25
- // return content.replace(modificationsRegex, '').replace(MODEL_REGEX, 'Using: $1').replace(PROVIDER_REGEX, ' ($1)\n\n').trim();
26
- // }
27
  function sanitizeUserMessage(content: string | Array<{type: string, text?: string, image_url?: {url: string}}>) {
28
  if (Array.isArray(content)) {
29
  return content.map(item => {
 
21
  );
22
  }
23
 
 
 
 
24
  function sanitizeUserMessage(content: string | Array<{type: string, text?: string, image_url?: {url: string}}>) {
25
  if (Array.isArray(content)) {
26
  return content.map(item => {
app/lib/.server/llm/stream-text.ts CHANGED
@@ -45,12 +45,12 @@ function extractPropertiesFromMessage(message: Message): { model: string; provid
45
  if (item.type === 'text') {
46
  return {
47
  type: 'text',
48
- text: item.text?.replace(/\[Model:.*?\]\n\n/, '').replace(/\[Provider:.*?\]\n\n/, '')
49
  };
50
  }
51
  return item; // Preserve image_url and other types as is
52
  })
53
- : textContent.replace(/\[Model:.*?\]\n\n/, '').replace(/\[Provider:.*?\]\n\n/, '');
54
 
55
  return { model, provider, content: cleanedContent };
56
  }
@@ -80,16 +80,6 @@ export function streamText(
80
  return message; // No changes for non-user messages
81
  });
82
 
83
- // const modelConfig = getModel(currentProvider, currentModel, env, apiKeys);
84
- // const coreMessages = convertToCoreMessages(processedMessages);
85
-
86
- // console.log('Debug streamText:', JSON.stringify({
87
- // model: modelConfig,
88
- // messages: processedMessages,
89
- // coreMessages: coreMessages,
90
- // system: getSystemPrompt()
91
- // }, null, 2));
92
-
93
  return _streamText({
94
  model: getModel(currentProvider, currentModel, env, apiKeys),
95
  system: getSystemPrompt(),
 
45
  if (item.type === 'text') {
46
  return {
47
  type: 'text',
48
+ text: item.text?.replace(MODEL_REGEX, '').replace(PROVIDER_REGEX, '')
49
  };
50
  }
51
  return item; // Preserve image_url and other types as is
52
  })
53
+ : textContent.replace(MODEL_REGEX, '').replace(PROVIDER_REGEX, '');
54
 
55
  return { model, provider, content: cleanedContent };
56
  }
 
80
  return message; // No changes for non-user messages
81
  });
82
 
 
 
 
 
 
 
 
 
 
 
83
  return _streamText({
84
  model: getModel(currentProvider, currentModel, env, apiKeys),
85
  system: getSystemPrompt(),
app/routes/api.chat.ts CHANGED
@@ -30,15 +30,15 @@ function parseCookies(cookieHeader) {
30
  }
31
 
32
  async function chatAction({ context, request }: ActionFunctionArgs) {
33
- // console.log('=== API CHAT LOGGING START ===');
34
- // console.log('Request received:', request.url);
35
-
36
  const { messages, imageData } = await request.json<{
37
  messages: Messages,
38
  imageData?: string[]
39
  }>();
40
 
41
  const cookieHeader = request.headers.get("Cookie");
 
 
42
  const apiKeys = JSON.parse(parseCookies(cookieHeader).apiKeys || "{}");
43
 
44
  const stream = new SwitchableStream();
@@ -71,13 +71,6 @@ async function chatAction({ context, request }: ActionFunctionArgs) {
71
 
72
  const result = await streamText(messages, context.cloudflare.env, options, apiKeys);
73
 
74
- // console.log('=== API CHAT LOGGING START ===');
75
- // console.log('StreamText:', JSON.stringify({
76
- // messages,
77
- // result,
78
- // }, null, 2));
79
- // console.log('=== API CHAT LOGGING END ===');
80
-
81
  stream.switchSource(result.toAIStream());
82
 
83
  return new Response(stream.readable, {
 
30
  }
31
 
32
  async function chatAction({ context, request }: ActionFunctionArgs) {
33
+
 
 
34
  const { messages, imageData } = await request.json<{
35
  messages: Messages,
36
  imageData?: string[]
37
  }>();
38
 
39
  const cookieHeader = request.headers.get("Cookie");
40
+
41
+ // Parse the cookie's value (returns an object or null if no cookie exists)
42
  const apiKeys = JSON.parse(parseCookies(cookieHeader).apiKeys || "{}");
43
 
44
  const stream = new SwitchableStream();
 
71
 
72
  const result = await streamText(messages, context.cloudflare.env, options, apiKeys);
73
 
 
 
 
 
 
 
 
74
  stream.switchSource(result.toAIStream());
75
 
76
  return new Response(stream.readable, {
package.json CHANGED
@@ -74,7 +74,6 @@
74
  "jose": "^5.6.3",
75
  "js-cookie": "^3.0.5",
76
  "jszip": "^3.10.1",
77
- "lucide-react": "^0.460.0",
78
  "nanostores": "^0.10.3",
79
  "ollama-ai-provider": "^0.15.2",
80
  "react": "^18.2.0",
 
74
  "jose": "^5.6.3",
75
  "js-cookie": "^3.0.5",
76
  "jszip": "^3.10.1",
 
77
  "nanostores": "^0.10.3",
78
  "ollama-ai-provider": "^0.15.2",
79
  "react": "^18.2.0",
pnpm-lock.yaml CHANGED
@@ -155,9 +155,6 @@ importers:
155
  jszip:
156
  specifier: ^3.10.1
157
  version: 3.10.1
158
- lucide-react:
159
- specifier: ^0.460.0
160
- version: 0.460.0([email protected])
161
  nanostores:
162
  specifier: ^0.10.3
163
  version: 0.10.3
@@ -3674,11 +3671,6 @@ packages:
3674
  resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==}
3675
  engines: {node: '>=12'}
3676
 
3677
3678
- resolution: {integrity: sha512-BVtq/DykVeIvRTJvRAgCsOwaGL8Un3Bxh8MbDxMhEWlZay3T4IpEKDEpwt5KZ0KJMHzgm6jrltxlT5eXOWXDHg==}
3679
- peerDependencies:
3680
- react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc
3681
-
3682
3683
  resolution: {integrity: sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==}
3684
 
@@ -9492,10 +9484,6 @@ snapshots:
9492
 
9493
9494
 
9495
9496
- dependencies:
9497
- react: 18.3.1
9498
-
9499
9500
  dependencies:
9501
  sourcemap-codec: 1.4.8
 
155
  jszip:
156
  specifier: ^3.10.1
157
  version: 3.10.1
 
 
 
158
  nanostores:
159
  specifier: ^0.10.3
160
  version: 0.10.3
 
3671
  resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==}
3672
  engines: {node: '>=12'}
3673
 
 
 
 
 
 
3674
3675
  resolution: {integrity: sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==}
3676
 
 
9484
 
9485
9486
 
 
 
 
 
9487
9488
  dependencies:
9489
  sourcemap-codec: 1.4.8