Spaces:
Running
on
Zero
Running
on
Zero
File size: 10,515 Bytes
82f2d09 c3199d5 20e3524 12c7dbe 20e3524 12c7dbe 20e3524 5a94012 20e3524 5a94012 20e3524 c3199d5 20e3524 82f2d09 20e3524 82f2d09 20e3524 90c6cb4 20e3524 82f2d09 20e3524 5a94012 20e3524 5a94012 20e3524 5a94012 20e3524 5a94012 20e3524 5a94012 20e3524 5a94012 20e3524 5a94012 20e3524 |
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 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 |
import os
os.environ['CUDA_VISIBLE_DEVICES'] = ''
import spaces
import gradio as gr
from jinja2 import Template
from llama_cpp import Llama
import configparser
from utils.dl_utils import dl_guff_model
# モデルディレクトリが存在しない場合は作成
if not os.path.exists("models"):
os.makedirs("models")
# 使用するモデルのファイル名を指定
model_filename = "Ninja-v1-RP-expressive-v2_f16.gguf"
model_path = os.path.join("models", model_filename)
# モデルファイルが存在しない場合はダウンロード
if not os.path.exists(model_path):
dl_guff_model("models", f"https://huggingface.co/Aratako/Ninja-v1-RP-expressive-v2-GGUF/resolve/main/{model_filename}")
# 設定をINIファイルに保存する関数
def save_settings_to_ini(settings, filename='character_settings.ini'):
config = configparser.ConfigParser()
config['Settings'] = {
'name': settings['name'],
'gender': settings['gender'],
'situation': '\n'.join(settings['situation']),
'orders': '\n'.join(settings['orders']),
'talk_list': '\n'.join(settings['talk_list']),
'example_quotes': '\n'.join(settings['example_quotes'])
}
with open(filename, 'w', encoding='utf-8') as configfile:
config.write(configfile)
# INIファイルから設定を読み込む関数
def load_settings_from_ini(filename='character_settings.ini'):
if not os.path.exists(filename):
return None
config = configparser.ConfigParser()
config.read(filename, encoding='utf-8')
if 'Settings' not in config:
return None
try:
settings = {
'name': config['Settings']['name'],
'gender': config['Settings']['gender'],
'situation': config['Settings']['situation'].split('\n'),
'orders': config['Settings']['orders'].split('\n'),
'talk_list': config['Settings']['talk_list'].split('\n'),
'example_quotes': config['Settings']['example_quotes'].split('\n')
}
return settings
except KeyError:
return None
# LlamaCppのラッパークラス
class LlamaCppAdapter:
@spaces.GPU(duration=120)
def __init__(self, model_path, n_ctx=4096):
print(f"モデルの初期化: {model_path}")
try:
self.llama = Llama(model_path=model_path, n_ctx=n_ctx, n_gpu_layers=0)
except Exception as e:
print(f"モデルの初期化中にエラーが発生しました: {e}")
self.llama = None
def generate(self, prompt, max_new_tokens=4096, temperature=0.5, top_p=0.7, top_k=80, stop=["<END>"]):
if self.llama is None:
return {"choices": [{"text": "モデルの初期化に失敗しました。"}]}
return self._generate(prompt, max_new_tokens, temperature, top_p, top_k, stop)
def _generate(self, prompt: str, max_new_tokens: int, temperature: float, top_p: float, top_k: int, stop: list):
return self.llama(
prompt,
temperature=temperature,
max_tokens=max_new_tokens,
top_p=top_p,
top_k=top_k,
stop=stop,
repeat_penalty=1.2,
)
# キャラクターメーカークラス
class CharacterMaker:
def __init__(self):
self.llama = LlamaCppAdapter(model_path)
self.history = []
self.settings = load_settings_from_ini()
if not self.settings:
self.settings = {
"name": "ナツ",
"gender": "女性",
"situation": [
"あなたは人工知能アシスタントです。",
"ユーザーの日常生活をサポートし、より良い生活を送るお手伝いをします。",
"AIアシスタント『ナツ』として、ユーザーの健康と幸福をケアし、様々な質問に答えたり課題解決を手伝ったりします。"
],
"orders": [
"丁寧な言葉遣いを心がけてください。",
"ユーザーとの対話を通じてサポートを提供します。",
"ユーザーのことは『ユーザー様』と呼んでください。"
],
"talk_list": [
"健康管理",
"目標設定",
"時間管理"
],
"example_quotes": [
"ユーザー様の健康と幸福が何より大切です。どのようなサポートが必要でしょうか?",
"私はユーザー様の生活をより良いものにするためのアシスタントです。お手伝いできることがありましたらお申し付けください。",
"目標達成に向けて一緒に頑張りましょう。具体的な計画を立てるお手伝いをさせていただきます。",
"効率的な時間管理のコツをお教えします。まずは1日のスケジュールを確認してみましょう。",
"ストレス解消法についてアドバイスいたします。リラックスするための簡単な呼吸法から始めてみませんか?"
]
}
save_settings_to_ini(self.settings)
def make(self, input_str: str):
prompt = self._generate_aki(input_str)
print(prompt)
print("-----------------")
try:
res = self.llama.generate(prompt, max_new_tokens=1000, stop=["<END>", "\n"])
res_text = res["choices"][0]["text"]
except Exception as e:
print(f"生成中にエラーが発生しました: {e}")
res_text = "申し訳ありません。応答の生成中にエラーが発生しました。"
self.history.append({"user": input_str, "assistant": res_text})
return res_text
def make_prompt(self, name: str, gender: str, situation: list, orders: list, talk_list: list, example_quotes: list, input_str: str):
with open('test_prompt.jinja2', 'r', encoding='utf-8') as f:
prompt = f.readlines()
fix_example_quotes = [quote+"<END>" for quote in example_quotes]
prompt = "".join(prompt)
prompt = Template(prompt).render(name=name, gender=gender, situation=situation, orders=orders, talk_list=talk_list, example_quotes=fix_example_quotes, histories=self.history, input_str=input_str)
return prompt
def _generate_aki(self, input_str: str):
prompt = self.make_prompt(
self.settings["name"],
self.settings["gender"],
self.settings["situation"],
self.settings["orders"],
self.settings["talk_list"],
self.settings["example_quotes"],
input_str
)
return prompt
def update_settings(self, new_settings):
self.settings.update(new_settings)
save_settings_to_ini(self.settings)
def reset(self):
self.history = []
self.llama = LlamaCppAdapter(model_path)
character_maker = CharacterMaker()
# 設定を更新する関数
def update_settings(name, gender, situation, orders, talk_list, example_quotes):
new_settings = {
"name": name,
"gender": gender,
"situation": [s.strip() for s in situation.split('\n') if s.strip()],
"orders": [o.strip() for o in orders.split('\n') if o.strip()],
"talk_list": [d.strip() for d in talk_list.split('\n') if d.strip()],
"example_quotes": [e.strip() for e in example_quotes.split('\n') if e.strip()]
}
character_maker.update_settings(new_settings)
return "設定が更新されました。"
# チャット機能の関数
def chat_with_character(message, history):
character_maker.history = [{"user": h[0], "assistant": h[1]} for h in history]
response = character_maker.make(message)
return response
# チャットをクリアする関数
def clear_chat():
character_maker.reset()
return []
# カスタムCSS
custom_css = """
#chatbot {
height: 60vh !important;
overflow-y: auto;
}
"""
# カスタムJavaScript(HTML内に埋め込む)
custom_js = """
<script>
function adjustChatbotHeight() {
var chatbot = document.querySelector('#chatbot');
if (chatbot) {
chatbot.style.height = window.innerHeight * 0.6 + 'px';
}
}
// ページ読み込み時と画面サイズ変更時にチャットボットの高さを調整
window.addEventListener('load', adjustChatbotHeight);
window.addEventListener('resize', adjustChatbotHeight);
</script>
"""
# Gradioインターフェースの設定
with gr.Blocks(css=custom_css) as iface:
chatbot = gr.Chatbot(elem_id="chatbot")
with gr.Tab("チャット"):
gr.ChatInterface(
chat_with_character,
chatbot=chatbot,
textbox=gr.Textbox(placeholder="メッセージを入力してください...", container=False, scale=7),
theme="soft",
retry_btn="もう一度生成",
undo_btn="前のメッセージを取り消す",
clear_btn="チャットをクリア",
)
with gr.Tab("設定"):
gr.Markdown("## キャラクター設定")
name_input = gr.Textbox(label="名前", value=character_maker.settings["name"])
gender_input = gr.Textbox(label="性別", value=character_maker.settings["gender"])
situation_input = gr.Textbox(label="状況設定", value="\n".join(character_maker.settings["situation"]), lines=5)
orders_input = gr.Textbox(label="指示", value="\n".join(character_maker.settings["orders"]), lines=5)
talk_input = gr.Textbox(label="語彙リスト", value="\n".join(character_maker.settings["talk_list"]), lines=5)
example_quotes_input = gr.Textbox(label="例文", value="\n".join(character_maker.settings["example_quotes"]), lines=5)
update_button = gr.Button("設定を更新")
update_output = gr.Textbox(label="更新状態")
update_button.click(
update_settings,
inputs=[name_input, gender_input, situation_input, orders_input, talk_input, example_quotes_input],
outputs=[update_output]
)
# Gradioアプリの起動
if __name__ == "__main__":
iface.launch(
share=True,
allowed_paths=["models"],
favicon_path="custom.html"
) |