kenken999 commited on
Commit
28729e6
·
1 Parent(s): 5990550
Files changed (1) hide show
  1. mysite/asgi.py +288 -40
mysite/asgi.py CHANGED
@@ -40,7 +40,9 @@ import os
40
 
41
  GENERATION_TIMEOUT_SEC = 60
42
  import os
43
-
 
 
44
  from llamafactory.webui.interface import create_ui
45
 
46
 
@@ -60,7 +62,39 @@ def init(app: FastAPI):
60
  app.mount("/static", StaticFiles(directory="staticfiles"), name="static")
61
 
62
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
63
  init(app)
 
 
64
 
65
  # 環境変数でOpenAI APIキーを保存および使用
66
  interpreter.auto_run = True
@@ -390,13 +424,17 @@ def add_memory(prompt, history, num_pair_messages_recall):
390
  prompt_with_memory = f"user's request: {prompt}. --- \nBelow is the transcript of your past conversation with the user: {memory} ---\n"
391
 
392
  return prompt_with_memory
 
 
393
  # データベース接続の設定
394
- db_path = './workspace/sample.duckdb'
395
  con = duckdb.connect(database=db_path)
396
 
 
397
  # テーブルが存在しない場合に作成
398
  def ensure_table_exists(con):
399
- con.execute("""
 
400
  CREATE SEQUENCE IF NOT EXISTS sample_id_seq START 1;
401
  CREATE TABLE IF NOT EXISTS samples (
402
  id INTEGER DEFAULT nextval('sample_id_seq'),
@@ -404,7 +442,10 @@ def ensure_table_exists(con):
404
  age INTEGER,
405
  PRIMARY KEY(id)
406
  );
407
- """)
 
 
 
408
  # Set the environment variable.
409
  def chat_with_interpreter(
410
  message, history, a=None, b=None, c=None, d=None
@@ -441,7 +482,8 @@ def chat_with_interpreter(
441
 
442
  age = 28
443
  con = duckdb.connect(database="./workspace/sample.duckdb")
444
- con.execute("""
 
445
  CREATE SEQUENCE IF NOT EXISTS sample_id_seq START 1;
446
  CREATE TABLE IF NOT EXISTS samples (
447
  id INTEGER DEFAULT nextval('sample_id_seq'),
@@ -449,7 +491,8 @@ def chat_with_interpreter(
449
  age INTEGER,
450
  PRIMARY KEY(id)
451
  );
452
- """)
 
453
  cur = con.cursor()
454
  con.execute("INSERT INTO samples (name, age) VALUES (?, ?)", (full_response, age))
455
  con.execute("INSERT INTO samples (name, age) VALUES (?, ?)", (message, age))
@@ -624,48 +667,155 @@ demo4 = gr.ChatInterface(
624
  logging.basicConfig(level=logging.INFO)
625
  logger = logging.getLogger(__name__)
626
 
627
- CHANNEL_ID = os.getenv('ChannelID')
628
- CHANNEL_SECRET = os.getenv('ChannelSecret')
629
- CHANNEL_ACCESS_TOKEN = os.getenv('ChannelAccessToken')
630
- WEBHOOK_URL = os.getenv('WEBHOOK_URL')
 
631
  import requests
632
  import hmac
633
  import hashlib
634
  import base64
 
 
635
  def validate_signature(body: str, signature: str, secret: str) -> bool:
636
- hash = hmac.new(secret.encode('utf-8'), body.encode('utf-8'), hashlib.sha256).digest()
637
- expected_signature = base64.b64encode(hash).decode('utf-8')
 
 
638
  return hmac.compare_digest(expected_signature, signature)
639
 
640
 
641
-
642
  def validate_signature(body: str, signature: str, secret: str) -> bool:
643
  if secret is None:
644
  logger.error("Secret is None")
645
  return False
646
 
647
- hash = hmac.new(secret.encode('utf-8'), body.encode('utf-8'), hashlib.sha256).digest()
648
- expected_signature = base64.b64encode(hash).decode('utf-8')
 
 
649
  return hmac.compare_digest(expected_signature, signature)
650
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
651
  @app.post("/webhook")
652
  async def webhook(request: Request):
 
653
  try:
654
  # 受信したデータとヘッダーを取得
655
  body = await request.body()
656
  received_headers = dict(request.headers)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
657
 
658
  # ログに記録
659
- logger.info('Received Headers: %s', received_headers)
660
- logger.info('Received Body: %s', body.decode('utf-8'))
661
 
662
  # 必要なヘッダー情報を抽出
663
- line_signature = received_headers.get('x-line-signature')
664
  if not line_signature:
665
- raise HTTPException(status_code=400, detail="X-Line-Signature header is missing.")
 
 
666
 
667
  # 署名を検証
668
- if not validate_signature(body.decode('utf-8'), line_signature, CHANNEL_SECRET):
669
  raise HTTPException(status_code=400, detail="Invalid signature.")
670
 
671
  # URLの検証
@@ -674,30 +824,65 @@ async def webhook(request: Request):
674
 
675
  # 送信するヘッダーを設定
676
  headers = {
677
- 'Content-Type': 'application/json',
678
- 'X-Line-Signature': line_signature,
679
- 'Authorization': f'Bearer {CHANNEL_ACCESS_TOKEN}'
680
  }
681
 
682
  # ログに転送先URLを記録
683
- logger.info('Forwarding to URL: %s', WEBHOOK_URL)
684
- logger.info('Forwarding Headers: %s', headers)
685
- logger.info('Forwarding Body: %s', body.decode('utf-8'))
686
 
687
  # データを転送
 
688
  response = requests.post(WEBHOOK_URL, headers=headers, data=body)
 
 
 
 
 
 
689
 
690
  # レスポンスをログに記録
691
- logger.info('Response Code: %s', response.status_code)
692
- logger.info('Response Content: %s', response.text)
693
- logger.info('Response Headers: %s', response.headers)
694
 
695
  # クライアントにレスポンスを返却
696
- return {"status": "success", "response_content": response.text}, response.status_code
 
 
 
697
 
698
  except Exception as e:
699
  logger.error("Error: %s", str(e))
700
  raise HTTPException(status_code=500, detail=str(e))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
701
 
702
  def do_something_to_file(file_path):
703
  # ファイルに対して実行する処理をここに記述
@@ -721,7 +906,7 @@ def set_environment_variables():
721
  chatbot = gr.Chatbot(height=650, placeholder=PLACEHOLDER, label="Gradio ChatInterface")
722
 
723
 
724
- def process_file(fileobj, prompt,foldername):
725
  set_environment_variables()
726
  # ファイルの処理
727
  # 'make run example' コマンドをサブプロセスとして実行
@@ -743,13 +928,13 @@ def process_file(fileobj, prompt,foldername):
743
  shutil.copyfile(fileobj, no_extension_path)
744
 
745
  # Append prompt contents to the file
746
- with open(no_extension_path, 'a') as f:
747
- f.write(prompt)
748
 
749
  # Promptの内容をファイルに書き込む
750
  try:
751
- prompt_file_path = os.path.join(project_path, "prompt.txt")
752
- with open(prompt_file_path, 'w') as prompt_file:
753
  prompt_file.write(prompt)
754
  except Exception as e:
755
  return f"Error writing prompt to file: {str(e)}"
@@ -988,14 +1173,77 @@ with gr.Blocks() as appdb:
988
 
989
  # gr.Interface.launch(app)
990
 
991
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
992
  # demo.launch()
993
  # キューを有効にする
994
  chat_interface.queue()
995
- tabs = gr.TabbedInterface(
996
- [demo, create_ui(), democ, democs, appdb],
997
- ["AIで開発", "FineTuning", "Chat", "仕様書から作成", "DataBase"],
998
- )
 
 
 
 
 
 
 
 
 
 
999
  # カスタムCSSを追加
1000
  tabs.css = """
1001
  .gradio-container {
 
40
 
41
  GENERATION_TIMEOUT_SEC = 60
42
  import os
43
+ import importlib
44
+ import os
45
+ import pkgutil
46
  from llamafactory.webui.interface import create_ui
47
 
48
 
 
62
  app.mount("/static", StaticFiles(directory="staticfiles"), name="static")
63
 
64
 
65
+ def include_routers(app):
66
+ package_dir = "/home/user/app/routers"
67
+ if not os.path.exists(package_dir):
68
+ logger.error(f"Package directory {package_dir} does not exist.")
69
+ return
70
+
71
+ for module_info in pkgutil.iter_modules([package_dir]):
72
+ try:
73
+ if module_info.ispkg:
74
+ sub_package_dir = os.path.join(package_dir, module_info.name)
75
+ for sub_module_info in pkgutil.iter_modules([sub_package_dir]):
76
+ module_name = (
77
+ f"routers.{module_info.name}.{sub_module_info.name}"
78
+ if sub_module_info.ispkg
79
+ else f"routers.{module_info.name}.{sub_module_info.name}"
80
+ )
81
+ module = importlib.import_module(module_name)
82
+ if hasattr(module, "router"):
83
+ app.include_router(module.router)
84
+ else:
85
+ module_name = f"routers.{module_info.name}"
86
+ module = importlib.import_module(module_name)
87
+ if hasattr(module, "router"):
88
+ app.include_router(module.router)
89
+ except ModuleNotFoundError as e:
90
+ logger.error(f"Module not found: {e}")
91
+ except Exception as e:
92
+ logger.error(f"An error occurred: {e}")
93
+
94
+
95
  init(app)
96
+ include_routers(app)
97
+
98
 
99
  # 環境変数でOpenAI APIキーを保存および使用
100
  interpreter.auto_run = True
 
424
  prompt_with_memory = f"user's request: {prompt}. --- \nBelow is the transcript of your past conversation with the user: {memory} ---\n"
425
 
426
  return prompt_with_memory
427
+
428
+
429
  # データベース接続の設定
430
+ db_path = "./workspace/sample.duckdb"
431
  con = duckdb.connect(database=db_path)
432
 
433
+
434
  # テーブルが存在しない場合に作成
435
  def ensure_table_exists(con):
436
+ con.execute(
437
+ """
438
  CREATE SEQUENCE IF NOT EXISTS sample_id_seq START 1;
439
  CREATE TABLE IF NOT EXISTS samples (
440
  id INTEGER DEFAULT nextval('sample_id_seq'),
 
442
  age INTEGER,
443
  PRIMARY KEY(id)
444
  );
445
+ """
446
+ )
447
+
448
+
449
  # Set the environment variable.
450
  def chat_with_interpreter(
451
  message, history, a=None, b=None, c=None, d=None
 
482
 
483
  age = 28
484
  con = duckdb.connect(database="./workspace/sample.duckdb")
485
+ con.execute(
486
+ """
487
  CREATE SEQUENCE IF NOT EXISTS sample_id_seq START 1;
488
  CREATE TABLE IF NOT EXISTS samples (
489
  id INTEGER DEFAULT nextval('sample_id_seq'),
 
491
  age INTEGER,
492
  PRIMARY KEY(id)
493
  );
494
+ """
495
+ )
496
  cur = con.cursor()
497
  con.execute("INSERT INTO samples (name, age) VALUES (?, ?)", (full_response, age))
498
  con.execute("INSERT INTO samples (name, age) VALUES (?, ?)", (message, age))
 
667
  logging.basicConfig(level=logging.INFO)
668
  logger = logging.getLogger(__name__)
669
 
670
+ CHANNEL_ID = os.getenv("ChannelID")
671
+ CHANNEL_SECRET = os.getenv("ChannelSecret")
672
+ CHANNEL_ACCESS_TOKEN = os.getenv("ChannelAccessToken")
673
+ WEBHOOK_URL = os.getenv("WEBHOOK_URL")
674
+ WEBHOOK_GAS = os.getenv("WEBHOOKGAS")
675
  import requests
676
  import hmac
677
  import hashlib
678
  import base64
679
+
680
+
681
  def validate_signature(body: str, signature: str, secret: str) -> bool:
682
+ hash = hmac.new(
683
+ secret.encode("utf-8"), body.encode("utf-8"), hashlib.sha256
684
+ ).digest()
685
+ expected_signature = base64.b64encode(hash).decode("utf-8")
686
  return hmac.compare_digest(expected_signature, signature)
687
 
688
 
 
689
  def validate_signature(body: str, signature: str, secret: str) -> bool:
690
  if secret is None:
691
  logger.error("Secret is None")
692
  return False
693
 
694
+ hash = hmac.new(
695
+ secret.encode("utf-8"), body.encode("utf-8"), hashlib.sha256
696
+ ).digest()
697
+ expected_signature = base64.b64encode(hash).decode("utf-8")
698
  return hmac.compare_digest(expected_signature, signature)
699
 
700
+
701
+ class LineWebhookEvent(BaseModel):
702
+ type: str
703
+ message: dict
704
+ timestamp: int
705
+ source: dict
706
+ replyToken: str
707
+
708
+
709
+ import time
710
+
711
+
712
+ def no_process_file(prompt, foldername):
713
+ set_environment_variables()
714
+ # ファイルの処理
715
+ # 'make run example' コマンドをサブプロセスとして実行
716
+ # 拡張子を取り除いたファイル名でコピー
717
+
718
+ try:
719
+ proc = subprocess.Popen(
720
+ ["mkdir", f"/home/user/app/routers/{foldername}"],
721
+ )
722
+ except subprocess.CalledProcessError as e:
723
+ return f"Processed Content:\n{stdout}\n\nMake Command Error:\n{e.stderr}"
724
+
725
+ # path = f"/home/user/app/gpt-engineer/projects/{foldername}/" + os.path.basename(
726
+ # fileobj
727
+ # ) # NB*
728
+ # shutil.copyfile(fileobj.name, path)
729
+
730
+ # base_name = os.path.splitext(os.path.basename(fileobj))[0]
731
+ no_extension_path = f"/home/user/app/routers/{foldername}/prompt"
732
+ # shutil.copyfile(fileobj, no_extension_path)
733
+ time.sleep(1)
734
+ # Append prompt contents to the file
735
+ with open(no_extension_path, "a") as f:
736
+ f.write(prompt)
737
+
738
+ # Promptの内容をファイルに書き込む
739
+ try:
740
+ prompt_file_path = no_extension_path # os.path.join(path, "prompt.txt")
741
+ with open(prompt_file_path, "w") as prompt_file:
742
+ prompt_file.write(prompt)
743
+ except Exception as e:
744
+ return f"Error writing prompt to file: {str(e)}"
745
+
746
+ try:
747
+ proc = subprocess.Popen(
748
+ ["make", "run", foldername],
749
+ stdin=subprocess.PIPE,
750
+ stdout=subprocess.PIPE,
751
+ stderr=subprocess.PIPE,
752
+ text=True,
753
+ )
754
+ stdout, stderr = proc.communicate(input="y\ny\ny\n")
755
+ return f"Processed Content:\n{stdout}\n\nMake Command Output:\n{stdout}\n\nMake Command Error:\n{stderr}"
756
+ except subprocess.CalledProcessError as e:
757
+ return f"Processed Content:\n{stdout}\n\nMake Command Error:\n{e.stderr}"
758
+
759
+
760
+ import json
761
+ from datetime import datetime
762
+
763
+
764
  @app.post("/webhook")
765
  async def webhook(request: Request):
766
+ logger.info("Start =============================================================")
767
  try:
768
  # 受信したデータとヘッダーを取得
769
  body = await request.body()
770
  received_headers = dict(request.headers)
771
+
772
+ body_str = body.decode("utf-8")
773
+ logger.info("Received Body: %s", body_str)
774
+ body_json = json.loads(body_str)
775
+ events = body_json.get("events", [])
776
+
777
+ # イベントデータを取得
778
+ for event in events:
779
+ if event["type"] == "message" and event["message"]["type"] == "text":
780
+ user_id = event["source"]["userId"]
781
+ text = event["message"]["text"]
782
+ logger.info("//////////////////////////////////////////////")
783
+ logger.info(f"User ID: {user_id}, Text: {text}")
784
+ # ここで必要な処理を実行
785
+ no_process_file(text, "ai")
786
+
787
+ body_str = body.decode("utf-8")
788
+ logger.info("Received Body: %s", body_str)
789
+ body_json = json.loads(body_str)
790
+ events = body_json.get("events", [])
791
+
792
+ # イベントデータを取得
793
+ for event in events:
794
+ if event["type"] == "message" and event["message"]["type"] == "text":
795
+ user_id = event["source"]["userId"]
796
+ text = event["message"]["text"]
797
+ logger.info(event)
798
+ logger.info(f"User ID: {user_id}, Text: {text}")
799
+ now = datetime.now().strftime("%Y%m%d%H%M%S")
800
+ title = text[:20]
801
+ # user_idに日時情報を付加
802
+ user_id_with_timestamp = f"{now}_{title}_{user_id}"
803
+ # ここで必要な処理を実行
804
+ no_process_file(text, user_id_with_timestamp)
805
 
806
  # ログに記録
807
+ logger.info("Received Headers: %s", received_headers)
808
+ logger.info("Received Body: %s", body.decode("utf-8"))
809
 
810
  # 必要なヘッダー情報を抽出
811
+ line_signature = received_headers.get("x-line-signature")
812
  if not line_signature:
813
+ raise HTTPException(
814
+ status_code=400, detail="X-Line-Signature header is missing."
815
+ )
816
 
817
  # 署名を検証
818
+ if not validate_signature(body.decode("utf-8"), line_signature, CHANNEL_SECRET):
819
  raise HTTPException(status_code=400, detail="Invalid signature.")
820
 
821
  # URLの検証
 
824
 
825
  # 送信するヘッダーを設定
826
  headers = {
827
+ "Content-Type": "application/json",
828
+ "X-Line-Signature": line_signature,
829
+ "Authorization": f"Bearer {CHANNEL_ACCESS_TOKEN}",
830
  }
831
 
832
  # ログに転送先URLを記録
833
+ logger.info("Forwarding to URL: %s", WEBHOOK_URL)
834
+ logger.info("Forwarding Headers: %s", headers)
835
+ logger.info("Forwarding Body: %s", body.decode("utf-8"))
836
 
837
  # データを転送
838
+ # https://script.google.com/macros/s/AKfycbzfPCvQS6aAPSDvxefU-rcpXpEd8yYKFFzMi0ZV2wuKontoU8cMLuZ8Cm_DC1L0x45UKw/exec
839
  response = requests.post(WEBHOOK_URL, headers=headers, data=body)
840
+ response = requests.post(
841
+ "https://script.google.com/macros/s/AKfycbwFrOSPmAFXP-sDH7_BxXe3oqzL9FQhllOIuwTO5ylNwjEw9RBI-BRCIWnZLQ53jvE9/exec",
842
+ headers=headers,
843
+ data=body,
844
+ )
845
+ # response = requests.post(WEBHOOK_URL, headers=headers, data=body)
846
 
847
  # レスポンスをログに記録
848
+ logger.info("Response Code: %s", response.status_code)
849
+ logger.info("Response Content: %s", response.text)
850
+ logger.info("Response Headers: %s", response.headers)
851
 
852
  # クライアントにレスポンスを返却
853
+ return {
854
+ "status": "success",
855
+ "response_content": response.text,
856
+ }, response.status_code
857
 
858
  except Exception as e:
859
  logger.error("Error: %s", str(e))
860
  raise HTTPException(status_code=500, detail=str(e))
861
+ try:
862
+ body = await request.json()
863
+ events = body.get("events", [])
864
+ parsed_events = [LineWebhookEvent(**event) for event in events]
865
+
866
+ for event in parsed_events:
867
+ # イベントタイプをチェック
868
+ if event.type == "message":
869
+ message_type = event.message.get("type")
870
+ if message_type == "text":
871
+ user_message = event.message.get("text")
872
+ user_id = event.source.get("userId")
873
+ print(f"User ID: {user_id}, Message: {user_message}")
874
+ no_process_file(user_message, user_id)
875
+ # ここでメッセージに対する処理を実行
876
+ # 他のイベントタイプの処理
877
+ else:
878
+ print(f"Unhandled event type: {event.type}")
879
+
880
+ return {"status": "success"}
881
+ except json.JSONDecodeError:
882
+ return {"status": "error", "message": "Invalid JSON"}
883
+ except Exception as e:
884
+ return {"status": "error", "message": str(e)}
885
+
886
 
887
  def do_something_to_file(file_path):
888
  # ファイルに対して実行する処理をここに記述
 
906
  chatbot = gr.Chatbot(height=650, placeholder=PLACEHOLDER, label="Gradio ChatInterface")
907
 
908
 
909
+ def process_file(fileobj, prompt, foldername):
910
  set_environment_variables()
911
  # ファイルの処理
912
  # 'make run example' コマンドをサブプロセスとして実行
 
928
  shutil.copyfile(fileobj, no_extension_path)
929
 
930
  # Append prompt contents to the file
931
+ with open(no_extension_path, "a") as f:
932
+ f.write(prompt)
933
 
934
  # Promptの内容をファイルに書き込む
935
  try:
936
+ prompt_file_path = no_extension_path # os.path.join(path, "prompt.txt")
937
+ with open(prompt_file_path, "w") as prompt_file:
938
  prompt_file.write(prompt)
939
  except Exception as e:
940
  return f"Error writing prompt to file: {str(e)}"
 
1173
 
1174
  # gr.Interface.launch(app)
1175
 
1176
+ import pdb # Pythonデバッガのインポート
1177
+
1178
+
1179
+ def include_routerss(app):
1180
+ package_dir = os.path.dirname(__file__) + "/routers"
1181
+ for module_info in pkgutil.iter_modules([package_dir]):
1182
+ if module_info.ispkg: # フォルダー(パッケージ)のみを対象とする
1183
+ sub_package_dir = os.path.join(package_dir, module_info.name)
1184
+ for sub_module_info in pkgutil.iter_modules([sub_package_dir]):
1185
+ if sub_module_info.ispkg:
1186
+ module = importlib.import_module(
1187
+ f"routers.{module_info.name}.{sub_module_info.name}.router"
1188
+ )
1189
+ else:
1190
+ module = importlib.import_module(
1191
+ f"routers.{module_info.name}.router"
1192
+ )
1193
+ if hasattr(module, "router"):
1194
+ app.include_router(module.router)
1195
+
1196
+
1197
+ def include_gradio_interfaces():
1198
+ package_dir = "/home/user/app/routers"
1199
+ gradio_interfaces = []
1200
+ gradio_names = set()
1201
+
1202
+ for module_info in pkgutil.walk_packages([package_dir], "routers."):
1203
+ sub_module_name = module_info.name
1204
+ try:
1205
+ print(f"Trying to import {sub_module_name}")
1206
+ module = importlib.import_module(sub_module_name)
1207
+ if hasattr(module, "gradio_interface"):
1208
+ print(f"Found gradio_interface in {sub_module_name}")
1209
+ interface_name = module_info.name.split(".")[-1]
1210
+ if interface_name not in gradio_names:
1211
+ gradio_interfaces.append(module.gradio_interface)
1212
+ gradio_names.add(interface_name)
1213
+ else:
1214
+ unique_name = f"{interface_name}_{len(gradio_names)}"
1215
+ gradio_interfaces.append(module.gradio_interface)
1216
+ gradio_names.add(unique_name)
1217
+ except ModuleNotFoundError:
1218
+ print(f"ModuleNotFoundError: {sub_module_name}")
1219
+ pass
1220
+ except Exception as e:
1221
+ print(f"Failed to import {sub_module_name}: {e}")
1222
+
1223
+ print(f"Collected Gradio Interfaces: {gradio_names}")
1224
+ return gradio_interfaces, list(gradio_names)
1225
+
1226
+
1227
+ # デバッグポイントを設定
1228
+ # pdb.set_trace()
1229
+ gradio_interfaces, gradio_names = include_gradio_interfaces()
1230
  # demo.launch()
1231
  # キューを有効にする
1232
  chat_interface.queue()
1233
+ # tabs = gr.TabbedInterface(
1234
+ # [demo, create_ui(), democ, democs, appdb],
1235
+ # ["AIで開発", "FineTuning", "Chat", "仕様書から作成", "DataBase"],
1236
+ # )
1237
+
1238
+ # 既存のGradioインターフェース
1239
+ default_interfaces = [demo, create_ui(), democ, democs, appdb]
1240
+ default_names = ["AIで開発", "FineTuning", "Chat", "仕様書から作成", "DataBase"]
1241
+
1242
+ # 動的に追加されたインターフェースを含める
1243
+ all_interfaces = default_interfaces + gradio_interfaces
1244
+ all_names = default_names + gradio_names
1245
+ tabs = gr.TabbedInterface(all_interfaces, all_names)
1246
+
1247
  # カスタムCSSを追加
1248
  tabs.css = """
1249
  .gradio-container {