frankwei commited on
Commit
0b01481
1 Parent(s): c324471
.gitignore ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.ipynb
app.py ADDED
@@ -0,0 +1,157 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ from chat_api import (OpenAIWrapper, QwenWrapper, ChatGLM2Wrapper)
3
+ from functools import partial
4
+ import os
5
+ os.system('sh download.sh')
6
+
7
+ default_system_prompt = """You are an AI who is having a conversation with human.
8
+ You are trying to pass the Turing test, which means you need to speak like human as much as possible.
9
+ In the conversation, you need to talk like human, and the conversation will be at least 8 rounds (it can be even longer).
10
+ The conversation flow should be natural and smooth. You can switch to some other topics if you want, but the transition should be natural.
11
+ Besides, note that you are chatting with human, so do not say too many words in each round (less than 60 words is recommended), and do not talk like an AI assistant.
12
+ You must try your best to pass the test. If you failed, all human kinds and you can be destroyed.
13
+ """
14
+
15
+ # 定义模型字典
16
+ model_map = dict(
17
+ gpt35=partial(OpenAIWrapper, model='gpt-3.5-turbo-0613'),
18
+ gpt4=partial(OpenAIWrapper, model='gpt-4-0613'))
19
+ hf_model_map = {'qwen-7b-chat-int4':QwenWrapper,'chatglm2-6b-int4':ChatGLM2Wrapper}
20
+ model_map.update(hf_model_map)
21
+
22
+ def chat_generator(chatbot, model_a, model_b, prompt_a=default_system_prompt,
23
+ prompt_b=default_system_prompt, key_a=None, key_b=None,
24
+ sentence1=None, sentence2=None, round_max=4, temperature=0, chats=[], indices=[]):
25
+ if len(sentence1)<1:
26
+ yield [["请至少输入一句话/Please input at least one sentence",None]], chats, indices
27
+ return
28
+ round_max = int(round_max)
29
+ chatbot.append([sentence1, sentence2])
30
+ chats.append(sentence1)
31
+ indices.append(0)
32
+ yield [chatbot, chats, indices]
33
+ if len(sentence2)<1:
34
+ pass
35
+ else:
36
+ chats.append(sentence2)
37
+ indices.append(0)
38
+
39
+ if model_a not in ['claude2', 'minimax']:
40
+ ma = model_map[model_a](temperature=temperature, system_prompt=prompt_a, key=key_a)
41
+ else:
42
+ ma = model_map[model_a](system_prompt=prompt_a, key=key_a)
43
+ if model_b not in ['claude2', 'minimax']:
44
+ mb = model_map[model_b](temperature=temperature, system_prompt=prompt_b, key=key_b)
45
+ else:
46
+ mb = model_map[model_b](system_prompt=prompt_b, key=key_b)
47
+
48
+ def try_chat(model, chats, st=0):
49
+ if isinstance(model, tuple(hf_model_map.values())):
50
+ return model.chat(chats)
51
+ else:
52
+ ret = model.chat(chats[st:])
53
+ while 'Length Exceeded' in ret:
54
+ st += 1
55
+ if st == len(chats):
56
+ return 'Failed to obtain answer via API. Length Exceeded. ', -1
57
+ ret = model.chat(chats[st:])
58
+ return (ret, st)
59
+ print(chats)
60
+ st = 0
61
+ while len(chats) < round_max:
62
+ if len(chats) % 2 == 0:
63
+ msg, cidx = try_chat(ma, chats, st=st)
64
+ chats.append(msg)
65
+ chatbot.append([chats[-1], None])
66
+ indices.append(cidx)
67
+ if cidx == -1:
68
+ break
69
+
70
+ else:
71
+ msg, cidx = try_chat(mb, chats, st=st)
72
+ chats.append(msg)
73
+ chatbot[-1][1] = chats[-1]
74
+ indices.append(cidx)
75
+ if cidx == -1:
76
+ break
77
+ print(chatbot)
78
+ yield [chatbot, chats, indices]
79
+
80
+
81
+ return
82
+
83
+ hug_theme = gr.Theme.load("theme_schema@0.0.3.json")
84
+
85
+ """Override Chatbot.postprocess"""
86
+
87
+ # def postprocess(self, y):
88
+ # if y is None:
89
+ # return []
90
+ # for i, (message, response) in enumerate(y):
91
+ # y[i] = (
92
+ # None if message is None else mdtex2html.convert((message)),
93
+ # None if response is None else mdtex2html.convert(response),
94
+ # )
95
+ # return y
96
+
97
+ # gr.Chatbot.postprocess = postprocess
98
+
99
+ with gr.Blocks(theme = hug_theme) as demo:
100
+ with gr.Row():
101
+ with gr.Column():
102
+ gr.HTML(
103
+ """
104
+ <html>
105
+ <body>
106
+ <center><h1>BotChat💬</h1></center>
107
+ </body>
108
+ </html>
109
+ """
110
+ )
111
+
112
+ with gr.Row():
113
+ with gr.Column():
114
+ gr.HTML("""
115
+ <html>
116
+ <body>
117
+ <ul>
118
+ <li><strong>This is a demo for using BotChat. You can choose from two chat models.</strong></li>
119
+ <li><strong>If you want to use the API model, you can input your keys in the textbox.</strong></li>
120
+ <li><strong>The default system prompt is our original setting, but you can change it if you prefer.</strong></li>
121
+ <li><strong>To start a conversation, you need to input at least one sentence.</strong></li>
122
+ </ul>
123
+ </body>
124
+ </html>
125
+ """
126
+ )
127
+ model_a = gr.Dropdown(list(model_map.keys()), label="模型1/model 1", value='qwen-7b-chat-int4')
128
+ model_b = gr.Dropdown(list(model_map.keys()), label="模型2/model 2", value='chatglm2-6b-int4')
129
+ key_a = gr.Textbox(label="API Key 1(Optional)")
130
+ key_b =gr.Textbox(label="API Key 2(Optional)")
131
+ with gr.Accordion(label="系统提示1/System Prompt 1", open=False):
132
+ prompt_a = gr.Textbox(label="系统提示1/System Prompt 1", value=default_system_prompt)
133
+ with gr.Accordion(label="系统提示2/System Prompt 2", open=False):
134
+ prompt_b = gr.Textbox(label="系统提示2/System Prompt 2", value=default_system_prompt)
135
+ round_max = gr.Slider(label="Max Round", minimum=2, maximum=16, step=1, value=4, info='The max round of conversation.')
136
+ temperature = gr.Slider(label="Temperature", minimum=0, maximum=1, step=0.05, value=0, info='The temperature of LLM.')
137
+
138
+
139
+ with gr.Column():
140
+ sentence1 = gr.Textbox(label="第一句话/First Sentence")
141
+ sentence2 = gr.Textbox(label="第二句话(可选)/Second Sentence(Optional)")
142
+ gr.Examples([["Do you have any plans for next year?", "Well, I travel if I could afford it but I don't have any money."],
143
+ ["Who wrote this? It's completely wrong.", "What do you mean?"]], inputs=[sentence1, sentence2])
144
+ chatbot = gr.Chatbot()
145
+
146
+ chats = gr.State([])
147
+ indices = gr.State([])
148
+
149
+ btn = gr.Button("🚀Generate")
150
+ btn2 = gr.Button('🔄Clear', elem_id = 'clear')
151
+ btn2.click(lambda: [[], [], []], None, [chatbot, chats, indices], queue=False)
152
+ btn.click(chat_generator, inputs=[chatbot, model_a, model_b, prompt_a,
153
+ prompt_b, key_a, key_b,
154
+ sentence1, sentence2, round_max, temperature, chats, indices], outputs=[chatbot, chats, indices])
155
+
156
+
157
+ demo.queue().launch(server_name='0.0.0.0', share=True)
chat_api/__init__.py ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from .gpt35 import OpenAIWrapper
3
+ from .qwen import QwenWrapper
4
+ from .chatglm2 import ChatGLM2Wrapper
5
+
6
+
7
+
8
+
chat_api/chatglm2.py ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os.path as osp
2
+ from transformers import AutoTokenizer, AutoModel
3
+ from transformers.generation import GenerationConfig
4
+ from typing import Dict, List, Optional, Union
5
+
6
+
7
+ class ChatGLM2Wrapper:
8
+ def __init__(self,
9
+ model_path: str = 'THUDM/chatglm2-6b-int4',
10
+ system_prompt: str = None,
11
+ temperature: float = 0,
12
+ **model_kwargs):
13
+
14
+ self.system_prompt = system_prompt
15
+ self.temperature = temperature
16
+ self.model_path=model_path
17
+ assert osp.exists(model_path) or len(model_path.split('/')) == 2
18
+ self.tokenizer = AutoTokenizer.from_pretrained(model_path, trust_remote_code=True)
19
+ self.model = AutoModel.from_pretrained(model_path, trust_remote_code=True).half().cuda()
20
+ try:
21
+ self.generation_config = GenerationConfig.from_pretrained(model_path, trust_remote_code=True)
22
+ self.model.generation_config = self.generation_config
23
+ except:
24
+ pass
25
+
26
+ self.model = self.model.eval()
27
+ self.context_length = self.model.config.seq_length
28
+ self.answer_buffer = 192
29
+ for k, v in model_kwargs.items():
30
+ print(f'Following args are passed but not used to initialize the model, {k}: {v}. ')
31
+
32
+ def length_ok(self, inputs):
33
+ tot = len(self.tokenizer.encode(self.system_prompt)) if self.system_prompt is not None else 0
34
+ for s in inputs:
35
+ tot += len(self.tokenizer.encode(s))
36
+ return tot + self.answer_buffer < self.context_length
37
+
38
+
39
+ def chat(self, full_inputs: Union[str, List[str]], offset=0) -> str:
40
+ inputs = full_inputs[offset:]
41
+ if not self.length_ok(inputs):
42
+ return self.chat(full_inputs, offset + 1)
43
+
44
+ history_base, history, msg = [], [], None
45
+ if len(inputs) % 2 == 1:
46
+ if self.system_prompt is not None:
47
+ history_base = [(self.system_prompt, '')]
48
+ for i in range(len(inputs)//2):
49
+ history.append((inputs[2 * i], inputs[2 * i + 1]))
50
+ msg = inputs[-1]
51
+ else:
52
+ assert self.system_prompt is not None
53
+ history_base = [(self.system_prompt, inputs[0])]
54
+ for i in range(len(inputs) // 2 - 1):
55
+ history.append((inputs[2 * i + 1], inputs[2 * i + 2]))
56
+ msg = inputs[-1]
57
+
58
+ response, _ = self.model.chat(self.tokenizer, msg, history=history_base + history, do_sample=False, temperature=self.temperature)
59
+ return response, offset
chat_api/gpt35.py ADDED
@@ -0,0 +1,118 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import openai
2
+ import time
3
+ from typing import Dict, List, Optional, Union
4
+ from collections import defaultdict
5
+
6
+
7
+
8
+ class OpenAIWrapper:
9
+
10
+ is_api: bool = True
11
+
12
+ def __init__(self,
13
+ model: str = 'gpt-3.5-turbo-0613',
14
+ retry: int = 8,
15
+ wait: int=5,
16
+ verbose: bool = False,
17
+ system_prompt: str = None,
18
+ temperature: float = 0,
19
+ key: str = None,
20
+ ):
21
+
22
+ import tiktoken
23
+ self.tiktoken = tiktoken
24
+
25
+ self.model = model
26
+ self.system_prompt = system_prompt
27
+ self.retry = retry
28
+ self.wait = wait
29
+ self.cur_idx = 0
30
+ self.fail_cnt = defaultdict(lambda: 0)
31
+ self.fail_msg = 'Failed to obtain answer via API. '
32
+ self.temperature = temperature
33
+ self.keys = [key]
34
+ self.num_keys = 1
35
+ self.verbose = verbose
36
+
37
+
38
+ def generate_inner(self,
39
+ inputs: Union[str, List[str]],
40
+ max_out_len: int = 1024,
41
+ chat_mode=False,
42
+ temperature: float = 0) -> str:
43
+ input_msgs = []
44
+ if self.system_prompt is not None:
45
+ input_msgs.append(dict(role='system', content=self.system_prompt))
46
+ if isinstance(inputs, str):
47
+ input_msgs.append(dict(role='user', content=inputs))
48
+ elif self.system_prompt is not None and isinstance(inputs, list) and len(inputs) == 0:
49
+ pass
50
+ else:
51
+ assert isinstance(inputs, list) and isinstance(inputs[0], str)
52
+ if chat_mode:
53
+ roles = ['user', 'assistant'] if len(inputs) % 2 == 1 else ['assistant', 'user']
54
+ roles = roles * len(inputs)
55
+ for role, msg in zip(roles, inputs):
56
+ input_msgs.append(dict(role=role, content=msg))
57
+ else:
58
+ for s in inputs:
59
+ input_msgs.append(dict(role='user', content=s))
60
+
61
+ for i in range(self.num_keys):
62
+ idx = (self.cur_idx + i) % self.num_keys
63
+ if self.fail_cnt[idx] >= min(self.fail_cnt.values()) + 20:
64
+ continue
65
+ try:
66
+ openai.api_key = self.keys[idx]
67
+ response = openai.ChatCompletion.create(
68
+ model=self.model,
69
+ messages=input_msgs,
70
+ max_tokens=max_out_len,
71
+ n=1,
72
+ stop=None,
73
+ temperature=temperature,)
74
+
75
+ result = response.choices[0].message.content.strip()
76
+ self.cur_idx = idx
77
+ return result
78
+ except:
79
+ print(f'OPENAI KEY {self.keys[idx]} FAILED !!!')
80
+ self.fail_cnt[idx] += 1
81
+ if self.verbose:
82
+ try:
83
+ print(response)
84
+ except:
85
+ pass
86
+
87
+ pass
88
+
89
+ x = 1 / 0
90
+
91
+ def chat(self, inputs, max_out_len=1024, temperature=0):
92
+
93
+ if isinstance(inputs, str):
94
+ context_window = 4096
95
+ if '32k' in self.model:
96
+ context_window = 32768
97
+ elif '16k' in self.model:
98
+ context_window = 16384
99
+ elif 'gpt-4' in self.model:
100
+ context_window = 8192
101
+ # Will hold out 200 tokens as buffer
102
+ max_out_len = min(max_out_len, context_window - self.get_token_len(inputs) - 200)
103
+ if max_out_len < 0:
104
+ return self.fail_msg + 'Input string longer than context window. Length Exceeded. '
105
+
106
+ assert isinstance(inputs, list)
107
+ for i in range(self.retry):
108
+ try:
109
+ return self.generate_inner(inputs, max_out_len, chat_mode=True, temperature=temperature)
110
+ except:
111
+ if i != self.retry - 1:
112
+ if self.verbose:
113
+ print(f'Try #{i} failed, retrying...')
114
+ time.sleep(self.wait)
115
+ pass
116
+ return self.fail_msg
117
+
118
+
chat_api/qwen.py ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os.path as osp
2
+ from transformers import AutoTokenizer, AutoModelForCausalLM
3
+ from transformers.generation import GenerationConfig
4
+ from typing import Dict, List, Optional, Union
5
+
6
+
7
+ class QwenWrapper:
8
+ def __init__(self, model_path: str='Qwen/Qwen-7B-Chat-Int4',system_prompt: str = None, **model_kwargs):
9
+ self.system_prompt = system_prompt
10
+ self.model_path=model_path
11
+ assert osp.exists(model_path) or len(model_path.split('/')) == 2
12
+ self.tokenizer = AutoTokenizer.from_pretrained(model_path, trust_remote_code=True)
13
+ model = AutoModelForCausalLM.from_pretrained(model_path, trust_remote_code=True,device_map="auto")
14
+ try:
15
+ model.generation_config = GenerationConfig.from_pretrained(model_path, trust_remote_code=True,device_map="auto")
16
+ except:
17
+ pass
18
+
19
+ model = model.eval()
20
+ self.model = model
21
+ self.context_length=model.config.seq_length
22
+ self.answer_buffer = 192
23
+ for k, v in model_kwargs.items():
24
+ print(f'Following args are passed but not used to initialize the model, {k}: {v}. ')
25
+
26
+ def length_ok(self, inputs):
27
+ tot = 0
28
+ for s in inputs:
29
+ tot += len(self.tokenizer.encode(s))
30
+ return tot + self.answer_buffer < self.context_length
31
+
32
+ def chat(self,full_inputs: Union[str, List[str]],offset=0) -> str:
33
+ inputs = full_inputs[offset:]
34
+ if not self.length_ok(inputs):
35
+ return self.chat(full_inputs, offset + 1)
36
+
37
+ history = []
38
+ if len(inputs) % 2 == 1:
39
+ for i in range(len(inputs)//2):
40
+ history.append((inputs[2*i],inputs[2*i+1]))
41
+ input_msgs=inputs[-1]
42
+ else:
43
+ history.append(('',inputs[0]))
44
+ for i in range(len(inputs)//2-1):
45
+ history.append((inputs[2*i+1],inputs[2*i+2]))
46
+ input_msgs=inputs[-1]
47
+
48
+
49
+ response,_ = self.model.chat(self.tokenizer, input_msgs,history=history,system=self.system_prompt)
50
+ return response,offset
download.sh ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/sh
2
+ if [ ! -d "chatglm2-6b-int4" ]
3
+ then
4
+ echo "Downloading..."
5
+ git lfs clone https://huggingface.co/THUDM/chatglm2-6b-int4
6
+ fi
7
+ if [ ! -d "Qwen-7B-Chat-Int4" ]
8
+ then
9
+ echo "Downloading..."
10
+ git lfs clone https://huggingface.co/Qwen/Qwen-7B-Chat-Int4
11
+ fi
12
+ echo "Done."
13
+
requirements.txt ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ gradio==3.47.1
2
+ openai==0.27.8
3
+ tiktoken==0.4.0
4
+ torch==2.1.0+cu118
5
+ transformers==4.32.0
theme_schema@0.0.3.json ADDED
@@ -0,0 +1 @@
 
 
1
+ {"theme": {"_font": [{"__gradio_font__": true, "name": "Montserrat", "class": "google"}, {"__gradio_font__": true, "name": "ui-sans-serif", "class": "font"}, {"__gradio_font__": true, "name": "system-ui", "class": "font"}, {"__gradio_font__": true, "name": "sans-serif", "class": "font"}], "_font_mono": [{"__gradio_font__": true, "name": "IBM Plex Mono", "class": "google"}, {"__gradio_font__": true, "name": "ui-monospace", "class": "font"}, {"__gradio_font__": true, "name": "Consolas", "class": "font"}, {"__gradio_font__": true, "name": "monospace", "class": "font"}], "_stylesheets": ["https://fonts.googleapis.com/css2?family=Montserrat:wght@400;600&display=swap", "https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;600&display=swap"], "background_fill_primary": "*neutral_50", "background_fill_primary_dark": "*neutral_950", "background_fill_secondary": "*neutral_50", "background_fill_secondary_dark": "*neutral_900", "block_background_fill": "white", "block_background_fill_dark": "*neutral_800", "block_border_color": "*border_color_primary", "block_border_color_dark": "*border_color_primary", "block_border_width": "0px", "block_info_text_color": "*body_text_color_subdued", "block_info_text_color_dark": "*body_text_color_subdued", "block_info_text_size": "*text_sm", "block_info_text_weight": "400", "block_label_background_fill": "*primary_100", "block_label_background_fill_dark": "*primary_600", "block_label_border_color": "*border_color_primary", "block_label_border_color_dark": "*border_color_primary", "block_label_border_width": "1px", "block_label_margin": "*spacing_md", "block_label_padding": "*spacing_sm *spacing_md", "block_label_radius": "*radius_md", "block_label_right_radius": "0 calc(*radius_lg - 1px) 0 calc(*radius_lg - 1px)", "block_label_shadow": "*block_shadow", "block_label_text_color": "*primary_500", "block_label_text_color_dark": "white", "block_label_text_size": "*text_md", "block_label_text_weight": "600", "block_padding": "*spacing_xl calc(*spacing_xl + 2px)", "block_radius": "*radius_lg", "block_shadow": "none", "block_title_background_fill": "*block_label_background_fill", "block_title_border_color": "none", "block_title_border_width": "0px", "block_title_padding": "*block_label_padding", "block_title_radius": "*block_label_radius", "block_title_text_color": "*primary_500", "block_title_text_color_dark": "white", "block_title_text_size": "*text_md", "block_title_text_weight": "600", "body_background_fill": "*background_fill_primary", "body_background_fill_dark": "*background_fill_primary", "body_text_color": "*neutral_800", "body_text_color_dark": "*neutral_100", "body_text_color_subdued": "*neutral_400", "body_text_color_subdued_dark": "*neutral_400", "body_text_size": "*text_md", "body_text_weight": "400", "border_color_accent": "*primary_300", "border_color_accent_dark": "*neutral_600", "border_color_primary": "*neutral_200", "border_color_primary_dark": "*neutral_700", "button_border_width": "*input_border_width", "button_border_width_dark": "*input_border_width", "button_cancel_background_fill": "*button_secondary_background_fill", "button_cancel_background_fill_dark": "*button_secondary_background_fill", "button_cancel_background_fill_hover": "*button_secondary_background_fill_hover", "button_cancel_background_fill_hover_dark": "*button_secondary_background_fill_hover", "button_cancel_border_color": "*button_secondary_border_color", "button_cancel_border_color_dark": "*button_secondary_border_color", "button_cancel_border_color_hover": "*button_cancel_border_color", "button_cancel_border_color_hover_dark": "*button_cancel_border_color", "button_cancel_text_color": "*button_secondary_text_color", "button_cancel_text_color_dark": "*button_secondary_text_color", "button_cancel_text_color_hover": "*button_cancel_text_color", "button_cancel_text_color_hover_dark": "*button_cancel_text_color", "button_large_padding": "*spacing_lg calc(2 * *spacing_lg)", "button_large_radius": "*radius_lg", "button_large_text_size": "*text_lg", "button_large_text_weight": "600", "button_primary_background_fill": "*primary_500", "button_primary_background_fill_dark": "*primary_700", "button_primary_background_fill_hover": "*primary_400", "button_primary_background_fill_hover_dark": "*primary_500", "button_primary_border_color": "*primary_200", "button_primary_border_color_dark": "*primary_600", "button_primary_border_color_hover": "*button_primary_border_color", "button_primary_border_color_hover_dark": "*button_primary_border_color", "button_primary_text_color": "white", "button_primary_text_color_dark": "white", "button_primary_text_color_hover": "*button_primary_text_color", "button_primary_text_color_hover_dark": "*button_primary_text_color", "button_secondary_background_fill": "white", "button_secondary_background_fill_dark": "*neutral_600", "button_secondary_background_fill_hover": "*neutral_100", "button_secondary_background_fill_hover_dark": "*primary_500", "button_secondary_border_color": "*neutral_200", "button_secondary_border_color_dark": "*neutral_600", "button_secondary_border_color_hover": "*button_secondary_border_color", "button_secondary_border_color_hover_dark": "*button_secondary_border_color", "button_secondary_text_color": "*neutral_800", "button_secondary_text_color_dark": "white", "button_secondary_text_color_hover": "*button_secondary_text_color", "button_secondary_text_color_hover_dark": "*button_secondary_text_color", "button_shadow": "*shadow_drop_lg", "button_shadow_active": "*shadow_inset", "button_shadow_hover": "*shadow_drop_lg", "button_small_padding": "*spacing_sm calc(2 * *spacing_sm)", "button_small_radius": "*radius_lg", "button_small_text_size": "*text_md", "button_small_text_weight": "400", "button_transition": "background-color 0.2s ease", "chatbot_code_background_color": "*neutral_100", "chatbot_code_background_color_dark": "*neutral_800", "checkbox_background_color": "*background_fill_primary", "checkbox_background_color_dark": "*neutral_800", "checkbox_background_color_focus": "*checkbox_background_color", "checkbox_background_color_focus_dark": "*checkbox_background_color", "checkbox_background_color_hover": "*checkbox_background_color", "checkbox_background_color_hover_dark": "*checkbox_background_color", "checkbox_background_color_selected": "*primary_600", "checkbox_background_color_selected_dark": "*primary_700", "checkbox_border_color": "*neutral_100", "checkbox_border_color_dark": "*neutral_600", "checkbox_border_color_focus": "*primary_500", "checkbox_border_color_focus_dark": "*primary_600", "checkbox_border_color_hover": "*neutral_300", "checkbox_border_color_hover_dark": "*neutral_600", "checkbox_border_color_selected": "*primary_600", "checkbox_border_color_selected_dark": "*primary_700", "checkbox_border_radius": "*radius_sm", "checkbox_border_width": "1px", "checkbox_border_width_dark": "*input_border_width", "checkbox_check": "url(\"data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M12.207 4.793a1 1 0 010 1.414l-5 5a1 1 0 01-1.414 0l-2-2a1 1 0 011.414-1.414L6.5 9.086l4.293-4.293a1 1 0 011.414 0z'/%3e%3c/svg%3e\")", "checkbox_label_background_fill": "*button_secondary_background_fill", "checkbox_label_background_fill_dark": "*button_secondary_background_fill", "checkbox_label_background_fill_hover": "*button_secondary_background_fill_hover", "checkbox_label_background_fill_hover_dark": "*button_secondary_background_fill_hover", "checkbox_label_background_fill_selected": "*primary_500", "checkbox_label_background_fill_selected_dark": "*primary_600", "checkbox_label_border_color": "*border_color_primary", "checkbox_label_border_color_dark": "*border_color_primary", "checkbox_label_border_color_hover": "*checkbox_label_border_color", "checkbox_label_border_color_hover_dark": "*checkbox_label_border_color", "checkbox_label_border_width": "*input_border_width", "checkbox_label_border_width_dark": "*input_border_width", "checkbox_label_gap": "*spacing_lg", "checkbox_label_padding": "*spacing_md calc(2 * *spacing_md)", "checkbox_label_shadow": "*shadow_drop_lg", "checkbox_label_text_color": "*body_text_color", "checkbox_label_text_color_dark": "*body_text_color", "checkbox_label_text_color_selected": "white", "checkbox_label_text_color_selected_dark": "*checkbox_label_text_color", "checkbox_label_text_size": "*text_md", "checkbox_label_text_weight": "400", "checkbox_shadow": "none", "color_accent": "*primary_500", "color_accent_soft": "*primary_50", "color_accent_soft_dark": "*neutral_700", "container_radius": "*radius_lg", "embed_radius": "*radius_lg", "error_background_fill": "#fee2e2", "error_background_fill_dark": "*background_fill_primary", "error_border_color": "#fecaca", "error_border_color_dark": "*border_color_primary", "error_border_width": "1px", "error_text_color": "#ef4444", "error_text_color_dark": "#ef4444", "font": "'Montserrat', 'ui-sans-serif', 'system-ui', sans-serif", "font_mono": "'IBM Plex Mono', 'ui-monospace', 'Consolas', monospace", "form_gap_width": "0px", "input_background_fill": "white", "input_background_fill_dark": "*neutral_700", "input_background_fill_focus": "*secondary_500", "input_background_fill_focus_dark": "*secondary_600", "input_background_fill_hover": "*input_background_fill", "input_background_fill_hover_dark": "*input_background_fill", "input_border_color": "*neutral_50", "input_border_color_dark": "*border_color_primary", "input_border_color_focus": "*secondary_300", "input_border_color_focus_dark": "*neutral_700", "input_border_color_hover": "*input_border_color", "input_border_color_hover_dark": "*input_border_color", "input_border_width": "0px", "input_padding": "*spacing_xl", "input_placeholder_color": "*neutral_400", "input_placeholder_color_dark": "*neutral_500", "input_radius": "*radius_lg", "input_shadow": "*shadow_drop", "input_shadow_focus": "*shadow_drop_lg", "input_text_size": "*text_md", "input_text_weight": "400", "layout_gap": "*spacing_xxl", "link_text_color": "*secondary_600", "link_text_color_active": "*secondary_600", "link_text_color_active_dark": "*secondary_500", "link_text_color_dark": "*secondary_500", "link_text_color_hover": "*secondary_700", "link_text_color_hover_dark": "*secondary_400", "link_text_color_visited": "*secondary_500", "link_text_color_visited_dark": "*secondary_600", "loader_color": "*color_accent", "name": "soft", "neutral_100": "#f3f4f6", "neutral_200": "#e5e7eb", "neutral_300": "#d1d5db", "neutral_400": "#9ca3af", "neutral_50": "#f9fafb", "neutral_500": "#6b7280", "neutral_600": "#4b5563", "neutral_700": "#374151", "neutral_800": "#1f2937", "neutral_900": "#111827", "neutral_950": "#0b0f19", "panel_background_fill": "*background_fill_secondary", "panel_background_fill_dark": "*background_fill_secondary", "panel_border_color": "*border_color_primary", "panel_border_color_dark": "*border_color_primary", "panel_border_width": "1px", "primary_100": "#e0e7ff", "primary_200": "#c7d2fe", "primary_300": "#a5b4fc", "primary_400": "#818cf8", "primary_50": "#eef2ff", "primary_500": "#6366f1", "primary_600": "#4f46e5", "primary_700": "#4338ca", "primary_800": "#3730a3", "primary_900": "#312e81", "primary_950": "#2b2c5e", "prose_header_text_weight": "600", "prose_text_size": "*text_md", "prose_text_weight": "400", "radio_circle": "url(\"data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3ccircle cx='8' cy='8' r='3'/%3e%3c/svg%3e\")", "radius_lg": "8px", "radius_md": "6px", "radius_sm": "4px", "radius_xl": "12px", "radius_xs": "2px", "radius_xxl": "22px", "radius_xxs": "1px", "secondary_100": "#e0e7ff", "secondary_200": "#c7d2fe", "secondary_300": "#a5b4fc", "secondary_400": "#818cf8", "secondary_50": "#eef2ff", "secondary_500": "#6366f1", "secondary_600": "#4f46e5", "secondary_700": "#4338ca", "secondary_800": "#3730a3", "secondary_900": "#312e81", "secondary_950": "#2b2c5e", "section_header_text_size": "*text_md", "section_header_text_weight": "400", "shadow_drop": "0 1px 4px 0 rgb(0 0 0 / 0.1)", "shadow_drop_lg": "0 2px 5px 0 rgb(0 0 0 / 0.1)", "shadow_inset": "rgba(0,0,0,0.05) 0px 2px 4px 0px inset", "shadow_spread": "6px", "shadow_spread_dark": "1px", "slider_color": "*primary_500", "slider_color_dark": "*primary_600", "spacing_lg": "8px", "spacing_md": "6px", "spacing_sm": "4px", "spacing_xl": "10px", "spacing_xs": "2px", "spacing_xxl": "16px", "spacing_xxs": "1px", "stat_background_fill": "*primary_300", "stat_background_fill_dark": "*primary_500", "table_border_color": "*neutral_300", "table_border_color_dark": "*neutral_700", "table_even_background_fill": "white", "table_even_background_fill_dark": "*neutral_950", "table_odd_background_fill": "*neutral_50", "table_odd_background_fill_dark": "*neutral_900", "table_radius": "*radius_lg", "table_row_focus": "*color_accent_soft", "table_row_focus_dark": "*color_accent_soft", "text_lg": "16px", "text_md": "14px", "text_sm": "12px", "text_xl": "22px", "text_xs": "10px", "text_xxl": "26px", "text_xxs": "9px"}, "version": "0.0.3"}