File size: 6,669 Bytes
20ec4ad
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
/* eslint-disable @typescript-eslint/no-explicit-any */
import React, { useState, useEffect } from "react";
import classNames from "classnames";
import { PiGearSixFill } from "react-icons/pi";
// @ts-expect-error not needed
import { PROVIDERS } from "./../../../utils/providers";

function Settings({
  open,
  onClose,
  provider,
  error,
  onChange,
}: {
  open: boolean;
  onClose: React.Dispatch<React.SetStateAction<boolean>>;
  provider: string;
  error?: string;
  onChange: (provider: string) => void;
}) {
  const [geminiKey, setGeminiKey] = useState(
    localStorage.getItem("geminiKey") || ""
  );
  const [chatgptKey, setChatgptKey] = useState(
    localStorage.getItem("chatgptKey") || ""
  );

  useEffect(() => {
    localStorage.setItem("geminiKey", geminiKey);
  }, [geminiKey]);

  useEffect(() => {
    localStorage.setItem("chatgptKey", chatgptKey);
  }, [chatgptKey]);

  return (
    <div>
      <button
        className="relative overflow-hidden cursor-pointer flex-none flex items-center justify-center rounded-full text-base font-semibold size-8 text-center bg-gray-800 hover:bg-gray-700 text-gray-100 shadow-sm dark:shadow-highlight/20"
        onClick={() => onClose((prev) => !prev)}
      >
        <PiGearSixFill />
      </button>
      <div
        className={classNames(
          "h-screen w-screen bg-black/20 fixed left-0 top-0 z-40",
          { "opacity-0 pointer-events-none": !open }
        )}
        onClick={() => onClose(false)}
      />
      <div
        className={classNames(
          "absolute top-0 -translate-y-[calc(100%+16px)] right-0 z-40 w-96 bg-white border border-gray-200 rounded-lg shadow-lg transition-all duration-75 overflow-hidden",
          { "opacity-0 pointer-events-none": !open }
        )}
      >
        <header className="flex items-center text-sm px-4 py-2 border-b border-gray-200 gap-2 bg-gray-100 font-semibold text-gray-700">
          <span className="text-xs bg-blue-500/10 text-blue-500 rounded-full pl-1.5 pr-2.5 py-0.5 flex items-center justify-start gap-1.5">
            Provider
          </span>
          Customize Settings
        </header>
        <main className="px-4 pt-3 pb-4 space-y-4">
          {/* Gemini API Key */}
          <div>
            <label className="block text-gray-800 text-sm font-medium mb-1">
              Gemini API Key
            </label>
            <input
              type="password"
              value={geminiKey}
              onChange={(e) => setGeminiKey(e.target.value)}
              placeholder="Insira sua Gemini API Key"
              className="w-full rounded border border-gray-200 px-2 py-1 text-sm mb-1"
            />
            <a
              href="https://console.cloud.google.com/apis/credentials"
              target="_blank"
              rel="noopener noreferrer"
              className="text-xs text-blue-500"
            >
              Onde obter
            </a>
          </div>

          {/* ChatGPT API Key */}
          <div>
            <label className="block text-gray-800 text-sm font-medium mb-1">
              ChatGPT API Key
            </label>
            <input
              type="password"
              value={chatgptKey}
              onChange={(e) => setChatgptKey(e.target.value)}
              placeholder="Insira sua OpenAI API Key"
              className="w-full rounded border border-gray-200 px-2 py-1 text-sm mb-1"
            />
            <a
              href="https://platform.openai.com/account/api-keys"
              target="_blank"
              rel="noopener noreferrer"
              className="text-xs text-blue-500"
            >
              Onde obter
            </a>
          </div>

          {/* auto-provider toggle */}
          <div>
            <a
              href="https://huggingface.co/spaces/enzostvs/deepsite/discussions/74"
              target="_blank"
              className="w-full flex items-center justify-between text-gray-600 bg-gray-50 border border-gray-100 px-2 py-2 rounded-lg mb-3 text-sm font-medium hover:brightness-95"
            >
              How to use it locally?
              <button className="bg-black text-white rounded-md px-3 py-1.5 text-xs font-semibold cursor-pointer">
                See the guide
              </button>
            </a>
            <div className="flex items-center justify-between">
              <p className="text-gray-800 text-sm font-medium">Use auto-provider</p>
              <div
                className={classNames(
                  "bg-gray-200 rounded-full w-10 h-6 flex items-center justify-between p-1 cursor-pointer transition-all duration-200",
                  { "!bg-blue-500": provider === "auto" }
                )}
                onClick={() => onChange(provider === "auto" ? "fireworks-ai" : "auto")}
              >
                <div
                  className={classNames(
                    "w-4 h-4 rounded-full shadow-md transition-all duration-200 bg-white",
                    { "translate-x-4": provider === "auto" }
                  )}
                />
              </div>
            </div>
            <p className="text-xs text-gray-500 mt-2">
              We'll automatically select the best provider for you based on your prompt.
            </p>
          </div>

          {error && (
            <p className="text-red-500 text-sm font-medium mb-2 flex items-center justify-between bg-red-500/10 p-2 rounded-md">
              {error}
            </p>
          )}

          {/* Inference Provider */}
          <label className="block">
            <p className="text-gray-800 text-sm font-medium mb-2">
              Inference Provider
            </p>
            <div className="grid grid-cols-2 gap-1.5">
              {Object.keys(PROVIDERS).map((id: string) => (
                <div
                  key={id}
                  className={classNames(
                    "text-gray-600 text-sm font-medium cursor-pointer border p-2 rounded-md flex items-center gap-2",
                    {
                      "bg-blue-500/10 border-blue-500/15 text-blue-500": id === provider,
                      "hover:bg-gray-100 border-gray-100": id !== provider,
                    }
                  )}
                  onClick={() => onChange(id)}
                >
                  <img
                    src={`/providers/${id}.svg`}
                    alt={PROVIDERS[id].name}
                    className="size-5"
                  />
                  {PROVIDERS[id].name}
                </div>
              ))}
            </div>
          </label>
        </main>
      </div>
    </div>
  );
}

export default Settings;