GitHub Action commited on
Commit
7cd8277
·
1 Parent(s): 0661b76

🚀 Auto-deploy from GitHub Actions

Browse files
.devcontainer/devcontainer.json CHANGED
@@ -42,5 +42,5 @@
42
  }
43
  }
44
  },
45
- "remoteUser": "vscode"
46
  }
 
42
  }
43
  }
44
  },
45
+ "remoteUser": "root"
46
  }
.env.example CHANGED
@@ -7,6 +7,12 @@ postgre_user=your_postgres_username
7
  postgre_pass=your_postgres_password
8
  postgre_host=your_postgres_host
9
  postgre_url=postgresql://user:pass@host/db?sslmode=require
 
 
 
 
 
 
10
 
11
  # API Keys
12
  api_key=your_groq_api_key
@@ -66,6 +72,8 @@ TOOL_KIT_DIR=usage
66
  # Google Cloud Service Account Credentials
67
  # Store as separate JSON file and reference path here
68
  GOOGLE_APPLICATION_CREDENTIALS=path/to/your/service-account-key.json
 
 
69
 
70
  # HuggingFace Configuration
71
  HF_DATASETS_TRUST_REMOTE_CODE=0
@@ -76,4 +84,22 @@ CPU_CORES=2
76
  MEMORY=16Gi
77
  PERSISTANT_STORAGE_ENABLED=false
78
  TQDM_POSITION=-1
79
- TQDM_MININTERVAL=1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7
  postgre_pass=your_postgres_password
8
  postgre_host=your_postgres_host
9
  postgre_url=postgresql://user:pass@host/db?sslmode=require
10
+ DATABASE_URL=sqlite:///./app.db
11
+ DB_HOST=localhost
12
+ DB_PORT=5432
13
+ DB_NAME=your_database_name
14
+ DB_USER=your_username
15
+ DB_PASSWORD=your_password
16
 
17
  # API Keys
18
  api_key=your_groq_api_key
 
72
  # Google Cloud Service Account Credentials
73
  # Store as separate JSON file and reference path here
74
  GOOGLE_APPLICATION_CREDENTIALS=path/to/your/service-account-key.json
75
+ # Alternative: Store JSON content directly in environment variable
76
+ GOOGLE_APPLICATION_CREDENTIALS_CONTENT=your_service_account_json_content
77
 
78
  # HuggingFace Configuration
79
  HF_DATASETS_TRUST_REMOTE_CODE=0
 
84
  MEMORY=16Gi
85
  PERSISTANT_STORAGE_ENABLED=false
86
  TQDM_POSITION=-1
87
+ TQDM_MININTERVAL=1
88
+
89
+ # Django Settings
90
+ DJANGO_SECRET_KEY=change-this-to-a-random-secret-key
91
+ DJANGO_DEBUG=True
92
+ DJANGO_ALLOWED_HOSTS=localhost,127.0.0.1
93
+
94
+ # FastAPI Settings
95
+ FASTAPI_HOST=0.0.0.0
96
+ FASTAPI_PORT=8000
97
+ FASTAPI_DEBUG=True
98
+
99
+ # Security
100
+ JWT_SECRET_KEY=change-this-to-a-random-jwt-secret
101
+ JWT_ALGORITHM=HS256
102
+ JWT_ACCESS_TOKEN_EXPIRE_MINUTES=30
103
+
104
+ # External APIs
105
+ API_KEY=your-api-key-here
FOLDER_STRUCTURE.md ADDED
@@ -0,0 +1,386 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 📁 プロジェクト構成ガイド
2
+
3
+ このドキュメントでは、`fastapi_django_main_live` プロジェクトのフォルダ構成について詳しく説明します。
4
+
5
+ ## 🏗️ 概要
6
+
7
+ このプロジェクトは、FastAPI、Django、Gradio、そして各種AI/ML ツールを統合したマルチフレームワーク開発環境です。
8
+
9
+ ```
10
+ fastapi_django_main_live/
11
+ ├── 🌐 Webアプリケーション層
12
+ ├── 🤖 AI/ML統合層
13
+ ├── 💾 データベース層
14
+ ├── 🔧 開発・運用ツール層
15
+ └── 📚 ドキュメント・リソース層
16
+ ```
17
+
18
+ ---
19
+
20
+ ## 📂 ルートディレクトリ構成
21
+
22
+ ### 🚀 **メインアプリケーションファイル**
23
+
24
+ | ファイル | 説明 | 用途 |
25
+ |---------|------|------|
26
+ | `app.py` | メインアプリケーションエントリーポイント | FastAPI/Django統合起動 |
27
+ | `manage.py` | Django管理コマンド | Django標準管理ツール |
28
+ | `app_debug_server.py` | デバッグ用サーバー | 開発時のデバッグサーバー |
29
+
30
+ ### ⚙️ **設定・構成ファイル**
31
+
32
+ | ファイル | 説明 | 用途 |
33
+ |---------|------|------|
34
+ | `Makefile` | プロジェクト管理コマンド | 開発・運用の自動化 |
35
+ | `docker-compose.yml` | Docker構成 | コンテナ化環境 |
36
+ | `Dockerfile` | Dockerイメージ定義 | アプリケーションコンテナ |
37
+ | `pyproject.toml` | Python依存関係管理 | Poetry設定 |
38
+ | `requirements.txt` | pip依存関係 | パッケージ管理 |
39
+ | `pytest.ini` | テスト設定 | pytest構成 |
40
+
41
+ ### 🔐 **環境・認証ファイル**
42
+
43
+ | ファイル | 説明 | 用途 |
44
+ |---------|------|------|
45
+ | `.env` | 環境変数設定 | API キー、DB接続情報等 |
46
+ | `.env.example` | 環境変数テンプレート | 設定例 |
47
+ | `fix_secrets.sh` | シークレット修正スクリプト | セキュリティ設定 |
48
+
49
+ ### 💾 **データベースファイル**
50
+
51
+ | ファイル | 説明 | 用途 |
52
+ |---------|------|------|
53
+ | `prompts.db` | プロンプト管理用SQLite | プロンプト履歴・テンプレート |
54
+ | `chat_history.db` | チャット履歴用SQLite | 会話履歴保存 |
55
+ | `users.db` | ユーザー情報用SQLite | ユーザー管理 |
56
+
57
+ ---
58
+
59
+ ## 🏢 **メインアプリケーション構造**
60
+
61
+ ### 🌐 `mysite/` - Django メインサイト
62
+ Djangoプロジェクトのコア部分
63
+
64
+ ```
65
+ mysite/
66
+ ├── settings.py # Django設定
67
+ ├── urls.py # URLルーティング
68
+ ├── asgi.py # ASGI設定
69
+ ├── wsgi.py # WSGI設定
70
+ ├── libs/ # 共通ライブラリ
71
+ ├── routers/ # FastAPIルーター
72
+ ├── config/ # 設定管理
73
+ ├── database/ # データベース操作
74
+ └── interpreter/ # インタープリター機能
75
+ ```
76
+
77
+ ### 🎮 `controllers/` - Gradio コントローラー
78
+ 各種Gradioインターフェースの実装
79
+
80
+ ```
81
+ controllers/
82
+ ├── gra_01_chat/ # チャット機能
83
+ ├── gra_02_openInterpreter/ # OpenInterpreter統合
84
+ ├── gra_03_programfromdoc/ # ドキュメントからプログラム生成
85
+ ├── gra_04_database/ # データベース操作UI
86
+ ├── gra_05_files/ # ファイル操作
87
+ ├── gra_07_html/ # HTML生成
88
+ ├── gra_08_hasula/ # Hasula機能
89
+ ├── gra_09_weather/ # 天気情報
90
+ ├── gra_10_frontend/ # フロントエンド生成
91
+ └── gra_11_multimodal/ # マルチモーダル機能
92
+ ```
93
+
94
+ ### 📱 `apps/` - Django アプリケーション
95
+ 業務固有のDjangoアプリケーション
96
+
97
+ ```
98
+ apps/
99
+ ├── buyback/ # 買取システム
100
+ ├── clothing_project/ # 衣類プロジェクト
101
+ ├── diamond_project/ # ダイヤモンドプロジェクト
102
+ ├── gold_price_project/ # 金価格プロジェクト
103
+ ├── metal_assessment/ # 金属査定
104
+ ├── mainapi/ # メインAPI
105
+ └── mydjangoapp/ # 汎用Djangoアプリ
106
+ ```
107
+
108
+ ---
109
+
110
+ ## 🤖 **AI/ML 統合層**
111
+
112
+ ### 🧠 `AutoPrompt/` - プロンプト最適化
113
+ 自動プロンプト生成・最適化システム
114
+
115
+ ```
116
+ AutoPrompt/
117
+ ├── optimization_pipeline.py # 最適化パイプライン
118
+ ├── run_pipeline.py # 実行スクリプト
119
+ ├── config/ # 設定ファイル
120
+ ├── prompts/ # プロンプトテンプレート
121
+ ├── estimator/ # 推定器
122
+ └── eval/ # 評価システム
123
+ ```
124
+
125
+ ### 🦙 `LLaMA-Factory/` - LLM ファインチューニング
126
+ LLaMAモデルのファインチューニング環境
127
+
128
+ ```
129
+ LLaMA-Factory/
130
+ ├── src/ # ソースコード
131
+ ├── data/ # 学習データ
132
+ ├── examples/ # 使用例
133
+ ├── evaluation/ # 評価スクリプト
134
+ └── scripts/ # ��行スクリプト
135
+ ```
136
+
137
+ ### 👶 `babyagi/` - 自律AIエージェント
138
+ BabyAGI実装とカスタマイズ
139
+
140
+ ```
141
+ babyagi/
142
+ ├── babyagi.py # メインエージェント
143
+ ├── classic/ # クラシック版
144
+ ├── babycoder/ # コーディング特化
145
+ ├── extensions/ # 拡張機能
146
+ └── tools/ # ツール群
147
+ ```
148
+
149
+ ### 🔍 `open-interpreter/` - オープンインタープリター
150
+ コード実行・解釈システム
151
+
152
+ ```
153
+ open-interpreter/
154
+ ├── interpreter/ # インタープリターコア
155
+ ├── docs/ # ドキュメント
156
+ └── examples/ # 使用例
157
+ ```
158
+
159
+ ### 🏗️ `gpt-engineer/` - AI コード生成
160
+ GPTベースのコード生成システム
161
+
162
+ ```
163
+ gpt-engineer/
164
+ ├── gpt_engineer/ # コア機能
165
+ ├── projects/ # 生成プロジェクト
166
+ └── benchmark/ # ベンチマーク
167
+ ```
168
+
169
+ ---
170
+
171
+ ## 💾 **データ・ストレージ層**
172
+
173
+ ### 🗄️ `chroma/` - ベクトルデータベース
174
+ 埋め込みベクトル保存・検索
175
+
176
+ ```
177
+ chroma/
178
+ ├── chroma.sqlite3 # ChromaDB データベース
179
+ └── [collection-id]/ # コレクションデータ
180
+ ```
181
+
182
+ ### 📊 `workspace/` - ワークスペース
183
+ プロジェクト固有のワークスペース
184
+
185
+ ### 🗃️ `static/` & `staticfiles/` - 静的ファイル
186
+ ```
187
+ static/ # 開発用静的ファイル
188
+ staticfiles/ # 本番用静的ファイル
189
+ ├── css/ # スタイルシート
190
+ ├── js/ # JavaScript
191
+ ├── images/ # 画像ファイル
192
+ └── admin/ # Django管理画面用
193
+ ```
194
+
195
+ ---
196
+
197
+ ## 🔧 **開発・運用ツール層**
198
+
199
+ ### 🐳 **コンテナ化**
200
+ - `Dockerfile` - アプリケーションコンテナ
201
+ - `docker-compose.yml` - マルチコンテナ構成
202
+ - `.dockerignore` - Docker除外ファイル
203
+
204
+ ### 🔄 **CI/CD**
205
+ ```
206
+ .github/
207
+ ├── workflows/ # GitHub Actions
208
+ ├── ISSUE_TEMPLATE/ # Issue テンプレート
209
+ └── PULL_REQUEST_TEMPLATE/ # PR テンプレート
210
+ ```
211
+
212
+ ### 🛠️ **開発環境**
213
+ ```
214
+ .devcontainer/
215
+ ├── devcontainer.json # VS Code 開発コンテナ設定
216
+ └── Dockerfile # 開発用コンテナ
217
+ ```
218
+
219
+ ### 🧪 `tests/` - テストスイート
220
+ ```
221
+ tests/
222
+ ├── test_*.py # 各種テストファイル
223
+ ├── test_folders*/ # テスト用データ
224
+ └── fixtures/ # テスト固定データ
225
+ ```
226
+
227
+ ---
228
+
229
+ ## 📝 **設定・コマンド詳細**
230
+
231
+ ### 🎯 **Makefileコマンド**
232
+
233
+ | コマンド | 説明 | 用途 |
234
+ |---------|------|------|
235
+ | `make app` | メインアプリ起動 | FastAPI/Django サーバー開始 |
236
+ | `make dev` | 開発モード起動 | ホットリロード有効 |
237
+ | `make debug` | デバッグモード起動 | ブレークポイント使用可能 |
238
+ | `make test` | テスト実行 | 全テストスイート実行 |
239
+ | `make clean` | クリーンアップ | 一時ファイル削除 |
240
+ | `make docker-up` | Docker起動 | コンテナ環境開始 |
241
+
242
+ ### 🌍 **環境変数 (.env)**
243
+
244
+ | 変数 | 説明 | 例 |
245
+ |------|------|-----|
246
+ | `GROQ_API_KEY` | GroqAI APIキー | `gsk_...` |
247
+ | `DATABASE_URL` | データベースURL | `sqlite:///./app.db` |
248
+ | `SPACE_ID` | Hugging Face Space ID | `username/space-name` |
249
+ | `WEBHOOK_URL` | Google Chat Webhook | `https://chat.googleapis.com/...` |
250
+
251
+ ### 🗄️ **データベーススキーマ**
252
+
253
+ #### `prompts.db`
254
+ ```sql
255
+ CREATE TABLE prompts (
256
+ id INTEGER PRIMARY KEY,
257
+ title TEXT NOT NULL,
258
+ content TEXT NOT NULL,
259
+ created_at TIMESTAMP,
260
+ updated_at TIMESTAMP
261
+ );
262
+ ```
263
+
264
+ #### `chat_history.db`
265
+ ```sql
266
+ CREATE TABLE history (
267
+ id INTEGER PRIMARY KEY,
268
+ role TEXT NOT NULL,
269
+ type TEXT,
270
+ content TEXT NOT NULL,
271
+ timestamp TIMESTAMP
272
+ );
273
+ ```
274
+
275
+ ---
276
+
277
+ ## 🚀 **クイックスタート**
278
+
279
+ ### 1. 環境セットアップ
280
+ ```bash
281
+ # 依存関係インストール
282
+ make requirements
283
+
284
+ # 環境変数設定
285
+ cp .env.example .env
286
+ # .env ファイルを編集してAPIキーを設定
287
+ ```
288
+
289
+ ### 2. アプリケーション起動
290
+ ```bash
291
+ # 開発モードで起動
292
+ make dev
293
+
294
+ # または通常モードで起動
295
+ make app
296
+ ```
297
+
298
+ ### 3. 主要URL
299
+ - **メインアプリ**: http://localhost:7860
300
+ - **Django管理**: http://localhost:7860/admin
301
+ - **API文書**: http://localhost:7860/docs
302
+
303
+ ---
304
+
305
+ ## 📚 **主要機能**
306
+
307
+ ### 🎨 **Gradio インターフェース**
308
+ - チャット機能 (`gra_01_chat`)
309
+ - プログラム自動生成 (`gra_03_programfromdoc`)
310
+ - データベース操作UI (`gra_04_database`)
311
+ - ファイル処理 (`gra_05_files`)
312
+
313
+ ### 🤖 **AI 統合**
314
+ - OpenInterpreter によるコード実行
315
+ - LLaMA ファインチューニング
316
+ - プロンプト自動最適化
317
+ - BabyAGI 自律エージェント
318
+
319
+ ### 💼 **業務アプリケーション**
320
+ - 買取システム (`buyback`)
321
+ - ��属査定システム (`metal_assessment`)
322
+ - 価格管理システム (`gold_price_project`)
323
+
324
+ ---
325
+
326
+ ## 🔍 **トラブルシューティング**
327
+
328
+ ### よくある問題
329
+
330
+ 1. **データベース接続エラー**
331
+ ```bash
332
+ # データベース初期化
333
+ python manage.py migrate
334
+ ```
335
+
336
+ 2. **依存関係エラー**
337
+ ```bash
338
+ # 依存関係再インストール
339
+ make clean
340
+ make requirements
341
+ ```
342
+
343
+ 3. **ポート競合**
344
+ ```bash
345
+ # 使用中ポートの確認
346
+ lsof -i :7860
347
+ ```
348
+
349
+ ---
350
+
351
+ ## 📈 **開発ガイドライン**
352
+
353
+ ### 🏗️ **新機能追加**
354
+ 1. `controllers/gra_XX_newfeature/` に新しいGradioインターフェースを作成
355
+ 2. `apps/newapp/` に新しいDjangoアプリを作成
356
+ 3. `mysite/routers/` にFastAPIルーターを追加
357
+
358
+ ### 🧪 **テスト**
359
+ ```bash
360
+ # 特定テスト実行
361
+ pytest tests/test_specific.py
362
+
363
+ # カバレッジ付きテスト
364
+ pytest --cov=mysite tests/
365
+ ```
366
+
367
+ ### 📦 **デプロイ**
368
+ ```bash
369
+ # Docker イメージビルド
370
+ make docker-build
371
+
372
+ # コンテナ起動
373
+ make docker-up
374
+ ```
375
+
376
+ ---
377
+
378
+ ## 📞 **サポート**
379
+
380
+ - 📖 **ドキュメント**: `/docs/` フォルダ参照
381
+ - 🐛 **バグ報告**: GitHub Issues
382
+ - 💡 **機能要求**: GitHub Discussions
383
+
384
+ ---
385
+
386
+ *最終更新: 2025年6月11日*
app/Http/controller/test_folders/prompt CHANGED
@@ -1,83 +1,32 @@
1
-
2
- # 社員がプロフィールを登録・公開し、お互いに参照できるシステム
3
-
4
- ## 機能
5
-
6
- ## LINEのクレーム対応システムの作成
7
- - クレームがあった用語をAPIでナレッジに登録するシステム
8
- - APIキー agentキーをいれ
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
- - 表示内容は、`ユーザー名`・`プロフィール`で、`プロフィール`は先頭10文字と三点リーダーを表示する。
41
- - ユーザー名をクリックすると、そのユーザーのユーザー詳細画面へ遷移する。
42
- - `チーム一覧へ`をクリックすると、チーム一覧画面へ遷移する。
43
-
44
- ### ユーザー詳細画面
45
-
46
- - 特定のユーザーの、`ユーザー名`・`所属チーム`・`プロフィール`・`タグ`が表示される。
47
- - プロフィールの表示はマークダウンに対応させる。
48
- - `一覧へ`リンクをクリックすると、ユーザー一覧画面へ遷移する。
49
-
50
- ## あなたが作成するもの
51
-
52
- バックエンドのプログラム一式を作成してください。
53
- フロントエンドのプログラムは不要です。
54
-
55
- - `/api`ディレクトリ以下に作成。
56
- - Python/FastAPI/SQLAlchemyを使う。
57
- - DBはSQLiteを使う。
58
- - 必要に応じて外部ライブラリを使う。
59
- - クラウドや外部サービス(外部API)は使わない。
60
- - .gitignoreを含めること。
61
- - バックエンド
62
- @app.post("
63
- def lumbda_function():
64
-
65
- gradio_interface でメイン関数から読み込めるようにして
66
-
67
- googleappsscript
68
- ラインの画像検索システム
69
-
70
- ファイルは1ファイルで作成して。
71
- 1ファイル1機能で難しくしたくない
72
-
73
- 1,lineからデータがくる
74
- 2,doPostで取得
75
- 3.typeがイメージの場合はドライブに保存
76
- 4,保存したデータをS3にアップロード
77
- 5.データはシークレットから取得
78
- 6,plantumlでフローの作成
79
- 7,システムドキュメントの作成
80
-
81
- gradio は gradio_interface というBlock名で作成
82
- fastapiはrouter の作成
83
-
 
1
+ # gradio で miiboのナレッジに登録する画面の作成
2
+ gradio_interface interfacec name
3
+
4
+ # fastapi
5
+ gradio apiに接続するAPI
6
+ router で作成
7
+
8
+ 1ファイルで作成
9
+ 仕様書の作成
10
+ plantumlで図にする
11
+
12
+ #sample fastapi
13
+ import requests
14
+ import json
15
+ import os
16
+
17
+ from fastapi import APIRouter, HTTPException
18
+ from gradio_client import Client
19
+
20
+ router = APIRouter(prefix="/gradio", tags=["gradio"])
21
+ @router.get("/route/gradio")
22
+
23
+ def get_senario(id,res):
24
+ table = "LOG"
25
+ client = Client("kenken999/fastapi_django_main_live")
26
+ result = client.predict(
27
+ message="Hello!!",
28
+ request=0.95,
29
+ param_3=512,
30
+ api_name="/chat"
31
+ )
32
+ return result
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cache/user_config.yaml CHANGED
@@ -1,6 +1,6 @@
1
  cache_dir: null
2
  lang: en
3
- last_model: DeepSeekCoder-33B-Chat
4
  path_dict:
5
  Falcon-180B: tiiuae/falcon-180b
6
  LLaMA3-70B-Chat: meta-llama/Meta-Llama-3-70B-Instruct
 
1
  cache_dir: null
2
  lang: en
3
+ last_model: Aya-23-8B-Chat
4
  path_dict:
5
  Falcon-180B: tiiuae/falcon-180b
6
  LLaMA3-70B-Chat: meta-llama/Meta-Llama-3-70B-Instruct
contbk/gra_03_programfromdocgas/__init__.py ADDED
File without changes
contbk/gra_03_programfromdocgas/programfromdocAI.py ADDED
@@ -0,0 +1,330 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import sys
2
+ import os
3
+ sys.path.append('/workspaces/fastapi_django_main_live')
4
+
5
+ import gradio as gr
6
+ from mysite.libs.utilities import chat_with_interpreter, completion, process_file, no_process_file
7
+ from interpreter import interpreter
8
+ import mysite.interpreter.interpreter_config # インポートするだけで設定が適用されます
9
+ import sqlite3
10
+ import os
11
+ from datetime import datetime
12
+ from typing import List, Tuple, Optional
13
+
14
+ # データベース設定
15
+ DB_PATH = "prompts.db"
16
+
17
+ def init_db():
18
+ """プロンプトデータベースの初期化"""
19
+ try:
20
+ conn = sqlite3.connect(DB_PATH)
21
+ cursor = conn.cursor()
22
+
23
+ cursor.execute('''
24
+ CREATE TABLE IF NOT EXISTS prompts (
25
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
26
+ title TEXT NOT NULL,
27
+ url TEXT,
28
+ content TEXT NOT NULL,
29
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
30
+ updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
31
+ )
32
+ ''')
33
+
34
+ # デフォルトプロンプトの追加(初回のみ)
35
+ cursor.execute('SELECT COUNT(*) FROM prompts')
36
+ if cursor.fetchone()[0] == 0:
37
+ default_prompt = """# gradio で miiboのナレッジに登録する画面の作成
38
+ gradio_interface interfacec name
39
+
40
+ # fastapi
41
+ gradio apiに接続するAPI
42
+ router で作成
43
+
44
+ 1ファイルで作成
45
+ 仕様書の作成
46
+ plantumlで図にする
47
+
48
+ #sample fastapi
49
+ import requests
50
+ import json
51
+ import os
52
+
53
+ from fastapi import APIRouter, HTTPException
54
+ from gradio_client import Client
55
+
56
+ router = APIRouter(prefix="/gradio", tags=["gradio"])
57
+ @router.get("/route/gradio")
58
+
59
+ def get_senario(id,res):
60
+ table = "LOG"
61
+ client = Client("kenken999/fastapi_django_main_live")
62
+ result = client.predict(
63
+ message="Hello!!",
64
+ request=0.95,
65
+ param_3=512,
66
+ api_name="/chat"
67
+ )
68
+ return result
69
+ """
70
+ cursor.execute(
71
+ 'INSERT INTO prompts (title, url, content) VALUES (?, ?, ?)',
72
+ ('デフォルト:Gradio + FastAPI作成', 'https://example.com', default_prompt)
73
+ )
74
+
75
+ conn.commit()
76
+ conn.close()
77
+ print("✅ データベース初期化完了")
78
+ except Exception as e:
79
+ print(f"❌ データベース初期化エラー: {e}")
80
+
81
+ def save_prompt(title: str, url: str, content: str) -> str:
82
+ """プロンプトを保存"""
83
+ try:
84
+ if not title.strip() or not content.strip():
85
+ return "❌ タイトルとプロンプト内容は必須です"
86
+
87
+ conn = sqlite3.connect(DB_PATH)
88
+ cursor = conn.cursor()
89
+
90
+ cursor.execute(
91
+ 'INSERT INTO prompts (title, url, content) VALUES (?, ?, ?)',
92
+ (title.strip(), url.strip(), content.strip())
93
+ )
94
+
95
+ conn.commit()
96
+ conn.close()
97
+ print(f"✅ プロンプト保存: {title}")
98
+ return f"✅ プロンプト '{title}' を保存しました!"
99
+ except Exception as e:
100
+ print(f"❌ 保存エラー: {e}")
101
+ return f"❌ エラー: {str(e)}"
102
+
103
+ def get_prompts() -> List[Tuple]:
104
+ """全プロンプトを取得"""
105
+ try:
106
+ conn = sqlite3.connect(DB_PATH)
107
+ cursor = conn.cursor()
108
+
109
+ cursor.execute('SELECT id, title, url, created_at FROM prompts ORDER BY created_at DESC')
110
+ prompts = cursor.fetchall()
111
+
112
+ conn.close()
113
+ print(f"✅ プロンプト取得: {len(prompts)}件")
114
+ return prompts
115
+ except Exception as e:
116
+ print(f"❌ プロンプト取得エラー: {e}")
117
+ return []
118
+
119
+ def get_prompt_content(prompt_id: int) -> str:
120
+ """指定IDのプロンプト内容を取得"""
121
+ try:
122
+ conn = sqlite3.connect(DB_PATH)
123
+ cursor = conn.cursor()
124
+
125
+ cursor.execute('SELECT content FROM prompts WHERE id = ?', (prompt_id,))
126
+ result = cursor.fetchone()
127
+
128
+ conn.close()
129
+ return result[0] if result else ""
130
+ except Exception as e:
131
+ print(f"❌ プロンプト内容取得エラー: {e}")
132
+ return ""
133
+
134
+ def delete_prompt(prompt_id: int) -> str:
135
+ """プロンプトを削除"""
136
+ try:
137
+ conn = sqlite3.connect(DB_PATH)
138
+ cursor = conn.cursor()
139
+
140
+ cursor.execute('DELETE FROM prompts WHERE id = ?', (prompt_id,))
141
+
142
+ if cursor.rowcount > 0:
143
+ conn.commit()
144
+ conn.close()
145
+ print(f"✅ プロンプト削除: ID {prompt_id}")
146
+ return "✅ プロンプトを削除しました"
147
+ else:
148
+ conn.close()
149
+ return "❌ プロンプトが見つかりません"
150
+ except Exception as e:
151
+ print(f"❌ 削除エラー: {e}")
152
+ return f"❌ 削除エラー: {str(e)}"
153
+
154
+ # データベース初期化
155
+ print("🗄️ データベースを初期化中...")
156
+ init_db()
157
+
158
+ def get_prompt_choices():
159
+ """プロンプト一覧のchoicesを取得"""
160
+ prompts = get_prompts()
161
+ choices = []
162
+ for prompt in prompts:
163
+ id_, title, url, created_at = prompt
164
+ display_text = f"[{id_}] {title} ({created_at[:10]})"
165
+ choices.append((display_text, str(id_)))
166
+ return choices
167
+
168
+ def refresh_prompt_dropdown():
169
+ """プロンプトドロップダウンを更新"""
170
+ choices = get_prompt_choices()
171
+ return gr.Dropdown(choices=choices, label="📋 保存済みプロンプト一覧", value=None)
172
+
173
+ # Gradioインターフェース作成
174
+ with gr.Blocks(title="🚀 プロンプト管理 & コード生成", theme=gr.themes.Soft()) as gradio_interface:
175
+ gr.Markdown("# 🚀 プロンプト管理 & ドキュメントからコード生成")
176
+
177
+ with gr.Tabs():
178
+ # タブ1: プロンプト管理
179
+ with gr.TabItem("📝 プロンプト管理"):
180
+ gr.Markdown("## プロンプトの保存・管理")
181
+
182
+ with gr.Row():
183
+ with gr.Column(scale=1):
184
+ # プロンプト保存フォーム
185
+ save_title = gr.Textbox(label="📋 タイトル", placeholder="例: FastAPI + Gradio作成プロンプト")
186
+ save_url = gr.Textbox(label="🔗 参考URL (任意)", placeholder="https://example.com")
187
+ save_content = gr.Textbox(
188
+ label="📝 プロンプト内容",
189
+ lines=10,
190
+ placeholder="プロンプトの内容を入力してください..."
191
+ )
192
+ save_btn = gr.Button("💾 プロンプトを保存", variant="primary")
193
+ save_status = gr.Textbox(label="保存結果", interactive=False)
194
+
195
+ with gr.Column(scale=1):
196
+ # プロンプト一覧
197
+ prompt_dropdown = gr.Dropdown(
198
+ choices=get_prompt_choices(),
199
+ label="📋 保存済みプロンプト一覧",
200
+ interactive=True
201
+ )
202
+ refresh_btn = gr.Button("🔄 一覧を更新")
203
+ load_btn = gr.Button("📥 選択したプロンプトを読み込み", variant="secondary")
204
+ delete_btn = gr.Button("🗑️ 選択したプロンプトを削除", variant="stop")
205
+ delete_status = gr.Textbox(label="削除結果", interactive=False)
206
+
207
+ # タブ2: コード生成
208
+ with gr.TabItem("⚡ コード生成"):
209
+ gr.Markdown("## ドキュメントからコード生成")
210
+
211
+ with gr.Row():
212
+ with gr.Column():
213
+ # ファイルアップロード
214
+ input_file = gr.File(label="📄 ドキュメントファイル")
215
+
216
+ # プロンプト表示・編集エリア
217
+ current_prompt = gr.Textbox(
218
+ label="📝 現在のプロンプト",
219
+ lines=15,
220
+ value="",
221
+ placeholder="上のタブでプロンプトを選択するか、直接入力してください..."
222
+ )
223
+
224
+ with gr.Column():
225
+ # 生成設定
226
+ folder_name = gr.Textbox(label="📁 出力フォルダ名", value="generated_code")
227
+ github_token = gr.Textbox(label="🔑 GitHub Token (任意)", type="password", value="")
228
+
229
+ # 生成ボタン
230
+ generate_btn = gr.Button("🚀 コード生成実行", variant="primary", size="lg")
231
+
232
+ # 結果表示
233
+ result_output = gr.Textbox(label="📤 生成結果", lines=10, interactive=False)
234
+
235
+ # イベントハンドラー
236
+ def handle_save_prompt(title, url, content):
237
+ result = save_prompt(title, url, content)
238
+ # 保存後に一覧を更新
239
+ updated_dropdown = refresh_prompt_dropdown()
240
+ print(f"💾 保存後の一覧更新完了")
241
+ return result, updated_dropdown
242
+
243
+ def handle_refresh_list():
244
+ updated_dropdown = refresh_prompt_dropdown()
245
+ print(f"🔄 一覧更新: ドロップダウンを更新")
246
+ return updated_dropdown
247
+
248
+ def handle_load_prompt(selected_prompt):
249
+ print(f"📥 プロンプト読み込み要求: {selected_prompt}")
250
+ if selected_prompt:
251
+ try:
252
+ prompt_id = selected_prompt.split(']')[0][1:] # [1] から ] までを取得してIDを抽出
253
+ print(f"🔍 抽出されたID: {prompt_id}")
254
+ content = get_prompt_content(int(prompt_id))
255
+ print(f"📄 取得した内容の長さ: {len(content)} 文字")
256
+ print(f"📄 内容のプレビュー: {content[:100]}...")
257
+ return content
258
+ except Exception as e:
259
+ print(f"❌ プロンプト読み込みエラー: {e}")
260
+ return ""
261
+ return ""
262
+
263
+ def handle_delete_prompt(selected_prompt):
264
+ if selected_prompt:
265
+ try:
266
+ prompt_id = selected_prompt.split(']')[0][1:] # IDを抽出
267
+ result = delete_prompt(int(prompt_id))
268
+ # 削除後に一覧を更新
269
+ updated_dropdown = refresh_prompt_dropdown()
270
+ print(f"🗑️ 削除後の一覧更新完了")
271
+ return result, updated_dropdown
272
+ except Exception as e:
273
+ print(f"❌ プロンプト削除エラー: {e}")
274
+ return f"❌ エラー: {str(e)}", refresh_prompt_dropdown()
275
+ return "❌ プロンプトが選択されていません", refresh_prompt_dropdown()
276
+
277
+ def handle_generate_code(file, prompt, folder, token):
278
+ if not prompt.strip():
279
+ return "❌ プロンプトが入力されていません"
280
+ try:
281
+ return process_file(file, prompt, folder, token)
282
+ except Exception as e:
283
+ return f"❌ コード生成エラー: {str(e)}"
284
+
285
+ # イベント接続
286
+ save_btn.click(
287
+ handle_save_prompt,
288
+ inputs=[save_title, save_url, save_content],
289
+ outputs=[save_status, prompt_dropdown]
290
+ )
291
+
292
+ refresh_btn.click(
293
+ handle_refresh_list,
294
+ outputs=[prompt_dropdown]
295
+ )
296
+
297
+ load_btn.click(
298
+ handle_load_prompt,
299
+ inputs=[prompt_dropdown],
300
+ outputs=[current_prompt]
301
+ )
302
+
303
+ # ドロップダウンの選択変更時も自動読み込み
304
+ prompt_dropdown.change(
305
+ handle_load_prompt,
306
+ inputs=[prompt_dropdown],
307
+ outputs=[current_prompt]
308
+ )
309
+
310
+ delete_btn.click(
311
+ handle_delete_prompt,
312
+ inputs=[prompt_dropdown],
313
+ outputs=[delete_status, prompt_dropdown]
314
+ )
315
+
316
+ generate_btn.click(
317
+ handle_generate_code,
318
+ inputs=[input_file, current_prompt, folder_name, github_token],
319
+ outputs=[result_output]
320
+ )
321
+
322
+ # スタンドアロン実行用
323
+ if __name__ == "__main__":
324
+ print("🚀 プロンプト管理システムを起動中...")
325
+ gradio_interface.launch(
326
+ server_name="0.0.0.0",
327
+ server_port=0, # 自動でポートを選択
328
+ share=False,
329
+ debug=True
330
+ )
contbk/gra_03_programfromdocgas/programfromdocAI_backup.py ADDED
@@ -0,0 +1,287 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ from mysite.libs.utilities import chat_with_interpreter, completion, process_file, no_process_file
3
+ from interpreter import interpreter
4
+ import mysite.interpreter.interpreter_config # インポートするだけで設定が適用されます
5
+ import sqlite3
6
+ import os
7
+ from datetime import datetime
8
+ from typing import List, Tuple, Optional
9
+
10
+ # データベース設定
11
+ DB_PATH = "prompts.db"
12
+
13
+ def init_db():
14
+ """プロンプトデータベースの初期化"""
15
+ conn = sqlite3.connect(DB_PATH)
16
+ cursor = conn.cursor()
17
+
18
+ cursor.execute('''
19
+ CREATE TABLE IF NOT EXISTS prompts (
20
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
21
+ title TEXT NOT NULL,
22
+ url TEXT,
23
+ content TEXT NOT NULL,
24
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
25
+ updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
26
+ )
27
+ ''')
28
+
29
+ # デフォルトプロンプトの追加(初回のみ)
30
+ cursor.execute('SELECT COUNT(*) FROM prompts')
31
+ if cursor.fetchone()[0] == 0:
32
+ default_prompt = """# gradio で miiboのナレッジに登録する画面の作成
33
+ gradio_interface interfacec name
34
+
35
+ # fastapi
36
+ gradio apiに接続するAPI
37
+ router で作成
38
+
39
+ 1ファイルで作成
40
+ 仕様書の作成
41
+ plantumlで図にする
42
+
43
+ #sample fastapi
44
+ import requests
45
+ import json
46
+ import os
47
+
48
+ from fastapi import APIRouter, HTTPException
49
+ from gradio_client import Client
50
+
51
+ router = APIRouter(prefix="/gradio", tags=["gradio"])
52
+ @router.get("/route/gradio")
53
+
54
+ def get_senario(id,res):
55
+ table = "LOG"
56
+ client = Client("kenken999/fastapi_django_main_live")
57
+ result = client.predict(
58
+ message="Hello!!",
59
+ request=0.95,
60
+ param_3=512,
61
+ api_name="/chat"
62
+ )
63
+ return result
64
+ """
65
+ cursor.execute(
66
+ 'INSERT INTO prompts (title, url, content) VALUES (?, ?, ?)',
67
+ ('デフォルト:Gradio + FastAPI作成', 'https://example.com', default_prompt)
68
+ )
69
+
70
+ conn.commit()
71
+ conn.close()
72
+
73
+ def save_prompt(title: str, url: str, content: str) -> str:
74
+ """プロンプトを保存"""
75
+ try:
76
+ conn = sqlite3.connect(DB_PATH)
77
+ cursor = conn.cursor()
78
+
79
+ cursor.execute(
80
+ 'INSERT INTO prompts (title, url, content) VALUES (?, ?, ?)',
81
+ (title, url, content)
82
+ )
83
+
84
+ conn.commit()
85
+ conn.close()
86
+ return f"✅ プロンプト '{title}' を保存しました!"
87
+ except Exception as e:
88
+ return f"❌ エラー: {str(e)}"
89
+
90
+ def get_prompts() -> List[Tuple]:
91
+ """全プロンプトを取得"""
92
+ try:
93
+ conn = sqlite3.connect(DB_PATH)
94
+ cursor = conn.cursor()
95
+
96
+ cursor.execute('SELECT id, title, url, created_at FROM prompts ORDER BY created_at DESC')
97
+ prompts = cursor.fetchall()
98
+
99
+ conn.close()
100
+ return prompts
101
+ except Exception as e:
102
+ print(f"プロンプト取得エラー: {e}")
103
+ return []
104
+
105
+ def get_prompt_content(prompt_id: int) -> str:
106
+ """指定IDのプロンプト内容を取得"""
107
+ try:
108
+ conn = sqlite3.connect(DB_PATH)
109
+ cursor = conn.cursor()
110
+
111
+ cursor.execute('SELECT content FROM prompts WHERE id = ?', (prompt_id,))
112
+ result = cursor.fetchone()
113
+
114
+ conn.close()
115
+ return result[0] if result else ""
116
+ except Exception as e:
117
+ print(f"プロンプト内容取得エラー: {e}")
118
+ return ""
119
+
120
+ def delete_prompt(prompt_id: int) -> str:
121
+ """プロンプトを削除"""
122
+ try:
123
+ conn = sqlite3.connect(DB_PATH)
124
+ cursor = conn.cursor()
125
+
126
+ cursor.execute('DELETE FROM prompts WHERE id = ?', (prompt_id,))
127
+
128
+ if cursor.rowcount > 0:
129
+ conn.commit()
130
+ conn.close()
131
+ return "✅ プロンプトを削除しました"
132
+ else:
133
+ conn.close()
134
+ return "❌ プロンプトが見つかりません"
135
+ except Exception as e:
136
+ return f"❌ 削除エラー: {str(e)}"
137
+
138
+ # データベース初期化
139
+ init_db()
140
+
141
+ def load_prompt_from_db(prompt_id):
142
+ """選択されたプロンプトを読み込み"""
143
+ if prompt_id:
144
+ content = get_prompt_content(int(prompt_id))
145
+ return content
146
+ return ""
147
+
148
+ def refresh_prompt_list():
149
+ """プロンプト一覧を更新"""
150
+ prompts = get_prompts()
151
+ choices = []
152
+ for prompt in prompts:
153
+ id_, title, url, created_at = prompt
154
+ display_text = f"[{id_}] {title} ({created_at[:10]})"
155
+ choices.append((display_text, str(id_)))
156
+ return gr.Dropdown(choices=choices, label="📋 保存済みプロンプト一覧", value=None)
157
+
158
+ # Gradioインターフェース作成
159
+ with gr.Blocks(title="🚀 プロンプト管理 & コード生成") as gradio_interface:
160
+ gr.Markdown("# 🚀 プロンプト管理 & ドキュメントからコード生成")
161
+
162
+ with gr.Tabs():
163
+ # タブ1: プロンプト管理
164
+ with gr.TabItem("📝 プロンプト管理"):
165
+ gr.Markdown("## プロンプトの保存・管理")
166
+
167
+ with gr.Row():
168
+ with gr.Column(scale=1):
169
+ # プロンプト保存フォーム
170
+ save_title = gr.Textbox(label="📋 タイトル", placeholder="例: FastAPI + Gradio作成プロンプト")
171
+ save_url = gr.Textbox(label="🔗 参考URL (任意)", placeholder="https://example.com")
172
+ save_content = gr.Textbox(
173
+ label="📝 プロンプト内容",
174
+ lines=10,
175
+ placeholder="プロンプトの内容を入力してください..."
176
+ )
177
+ save_btn = gr.Button("💾 プロンプトを保存", variant="primary")
178
+ save_status = gr.Textbox(label="保存結果", interactive=False)
179
+
180
+ with gr.Column(scale=1):
181
+ # プロンプト一覧
182
+ prompt_dropdown = gr.Dropdown(
183
+ choices=[],
184
+ label="📋 保存済みプロンプト一覧",
185
+ interactive=True
186
+ )
187
+ refresh_btn = gr.Button("🔄 一覧を更新")
188
+ load_btn = gr.Button("📥 選択したプロンプトを読み込み", variant="secondary")
189
+ delete_btn = gr.Button("🗑️ 選択したプロンプトを削除", variant="stop")
190
+ delete_status = gr.Textbox(label="削除結果", interactive=False)
191
+
192
+ # タブ2: コード生成
193
+ with gr.TabItem("⚡ コード生成"):
194
+ gr.Markdown("## ドキュメントからコード生成")
195
+
196
+ with gr.Row():
197
+ with gr.Column():
198
+ # ファイルアップロード
199
+ input_file = gr.File(label="📄 ドキュメントファイル")
200
+
201
+ # プロンプト表示・編集エリア
202
+ current_prompt = gr.Textbox(
203
+ label="📝 現在のプロンプト",
204
+ lines=15,
205
+ value="",
206
+ placeholder="上のタブでプロンプトを選択するか、直接入力してください..."
207
+ )
208
+
209
+ with gr.Column():
210
+ # 生成設定
211
+ folder_name = gr.Textbox(label="📁 出力フォルダ名", value="generated_code")
212
+ github_token = gr.Textbox(label="🔑 GitHub Token (任意)", type="password", value="")
213
+
214
+ # 生成ボタン
215
+ generate_btn = gr.Button("🚀 コード生成実行", variant="primary", size="lg")
216
+
217
+ # 結果表示
218
+ result_output = gr.Textbox(label="📤 生成結果", lines=10, interactive=False)
219
+
220
+ # イベントハンドラー
221
+ def handle_save_prompt(title, url, content):
222
+ if not title.strip() or not content.strip():
223
+ return "❌ タイトルとプロンプト内容は必須です"
224
+ return save_prompt(title, url, content)
225
+
226
+ def handle_refresh_list():
227
+ prompts = get_prompts()
228
+ choices = []
229
+ for prompt in prompts:
230
+ id_, title, url, created_at = prompt
231
+ display_text = f"[{id_}] {title} ({created_at[:10]})"
232
+ choices.append((display_text, str(id_)))
233
+ return gr.Dropdown(choices=choices, value=None)
234
+
235
+ def handle_load_prompt(selected_prompt):
236
+ if selected_prompt:
237
+ prompt_id = selected_prompt.split(']')[0][1:] # [1] から ] までを取得してIDを抽出
238
+ content = get_prompt_content(int(prompt_id))
239
+ return content
240
+ return ""
241
+
242
+ def handle_delete_prompt(selected_prompt):
243
+ if selected_prompt:
244
+ prompt_id = selected_prompt.split(']')[0][1:] # IDを抽出
245
+ return delete_prompt(int(prompt_id))
246
+ return "❌ プロンプトが選択されていません"
247
+
248
+ def handle_generate_code(file, prompt, folder, token):
249
+ if not prompt.strip():
250
+ return "❌ プロンプトが入力されていません"
251
+ return process_file(file, prompt, folder, token)
252
+
253
+ # イベント接続
254
+ save_btn.click(
255
+ handle_save_prompt,
256
+ inputs=[save_title, save_url, save_content],
257
+ outputs=[save_status]
258
+ )
259
+
260
+ refresh_btn.click(
261
+ handle_refresh_list,
262
+ outputs=[prompt_dropdown]
263
+ )
264
+
265
+ load_btn.click(
266
+ handle_load_prompt,
267
+ inputs=[prompt_dropdown],
268
+ outputs=[current_prompt]
269
+ )
270
+
271
+ delete_btn.click(
272
+ handle_delete_prompt,
273
+ inputs=[prompt_dropdown],
274
+ outputs=[delete_status]
275
+ )
276
+
277
+ generate_btn.click(
278
+ handle_generate_code,
279
+ inputs=[input_file, current_prompt, folder_name, github_token],
280
+ outputs=[result_output]
281
+ )
282
+
283
+ # ページ読み込み時にプロンプト一覧を初期化
284
+ gradio_interface.load(
285
+ handle_refresh_list,
286
+ outputs=[prompt_dropdown]
287
+ )
contbk/gra_03_programfromdocgas/programfromdocAI_fixed.py ADDED
@@ -0,0 +1,298 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ from mysite.libs.utilities import chat_with_interpreter, completion, process_file, no_process_file
3
+ from interpreter import interpreter
4
+ import mysite.interpreter.interpreter_config # インポートするだけで設定が適用されます
5
+ import sqlite3
6
+ import os
7
+ from datetime import datetime
8
+ from typing import List, Tuple, Optional
9
+
10
+ # データベース設定
11
+ DB_PATH = "prompts.db"
12
+
13
+ def init_db():
14
+ """プロンプトデータベースの初期化"""
15
+ try:
16
+ conn = sqlite3.connect(DB_PATH)
17
+ cursor = conn.cursor()
18
+
19
+ cursor.execute('''
20
+ CREATE TABLE IF NOT EXISTS prompts (
21
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
22
+ title TEXT NOT NULL,
23
+ url TEXT,
24
+ content TEXT NOT NULL,
25
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
26
+ updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
27
+ )
28
+ ''')
29
+
30
+ # デフォルトプロンプトの追加(初回のみ)
31
+ cursor.execute('SELECT COUNT(*) FROM prompts')
32
+ if cursor.fetchone()[0] == 0:
33
+ default_prompt = """# gradio で miiboのナレッジに登録する画面の作成
34
+ gradio_interface interfacec name
35
+
36
+ # fastapi
37
+ gradio apiに接続するAPI
38
+ router で作成
39
+
40
+ 1ファイルで作成
41
+ 仕様書の作成
42
+ plantumlで図にする
43
+
44
+ #sample fastapi
45
+ import requests
46
+ import json
47
+ import os
48
+
49
+ from fastapi import APIRouter, HTTPException
50
+ from gradio_client import Client
51
+
52
+ router = APIRouter(prefix="/gradio", tags=["gradio"])
53
+ @router.get("/route/gradio")
54
+
55
+ def get_senario(id,res):
56
+ table = "LOG"
57
+ client = Client("kenken999/fastapi_django_main_live")
58
+ result = client.predict(
59
+ message="Hello!!",
60
+ request=0.95,
61
+ param_3=512,
62
+ api_name="/chat"
63
+ )
64
+ return result
65
+ """
66
+ cursor.execute(
67
+ 'INSERT INTO prompts (title, url, content) VALUES (?, ?, ?)',
68
+ ('デフォルト:Gradio + FastAPI作成', 'https://example.com', default_prompt)
69
+ )
70
+
71
+ conn.commit()
72
+ conn.close()
73
+ print("✅ データベース初期化完了")
74
+ except Exception as e:
75
+ print(f"❌ データベース初期化エラー: {e}")
76
+
77
+ def save_prompt(title: str, url: str, content: str) -> str:
78
+ """プロンプトを保存"""
79
+ try:
80
+ if not title.strip() or not content.strip():
81
+ return "❌ タイトルとプロンプト内容は必須です"
82
+
83
+ conn = sqlite3.connect(DB_PATH)
84
+ cursor = conn.cursor()
85
+
86
+ cursor.execute(
87
+ 'INSERT INTO prompts (title, url, content) VALUES (?, ?, ?)',
88
+ (title.strip(), url.strip(), content.strip())
89
+ )
90
+
91
+ conn.commit()
92
+ conn.close()
93
+ print(f"✅ プロンプト保存: {title}")
94
+ return f"✅ プロンプト '{title}' を保存しました!"
95
+ except Exception as e:
96
+ print(f"❌ 保存エラー: {e}")
97
+ return f"❌ エラー: {str(e)}"
98
+
99
+ def get_prompts() -> List[Tuple]:
100
+ """全プロンプトを取得"""
101
+ try:
102
+ conn = sqlite3.connect(DB_PATH)
103
+ cursor = conn.cursor()
104
+
105
+ cursor.execute('SELECT id, title, url, created_at FROM prompts ORDER BY created_at DESC')
106
+ prompts = cursor.fetchall()
107
+
108
+ conn.close()
109
+ print(f"✅ プロンプト取得: {len(prompts)}件")
110
+ return prompts
111
+ except Exception as e:
112
+ print(f"❌ プロンプト取得エラー: {e}")
113
+ return []
114
+
115
+ def get_prompt_content(prompt_id: int) -> str:
116
+ """指定IDのプロンプト内容を取得"""
117
+ try:
118
+ conn = sqlite3.connect(DB_PATH)
119
+ cursor = conn.cursor()
120
+
121
+ cursor.execute('SELECT content FROM prompts WHERE id = ?', (prompt_id,))
122
+ result = cursor.fetchone()
123
+
124
+ conn.close()
125
+ return result[0] if result else ""
126
+ except Exception as e:
127
+ print(f"❌ プロンプト内容取得エラー: {e}")
128
+ return ""
129
+
130
+ def delete_prompt(prompt_id: int) -> str:
131
+ """プロンプトを削除"""
132
+ try:
133
+ conn = sqlite3.connect(DB_PATH)
134
+ cursor = conn.cursor()
135
+
136
+ cursor.execute('DELETE FROM prompts WHERE id = ?', (prompt_id,))
137
+
138
+ if cursor.rowcount > 0:
139
+ conn.commit()
140
+ conn.close()
141
+ print(f"✅ プロンプト削除: ID {prompt_id}")
142
+ return "✅ プロンプトを削除しました"
143
+ else:
144
+ conn.close()
145
+ return "❌ プロンプトが見つかりません"
146
+ except Exception as e:
147
+ print(f"❌ 削除エラー: {e}")
148
+ return f"❌ 削除エラー: {str(e)}"
149
+
150
+ # データベース初期化
151
+ print("🗄️ データベースを初期化中...")
152
+ init_db()
153
+
154
+ def refresh_prompt_list():
155
+ """プロンプト一覧を更新"""
156
+ prompts = get_prompts()
157
+ choices = []
158
+ for prompt in prompts:
159
+ id_, title, url, created_at = prompt
160
+ display_text = f"[{id_}] {title} ({created_at[:10]})"
161
+ choices.append((display_text, str(id_)))
162
+ return choices
163
+
164
+ # Gradioインターフェース作成
165
+ with gr.Blocks(title="🚀 プロンプト管理 & コード生成", theme=gr.themes.Soft()) as gradio_interface:
166
+ gr.Markdown("# 🚀 プロンプト管理 & ドキュメントからコード生成")
167
+
168
+ with gr.Tabs():
169
+ # タブ1: プロンプト管理
170
+ with gr.TabItem("📝 プロンプト管理"):
171
+ gr.Markdown("## プロンプトの保存・管理")
172
+
173
+ with gr.Row():
174
+ with gr.Column(scale=1):
175
+ # プロンプト保存フォーム
176
+ save_title = gr.Textbox(label="📋 タイトル", placeholder="例: FastAPI + Gradio作成プロンプト")
177
+ save_url = gr.Textbox(label="🔗 参考URL (任意)", placeholder="https://example.com")
178
+ save_content = gr.Textbox(
179
+ label="📝 プロンプト内容",
180
+ lines=10,
181
+ placeholder="プロンプトの内容を入力してください..."
182
+ )
183
+ save_btn = gr.Button("💾 プロンプトを保存", variant="primary")
184
+ save_status = gr.Textbox(label="保存結果", interactive=False)
185
+
186
+ with gr.Column(scale=1):
187
+ # プロンプト一覧
188
+ prompt_dropdown = gr.Dropdown(
189
+ choices=[],
190
+ label="📋 保存済みプロンプト一覧",
191
+ interactive=True
192
+ )
193
+ refresh_btn = gr.Button("🔄 一覧を更新")
194
+ load_btn = gr.Button("📥 選択したプロンプトを読み込み", variant="secondary")
195
+ delete_btn = gr.Button("🗑️ 選択したプロンプトを削除", variant="stop")
196
+ delete_status = gr.Textbox(label="削除結果", interactive=False)
197
+
198
+ # タブ2: コード生成
199
+ with gr.TabItem("⚡ コード生成"):
200
+ gr.Markdown("## ドキュメントからコード生成")
201
+
202
+ with gr.Row():
203
+ with gr.Column():
204
+ # ファイルアップロード
205
+ input_file = gr.File(label="📄 ドキュメントファイル")
206
+
207
+ # プロンプト表示・編集エリア
208
+ current_prompt = gr.Textbox(
209
+ label="📝 現在のプロンプト",
210
+ lines=15,
211
+ value="",
212
+ placeholder="上のタブでプロンプトを選択するか、直接入力してください..."
213
+ )
214
+
215
+ with gr.Column():
216
+ # 生成設定
217
+ folder_name = gr.Textbox(label="📁 出力フォルダ名", value="generated_code")
218
+ github_token = gr.Textbox(label="🔑 GitHub Token (任意)", type="password", value="")
219
+
220
+ # 生成ボタン
221
+ generate_btn = gr.Button("🚀 コード生成実行", variant="primary", size="lg")
222
+
223
+ # 結果表示
224
+ result_output = gr.Textbox(label="📤 生成結果", lines=10, interactive=False)
225
+
226
+ # イベントハンドラー
227
+ def handle_save_prompt(title, url, content):
228
+ result = save_prompt(title, url, content)
229
+ return result
230
+
231
+ def handle_refresh_list():
232
+ choices = refresh_prompt_list()
233
+ return gr.Dropdown(choices=choices, value=None)
234
+
235
+ def handle_load_prompt(selected_prompt):
236
+ if selected_prompt:
237
+ try:
238
+ prompt_id = selected_prompt.split(']')[0][1:] # [1] から ] までを取得してIDを抽出
239
+ content = get_prompt_content(int(prompt_id))
240
+ return content
241
+ except Exception as e:
242
+ print(f"❌ プロンプト読み込みエラー: {e}")
243
+ return ""
244
+ return ""
245
+
246
+ def handle_delete_prompt(selected_prompt):
247
+ if selected_prompt:
248
+ try:
249
+ prompt_id = selected_prompt.split(']')[0][1:] # IDを抽出
250
+ return delete_prompt(int(prompt_id))
251
+ except Exception as e:
252
+ print(f"❌ プロンプト削除エラー: {e}")
253
+ return f"❌ エラー: {str(e)}"
254
+ return "❌ プロンプトが選択されていません"
255
+
256
+ def handle_generate_code(file, prompt, folder, token):
257
+ if not prompt.strip():
258
+ return "❌ プロンプトが入力されていません"
259
+ try:
260
+ return process_file(file, prompt, folder, token)
261
+ except Exception as e:
262
+ return f"❌ コード生成エラー: {str(e)}"
263
+
264
+ # イベント接続
265
+ save_btn.click(
266
+ handle_save_prompt,
267
+ inputs=[save_title, save_url, save_content],
268
+ outputs=[save_status]
269
+ )
270
+
271
+ refresh_btn.click(
272
+ handle_refresh_list,
273
+ outputs=[prompt_dropdown]
274
+ )
275
+
276
+ load_btn.click(
277
+ handle_load_prompt,
278
+ inputs=[prompt_dropdown],
279
+ outputs=[current_prompt]
280
+ )
281
+
282
+ delete_btn.click(
283
+ handle_delete_prompt,
284
+ inputs=[prompt_dropdown],
285
+ outputs=[delete_status]
286
+ )
287
+
288
+ generate_btn.click(
289
+ handle_generate_code,
290
+ inputs=[input_file, current_prompt, folder_name, github_token],
291
+ outputs=[result_output]
292
+ )
293
+
294
+ # ページ読み込み時にプロンプト一覧を初期化
295
+ gradio_interface.load(
296
+ handle_refresh_list,
297
+ outputs=[prompt_dropdown]
298
+ )
contbk/gra_03_programfromdocs/__init__.py ADDED
File without changes
contbk/gra_03_programfromdocs/lavelo.py ADDED
@@ -0,0 +1,357 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ from mysite.libs.utilities import chat_with_interpreter, completion, process_file,no_process_file
3
+ from interpreter import interpreter
4
+ import mysite.interpreter.interpreter_config # インポートするだけで設定が適用されます
5
+ import duckdb
6
+ import gradio as gr
7
+ import psycopg2
8
+ from dataclasses import dataclass, field
9
+ from typing import List, Optional, Tuple
10
+ from mysite.interpreter.process import no_process_file,process_file,process_nofile
11
+ #from controllers.gra_04_database.rides import test_set_lide
12
+ import requests
13
+ import sqlite3
14
+ import os
15
+ from datetime import datetime
16
+
17
+ # データベース設定
18
+ DB_PATH = "prompts.db"
19
+
20
+ def init_db():
21
+ """プロンプトデータベースの初期化"""
22
+ try:
23
+ conn = sqlite3.connect(DB_PATH)
24
+ cursor = conn.cursor()
25
+
26
+ cursor.execute('''
27
+ CREATE TABLE IF NOT EXISTS prompts (
28
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
29
+ title TEXT NOT NULL,
30
+ url TEXT,
31
+ content TEXT NOT NULL,
32
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
33
+ updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
34
+ )
35
+ ''')
36
+
37
+ # デフォルトプロンプトの追加(初回のみ)
38
+ cursor.execute('SELECT COUNT(*) FROM prompts')
39
+ if cursor.fetchone()[0] == 0:
40
+ default_prompts = [
41
+ ("社員プロフィールシステム", "", val),
42
+ ("FastAPI + SQLAlchemy", "", "FastAPIとSQLAlchemyを使用したAPIの作成\n- ユーザー管理\n- 認証機能\n- CRUD操作"),
43
+ ("Gradio Interface", "", "Gradioインターフェースの作成\n- ファイルアップロード\n- チャット機能\n- データ表示"),
44
+ ]
45
+
46
+ for title, url, content in default_prompts:
47
+ cursor.execute(
48
+ 'INSERT INTO prompts (title, url, content) VALUES (?, ?, ?)',
49
+ (title, url, content)
50
+ )
51
+
52
+ conn.commit()
53
+ conn.close()
54
+ print("✅ プロンプトデータベース初期化完了")
55
+
56
+ except Exception as e:
57
+ print(f"❌ データベース初期化エラー: {e}")
58
+
59
+ def save_prompt(title: str, content: str) -> str:
60
+ """プロンプトを保存"""
61
+ try:
62
+ if not title.strip() or not content.strip():
63
+ return "❌ タイトルと内容は必須です"
64
+
65
+ conn = sqlite3.connect(DB_PATH)
66
+ cursor = conn.cursor()
67
+
68
+ cursor.execute(
69
+ 'INSERT INTO prompts (title, url, content) VALUES (?, ?, ?)',
70
+ (title.strip(), "", content.strip())
71
+ )
72
+
73
+ conn.commit()
74
+ conn.close()
75
+ print(f"✅ プロンプト保存: {title}")
76
+ return f"✅ プロンプト「{title}」を保存しました"
77
+
78
+ except Exception as e:
79
+ print(f"❌ プロンプト保存エラー: {e}")
80
+ return f"❌ 保存エラー: {e}"
81
+
82
+ def get_prompts() -> List[Tuple]:
83
+ """全プロンプトを取得"""
84
+ try:
85
+ conn = sqlite3.connect(DB_PATH)
86
+ cursor = conn.cursor()
87
+
88
+ cursor.execute('SELECT id, title, created_at FROM prompts ORDER BY created_at DESC')
89
+ prompts = cursor.fetchall()
90
+
91
+ conn.close()
92
+ print(f"✅ プロンプト取得: {len(prompts)}件")
93
+ return prompts
94
+ except Exception as e:
95
+ print(f"❌ プロンプト取得エラー: {e}")
96
+ return []
97
+
98
+ def get_prompt_content(prompt_id: int) -> str:
99
+ """指定IDのプロンプト内容を取得"""
100
+ try:
101
+ conn = sqlite3.connect(DB_PATH)
102
+ cursor = conn.cursor()
103
+
104
+ cursor.execute('SELECT content FROM prompts WHERE id = ?', (prompt_id,))
105
+ result = cursor.fetchone()
106
+
107
+ conn.close()
108
+
109
+ if result:
110
+ print(f"✅ プロンプト内容取得: ID {prompt_id}")
111
+ return result[0]
112
+ else:
113
+ print(f"❌ プロンプトが見つかりません: ID {prompt_id}")
114
+ return ""
115
+
116
+ except Exception as e:
117
+ print(f"❌ プロンプト内容取得エラー: {e}")
118
+ return ""
119
+
120
+ def delete_prompt(prompt_id: int) -> str:
121
+ """プロンプトを削除"""
122
+ try:
123
+ conn = sqlite3.connect(DB_PATH)
124
+ cursor = conn.cursor()
125
+
126
+ cursor.execute('DELETE FROM prompts WHERE id = ?', (prompt_id,))
127
+
128
+ if cursor.rowcount > 0:
129
+ conn.commit()
130
+ conn.close()
131
+ print(f"✅ プロンプト削除: ID {prompt_id}")
132
+ return f"✅ プロンプト ID {prompt_id} を削除しました"
133
+ else:
134
+ conn.close()
135
+ return f"❌ プロンプト ID {prompt_id} が見つかりません"
136
+
137
+ except Exception as e:
138
+ print(f"❌ プロンプト削除エラー: {e}")
139
+ return f"❌ 削���エラー: {e}"
140
+
141
+ def update_prompt_display():
142
+ """プロンプト一覧の表示を更新"""
143
+ prompts = get_prompts()
144
+ if prompts:
145
+ # テーブル形式でデータを準備
146
+ table_data = []
147
+ for prompt_id, title, created_at in prompts:
148
+ # 日時の表示を短くする
149
+ date_str = created_at[:16] if created_at else ""
150
+ table_data.append([prompt_id, title, date_str])
151
+ return table_data
152
+ return []
153
+
154
+ val = """
155
+ # 社員がプロフィールを登録・公開し、お互いに参照できるシステム
156
+
157
+ ## 機能
158
+
159
+ ## LINEのクレーム対応システムの作成
160
+ - クレームがあった用語をAPIでナレッジに登録するシステム
161
+ - APIキー agentキーをいれ
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
+ - 表示内容は、`ユーザー名`・`プロフィール`で、`プロフィール`は先頭10文字と三点リーダーを表示する。
194
+ - ユーザー名をクリックすると、そのユーザーのユーザー詳細画面へ遷移する。
195
+ - `チーム一覧へ`をクリックすると、チーム一覧画面へ遷移する。
196
+
197
+ ### ユーザー詳細画面
198
+
199
+ - 特定のユーザーの、`ユーザー名`・`所属チーム`・`プロフィール`・`タグ`が表示される。
200
+ - プロフィールの表示はマークダウンに対応させる。
201
+ - `一覧へ`リンクをクリックすると、ユーザー一覧画面へ遷移する。
202
+
203
+ ## あなたが作成するもの
204
+
205
+ バックエンドのプログラム一式を作成してください。
206
+ フロントエンドのプログラムは不要です。
207
+
208
+ - `/api`ディレクトリ以下に作成。
209
+ - Python/FastAPI/SQLAlchemyを使う。
210
+ - DBはSQLiteを使う。
211
+ - 必要に応じて外部ライブラリを使う。
212
+ - クラウドや外部サービス(外部API)は使わない。
213
+ - .gitignoreを含めること。
214
+ - バックエンド
215
+ @app.post("
216
+ def lumbda_function():
217
+
218
+ gradio_interface でメイン関数から読み込めるようにして
219
+
220
+ googleappsscript
221
+ ラインの画像検索システム
222
+
223
+ ファイルは1ファイルで作成して。
224
+ 1ファイル1機能で難しくしたくない
225
+
226
+ 1,lineからデータがくる
227
+ 2,doPostで取得
228
+ 3.typeがイメージの場合はドライブに保存
229
+ 4,保存したデータをS3にアップロード
230
+ 5.データはシークレットから取得
231
+ 6,plantumlでフローの作成
232
+ 7,システムドキュメントの作成
233
+
234
+ gradio は gradio_interface というBlock名で作成
235
+ fastapiはrouter の作成
236
+
237
+ """
238
+
239
+ def send_to_google_chat(message: str):
240
+ webhook_url = 'https://chat.googleapis.com/v1/spaces/AAAANwDF_KE/messages?key=AIzaSyDdI0hCZtE6vySjMm-WEfRq3CPzqKqqsHI&token=qSigSPSbTINJITgO30iGKnyeY48emcUJd9LST7FBLLY'
241
+ headers = {'Content-Type': 'application/json; charset=UTF-8'}
242
+ data = {'text': message}
243
+ response = requests.post(webhook_url, headers=headers, json=data)
244
+ response.raise_for_status()
245
+
246
+ def process_file_and_notify(*args, **kwargs):
247
+ result = process_nofile(*args, **kwargs)
248
+ send_to_google_chat(result)
249
+
250
+ # プロンプト実行後、内容をデータベースに保存
251
+ try:
252
+ prompt_content = args[0] if args else ""
253
+ if prompt_content.strip():
254
+ # 実行されたプロンプトのタイトルを生成(最初の行または最初の50文字)
255
+ title_lines = prompt_content.strip().split('\n')
256
+ title = title_lines[0][:50] if title_lines[0] else "実行されたプロンプト"
257
+ if title.startswith('#'):
258
+ title = title[1:].strip()
259
+
260
+ save_prompt(f"実行履歴: {title}", prompt_content)
261
+ except Exception as e:
262
+ print(f"実行履歴保存エラー: {e}")
263
+
264
+ return result
265
+
266
+ def load_prompt_to_textbox(evt: gr.SelectData):
267
+ """テーブルクリック時にプロンプト内容をテキストボックスに読み込む"""
268
+ try:
269
+ if evt.index is not None and len(evt.index) >= 2:
270
+ # テーブルの行インデックスから prompt_id を取得
271
+ prompts = get_prompts()
272
+ if evt.index[0] < len(prompts):
273
+ prompt_id = prompts[evt.index[0]][0] # 最初の列がID
274
+ content = get_prompt_content(prompt_id)
275
+ return content
276
+ except Exception as e:
277
+ print(f"プロンプト読み込みエラー: {e}")
278
+ return ""
279
+
280
+ # データベース初期化
281
+ init_db()
282
+
283
+ with gr.Blocks() as gradio_interface:
284
+ gr.Markdown("# プロンプト管理システム")
285
+
286
+ with gr.Row():
287
+ with gr.Column(scale=1):
288
+ gr.Markdown("## 📚 プロンプト一覧")
289
+
290
+ # プロンプト一覧テーブル
291
+ prompt_table = gr.Dataframe(
292
+ headers=["ID", "タイトル", "作成日時"],
293
+ datatype=["number", "str", "str"],
294
+ value=update_prompt_display(),
295
+ interactive=False,
296
+ height=300
297
+ )
298
+
299
+ # 更新ボタン
300
+ refresh_btn = gr.Button("🔄 一覧更新", variant="secondary")
301
+
302
+ # プロンプト保存エリア
303
+ gr.Markdown("## 💾 プロンプト保存")
304
+ with gr.Row():
305
+ save_title = gr.Textbox(label="タイトル", placeholder="プロンプトのタイトルを入力")
306
+ save_btn = gr.Button("💾 保存", variant="primary")
307
+ save_result = gr.Textbox(label="保存結果", interactive=False)
308
+
309
+ with gr.Column(scale=2):
310
+ gr.Markdown("## ⚡ プロンプト実行")
311
+
312
+ # メインのプロンプト入力エリア
313
+ prompt_input = gr.Textbox(
314
+ label="プロンプト内容",
315
+ lines=15,
316
+ value=val,
317
+ placeholder="プロンプトを入力するか、左の一覧からクリックして選択してください"
318
+ )
319
+
320
+ with gr.Row():
321
+ folder_name = gr.Textbox(label="フォルダ名", value="test_folders")
322
+ github_token = gr.Textbox(label="GitHub Token", value="***********************", type="password")
323
+
324
+ execute_btn = gr.Button("🚀 実行", variant="primary", size="lg")
325
+ result_output = gr.Textbox(label="実行結果", lines=10, interactive=False)
326
+
327
+ # イベントハンドラー
328
+ prompt_table.select(
329
+ fn=load_prompt_to_textbox,
330
+ outputs=prompt_input
331
+ )
332
+
333
+ refresh_btn.click(
334
+ fn=update_prompt_display,
335
+ outputs=prompt_table
336
+ )
337
+
338
+ save_btn.click(
339
+ fn=lambda title, content: save_prompt(title, content),
340
+ inputs=[save_title, prompt_input],
341
+ outputs=save_result
342
+ ).then(
343
+ fn=update_prompt_display,
344
+ outputs=prompt_table
345
+ ).then(
346
+ fn=lambda: "",
347
+ outputs=save_title
348
+ )
349
+
350
+ execute_btn.click(
351
+ fn=process_file_and_notify,
352
+ inputs=[prompt_input, folder_name, github_token],
353
+ outputs=result_output
354
+ ).then(
355
+ fn=update_prompt_display,
356
+ outputs=prompt_table
357
+ )
contbk/gra_10_frontend/__init__.py ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ # Frontend Framework Generator
2
+ # This module automatically generates React and Vue.js components based on AI instructions
contbk/gra_10_frontend/frontend_generator.py ADDED
@@ -0,0 +1,442 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import os
3
+ import json
4
+ from pathlib import Path
5
+
6
+ def generate_react_component(component_name, props_description, styling_preference):
7
+ """
8
+ React コンポーネントを動的生成する関数
9
+ """
10
+ if not component_name:
11
+ return "コンポーネント名を入力してください", "", ""
12
+
13
+ # React コンポーネントの基本構造を生成
14
+ react_jsx = f"""import React, {{ useState, useEffect }} from 'react';
15
+ import './{{component_name}}.css';
16
+
17
+ const {component_name} = (props) => {{
18
+ const [data, setData] = useState(null);
19
+ const [loading, setLoading] = useState(false);
20
+
21
+ useEffect(() => {{
22
+ // コンポーネント初期化処理
23
+ console.log('{component_name} component mounted');
24
+ }}, []);
25
+
26
+ const handleAction = () => {{
27
+ setLoading(true);
28
+ // AI が生成したアクション処理
29
+ setTimeout(() => {{
30
+ setLoading(false);
31
+ console.log('Action completed');
32
+ }}, 1000);
33
+ }};
34
+
35
+ return (
36
+ <div className="{component_name.lower()}-container">
37
+ <div className="header">
38
+ <h2>{component_name}</h2>
39
+ <p>{{props_description}}</p>
40
+ </div>
41
+
42
+ <div className="content">
43
+ {{loading ? (
44
+ <div className="loading">Loading...</div>
45
+ ) : (
46
+ <div className="main-content">
47
+ <button
48
+ onClick={{handleAction}}
49
+ className="action-button"
50
+ disabled={{loading}}
51
+ >
52
+ Execute Action
53
+ </button>
54
+ </div>
55
+ )}}
56
+ </div>
57
+ </div>
58
+ );
59
+ }};
60
+
61
+ export default {component_name};"""
62
+
63
+ # CSS スタイルを生成
64
+ css_styles = f""".{component_name.lower()}-container {{
65
+ max-width: 800px;
66
+ margin: 0 auto;
67
+ padding: 20px;
68
+ border-radius: 8px;
69
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
70
+ background: {get_background_color(styling_preference)};
71
+ }}
72
+
73
+ .header {{
74
+ text-align: center;
75
+ margin-bottom: 30px;
76
+ }}
77
+
78
+ .header h2 {{
79
+ color: {get_text_color(styling_preference)};
80
+ font-size: 2rem;
81
+ margin-bottom: 10px;
82
+ }}
83
+
84
+ .header p {{
85
+ color: {get_secondary_color(styling_preference)};
86
+ font-size: 1.1rem;
87
+ }}
88
+
89
+ .content {{
90
+ display: flex;
91
+ flex-direction: column;
92
+ align-items: center;
93
+ }}
94
+
95
+ .action-button {{
96
+ background: {get_primary_color(styling_preference)};
97
+ color: white;
98
+ border: none;
99
+ padding: 12px 24px;
100
+ border-radius: 6px;
101
+ font-size: 1rem;
102
+ cursor: pointer;
103
+ transition: all 0.3s ease;
104
+ }}
105
+
106
+ .action-button:hover {{
107
+ transform: translateY(-2px);
108
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
109
+ }}
110
+
111
+ .action-button:disabled {{
112
+ opacity: 0.6;
113
+ cursor: not-allowed;
114
+ }}
115
+
116
+ .loading {{
117
+ padding: 20px;
118
+ text-align: center;
119
+ font-style: italic;
120
+ color: {get_secondary_color(styling_preference)};
121
+ }}
122
+
123
+ @media (max-width: 768px) {{
124
+ .{component_name.lower()}-container {{
125
+ margin: 10px;
126
+ padding: 15px;
127
+ }}
128
+
129
+ .header h2 {{
130
+ font-size: 1.5rem;
131
+ }}
132
+ }}"""
133
+
134
+ # パッケージ.json の設定
135
+ package_json = {
136
+ "name": f"{component_name.lower()}-component",
137
+ "version": "1.0.0",
138
+ "description": f"AI generated React component: {component_name}",
139
+ "main": f"{component_name}.jsx",
140
+ "dependencies": {
141
+ "react": "^18.2.0",
142
+ "react-dom": "^18.2.0"
143
+ },
144
+ "devDependencies": {
145
+ "@vitejs/plugin-react": "^4.0.0",
146
+ "vite": "^4.0.0"
147
+ },
148
+ "scripts": {
149
+ "dev": "vite",
150
+ "build": "vite build",
151
+ "preview": "vite preview"
152
+ },
153
+ "ai_generated": True,
154
+ "created_by": "AI Auto-Generation System",
155
+ "component_description": props_description
156
+ }
157
+
158
+ return (
159
+ f"✅ React component '{component_name}' generated successfully!",
160
+ react_jsx,
161
+ css_styles,
162
+ json.dumps(package_json, indent=2)
163
+ )
164
+
165
+ def get_background_color(style):
166
+ styles = {
167
+ "Modern": "#ffffff",
168
+ "Dark": "#1a1a1a",
169
+ "Colorful": "#f0f8ff",
170
+ "Minimal": "#fafafa"
171
+ }
172
+ return styles.get(style, "#ffffff")
173
+
174
+ def get_text_color(style):
175
+ styles = {
176
+ "Modern": "#2c3e50",
177
+ "Dark": "#ffffff",
178
+ "Colorful": "#2c3e50",
179
+ "Minimal": "#333333"
180
+ }
181
+ return styles.get(style, "#2c3e50")
182
+
183
+ def get_primary_color(style):
184
+ styles = {
185
+ "Modern": "#3498db",
186
+ "Dark": "#e74c3c",
187
+ "Colorful": "#9b59b6",
188
+ "Minimal": "#95a5a6"
189
+ }
190
+ return styles.get(style, "#3498db")
191
+
192
+ def get_secondary_color(style):
193
+ styles = {
194
+ "Modern": "#7f8c8d",
195
+ "Dark": "#bdc3c7",
196
+ "Colorful": "#34495e",
197
+ "Minimal": "#666666"
198
+ }
199
+ return styles.get(style, "#7f8c8d")
200
+
201
+ def generate_vue_component(component_name, props_description, styling_preference):
202
+ """
203
+ Vue.js コンポーネントを動的生成する関数
204
+ """
205
+ if not component_name:
206
+ return "コンポーネント名を入力してください", ""
207
+
208
+ vue_component = f"""<template>
209
+ <div class="{component_name.lower()}-container">
210
+ <div class="header">
211
+ <h2>{component_name}</h2>
212
+ <p>{props_description}</p>
213
+ </div>
214
+
215
+ <div class="content">
216
+ <div v-if="loading" class="loading">
217
+ Loading...
218
+ </div>
219
+ <div v-else class="main-content">
220
+ <button
221
+ @click="handleAction"
222
+ class="action-button"
223
+ :disabled="loading"
224
+ >
225
+ Execute Action
226
+ </button>
227
+
228
+ <div v-if="result" class="result">
229
+ {{{{ result }}}}
230
+ </div>
231
+ </div>
232
+ </div>
233
+ </div>
234
+ </template>
235
+
236
+ <script>
237
+ import {{ ref, onMounted }} from 'vue'
238
+
239
+ export default {{
240
+ name: '{component_name}',
241
+ props: {{
242
+ initialData: {{
243
+ type: Object,
244
+ default: () => ({{}})
245
+ }}
246
+ }},
247
+ setup(props) {{
248
+ const loading = ref(false)
249
+ const result = ref(null)
250
+ const data = ref(props.initialData)
251
+
252
+ const handleAction = async () => {{
253
+ loading.value = true
254
+ try {{
255
+ // AI が生成したアクション処理
256
+ await new Promise(resolve => setTimeout(resolve, 1000))
257
+ result.value = 'Action completed successfully!'
258
+ }} catch (error) {{
259
+ result.value = 'Action failed: ' + error.message
260
+ }} finally {{
261
+ loading.value = false
262
+ }}
263
+ }}
264
+
265
+ onMounted(() => {{
266
+ console.log('{component_name} component mounted')
267
+ }})
268
+
269
+ return {{
270
+ loading,
271
+ result,
272
+ data,
273
+ handleAction
274
+ }}
275
+ }}
276
+ }}
277
+ </script>
278
+
279
+ <style scoped>
280
+ .{component_name.lower()}-container {{
281
+ max-width: 800px;
282
+ margin: 0 auto;
283
+ padding: 20px;
284
+ border-radius: 8px;
285
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
286
+ background: {get_background_color(styling_preference)};
287
+ }}
288
+
289
+ .header {{
290
+ text-align: center;
291
+ margin-bottom: 30px;
292
+ }}
293
+
294
+ .header h2 {{
295
+ color: {get_text_color(styling_preference)};
296
+ font-size: 2rem;
297
+ margin-bottom: 10px;
298
+ }}
299
+
300
+ .header p {{
301
+ color: {get_secondary_color(styling_preference)};
302
+ font-size: 1.1rem;
303
+ }}
304
+
305
+ .content {{
306
+ display: flex;
307
+ flex-direction: column;
308
+ align-items: center;
309
+ }}
310
+
311
+ .action-button {{
312
+ background: {get_primary_color(styling_preference)};
313
+ color: white;
314
+ border: none;
315
+ padding: 12px 24px;
316
+ border-radius: 6px;
317
+ font-size: 1rem;
318
+ cursor: pointer;
319
+ transition: all 0.3s ease;
320
+ }}
321
+
322
+ .action-button:hover {{
323
+ transform: translateY(-2px);
324
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
325
+ }}
326
+
327
+ .action-button:disabled {{
328
+ opacity: 0.6;
329
+ cursor: not-allowed;
330
+ }}
331
+
332
+ .loading {{
333
+ padding: 20px;
334
+ text-align: center;
335
+ font-style: italic;
336
+ color: {get_secondary_color(styling_preference)};
337
+ }}
338
+
339
+ .result {{
340
+ margin-top: 20px;
341
+ padding: 15px;
342
+ border-radius: 6px;
343
+ background: rgba(52, 152, 219, 0.1);
344
+ color: {get_text_color(styling_preference)};
345
+ text-align: center;
346
+ }}
347
+
348
+ @media (max-width: 768px) {{
349
+ .{component_name.lower()}-container {{
350
+ margin: 10px;
351
+ padding: 15px;
352
+ }}
353
+
354
+ .header h2 {{
355
+ font-size: 1.5rem;
356
+ }}
357
+ }}
358
+ </style>"""
359
+
360
+ return f"✅ Vue component '{component_name}' generated successfully!", vue_component
361
+
362
+ # AI指示による自動検出のための必須オブジェクト
363
+ with gr.Blocks(title="Frontend Framework Generator") as gradio_interface:
364
+ gr.Markdown("# 🚀 Frontend Framework Auto-Generator")
365
+ gr.Markdown("AIがReact・Vue.jsコンポーネントを自動生成します")
366
+
367
+ with gr.Tab("⚛️ React Generator"):
368
+ gr.Markdown("### React Component Generator")
369
+
370
+ with gr.Row():
371
+ react_name = gr.Textbox(
372
+ label="Component Name",
373
+ placeholder="MyAwesomeComponent",
374
+ value="WeatherWidget"
375
+ )
376
+ react_props = gr.Textbox(
377
+ label="Component Description",
378
+ placeholder="天気情報を表示するウィジェット",
379
+ value="Interactive weather information display"
380
+ )
381
+ react_style = gr.Dropdown(
382
+ label="Styling Preference",
383
+ choices=["Modern", "Dark", "Colorful", "Minimal"],
384
+ value="Modern"
385
+ )
386
+
387
+ react_generate_btn = gr.Button("Generate React Component", variant="primary")
388
+
389
+ with gr.Row():
390
+ react_status = gr.Textbox(label="Generation Status", interactive=False)
391
+
392
+ with gr.Tabs():
393
+ with gr.Tab("JSX Code"):
394
+ react_jsx_output = gr.Code(label="React Component", language="javascript")
395
+ with gr.Tab("CSS Styles"):
396
+ react_css_output = gr.Code(label="CSS Styles", language="css")
397
+ with gr.Tab("Package.json"):
398
+ react_package_output = gr.Code(label="Package Configuration", language="json")
399
+
400
+ with gr.Tab("🔧 Vue.js Generator"):
401
+ gr.Markdown("### Vue.js Component Generator")
402
+
403
+ with gr.Row():
404
+ vue_name = gr.Textbox(
405
+ label="Component Name",
406
+ placeholder="MyVueComponent",
407
+ value="DataDashboard"
408
+ )
409
+ vue_props = gr.Textbox(
410
+ label="Component Description",
411
+ placeholder="データ可視化ダッシュボード",
412
+ value="Interactive data visualization dashboard"
413
+ )
414
+ vue_style = gr.Dropdown(
415
+ label="Styling Preference",
416
+ choices=["Modern", "Dark", "Colorful", "Minimal"],
417
+ value="Modern"
418
+ )
419
+
420
+ vue_generate_btn = gr.Button("Generate Vue Component", variant="primary")
421
+
422
+ with gr.Row():
423
+ vue_status = gr.Textbox(label="Generation Status", interactive=False)
424
+
425
+ vue_output = gr.Code(label="Vue.js Component", language="javascript")
426
+
427
+ # Event bindings
428
+ react_generate_btn.click(
429
+ fn=generate_react_component,
430
+ inputs=[react_name, react_props, react_style],
431
+ outputs=[react_status, react_jsx_output, react_css_output, react_package_output]
432
+ )
433
+
434
+ vue_generate_btn.click(
435
+ fn=generate_vue_component,
436
+ inputs=[vue_name, vue_props, vue_style],
437
+ outputs=[vue_status, vue_output]
438
+ )
439
+
440
+ # テスト用のスタンドアロン実行(コメントアウト - 自動検出システムとの競合を防ぐため)
441
+ # if __name__ == "__main__":
442
+ # gradio_interface.launch()
contbk/gra_11_multimodal/__init__.py ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ # Multimodal UI Generator
2
+ # This module converts images to frontend code using AI analysis
contbk/gra_11_multimodal/image_to_ui.py ADDED
@@ -0,0 +1,1421 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import base64
3
+ import io
4
+ from PIL import Image
5
+ import json
6
+ import re
7
+
8
+ def analyze_image_and_generate_ui(image, description, framework_choice):
9
+ """
10
+ アップロードされた画像を解析してUIコードを自動生成
11
+ """
12
+ if image is None:
13
+ return "画像をアップロードしてください", "", "", ""
14
+
15
+ # 画像解析(実際のAIモデルの代わりにルールベースで実装)
16
+ analysis_result = analyze_ui_elements(image)
17
+
18
+ # 選択されたフレームワークに応じてコード生成
19
+ if framework_choice == "React":
20
+ status, jsx_code, css_code = generate_react_from_analysis(analysis_result, description)
21
+ return status, jsx_code, css_code, ""
22
+ elif framework_choice == "Vue":
23
+ status, vue_code = generate_vue_from_analysis(analysis_result, description)
24
+ return status, vue_code, "", ""
25
+ elif framework_choice == "HTML/CSS":
26
+ status, html_code, css_code = generate_html_from_analysis(analysis_result, description)
27
+ return status, html_code, css_code, ""
28
+ else:
29
+ return "フレームワークを選択してください", "", "", ""
30
+
31
+ def analyze_ui_elements(image):
32
+ """
33
+ 画像からUI要素を動的に検出・分析
34
+ 実際の画像コンテンツに基づいてUIパターンを決定
35
+ """
36
+ import numpy as np
37
+ from collections import Counter
38
+
39
+ width, height = image.size
40
+
41
+ # より詳細な画像分析
42
+ analysis = {
43
+ "image_size": (width, height),
44
+ "aspect_ratio": width / height,
45
+ "detected_elements": [],
46
+ "color_scheme": "modern",
47
+ "layout_type": "grid" if width > height else "vertical"
48
+ }
49
+
50
+ # カラーパレット抽出
51
+ image_array = np.array(image)
52
+ if len(image_array.shape) == 3:
53
+ # カラー画像の場合
54
+ pixels = image_array.reshape(-1, 3)
55
+ # 主要な色を抽出(K-means的なアプローチの簡易版)
56
+ unique_colors = []
57
+ for i in range(0, len(pixels), max(1, len(pixels)//100)): # サンプリング
58
+ color = pixels[i]
59
+ unique_colors.append(tuple(color))
60
+
61
+ color_counts = Counter(unique_colors)
62
+ dominant_colors = color_counts.most_common(5)
63
+
64
+ # 主要色に基づいてテーマ決定
65
+ avg_r = sum([color[0][0] * color[1] for color in dominant_colors]) / sum([color[1] for color in dominant_colors])
66
+ avg_g = sum([color[0][1] * color[1] for color in dominant_colors]) / sum([color[1] for color in dominant_colors])
67
+ avg_b = sum([color[0][2] * color[1] for color in dominant_colors]) / sum([color[1] for color in dominant_colors])
68
+
69
+ # HSVベースの分析
70
+ max_rgb = max(avg_r, avg_g, avg_b)
71
+ min_rgb = min(avg_r, avg_g, avg_b)
72
+ saturation = (max_rgb - min_rgb) / max_rgb if max_rgb > 0 else 0
73
+
74
+ else:
75
+ # グレースケール画像
76
+ avg_r = avg_g = avg_b = np.mean(image_array)
77
+ saturation = 0
78
+
79
+ # 明度計算
80
+ brightness = (avg_r + avg_g + avg_b) / 3
81
+
82
+ # 画像の複雑さを分析(エッジ検出的アプローチ)
83
+ grayscale = image.convert('L')
84
+ gray_array = np.array(grayscale)
85
+
86
+ # 簡易エッジ検出
87
+ edges = 0
88
+ for i in range(1, gray_array.shape[0]-1):
89
+ for j in range(1, gray_array.shape[1]-1):
90
+ grad_x = abs(int(gray_array[i+1, j]) - int(gray_array[i-1, j]))
91
+ grad_y = abs(int(gray_array[i, j+1]) - int(gray_array[i, j-1]))
92
+ if grad_x + grad_y > 50: # エッジ閾値
93
+ edges += 1
94
+
95
+ complexity = edges / (width * height)
96
+
97
+ # 動的テーマ決定
98
+ if brightness < 60:
99
+ analysis["theme"] = "dark"
100
+ analysis["bg_color"] = f"#1a1a1a"
101
+ analysis["text_color"] = "#ffffff"
102
+ analysis["accent_color"] = f"#{int(avg_r*0.8):02x}{int(avg_g*0.8):02x}{int(avg_b*0.8):02x}"
103
+ elif brightness > 200:
104
+ analysis["theme"] = "light"
105
+ analysis["bg_color"] = "#ffffff"
106
+ analysis["text_color"] = "#333333"
107
+ analysis["accent_color"] = f"#{int(avg_r*0.6):02x}{int(avg_g*0.6):02x}{int(avg_b*0.6):02x}"
108
+ else:
109
+ analysis["theme"] = "modern"
110
+ analysis["bg_color"] = f"#{int(255-brightness*0.3):02x}{int(255-brightness*0.3):02x}{int(255-brightness*0.2):02x}"
111
+ analysis["text_color"] = "#2c3e50"
112
+ analysis["accent_color"] = f"#{int(avg_r):02x}{int(avg_g):02x}{int(avg_b):02x}"
113
+
114
+ # 複雑さに基づくレイアウト決定
115
+ if complexity > 0.1:
116
+ analysis["layout_type"] = "complex_grid"
117
+ analysis["components"] = ["header", "sidebar", "main_content", "footer", "cards"]
118
+ elif complexity > 0.05:
119
+ analysis["layout_type"] = "standard_grid"
120
+ analysis["components"] = ["header", "navigation", "content_grid", "footer"]
121
+ else:
122
+ analysis["layout_type"] = "simple"
123
+ analysis["components"] = ["header", "main_content", "actions"]
124
+
125
+ # 色の彩度に基づく動的要素決定
126
+ if saturation > 0.5:
127
+ analysis["ui_style"] = "vibrant"
128
+ analysis["has_animations"] = True
129
+ analysis["gradient_style"] = "bold"
130
+ elif saturation > 0.2:
131
+ analysis["ui_style"] = "balanced"
132
+ analysis["has_animations"] = True
133
+ analysis["gradient_style"] = "subtle"
134
+ else:
135
+ analysis["ui_style"] = "minimal"
136
+ analysis["has_animations"] = False
137
+ analysis["gradient_style"] = "monochrome"
138
+
139
+ # アスペクト比に基づくコンポーネント配置
140
+ if width > height * 1.5:
141
+ analysis["layout_orientation"] = "horizontal"
142
+ analysis["nav_style"] = "horizontal"
143
+ elif height > width * 1.5:
144
+ analysis["layout_orientation"] = "vertical"
145
+ analysis["nav_style"] = "vertical"
146
+ else:
147
+ analysis["layout_orientation"] = "square"
148
+ analysis["nav_style"] = "compact"
149
+
150
+ # 動的UI要素リスト生成
151
+ base_elements = ["header", "navigation"]
152
+
153
+ if complexity > 0.08:
154
+ base_elements.extend(["sidebar", "search", "filters"])
155
+ if saturation > 0.3:
156
+ base_elements.extend(["hero_section", "call_to_action"])
157
+ if width > 800:
158
+ base_elements.extend(["content_grid", "cards"])
159
+ else:
160
+ base_elements.extend(["content_list"])
161
+
162
+ analysis["detected_elements"] = [
163
+ {"type": elem, "confidence": min(0.9, complexity + saturation + 0.3)}
164
+ for elem in base_elements
165
+ ]
166
+
167
+ # メタデータ追加
168
+ analysis["complexity_score"] = complexity
169
+ analysis["saturation_score"] = saturation
170
+ analysis["brightness_score"] = brightness / 255
171
+ analysis["dominant_color"] = f"#{int(avg_r):02x}{int(avg_g):02x}{int(avg_b):02x}"
172
+
173
+ return analysis
174
+
175
+ def generate_card_components(analysis, card_count=4):
176
+ """動的なカードコンポーネント文字列を生成"""
177
+ theme = analysis.get("theme", "modern")
178
+ complexity = analysis.get("complexity_score", 0.05)
179
+ ui_style = analysis.get("ui_style", "minimal")
180
+ accent_color = analysis.get("accent_color", "#007bff")
181
+
182
+ cards = []
183
+
184
+ # 複雑さに基づいてカードの内容を動的生成
185
+ card_types = [
186
+ {
187
+ "title": f"{theme.title()} Dashboard",
188
+ "description": f"Image complexity: {complexity:.2f} - {ui_style} style interface",
189
+ "action": "dashboard",
190
+ "icon": "📊"
191
+ },
192
+ {
193
+ "title": "Smart Analytics",
194
+ "description": f"AI-detected layout: {analysis.get('layout_type', 'grid')}",
195
+ "action": "analytics",
196
+ "icon": "🔍"
197
+ },
198
+ {
199
+ "title": "Dynamic Controls",
200
+ "description": f"Theme: {theme} | Animations: {analysis.get('has_animations', False)}",
201
+ "action": "controls",
202
+ "icon": "⚙️"
203
+ },
204
+ {
205
+ "title": "Visual Elements",
206
+ "description": f"Dominant color: {analysis.get('dominant_color', '#333')}",
207
+ "action": "visual",
208
+ "icon": "🎨"
209
+ },
210
+ {
211
+ "title": "User Interface",
212
+ "description": f"Navigation: {analysis.get('nav_style', 'horizontal')}",
213
+ "action": "interface",
214
+ "icon": "🖥️"
215
+ },
216
+ {
217
+ "title": "Content Layout",
218
+ "description": f"Aspect ratio: {analysis.get('aspect_ratio', 1):.2f}",
219
+ "action": "layout",
220
+ "icon": "📱"
221
+ }
222
+ ]
223
+
224
+ for i in range(min(card_count, len(card_types))):
225
+ card = card_types[i]
226
+ card_jsx = f"""
227
+ <div className="feature-card dynamic-card-{i}">
228
+ <div className="card-icon">{card['icon']}</div>
229
+ <h3>{card['title']}</h3>
230
+ <p>{card['description']}</p>
231
+ <button
232
+ onClick={{() => handleAction('{card['action']}')}}
233
+ disabled={{isLoading}}
234
+ className="action-button"
235
+ style={{{{background: '{accent_color}'}}}}
236
+ >
237
+ {{isLoading ? 'Processing...' : 'Execute'}}
238
+ </button>
239
+ </div>"""
240
+ cards.append(card_jsx)
241
+
242
+ return ''.join(cards)
243
+
244
+ def generate_react_from_analysis(analysis, description):
245
+ """
246
+ 分析結果からReactコンポーネントを動的生成
247
+ """
248
+ component_name = "ImageGeneratedComponent"
249
+
250
+ # 分析結果から動的値を取得
251
+ theme = analysis.get("theme", "modern")
252
+ bg_color = analysis.get("bg_color", "#f8f9fa")
253
+ text_color = analysis.get("text_color", "#333333")
254
+ accent_color = analysis.get("accent_color", "#007bff")
255
+ ui_style = analysis.get("ui_style", "minimal")
256
+ has_animations = analysis.get("has_animations", False)
257
+ complexity = analysis.get("complexity_score", 0.05)
258
+ layout_type = analysis.get("layout_type", "grid")
259
+
260
+ # 動的グラデーション
261
+ gradient_bg = f"linear-gradient(135deg, {accent_color}, {bg_color})"
262
+ if theme == "dark":
263
+ gradient_bg = f"linear-gradient(135deg, #2c3e50, #34495e)"
264
+ elif theme == "light":
265
+ gradient_bg = f"linear-gradient(135deg, #ecf0f1, #bdc3c7)"
266
+
267
+ # 複雑さに基づくレイアウト決定
268
+ grid_columns = "repeat(auto-fit, minmax(300px, 1fr))" if complexity > 0.1 else "repeat(auto-fit, minmax(250px, 1fr))"
269
+ card_count = 6 if complexity > 0.08 else 4 if complexity > 0.05 else 2
270
+
271
+ # 動的カードコンポーネント生成
272
+ dynamic_cards = generate_card_components(analysis, card_count)
273
+
274
+ # アニメーション用CSS
275
+ animation_styles = ""
276
+ if has_animations:
277
+ animation_styles = """
278
+ @keyframes fadeInUp {
279
+ from { opacity: 0; transform: translateY(30px); }
280
+ to { opacity: 1; transform: translateY(0); }
281
+ }
282
+ @keyframes slideInLeft {
283
+ from { opacity: 0; transform: translateX(-50px); }
284
+ to { opacity: 1; transform: translateX(0); }
285
+ }
286
+ .animate-fade { animation: fadeInUp 0.6s ease-out; }
287
+ .animate-slide { animation: slideInLeft 0.4s ease-out; }
288
+ """
289
+
290
+ jsx_template = f"""import React, {{ useState, useEffect }} from 'react';
291
+ import './ImageGeneratedComponent.css';
292
+
293
+ const {component_name} = () => {{
294
+ const [activeTab, setActiveTab] = useState('home');
295
+ const [isLoading, setIsLoading] = useState(false);
296
+ const [analysisData, setAnalysisData] = useState(null);
297
+
298
+ useEffect(() => {{
299
+ // 画像分析データをシミュレート
300
+ setAnalysisData({{
301
+ theme: '{theme}',
302
+ complexity: {complexity:.3f},
303
+ uiStyle: '{ui_style}',
304
+ layoutType: '{layout_type}',
305
+ dominantColor: '{analysis.get("dominant_color", "#333")}',
306
+ hasAnimations: {str(has_animations).lower()}
307
+ }});
308
+ }}, []);
309
+
310
+ const handleAction = (action) => {{
311
+ setIsLoading(true);
312
+ console.log(`Executing AI-detected action: ${{action}}`);
313
+
314
+ // AIが画像から推定したアクション処理
315
+ setTimeout(() => {{
316
+ setIsLoading(false);
317
+ console.log(`Action completed: ${{action}}`);
318
+ }}, 1000 + Math.random() * 2000);
319
+ }};
320
+
321
+ const tabs = ['home', 'features', 'analytics', 'settings'];
322
+
323
+ return (
324
+ <div className="image-generated-container">
325
+ <header className="app-header {('animate-fade' if has_animations else '')}">
326
+ <h1>AI Generated {theme.title()} UI</h1>
327
+ <p className="description">{description}</p>
328
+ {{analysisData && (
329
+ <div className="analysis-info">
330
+ <span>Complexity: {complexity:.2f}</span>
331
+ <span>Style: {ui_style}</span>
332
+ <span>Layout: {layout_type}</span>
333
+ </div>
334
+ )}}
335
+ </header>
336
+
337
+ <nav className="app-navigation {('animate-slide' if has_animations else '')}">
338
+ {{tabs.map(tab => (
339
+ <button
340
+ key={{tab}}
341
+ onClick={{() => setActiveTab(tab)}}
342
+ className={{`nav-button ${{activeTab === tab ? 'active' : ''}}`}}
343
+ >
344
+ {{tab.charAt(0).toUpperCase() + tab.slice(1)}}
345
+ </button>
346
+ ))}}
347
+ </nav>
348
+
349
+ <main className="app-main">
350
+ <div className="content-grid" style={{{{
351
+ gridTemplateColumns: '{grid_columns}',
352
+ gap: '{("2rem" if complexity > 0.1 else "1.5rem")}'
353
+ }}}}>
354
+ {dynamic_cards}
355
+ </div>
356
+
357
+ {{theme === 'dark' && (
358
+ <div className="dark-mode-indicator">
359
+ 🌙 Dark theme detected from image
360
+ </div>
361
+ )}}
362
+
363
+ {{complexity > 0.1 && (
364
+ <div className="complexity-notice">
365
+ ⚡ High complexity interface - Advanced features enabled
366
+ </div>
367
+ )}}
368
+ </main>
369
+
370
+ <footer className="app-footer">
371
+ <p>Generated by AI from image analysis • Theme: {theme} • Style: {ui_style}</p>
372
+ <small>Complexity Score: {complexity:.3f} | Animations: {{analysis.get("has_animations", False)}}</small>
373
+ </footer>
374
+ </div>
375
+ );
376
+ }};
377
+
378
+ export default {component_name};"""
379
+
380
+ # 動的CSS生成
381
+ css_template = f""".image-generated-container {{
382
+ min-height: 100vh;
383
+ background: {bg_color};
384
+ color: {text_color};
385
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
386
+ transition: all 0.3s ease;
387
+ }}
388
+
389
+ {animation_styles}
390
+
391
+ .app-header {{
392
+ text-align: center;
393
+ padding: 40px 20px;
394
+ background: {gradient_bg};
395
+ color: white;
396
+ border-bottom: 3px solid {accent_color};
397
+ }}
398
+
399
+ .app-header h1 {{
400
+ font-size: {("3rem" if complexity > 0.1 else "2.5rem")};
401
+ margin-bottom: 10px;
402
+ text-shadow: 2px 2px 4px rgba(0,0,0,0.3);
403
+ }}
404
+
405
+ .description {{
406
+ font-size: 1.1rem;
407
+ margin: 10px 0;
408
+ opacity: 0.9;
409
+ }}
410
+
411
+ .analysis-info {{
412
+ display: flex;
413
+ justify-content: center;
414
+ gap: 20px;
415
+ margin-top: 15px;
416
+ font-size: 0.9rem;
417
+ }}
418
+
419
+ .analysis-info span {{
420
+ background: rgba(255,255,255,0.2);
421
+ padding: 5px 12px;
422
+ border-radius: 15px;
423
+ backdrop-filter: blur(10px);
424
+ }}
425
+
426
+ .app-navigation {{
427
+ display: flex;
428
+ justify-content: center;
429
+ gap: 20px;
430
+ padding: 20px;
431
+ background: rgba(255, 255, 255, 0.1);
432
+ backdrop-filter: blur(10px);
433
+ flex-wrap: wrap;
434
+ }}
435
+
436
+ .nav-button {{
437
+ padding: 12px 24px;
438
+ border: none;
439
+ border-radius: 25px;
440
+ background: transparent;
441
+ color: {text_color};
442
+ cursor: pointer;
443
+ transition: all 0.3s ease;
444
+ font-weight: 500;
445
+ font-size: 1rem;
446
+ }}
447
+
448
+ .nav-button:hover,
449
+ .nav-button.active {{
450
+ background: {accent_color};
451
+ color: white;
452
+ transform: translateY(-2px);
453
+ box-shadow: 0 5px 15px rgba(0,0,0,0.2);
454
+ }}
455
+
456
+ .app-main {{
457
+ max-width: {("1400px" if complexity > 0.1 else "1200px")};
458
+ margin: 0 auto;
459
+ padding: 40px 20px;
460
+ }}
461
+
462
+ .content-grid {{
463
+ display: grid;
464
+ margin-top: 30px;
465
+ }}
466
+
467
+ .feature-card {{
468
+ background: {("linear-gradient(135deg, #fff, #f8f9fa)" if theme == "light" else "#2c3e50" if theme == "dark" else "white")};
469
+ padding: 30px;
470
+ border-radius: 15px;
471
+ box-shadow: 0 10px 25px rgba(0, 0, 0, {("0.3" if theme == "dark" else "0.1")});
472
+ transition: transform 0.3s ease, box-shadow 0.3s ease;
473
+ border: 1px solid {accent_color}22;
474
+ }}
475
+
476
+ .feature-card:hover {{
477
+ transform: translateY(-8px);
478
+ box-shadow: 0 15px 35px rgba(0, 0, 0, {("0.4" if theme == "dark" else "0.15")});
479
+ }}
480
+
481
+ .card-icon {{
482
+ font-size: 2.5rem;
483
+ margin-bottom: 15px;
484
+ display: block;
485
+ }}
486
+
487
+ .feature-card h3 {{
488
+ color: {accent_color};
489
+ margin-bottom: 15px;
490
+ font-size: 1.5rem;
491
+ }}
492
+
493
+ .feature-card p {{
494
+ color: {text_color}88;
495
+ line-height: 1.6;
496
+ margin-bottom: 20px;
497
+ }}
498
+
499
+ .action-button {{
500
+ background: {accent_color};
501
+ color: white;
502
+ border: none;
503
+ padding: 12px 25px;
504
+ border-radius: 8px;
505
+ cursor: pointer;
506
+ font-weight: 600;
507
+ transition: all 0.3s ease;
508
+ margin-top: 15px;
509
+ font-size: 1rem;
510
+ }}
511
+
512
+ .action-button:hover {{
513
+ transform: translateY(-2px);
514
+ box-shadow: 0 8px 20px {accent_color}66;
515
+ filter: brightness(110%);
516
+ }}
517
+
518
+ .action-button:disabled {{
519
+ opacity: 0.6;
520
+ cursor: not-allowed;
521
+ transform: none;
522
+ }}
523
+
524
+ .dark-mode-indicator,
525
+ .complexity-notice {{
526
+ text-align: center;
527
+ padding: 15px;
528
+ margin: 30px 0;
529
+ background: {accent_color}11;
530
+ border-radius: 10px;
531
+ border-left: 4px solid {accent_color};
532
+ }}
533
+
534
+ .app-footer {{
535
+ text-align: center;
536
+ padding: 30px;
537
+ background: {bg_color};
538
+ border-top: 1px solid {accent_color}22;
539
+ margin-top: 50px;
540
+ }}
541
+
542
+ .app-footer small {{
543
+ display: block;
544
+ margin-top: 10px;
545
+ opacity: 0.7;
546
+ }}
547
+
548
+ @media (max-width: 768px) {{
549
+ .app-navigation {{
550
+ flex-direction: column;
551
+ align-items: center;
552
+ }}
553
+
554
+ .content-grid {{
555
+ grid-template-columns: 1fr !important;
556
+ }}
557
+
558
+ .app-header h1 {{
559
+ font-size: 2rem;
560
+ }}
561
+
562
+ .analysis-info {{
563
+ flex-direction: column;
564
+ gap: 10px;
565
+ }}
566
+ }}"""
567
+
568
+ # プレースホルダーの置換
569
+ jsx_code = jsx_template
570
+ css_code = css_template
571
+
572
+ return f"✅ Dynamic React component generated! Theme: {theme}, Complexity: {complexity:.2f}, Style: {ui_style}", jsx_code, css_code
573
+
574
+ def generate_vue_from_analysis(analysis, description):
575
+ """
576
+ 分析結果からVue.jsコンポーネントを動的生成
577
+ """
578
+
579
+ # 分析結果から動的値を取得
580
+ theme = analysis.get("theme", "modern")
581
+ bg_color = analysis.get("bg_color", "#f8f9fa")
582
+ text_color = analysis.get("text_color", "#333333")
583
+ accent_color = analysis.get("accent_color", "#42b883")
584
+ ui_style = analysis.get("ui_style", "minimal")
585
+ has_animations = analysis.get("has_animations", False)
586
+ complexity = analysis.get("complexity_score", 0.05)
587
+ layout_type = analysis.get("layout_type", "grid")
588
+ components = analysis.get("components", ["header", "main_content"])
589
+
590
+ # 複雑さに基づいて機能を動的生成
591
+ features = []
592
+ feature_templates = [
593
+ {
594
+ "title": f"{theme.title()} Dashboard",
595
+ "description": f"Image complexity: {complexity:.2f} - {ui_style} style",
596
+ "action": "dashboard",
597
+ "variant": "primary",
598
+ "icon": "📊"
599
+ },
600
+ {
601
+ "title": "Smart Analytics",
602
+ "description": f"Layout: {layout_type} | Theme: {theme}",
603
+ "action": "analytics",
604
+ "variant": "secondary",
605
+ "icon": "🔍"
606
+ },
607
+ {
608
+ "title": "Dynamic Controls",
609
+ "description": f"Animations: {has_animations} | Style: {ui_style}",
610
+ "action": "controls",
611
+ "variant": "primary",
612
+ "icon": "⚙️"
613
+ },
614
+ {
615
+ "title": "Visual Elements",
616
+ "description": f"Color: {analysis.get('dominant_color', '#333')}",
617
+ "action": "visual",
618
+ "variant": "accent",
619
+ "icon": "🎨"
620
+ }
621
+ ]
622
+
623
+ # 複雑さに基づいて表示する機能数を決定
624
+ feature_count = 4 if complexity > 0.08 else 3 if complexity > 0.05 else 2
625
+ features = feature_templates[:feature_count]
626
+
627
+ # アニメーション設定
628
+ transition_class = "transition-all duration-300" if has_animations else ""
629
+
630
+ vue_template = f"""<template>
631
+ <div class="image-generated-container">
632
+ <header class="app-header {transition_class}">
633
+ <h1>AI Generated {theme.title()} Vue UI</h1>
634
+ <p class="description">{description}</p>
635
+ <div class="analysis-info" v-if="analysisData">
636
+ <span>Complexity: {{{{ analysisData.complexity.toFixed(2) }}}}</span>
637
+ <span>Style: {{{{ analysisData.uiStyle }}}}</span>
638
+ <span>Layout: {{{{ analysisData.layoutType }}}}</span>
639
+ </div>
640
+ </header>
641
+
642
+ <nav class="app-navigation {transition_class}">
643
+ <button
644
+ v-for="tab in tabs"
645
+ :key="tab"
646
+ @click="setActiveTab(tab)"
647
+ :class="['nav-button', {{ active: activeTab === tab }}]"
648
+ :style="tabButtonStyle"
649
+ >
650
+ {{{{ tab.charAt(0).toUpperCase() + tab.slice(1) }}}}
651
+ </button>
652
+ </nav>
653
+
654
+ <main class="app-main">
655
+ <div class="content-grid" :style="gridStyle">
656
+ <div
657
+ v-for="feature in features"
658
+ :key="feature.id"
659
+ :class="['feature-card', '{transition_class}', `card-${{feature.variant}}`]"
660
+ >
661
+ <div class="card-icon">{{{{ feature.icon }}}}</div>
662
+ <h3>{{{{ feature.title }}}}</h3>
663
+ <p>{{{{ feature.description }}}}</p>
664
+ <button
665
+ @click="handleAction(feature.action)"
666
+ :disabled="isLoading"
667
+ :class="['action-button', feature.variant]"
668
+ :style="getButtonStyle(feature.variant)"
669
+ >
670
+ {{{{ isLoading ? 'Processing...' : 'Execute' }}}}
671
+ </button>
672
+ </div>
673
+ </div>
674
+
675
+ <div v-if="theme === 'dark'" class="theme-indicator">
676
+ 🌙 Dark theme detected from image analysis
677
+ </div>
678
+
679
+ <div v-if="complexity > 0.1" class="complexity-notice">
680
+ ⚡ High complexity interface - Advanced features enabled
681
+ </div>
682
+ </main>
683
+
684
+ <footer class="app-footer">
685
+ <p>Generated by AI from image analysis using Vue.js</p>
686
+ <small>Theme: {theme} | Style: {ui_style} | Complexity: {{{{ complexity.toFixed(3) }}}}</small>
687
+ </footer>
688
+ </div>
689
+ </template>
690
+
691
+ <script>
692
+ import {{ ref, reactive, computed, onMounted }} from 'vue'
693
+
694
+ export default {{
695
+ name: 'ImageGeneratedComponent',
696
+ setup() {{
697
+ const activeTab = ref('home')
698
+ const isLoading = ref(false)
699
+ const complexity = ref({complexity})
700
+
701
+ const tabs = ['home', 'features', 'analytics', 'settings']
702
+
703
+ const analysisData = reactive({{
704
+ theme: '{theme}',
705
+ complexity: {complexity},
706
+ uiStyle: '{ui_style}',
707
+ layoutType: '{layout_type}',
708
+ dominantColor: '{analysis.get("dominant_color", "#333")}',
709
+ hasAnimations: {str(has_animations).lower()}
710
+ }})
711
+
712
+ const features = reactive({features})
713
+
714
+ const gridStyle = computed(() => ({{
715
+ gridTemplateColumns: '{("repeat(auto-fit, minmax(300px, 1fr))" if complexity > 0.1 else "repeat(auto-fit, minmax(250px, 1fr))")}',
716
+ gap: '{("2rem" if complexity > 0.1 else "1.5rem")}'
717
+ }}))
718
+
719
+ const tabButtonStyle = computed(() => ({{
720
+ padding: '12px 24px',
721
+ borderRadius: '25px',
722
+ border: 'none',
723
+ backgroundColor: 'transparent',
724
+ color: '{text_color}',
725
+ cursor: 'pointer',
726
+ transition: 'all 0.3s ease',
727
+ fontWeight: '500'
728
+ }}))
729
+
730
+ const setActiveTab = (tab) => {{
731
+ activeTab.value = tab
732
+ }}
733
+
734
+ const handleAction = (action) => {{
735
+ isLoading.value = true
736
+ console.log(`Executing AI-detected action: ${{action}}`)
737
+
738
+ setTimeout(() => {{
739
+ isLoading.value = false
740
+ console.log(`Action completed: ${{action}}`)
741
+ }}, 1000 + Math.random() * 2000)
742
+ }}
743
+
744
+ const getButtonStyle = (variant) => {{
745
+ const baseStyle = {{
746
+ border: 'none',
747
+ padding: '12px 25px',
748
+ borderRadius: '8px',
749
+ cursor: 'pointer',
750
+ fontWeight: '600',
751
+ transition: 'all 0.3s ease',
752
+ marginTop: '15px',
753
+ color: 'white'
754
+ }}
755
+
756
+ switch(variant) {{
757
+ case 'primary':
758
+ return {{ ...baseStyle, background: '{accent_color}' }}
759
+ case 'secondary':
760
+ return {{ ...baseStyle, background: 'linear-gradient(135deg, #ffecd2 0%, #fcb69f 100%)', color: '#8b4513' }}
761
+ case 'accent':
762
+ return {{ ...baseStyle, background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)' }}
763
+ default:
764
+ return {{ ...baseStyle, background: '{accent_color}' }}
765
+ }}
766
+ }}
767
+
768
+ onMounted(() => {{
769
+ console.log('Vue component mounted with analysis data:', analysisData)
770
+ }})
771
+
772
+ return {{
773
+ activeTab,
774
+ isLoading,
775
+ complexity,
776
+ tabs,
777
+ features,
778
+ analysisData,
779
+ gridStyle,
780
+ tabButtonStyle,
781
+ setActiveTab,
782
+ handleAction,
783
+ getButtonStyle
784
+ }}
785
+ }}
786
+ }}
787
+ </script>
788
+
789
+ <style scoped>
790
+ .image-generated-container {{
791
+ min-height: 100vh;
792
+ background: {bg_color};
793
+ color: {text_color};
794
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
795
+ }}
796
+
797
+ {("@keyframes fadeInUp { from { opacity: 0; transform: translateY(30px); } to { opacity: 1; transform: translateY(0); } }" if has_animations else "")}
798
+ {(".transition-all { animation: fadeInUp 0.6s ease-out; }" if has_animations else "")}
799
+
800
+ .app-header {{
801
+ text-align: center;
802
+ padding: 40px 20px;
803
+ background: linear-gradient(135deg, {accent_color} 0%, #35495e 100%);
804
+ color: white;
805
+ border-bottom: 3px solid {accent_color};
806
+ }}
807
+
808
+ .app-header h1 {{
809
+ font-size: {("3rem" if complexity > 0.1 else "2.5rem")};
810
+ margin-bottom: 10px;
811
+ text-shadow: 2px 2px 4px rgba(0,0,0,0.3);
812
+ }}
813
+
814
+ .description {{
815
+ font-size: 1.1rem;
816
+ margin: 10px 0;
817
+ opacity: 0.9;
818
+ }}
819
+
820
+ .analysis-info {{
821
+ display: flex;
822
+ justify-content: center;
823
+ gap: 20px;
824
+ margin-top: 15px;
825
+ font-size: 0.9rem;
826
+ flex-wrap: wrap;
827
+ }}
828
+
829
+ .analysis-info span {{
830
+ background: rgba(255,255,255,0.2);
831
+ padding: 5px 12px;
832
+ border-radius: 15px;
833
+ backdrop-filter: blur(10px);
834
+ }}
835
+
836
+ .app-navigation {{
837
+ display: flex;
838
+ justify-content: center;
839
+ gap: 20px;
840
+ padding: 20px;
841
+ background: rgba(255, 255, 255, 0.1);
842
+ backdrop-filter: blur(10px);
843
+ flex-wrap: wrap;
844
+ }}
845
+
846
+ .nav-button:hover,
847
+ .nav-button.active {{
848
+ background: {accent_color} !important;
849
+ color: white !important;
850
+ transform: translateY(-2px);
851
+ box-shadow: 0 5px 15px rgba(0,0,0,0.2);
852
+ }}
853
+
854
+ .app-main {{
855
+ max-width: {("1400px" if complexity > 0.1 else "1200px")};
856
+ margin: 0 auto;
857
+ padding: 40px 20px;
858
+ }}
859
+
860
+ .content-grid {{
861
+ display: grid;
862
+ margin-top: 30px;
863
+ }}
864
+
865
+ .feature-card {{
866
+ background: {("linear-gradient(135deg, #fff, #f8f9fa)" if theme == "light" else "#2c3e50" if theme == "dark" else "white")};
867
+ padding: 30px;
868
+ border-radius: 15px;
869
+ box-shadow: 0 10px 25px rgba(0, 0, 0, {("0.3" if theme == "dark" else "0.1")});
870
+ transition: transform 0.3s ease, box-shadow 0.3s ease;
871
+ border: 1px solid {accent_color}22;
872
+ }}
873
+
874
+ .feature-card:hover {{
875
+ transform: translateY(-8px);
876
+ box-shadow: 0 15px 35px rgba(0, 0, 0, {("0.4" if theme == "dark" else "0.15")});
877
+ }}
878
+
879
+ .card-icon {{
880
+ font-size: 2.5rem;
881
+ margin-bottom: 15px;
882
+ display: block;
883
+ }}
884
+
885
+ .feature-card h3 {{
886
+ color: {accent_color};
887
+ margin-bottom: 15px;
888
+ font-size: 1.5rem;
889
+ }}
890
+
891
+ .feature-card p {{
892
+ color: {text_color}88;
893
+ line-height: 1.6;
894
+ margin-bottom: 20px;
895
+ }}
896
+
897
+ .action-button:hover {{
898
+ transform: translateY(-2px);
899
+ box-shadow: 0 8px 20px rgba(66, 184, 131, 0.4);
900
+ filter: brightness(110%);
901
+ }}
902
+
903
+ .action-button:disabled {{
904
+ opacity: 0.6;
905
+ cursor: not-allowed;
906
+ transform: none;
907
+ }}
908
+
909
+ .theme-indicator,
910
+ .complexity-notice {{
911
+ text-align: center;
912
+ padding: 15px;
913
+ margin: 30px 0;
914
+ background: {accent_color}11;
915
+ border-radius: 10px;
916
+ border-left: 4px solid {accent_color};
917
+ }}
918
+
919
+ .app-footer {{
920
+ text-align: center;
921
+ padding: 30px;
922
+ background: {bg_color};
923
+ border-top: 1px solid {accent_color}22;
924
+ margin-top: 50px;
925
+ }}
926
+
927
+ .app-footer small {{
928
+ display: block;
929
+ margin-top: 10px;
930
+ opacity: 0.7;
931
+ }}
932
+
933
+ @media (max-width: 768px) {{
934
+ .app-navigation {{
935
+ flex-direction: column;
936
+ align-items: center;
937
+ }}
938
+
939
+ .content-grid {{
940
+ grid-template-columns: 1fr !important;
941
+ }}
942
+
943
+ .app-header h1 {{
944
+ font-size: 2rem;
945
+ }}
946
+
947
+ .analysis-info {{
948
+ flex-direction: column;
949
+ gap: 10px;
950
+ }}
951
+ }}
952
+ </style>"""
953
+
954
+ return f"✅ Dynamic Vue.js component generated! Theme: {theme}, Complexity: {complexity:.2f}, Style: {ui_style}", vue_template
955
+
956
+ def generate_html_from_analysis(analysis, description):
957
+ """
958
+ 分析結果からHTML/CSSを動的生成
959
+ """
960
+
961
+ # 分析結果から動的値を取得
962
+ theme = analysis.get("theme", "modern")
963
+ bg_color = analysis.get("bg_color", "#f8f9fa")
964
+ text_color = analysis.get("text_color", "#333333")
965
+ accent_color = analysis.get("accent_color", "#007bff")
966
+ ui_style = analysis.get("ui_style", "minimal")
967
+ has_animations = analysis.get("has_animations", False)
968
+ complexity = analysis.get("complexity_score", 0.05)
969
+ layout_type = analysis.get("layout_type", "grid")
970
+
971
+ # 複雑さに基づいて機能カードを生成
972
+ feature_cards = []
973
+ feature_data = [
974
+ {
975
+ "title": f"{theme.title()} Dashboard",
976
+ "description": f"Image complexity: {complexity:.2f} - {ui_style} style",
977
+ "action": "dashboard",
978
+ "icon": "📊"
979
+ },
980
+ {
981
+ "title": "Smart Analytics",
982
+ "description": f"Layout: {layout_type} | Theme: {theme}",
983
+ "action": "analytics",
984
+ "icon": "🔍"
985
+ },
986
+ {
987
+ "title": "Dynamic Controls",
988
+ "description": f"Animations: {has_animations} | Navigation: {analysis.get('nav_style', 'horizontal')}",
989
+ "action": "controls",
990
+ "icon": "⚙️"
991
+ },
992
+ {
993
+ "title": "Visual Elements",
994
+ "description": f"Dominant color: {analysis.get('dominant_color', '#333')} | Brightness: {analysis.get('brightness_score', 0.5):.2f}",
995
+ "action": "visual",
996
+ "icon": "🎨"
997
+ }
998
+ ]
999
+
1000
+ # 複雑さに基づいてカード数を決定
1001
+ card_count = 4 if complexity > 0.08 else 3 if complexity > 0.05 else 2
1002
+
1003
+ for i, feature in enumerate(feature_data[:card_count]):
1004
+ card_html = f"""
1005
+ <div class="feature-card dynamic-card-{i}" data-feature="{feature['action']}">
1006
+ <div class="card-icon">{feature['icon']}</div>
1007
+ <h3>{feature['title']}</h3>
1008
+ <p>{feature['description']}</p>
1009
+ <button class="action-button" onclick="handleAction('{feature['action']}', this)">
1010
+ Execute
1011
+ </button>
1012
+ </div>"""
1013
+ feature_cards.append(card_html)
1014
+
1015
+ # グリッドスタイル
1016
+ grid_columns = "repeat(auto-fit, minmax(300px, 1fr))" if complexity > 0.1 else "repeat(auto-fit, minmax(250px, 1fr))"
1017
+
1018
+ html_template = f"""<!DOCTYPE html>
1019
+ <html lang="ja">
1020
+ <head>
1021
+ <meta charset="UTF-8">
1022
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
1023
+ <title>AI Generated {theme.title()} UI</title>
1024
+ <link rel="stylesheet" href="styles.css">
1025
+ </head>
1026
+ <body data-theme="{theme}" data-complexity="{complexity:.3f}">
1027
+ <div class="image-generated-container">
1028
+ <header class="app-header {('animate-fade' if has_animations else '')}">
1029
+ <h1>AI Generated {theme.title()} HTML UI</h1>
1030
+ <p class="description">{description}</p>
1031
+ <div class="analysis-info">
1032
+ <span>Complexity: {complexity:.2f}</span>
1033
+ <span>Style: {ui_style}</span>
1034
+ <span>Layout: {layout_type}</span>
1035
+ </div>
1036
+ </header>
1037
+
1038
+ <nav class="app-navigation {('animate-slide' if has_animations else '')}">
1039
+ <button class="nav-button active" onclick="setActiveTab('home', this)">Home</button>
1040
+ <button class="nav-button" onclick="setActiveTab('features', this)">Features</button>
1041
+ <button class="nav-button" onclick="setActiveTab('analytics', this)">Analytics</button>
1042
+ <button class="nav-button" onclick="setActiveTab('settings', this)">Settings</button>
1043
+ </nav>
1044
+
1045
+ <main class="app-main">
1046
+ <div class="content-grid" style="grid-template-columns: {grid_columns}; gap: {('2rem' if complexity > 0.1 else '1.5rem')};">
1047
+ {''.join(feature_cards)}
1048
+ </div>
1049
+
1050
+ {('<div class="theme-indicator">🌙 Dark theme detected from image analysis</div>' if theme == 'dark' else '')}
1051
+ {('<div class="complexity-notice">⚡ High complexity interface - Advanced features enabled</div>' if complexity > 0.1 else '')}
1052
+ </main>
1053
+
1054
+ <footer class="app-footer">
1055
+ <p>Generated by AI from image analysis using HTML/CSS</p>
1056
+ <small>Theme: {theme} | Style: {ui_style} | Complexity: {complexity:.3f}</small>
1057
+ </footer>
1058
+ </div>
1059
+
1060
+ <script>
1061
+ // グローバル変数
1062
+ let isLoading = false;
1063
+ let analysisData = {{
1064
+ theme: '{theme}',
1065
+ complexity: {complexity},
1066
+ uiStyle: '{ui_style}',
1067
+ layoutType: '{layout_type}',
1068
+ dominantColor: '{analysis.get("dominant_color", "#333")}',
1069
+ hasAnimations: {str(has_animations).lower()}
1070
+ }};
1071
+
1072
+ function setActiveTab(tab, button) {{
1073
+ // すべてのボタンからactiveクラスを削除
1074
+ document.querySelectorAll('.nav-button').forEach(btn => {{
1075
+ btn.classList.remove('active');
1076
+ }});
1077
+
1078
+ // クリックされたボタンにactiveクラスを追加
1079
+ button.classList.add('active');
1080
+
1081
+ console.log('Active tab:', tab);
1082
+ console.log('Analysis data:', analysisData);
1083
+ }}
1084
+
1085
+ function handleAction(action, button) {{
1086
+ if (isLoading) return;
1087
+
1088
+ isLoading = true;
1089
+ const originalText = button.textContent;
1090
+ button.disabled = true;
1091
+ button.textContent = 'Processing...';
1092
+ button.style.opacity = '0.6';
1093
+
1094
+ console.log(`Executing AI-detected action: ${{action}}`);
1095
+
1096
+ // AIが画像から推定したアクション処理
1097
+ const processingTime = 1000 + Math.random() * 2000;
1098
+ setTimeout(() => {{
1099
+ isLoading = false;
1100
+ button.disabled = false;
1101
+ button.textContent = originalText;
1102
+ button.style.opacity = '1';
1103
+ console.log(`Action completed: ${{action}}`);
1104
+
1105
+ // 視覚的フィードバック
1106
+ const card = button.closest('.feature-card');
1107
+ card.style.transform = 'scale(1.05)';
1108
+ setTimeout(() => {{
1109
+ card.style.transform = '';
1110
+ }}, 200);
1111
+ }}, processingTime);
1112
+ }}
1113
+
1114
+ // 動的インタラクション
1115
+ function addDynamicEffects() {{
1116
+ const cards = document.querySelectorAll('.feature-card');
1117
+ cards.forEach((card, index) => {{
1118
+ card.addEventListener('mouseenter', () => {{
1119
+ if (analysisData.hasAnimations) {{
1120
+ card.style.transform = 'translateY(-10px) scale(1.02)';
1121
+ card.style.boxShadow = '0 20px 40px rgba(0,0,0,0.15)';
1122
+ }}
1123
+ }});
1124
+
1125
+ card.addEventListener('mouseleave', () => {{
1126
+ card.style.transform = '';
1127
+ card.style.boxShadow = '';
1128
+ }});
1129
+ }});
1130
+ }}
1131
+
1132
+ // ページ読み込み時の初期化
1133
+ document.addEventListener('DOMContentLoaded', () => {{
1134
+ console.log('HTML UI initialized with analysis data:', analysisData);
1135
+ addDynamicEffects();
1136
+
1137
+ // テーマに基づく動的スタイル調整
1138
+ if (analysisData.theme === 'dark') {{
1139
+ document.body.classList.add('dark-theme');
1140
+ }}
1141
+
1142
+ // 複雑さに基づく動的調整
1143
+ if (analysisData.complexity > 0.1) {{
1144
+ document.body.classList.add('high-complexity');
1145
+ }}
1146
+ }});
1147
+ </script>
1148
+ </body>
1149
+ </html>"""
1150
+
1151
+ # 動的CSS生成
1152
+ css_template = f""".image-generated-container {{
1153
+ min-height: 100vh;
1154
+ background: {bg_color};
1155
+ color: {text_color};
1156
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
1157
+ transition: all 0.3s ease;
1158
+ }}
1159
+
1160
+ {("@keyframes fadeInUp { from { opacity: 0; transform: translateY(30px); } to { opacity: 1; transform: translateY(0); } }" if has_animations else "")}
1161
+ {("@keyframes slideInLeft { from { opacity: 0; transform: translateX(-50px); } to { opacity: 1; transform: translateX(0); } }" if has_animations else "")}
1162
+ {(".animate-fade { animation: fadeInUp 0.6s ease-out; }" if has_animations else "")}
1163
+ {(".animate-slide { animation: slideInLeft 0.4s ease-out; }" if has_animations else "")}
1164
+
1165
+ .app-header {{
1166
+ text-align: center;
1167
+ padding: 40px 20px;
1168
+ background: linear-gradient(135deg, {accent_color} 0%, {bg_color} 100%);
1169
+ color: white;
1170
+ border-bottom: 3px solid {accent_color};
1171
+ }}
1172
+
1173
+ .app-header h1 {{
1174
+ font-size: {("3rem" if complexity > 0.1 else "2.5rem")};
1175
+ margin-bottom: 10px;
1176
+ text-shadow: 2px 2px 4px rgba(0,0,0,0.3);
1177
+ }}
1178
+
1179
+ .description {{
1180
+ font-size: 1.1rem;
1181
+ margin: 10px 0;
1182
+ opacity: 0.9;
1183
+ }}
1184
+
1185
+ .analysis-info {{
1186
+ display: flex;
1187
+ justify-content: center;
1188
+ gap: 20px;
1189
+ margin-top: 15px;
1190
+ font-size: 0.9rem;
1191
+ flex-wrap: wrap;
1192
+ }}
1193
+
1194
+ .analysis-info span {{
1195
+ background: rgba(255,255,255,0.2);
1196
+ padding: 5px 12px;
1197
+ border-radius: 15px;
1198
+ backdrop-filter: blur(10px);
1199
+ }}
1200
+
1201
+ .app-navigation {{
1202
+ display: flex;
1203
+ justify-content: center;
1204
+ gap: 20px;
1205
+ padding: 20px;
1206
+ background: rgba(255, 255, 255, 0.1);
1207
+ backdrop-filter: blur(10px);
1208
+ flex-wrap: wrap;
1209
+ }}
1210
+
1211
+ .nav-button {{
1212
+ padding: 12px 24px;
1213
+ border: none;
1214
+ border-radius: 25px;
1215
+ background: transparent;
1216
+ color: {text_color};
1217
+ cursor: pointer;
1218
+ transition: all 0.3s ease;
1219
+ font-weight: 500;
1220
+ font-size: 1rem;
1221
+ }}
1222
+
1223
+ .nav-button:hover,
1224
+ .nav-button.active {{
1225
+ background: {accent_color};
1226
+ color: white;
1227
+ transform: translateY(-2px);
1228
+ box-shadow: 0 5px 15px rgba(0,0,0,0.2);
1229
+ }}
1230
+
1231
+ .app-main {{
1232
+ max-width: {("1400px" if complexity > 0.1 else "1200px")};
1233
+ margin: 0 auto;
1234
+ padding: 40px 20px;
1235
+ }}
1236
+
1237
+ .content-grid {{
1238
+ display: grid;
1239
+ margin-top: 30px;
1240
+ }}
1241
+
1242
+ .feature-card {{
1243
+ background: {("linear-gradient(135deg, #fff, #f8f9fa)" if theme == "light" else "#2c3e50" if theme == "dark" else "white")};
1244
+ padding: 30px;
1245
+ border-radius: 15px;
1246
+ box-shadow: 0 10px 25px rgba(0, 0, 0, {("0.3" if theme == "dark" else "0.1")});
1247
+ transition: transform 0.3s ease, box-shadow 0.3s ease;
1248
+ border: 1px solid {accent_color}22;
1249
+ cursor: pointer;
1250
+ }}
1251
+
1252
+ .feature-card:hover {{
1253
+ transform: translateY(-8px);
1254
+ box-shadow: 0 15px 35px rgba(0, 0, 0, {("0.4" if theme == "dark" else "0.15")});
1255
+ }}
1256
+
1257
+ .card-icon {{
1258
+ font-size: 2.5rem;
1259
+ margin-bottom: 15px;
1260
+ display: block;
1261
+ }}
1262
+
1263
+ .feature-card h3 {{
1264
+ color: {accent_color};
1265
+ margin-bottom: 15px;
1266
+ font-size: 1.5rem;
1267
+ }}
1268
+
1269
+ .feature-card p {{
1270
+ color: {text_color}88;
1271
+ line-height: 1.6;
1272
+ margin-bottom: 20px;
1273
+ }}
1274
+
1275
+ .action-button {{
1276
+ background: {accent_color};
1277
+ color: white;
1278
+ border: none;
1279
+ padding: 12px 25px;
1280
+ border-radius: 8px;
1281
+ cursor: pointer;
1282
+ font-weight: 600;
1283
+ transition: all 0.3s ease;
1284
+ margin-top: 15px;
1285
+ font-size: 1rem;
1286
+ width: 100%;
1287
+ }}
1288
+
1289
+ .action-button:hover {{
1290
+ transform: translateY(-2px);
1291
+ box-shadow: 0 8px 20px {accent_color}66;
1292
+ filter: brightness(110%);
1293
+ }}
1294
+
1295
+ .action-button:disabled {{
1296
+ opacity: 0.6;
1297
+ cursor: not-allowed;
1298
+ transform: none;
1299
+ }}
1300
+
1301
+ .theme-indicator,
1302
+ .complexity-notice {{
1303
+ text-align: center;
1304
+ padding: 15px;
1305
+ margin: 30px 0;
1306
+ background: {accent_color}11;
1307
+ border-radius: 10px;
1308
+ border-left: 4px solid {accent_color};
1309
+ }}
1310
+
1311
+ .app-footer {{
1312
+ text-align: center;
1313
+ padding: 30px;
1314
+ background: {bg_color};
1315
+ border-top: 1px solid {accent_color}22;
1316
+ margin-top: 50px;
1317
+ }}
1318
+
1319
+ .app-footer small {{
1320
+ display: block;
1321
+ margin-top: 10px;
1322
+ opacity: 0.7;
1323
+ }}
1324
+
1325
+ /* テーマ固有のスタイル */
1326
+ .dark-theme .feature-card {{
1327
+ background: #34495e;
1328
+ color: #ecf0f1;
1329
+ }}
1330
+
1331
+ .high-complexity .feature-card {{
1332
+ border-width: 2px;
1333
+ }}
1334
+
1335
+ .high-complexity .action-button {{
1336
+ background: linear-gradient(135deg, {accent_color}, #8e44ad);
1337
+ }}
1338
+
1339
+ @media (max-width: 768px) {{
1340
+ .app-navigation {{
1341
+ flex-direction: column;
1342
+ align-items: center;
1343
+ }}
1344
+
1345
+ .content-grid {{
1346
+ grid-template-columns: 1fr !important;
1347
+ }}
1348
+
1349
+ .app-header h1 {{
1350
+ font-size: 2rem;
1351
+ }}
1352
+
1353
+ .analysis-info {{
1354
+ flex-direction: column;
1355
+ gap: 10px;
1356
+ }}
1357
+ }}"""
1358
+
1359
+ return f"✅ Dynamic HTML/CSS generated! Theme: {theme}, Complexity: {complexity:.2f}, Style: {ui_style}", html_template, css_template
1360
+
1361
+ # AI指示による自動検出のための必須オブジェクト
1362
+ with gr.Blocks(title="Multimodal UI Generator") as gradio_interface:
1363
+ gr.Markdown("# 🖼️ Multimodal UI Code Generator")
1364
+ gr.Markdown("画像をアップロードしてフロントエンドコードを自動生成します")
1365
+
1366
+ with gr.Row():
1367
+ with gr.Column(scale=1):
1368
+ image_input = gr.Image(
1369
+ label="UI Design Image",
1370
+ type="pil",
1371
+ height=400
1372
+ )
1373
+
1374
+ description_input = gr.Textbox(
1375
+ label="Implementation Details",
1376
+ placeholder="このUIの機能や動作について説明してください...",
1377
+ lines=4,
1378
+ value="モダンなダッシュボード画面を作成"
1379
+ )
1380
+
1381
+ framework_choice = gr.Radio(
1382
+ label="Target Framework",
1383
+ choices=["React", "Vue", "HTML/CSS"],
1384
+ value="React"
1385
+ )
1386
+
1387
+ generate_btn = gr.Button("Generate UI Code", variant="primary", size="lg")
1388
+
1389
+ with gr.Column(scale=2):
1390
+ status_output = gr.Textbox(label="Generation Status", interactive=False)
1391
+
1392
+ with gr.Tabs():
1393
+ with gr.Tab("Primary Code"):
1394
+ primary_code_output = gr.Code(label="Main Component Code")
1395
+
1396
+ with gr.Tab("Styles"):
1397
+ css_code_output = gr.Code(label="CSS Styles", language="css")
1398
+
1399
+ with gr.Tab("Additional Files"):
1400
+ additional_output = gr.Code(label="Additional Configuration")
1401
+
1402
+ # Event binding
1403
+ generate_btn.click(
1404
+ fn=analyze_image_and_generate_ui,
1405
+ inputs=[image_input, description_input, framework_choice],
1406
+ outputs=[status_output, primary_code_output, css_code_output, additional_output]
1407
+ )
1408
+
1409
+ # サンプル例
1410
+ gr.Examples(
1411
+ examples=[
1412
+ [None, "シンプルなログイン画面", "React"],
1413
+ [None, "データ可視化ダッシュボード", "Vue"],
1414
+ [None, "商品一覧ページ", "HTML/CSS"]
1415
+ ],
1416
+ inputs=[image_input, description_input, framework_choice]
1417
+ )
1418
+
1419
+ # テスト用のスタンドアロン実行(コメントアウト - 自動検出システムとの競合を防ぐため)
1420
+ # if __name__ == "__main__":
1421
+ # gradio_interface.launch()
contbk/gra_11_multimodal/image_to_ui_fixed.py ADDED
@@ -0,0 +1,795 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import base64
3
+ import io
4
+ from PIL import Image
5
+ import json
6
+ import re
7
+
8
+ def analyze_image_and_generate_ui(image, description, framework_choice):
9
+ """
10
+ アップロードされた画像を解析してUIコードを自動生成
11
+ """
12
+ if image is None:
13
+ return "画像をアップロードしてください", "", "", ""
14
+
15
+ # 画像解析(実際のAIモデルの代わりにルールベースで実装)
16
+ analysis_result = analyze_ui_elements(image)
17
+
18
+ # 選択されたフレームワークに応じてコード生成
19
+ if framework_choice == "React":
20
+ status, jsx_code, css_code = generate_react_from_analysis(analysis_result, description)
21
+ return status, jsx_code, css_code, ""
22
+ elif framework_choice == "Vue":
23
+ status, vue_code = generate_vue_from_analysis(analysis_result, description)
24
+ return status, vue_code, "", ""
25
+ elif framework_choice == "HTML/CSS":
26
+ status, html_code, css_code = generate_html_from_analysis(analysis_result, description)
27
+ return status, html_code, css_code, ""
28
+ else:
29
+ return "フレームワークを選択してください", "", "", ""
30
+
31
+ def analyze_ui_elements(image):
32
+ """
33
+ 画像からUI要素を検出(簡易版実装)
34
+ 実際の実装では、YOLOやCNNベースのモデルを使用
35
+ """
36
+ width, height = image.size
37
+
38
+ # 基本的な画像分析
39
+ analysis = {
40
+ "image_size": (width, height),
41
+ "aspect_ratio": width / height,
42
+ "detected_elements": [],
43
+ "color_scheme": "modern",
44
+ "layout_type": "grid" if width > height else "vertical"
45
+ }
46
+
47
+ # 画像の明度から背景色を推定
48
+ grayscale = image.convert('L')
49
+ pixels = list(grayscale.getdata())
50
+ avg_brightness = sum(pixels) / len(pixels)
51
+
52
+ if avg_brightness < 85:
53
+ analysis["theme"] = "dark"
54
+ analysis["bg_color"] = "#1a1a1a"
55
+ analysis["text_color"] = "#ffffff"
56
+ elif avg_brightness > 200:
57
+ analysis["theme"] = "light"
58
+ analysis["bg_color"] = "#ffffff"
59
+ analysis["text_color"] = "#333333"
60
+ else:
61
+ analysis["theme"] = "modern"
62
+ analysis["bg_color"] = "#f8f9fa"
63
+ analysis["text_color"] = "#2c3e50"
64
+
65
+ # UI要素の検出(簡易版)
66
+ analysis["detected_elements"] = [
67
+ {"type": "header", "confidence": 0.9},
68
+ {"type": "button", "confidence": 0.8},
69
+ {"type": "card", "confidence": 0.7},
70
+ {"type": "navigation", "confidence": 0.6}
71
+ ]
72
+
73
+ return analysis
74
+
75
+ def generate_react_from_analysis(analysis, description):
76
+ """
77
+ 分析結果からReactコンポーネントを生成
78
+ """
79
+ component_name = "ImageGeneratedComponent"
80
+
81
+ # Template strings to avoid f-string complexity
82
+ jsx_template = """import React, { useState } from 'react';
83
+ import './ImageGeneratedComponent.css';
84
+
85
+ const COMPONENT_NAME = () => {
86
+ const [activeTab, setActiveTab] = useState('home');
87
+ const [isLoading, setIsLoading] = useState(false);
88
+
89
+ const handleAction = (action) => {
90
+ setIsLoading(true);
91
+ // AIが画像から推定したアクション処理
92
+ setTimeout(() => {
93
+ setIsLoading(false);
94
+ console.log(`Executed action: ${action}`);
95
+ }, 1000);
96
+ };
97
+
98
+ return (
99
+ <div className="image-generated-container">
100
+ <header className="app-header">
101
+ <h1>AI Generated UI</h1>
102
+ <p>DESCRIPTION_PLACEHOLDER</p>
103
+ </header>
104
+
105
+ <nav className="app-navigation">
106
+ {['home', 'features', 'about'].map(tab => (
107
+ <button
108
+ key={tab}
109
+ onClick={() => setActiveTab(tab)}
110
+ className={`nav-button ${activeTab === tab ? 'active' : ''}`}
111
+ >
112
+ {tab.charAt(0).toUpperCase() + tab.slice(1)}
113
+ </button>
114
+ ))}
115
+ </nav>
116
+
117
+ <main className="app-main">
118
+ <div className="content-grid">
119
+ <div className="feature-card">
120
+ <h3>Feature 1</h3>
121
+ <p>AIが画像から検出した機能</p>
122
+ <button
123
+ onClick={() => handleAction('feature1')}
124
+ disabled={isLoading}
125
+ className="action-button"
126
+ >
127
+ {isLoading ? 'Processing...' : 'Execute'}
128
+ </button>
129
+ </div>
130
+
131
+ <div className="feature-card">
132
+ <h3>Feature 2</h3>
133
+ <p>画像解析に基づく機能</p>
134
+ <button
135
+ onClick={() => handleAction('feature2')}
136
+ disabled={isLoading}
137
+ className="action-button secondary"
138
+ >
139
+ {isLoading ? 'Processing...' : 'Execute'}
140
+ </button>
141
+ </div>
142
+ </div>
143
+ </main>
144
+
145
+ <footer className="app-footer">
146
+ <p>Generated by AI from image analysis</p>
147
+ </footer>
148
+ </div>
149
+ );
150
+ };
151
+
152
+ export default COMPONENT_NAME;"""
153
+
154
+ css_template = """.image-generated-container {
155
+ min-height: 100vh;
156
+ background: BG_COLOR_PLACEHOLDER;
157
+ color: TEXT_COLOR_PLACEHOLDER;
158
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
159
+ }
160
+
161
+ .app-header {
162
+ text-align: center;
163
+ padding: 40px 20px;
164
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
165
+ color: white;
166
+ }
167
+
168
+ .app-header h1 {
169
+ font-size: 2.5rem;
170
+ margin-bottom: 10px;
171
+ }
172
+
173
+ .app-navigation {
174
+ display: flex;
175
+ justify-content: center;
176
+ gap: 20px;
177
+ padding: 20px;
178
+ background: rgba(255, 255, 255, 0.1);
179
+ backdrop-filter: blur(10px);
180
+ }
181
+
182
+ .nav-button {
183
+ padding: 10px 20px;
184
+ border: none;
185
+ border-radius: 25px;
186
+ background: transparent;
187
+ color: TEXT_COLOR_PLACEHOLDER;
188
+ cursor: pointer;
189
+ transition: all 0.3s ease;
190
+ font-weight: 500;
191
+ }
192
+
193
+ .nav-button:hover,
194
+ .nav-button.active {
195
+ background: #667eea;
196
+ color: white;
197
+ transform: translateY(-2px);
198
+ }
199
+
200
+ .app-main {
201
+ max-width: 1200px;
202
+ margin: 0 auto;
203
+ padding: 40px 20px;
204
+ }
205
+
206
+ .content-grid {
207
+ display: grid;
208
+ grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
209
+ gap: 30px;
210
+ margin-top: 30px;
211
+ }
212
+
213
+ .feature-card {
214
+ background: white;
215
+ padding: 30px;
216
+ border-radius: 15px;
217
+ box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
218
+ transition: transform 0.3s ease;
219
+ }
220
+
221
+ .feature-card:hover {
222
+ transform: translateY(-5px);
223
+ }
224
+
225
+ .feature-card h3 {
226
+ color: #2c3e50;
227
+ margin-bottom: 15px;
228
+ font-size: 1.5rem;
229
+ }
230
+
231
+ .action-button {
232
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
233
+ color: white;
234
+ border: none;
235
+ padding: 12px 25px;
236
+ border-radius: 8px;
237
+ cursor: pointer;
238
+ font-weight: 600;
239
+ transition: all 0.3s ease;
240
+ margin-top: 15px;
241
+ }
242
+
243
+ .action-button:hover {
244
+ transform: translateY(-2px);
245
+ box-shadow: 0 8px 20px rgba(102, 126, 234, 0.4);
246
+ }
247
+
248
+ .action-button.secondary {
249
+ background: linear-gradient(135deg, #ffecd2 0%, #fcb69f 100%);
250
+ color: #8b4513;
251
+ }
252
+
253
+ .action-button:disabled {
254
+ opacity: 0.6;
255
+ cursor: not-allowed;
256
+ }
257
+
258
+ .app-footer {
259
+ text-align: center;
260
+ padding: 30px;
261
+ background: BG_COLOR_PLACEHOLDER;
262
+ border-top: 1px solid rgba(0, 0, 0, 0.1);
263
+ margin-top: 50px;
264
+ }
265
+
266
+ @media (max-width: 768px) {
267
+ .app-navigation {
268
+ flex-direction: column;
269
+ align-items: center;
270
+ }
271
+
272
+ .content-grid {
273
+ grid-template-columns: 1fr;
274
+ }
275
+
276
+ .app-header h1 {
277
+ font-size: 2rem;
278
+ }
279
+ }"""
280
+
281
+ # Replace placeholders
282
+ jsx_code = jsx_template.replace("COMPONENT_NAME", component_name)
283
+ jsx_code = jsx_code.replace("DESCRIPTION_PLACEHOLDER", description)
284
+
285
+ css_code = css_template.replace("BG_COLOR_PLACEHOLDER", analysis['bg_color'])
286
+ css_code = css_code.replace("TEXT_COLOR_PLACEHOLDER", analysis['text_color'])
287
+
288
+ return "✅ React component generated from image analysis!", jsx_code, css_code
289
+
290
+ def generate_vue_from_analysis(analysis, description):
291
+ """
292
+ 分析結果からVue.jsコンポーネントを生成
293
+ """
294
+ vue_template = """<template>
295
+ <div class="image-generated-container">
296
+ <header class="app-header">
297
+ <h1>AI Generated Vue UI</h1>
298
+ <p>DESCRIPTION_PLACEHOLDER</p>
299
+ </header>
300
+
301
+ <nav class="app-navigation">
302
+ <button
303
+ v-for="tab in tabs"
304
+ :key="tab"
305
+ @click="activeTab = tab"
306
+ :class="['nav-button', { active: activeTab === tab }]"
307
+ >
308
+ {{ tab.charAt(0).toUpperCase() + tab.slice(1) }}
309
+ </button>
310
+ </nav>
311
+
312
+ <main class="app-main">
313
+ <div class="content-grid">
314
+ <div
315
+ v-for="feature in features"
316
+ :key="feature.id"
317
+ class="feature-card"
318
+ >
319
+ <h3>{{ feature.title }}</h3>
320
+ <p>{{ feature.description }}</p>
321
+ <button
322
+ @click="handleAction(feature.action)"
323
+ :disabled="isLoading"
324
+ :class="['action-button', feature.variant]"
325
+ >
326
+ {{ isLoading ? 'Processing...' : 'Execute' }}
327
+ </button>
328
+ </div>
329
+ </div>
330
+ </main>
331
+
332
+ <footer class="app-footer">
333
+ <p>Generated by AI from image analysis using Vue.js</p>
334
+ </footer>
335
+ </div>
336
+ </template>
337
+
338
+ <script>
339
+ import { ref, reactive } from 'vue'
340
+
341
+ export default {
342
+ name: 'ImageGeneratedComponent',
343
+ setup() {
344
+ const activeTab = ref('home')
345
+ const isLoading = ref(false)
346
+
347
+ const tabs = ['home', 'features', 'about']
348
+
349
+ const features = reactive([
350
+ {
351
+ id: 1,
352
+ title: 'Feature 1',
353
+ description: 'AIが画像から検出した機能',
354
+ action: 'feature1',
355
+ variant: 'primary'
356
+ },
357
+ {
358
+ id: 2,
359
+ title: 'Feature 2',
360
+ description: '画像解析に基づく機能',
361
+ action: 'feature2',
362
+ variant: 'secondary'
363
+ }
364
+ ])
365
+
366
+ const handleAction = (action) => {
367
+ isLoading.value = true
368
+ setTimeout(() => {
369
+ isLoading.value = false
370
+ console.log(`Executed action: ${action}`)
371
+ }, 1000)
372
+ }
373
+
374
+ return {
375
+ activeTab,
376
+ isLoading,
377
+ tabs,
378
+ features,
379
+ handleAction
380
+ }
381
+ }
382
+ }
383
+ </script>
384
+
385
+ <style scoped>
386
+ .image-generated-container {
387
+ min-height: 100vh;
388
+ background: BG_COLOR_PLACEHOLDER;
389
+ color: TEXT_COLOR_PLACEHOLDER;
390
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
391
+ }
392
+
393
+ .app-header {
394
+ text-align: center;
395
+ padding: 40px 20px;
396
+ background: linear-gradient(135deg, #42b883 0%, #35495e 100%);
397
+ color: white;
398
+ }
399
+
400
+ .app-header h1 {
401
+ font-size: 2.5rem;
402
+ margin-bottom: 10px;
403
+ }
404
+
405
+ .app-navigation {
406
+ display: flex;
407
+ justify-content: center;
408
+ gap: 20px;
409
+ padding: 20px;
410
+ background: rgba(255, 255, 255, 0.1);
411
+ backdrop-filter: blur(10px);
412
+ }
413
+
414
+ .nav-button {
415
+ padding: 10px 20px;
416
+ border: none;
417
+ border-radius: 25px;
418
+ background: transparent;
419
+ color: TEXT_COLOR_PLACEHOLDER;
420
+ cursor: pointer;
421
+ transition: all 0.3s ease;
422
+ font-weight: 500;
423
+ }
424
+
425
+ .nav-button:hover,
426
+ .nav-button.active {
427
+ background: #42b883;
428
+ color: white;
429
+ transform: translateY(-2px);
430
+ }
431
+
432
+ .app-main {
433
+ max-width: 1200px;
434
+ margin: 0 auto;
435
+ padding: 40px 20px;
436
+ }
437
+
438
+ .content-grid {
439
+ display: grid;
440
+ grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
441
+ gap: 30px;
442
+ margin-top: 30px;
443
+ }
444
+
445
+ .feature-card {
446
+ background: white;
447
+ padding: 30px;
448
+ border-radius: 15px;
449
+ box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
450
+ transition: transform 0.3s ease;
451
+ }
452
+
453
+ .feature-card:hover {
454
+ transform: translateY(-5px);
455
+ }
456
+
457
+ .feature-card h3 {
458
+ color: #2c3e50;
459
+ margin-bottom: 15px;
460
+ font-size: 1.5rem;
461
+ }
462
+
463
+ .action-button {
464
+ border: none;
465
+ padding: 12px 25px;
466
+ border-radius: 8px;
467
+ cursor: pointer;
468
+ font-weight: 600;
469
+ transition: all 0.3s ease;
470
+ margin-top: 15px;
471
+ color: white;
472
+ }
473
+
474
+ .action-button.primary {
475
+ background: linear-gradient(135deg, #42b883 0%, #35495e 100%);
476
+ }
477
+
478
+ .action-button.secondary {
479
+ background: linear-gradient(135deg, #ffecd2 0%, #fcb69f 100%);
480
+ color: #8b4513;
481
+ }
482
+
483
+ .action-button:hover {
484
+ transform: translateY(-2px);
485
+ box-shadow: 0 8px 20px rgba(66, 184, 131, 0.4);
486
+ }
487
+
488
+ .action-button:disabled {
489
+ opacity: 0.6;
490
+ cursor: not-allowed;
491
+ }
492
+
493
+ .app-footer {
494
+ text-align: center;
495
+ padding: 30px;
496
+ background: BG_COLOR_PLACEHOLDER;
497
+ border-top: 1px solid rgba(0, 0, 0, 0.1);
498
+ margin-top: 50px;
499
+ }
500
+
501
+ @media (max-width: 768px) {
502
+ .app-navigation {
503
+ flex-direction: column;
504
+ align-items: center;
505
+ }
506
+
507
+ .content-grid {
508
+ grid-template-columns: 1fr;
509
+ }
510
+
511
+ .app-header h1 {
512
+ font-size: 2rem;
513
+ }
514
+ }
515
+ </style>"""
516
+
517
+ vue_code = vue_template.replace("DESCRIPTION_PLACEHOLDER", description)
518
+ vue_code = vue_code.replace("BG_COLOR_PLACEHOLDER", analysis['bg_color'])
519
+ vue_code = vue_code.replace("TEXT_COLOR_PLACEHOLDER", analysis['text_color'])
520
+
521
+ return "✅ Vue.js component generated from image analysis!", vue_code
522
+
523
+ def generate_html_from_analysis(analysis, description):
524
+ """
525
+ 分析結果からHTML/CSSを生成
526
+ """
527
+ html_template = """<!DOCTYPE html>
528
+ <html lang="ja">
529
+ <head>
530
+ <meta charset="UTF-8">
531
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
532
+ <title>AI Generated UI</title>
533
+ <link rel="stylesheet" href="styles.css">
534
+ </head>
535
+ <body>
536
+ <div class="image-generated-container">
537
+ <header class="app-header">
538
+ <h1>AI Generated HTML UI</h1>
539
+ <p>DESCRIPTION_PLACEHOLDER</p>
540
+ </header>
541
+
542
+ <nav class="app-navigation">
543
+ <button class="nav-button active" onclick="setActiveTab('home')">Home</button>
544
+ <button class="nav-button" onclick="setActiveTab('features')">Features</button>
545
+ <button class="nav-button" onclick="setActiveTab('about')">About</button>
546
+ </nav>
547
+
548
+ <main class="app-main">
549
+ <div class="content-grid">
550
+ <div class="feature-card">
551
+ <h3>Feature 1</h3>
552
+ <p>AIが画像から検出した機能</p>
553
+ <button class="action-button" onclick="handleAction('feature1')">
554
+ Execute
555
+ </button>
556
+ </div>
557
+
558
+ <div class="feature-card">
559
+ <h3>Feature 2</h3>
560
+ <p>画像解析に基づく機能</p>
561
+ <button class="action-button secondary" onclick="handleAction('feature2')">
562
+ Execute
563
+ </button>
564
+ </div>
565
+ </div>
566
+ </main>
567
+
568
+ <footer class="app-footer">
569
+ <p>Generated by AI from image analysis using HTML/CSS</p>
570
+ </footer>
571
+ </div>
572
+
573
+ <script>
574
+ function setActiveTab(tab) {
575
+ // すべてのボタンからactiveクラスを削除
576
+ document.querySelectorAll('.nav-button').forEach(btn => {
577
+ btn.classList.remove('active');
578
+ });
579
+
580
+ // クリックされたボタンにactiveクラスを追加
581
+ event.target.classList.add('active');
582
+
583
+ console.log('Active tab:', tab);
584
+ }
585
+
586
+ function handleAction(action) {
587
+ const button = event.target;
588
+ button.disabled = true;
589
+ button.textContent = 'Processing...';
590
+
591
+ // AIが画像から推定したアクション処理
592
+ setTimeout(() => {
593
+ button.disabled = false;
594
+ button.textContent = 'Execute';
595
+ console.log('Executed action:', action);
596
+ }, 1000);
597
+ }
598
+ </script>
599
+ </body>
600
+ </html>"""
601
+
602
+ css_template = """.image-generated-container {
603
+ min-height: 100vh;
604
+ background: BG_COLOR_PLACEHOLDER;
605
+ color: TEXT_COLOR_PLACEHOLDER;
606
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
607
+ }
608
+
609
+ .app-header {
610
+ text-align: center;
611
+ padding: 40px 20px;
612
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
613
+ color: white;
614
+ }
615
+
616
+ .app-header h1 {
617
+ font-size: 2.5rem;
618
+ margin-bottom: 10px;
619
+ }
620
+
621
+ .app-navigation {
622
+ display: flex;
623
+ justify-content: center;
624
+ gap: 20px;
625
+ padding: 20px;
626
+ background: rgba(255, 255, 255, 0.1);
627
+ backdrop-filter: blur(10px);
628
+ }
629
+
630
+ .nav-button {
631
+ padding: 10px 20px;
632
+ border: none;
633
+ border-radius: 25px;
634
+ background: transparent;
635
+ color: TEXT_COLOR_PLACEHOLDER;
636
+ cursor: pointer;
637
+ transition: all 0.3s ease;
638
+ font-weight: 500;
639
+ }
640
+
641
+ .nav-button:hover,
642
+ .nav-button.active {
643
+ background: #667eea;
644
+ color: white;
645
+ transform: translateY(-2px);
646
+ }
647
+
648
+ .app-main {
649
+ max-width: 1200px;
650
+ margin: 0 auto;
651
+ padding: 40px 20px;
652
+ }
653
+
654
+ .content-grid {
655
+ display: grid;
656
+ grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
657
+ gap: 30px;
658
+ margin-top: 30px;
659
+ }
660
+
661
+ .feature-card {
662
+ background: white;
663
+ padding: 30px;
664
+ border-radius: 15px;
665
+ box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
666
+ transition: transform 0.3s ease;
667
+ }
668
+
669
+ .feature-card:hover {
670
+ transform: translateY(-5px);
671
+ }
672
+
673
+ .feature-card h3 {
674
+ color: #2c3e50;
675
+ margin-bottom: 15px;
676
+ font-size: 1.5rem;
677
+ }
678
+
679
+ .action-button {
680
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
681
+ color: white;
682
+ border: none;
683
+ padding: 12px 25px;
684
+ border-radius: 8px;
685
+ cursor: pointer;
686
+ font-weight: 600;
687
+ transition: all 0.3s ease;
688
+ margin-top: 15px;
689
+ }
690
+
691
+ .action-button:hover {
692
+ transform: translateY(-2px);
693
+ box-shadow: 0 8px 20px rgba(102, 126, 234, 0.4);
694
+ }
695
+
696
+ .action-button.secondary {
697
+ background: linear-gradient(135deg, #ffecd2 0%, #fcb69f 100%);
698
+ color: #8b4513;
699
+ }
700
+
701
+ .action-button:disabled {
702
+ opacity: 0.6;
703
+ cursor: not-allowed;
704
+ }
705
+
706
+ .app-footer {
707
+ text-align: center;
708
+ padding: 30px;
709
+ background: BG_COLOR_PLACEHOLDER;
710
+ border-top: 1px solid rgba(0, 0, 0, 0.1);
711
+ margin-top: 50px;
712
+ }
713
+
714
+ @media (max-width: 768px) {
715
+ .app-navigation {
716
+ flex-direction: column;
717
+ align-items: center;
718
+ }
719
+
720
+ .content-grid {
721
+ grid-template-columns: 1fr;
722
+ }
723
+
724
+ .app-header h1 {
725
+ font-size: 2rem;
726
+ }
727
+ }"""
728
+
729
+ html_code = html_template.replace("DESCRIPTION_PLACEHOLDER", description)
730
+ css_code = css_template.replace("BG_COLOR_PLACEHOLDER", analysis['bg_color'])
731
+ css_code = css_code.replace("TEXT_COLOR_PLACEHOLDER", analysis['text_color'])
732
+
733
+ return "✅ HTML/CSS generated from image analysis!", html_code, css_code
734
+
735
+ # AI指示による自動検出のための必須オブジェクト
736
+ with gr.Blocks(title="Multimodal UI Generator") as gradio_interface:
737
+ gr.Markdown("# 🖼️ Multimodal UI Code Generator")
738
+ gr.Markdown("画像をアップロードしてフロントエンドコードを自動生成します")
739
+
740
+ with gr.Row():
741
+ with gr.Column(scale=1):
742
+ image_input = gr.Image(
743
+ label="UI Design Image",
744
+ type="pil",
745
+ height=400
746
+ )
747
+
748
+ description_input = gr.Textbox(
749
+ label="Implementation Details",
750
+ placeholder="このUIの機能や動作について説明してください...",
751
+ lines=4,
752
+ value="モダンなダッシュボード画面を作成"
753
+ )
754
+
755
+ framework_choice = gr.Radio(
756
+ label="Target Framework",
757
+ choices=["React", "Vue", "HTML/CSS"],
758
+ value="React"
759
+ )
760
+
761
+ generate_btn = gr.Button("Generate UI Code", variant="primary", size="lg")
762
+
763
+ with gr.Column(scale=2):
764
+ status_output = gr.Textbox(label="Generation Status", interactive=False)
765
+
766
+ with gr.Tabs():
767
+ with gr.Tab("Primary Code"):
768
+ primary_code_output = gr.Code(label="Main Component Code")
769
+
770
+ with gr.Tab("Styles"):
771
+ css_code_output = gr.Code(label="CSS Styles", language="css")
772
+
773
+ with gr.Tab("Additional Files"):
774
+ additional_output = gr.Code(label="Additional Configuration")
775
+
776
+ # Event binding
777
+ generate_btn.click(
778
+ fn=analyze_image_and_generate_ui,
779
+ inputs=[image_input, description_input, framework_choice],
780
+ outputs=[status_output, primary_code_output, css_code_output, additional_output]
781
+ )
782
+
783
+ # サンプル例
784
+ gr.Examples(
785
+ examples=[
786
+ [None, "シンプルなログイン画面", "React"],
787
+ [None, "データ可視化ダッシュボード", "Vue"],
788
+ [None, "商品一覧ページ", "HTML/CSS"]
789
+ ],
790
+ inputs=[image_input, description_input, framework_choice]
791
+ )
792
+
793
+ # テスト用のスタンドアロン実行(コメントアウト - 自動検出システムとの競合を防ぐため)
794
+ # if __name__ == "__main__":
795
+ # gradio_interface.launch()
controllers/gradio_interface.py CHANGED
@@ -1,22 +1,201 @@
1
  import gradio as gr
2
- from llamafactory.webui.interface import create_ui
 
3
 
4
- def create_gradio_interface():
5
- """Gradio インターフェースを作成する"""
6
- return create_ui()
7
 
8
- # Gradio インターフェースを作成
9
- with gr.Blocks() as gradio_interface:
10
- # LlamaFactory UIを追加
11
- llamafactory_demo = create_gradio_interface()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
 
13
- # LlamaFactory UIを現在のBlocksに統合
14
- with gr.Row():
15
- with gr.Column():
16
- gr.HTML("""
17
- <h2>🦙 LlamaFactory WebUI</h2>
18
- <p>LlamaFactoryのWebUIインターフェースです</p>
19
- """)
20
 
21
- # LlamaFactory UIをマウント
22
- llamafactory_demo.render()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import gradio as gr
2
+ import sys
3
+ import os
4
 
5
+ # LlamaFactoryのパスを追加
6
+ llamafactory_path = '/workspaces/fastapi_django_main_live/LLaMA-Factory'
7
+ sys.path.append(llamafactory_path)
8
 
9
+ def create_llamafactory_interface():
10
+ """LlamaFactory Gradio インターフェースを作成する"""
11
+ try:
12
+ # 作業ディレクトリをLlamaFactoryに変更
13
+ original_cwd = os.getcwd()
14
+ llamafactory_path = '/workspaces/fastapi_django_main_live/LLaMA-Factory'
15
+ os.chdir(llamafactory_path)
16
+
17
+ # 環境変数を設定
18
+ os.environ['LLAMAFACTORY_HOME'] = llamafactory_path
19
+ os.environ['PYTHONPATH'] = f"{llamafactory_path}:{os.environ.get('PYTHONPATH', '')}"
20
+
21
+ # 必要なファイルの存在確認
22
+ dataset_info_path = os.path.join(llamafactory_path, 'data', 'dataset_info.json')
23
+ if not os.path.exists(dataset_info_path):
24
+ print(f"⚠️ Dataset info file not found: {dataset_info_path}")
25
+ os.chdir(original_cwd)
26
+ with gr.Blocks() as missing_file_ui:
27
+ gr.Markdown("## ⚠️ Configuration Missing")
28
+ gr.Markdown(f"データセット情報ファイルが見つかりません: `{dataset_info_path}`")
29
+ gr.Markdown("LlamaFactoryの初期設定が必要です。")
30
+ return missing_file_ui
31
+
32
+ print(f"✅ Found dataset info: {dataset_info_path}")
33
+ print(f"✅ Working directory: {os.getcwd()}")
34
+
35
+ # LlamaFactoryのUIを作成
36
+ from llamafactory.webui.interface import create_ui
37
+ ui = create_ui()
38
+
39
+ # 作業ディレクトリを元に戻す
40
+ os.chdir(original_cwd)
41
+ return ui
42
+
43
+ except ImportError as e:
44
+ if 'original_cwd' in locals():
45
+ os.chdir(original_cwd)
46
+ print(f"LlamaFactory import error: {e}")
47
+ # フォールバック UI を作成
48
+ with gr.Blocks() as fallback_ui:
49
+ gr.Markdown("## ⚠️ LlamaFactory Unavailable")
50
+ gr.Markdown("LlamaFactoryモジュールが見つかりません。")
51
+ gr.Markdown("### 解決方法:")
52
+ gr.Markdown("1. LlamaFactoryの依存関係をインストール")
53
+ gr.Markdown("2. パスの設定を確認")
54
+ gr.Code("pip install -e /workspaces/fastapi_django_main_live/LLaMA-Factory", language="bash")
55
+ return fallback_ui
56
+ except Exception as e:
57
+ if 'original_cwd' in locals():
58
+ os.chdir(original_cwd)
59
+ print(f"LlamaFactory UI creation error: {e}")
60
+ with gr.Blocks() as error_ui:
61
+ gr.Markdown("## ❌ LlamaFactory Error")
62
+ gr.Markdown(f"エラー: {str(e)}")
63
+ gr.Markdown("### トラブルシューティング:")
64
+ gr.Markdown("1. LlamaFactoryのファイル構成を確認")
65
+ gr.Markdown("2. 必要な依存関係をインストール")
66
+ gr.Markdown("3. 権限設定を確認")
67
+ with gr.Code():
68
+ gr.Textbox(value=f"エラー詳細: {str(e)}", interactive=False)
69
+ return error_ui
70
+
71
+ # メインGradio インターフェースを作成
72
+ with gr.Blocks(title="🤖 AI Development Platform", theme=gr.themes.Soft()) as gradio_interface:
73
+ # ヘッダー
74
+ gr.Markdown("""
75
+ # 🤖 AI開発プラットフォーム
76
 
77
+ このプラットフォームでは、LlamaFactoryを使用してLLMのファインチューニングを行うことができます。
78
+ """)
 
 
 
 
 
79
 
80
+ with gr.Tabs() as tabs:
81
+ # LlamaFactory タブ
82
+ with gr.TabItem("🦙 LlamaFactory WebUI"):
83
+ gr.Markdown("""
84
+ ## 🦙 LlamaFactory WebUI
85
+
86
+ LLM(Large Language Models)のファインチューニングを行うためのWebインターフェースです。
87
+
88
+ ### 主な機能:
89
+ - 🎯 **モデル訓練**: カスタムデータセットでLLMを訓練
90
+ - 📊 **データセット管理**: 訓練用データの管理・前処理
91
+ - ⚙️ **ハイパーパラメータ調整**: 学習パラメータの最適化
92
+ - 📈 **訓練監視**: リアルタイムでの訓練進捗確認
93
+ """)
94
+
95
+ # LlamaFactory UIを統合
96
+ try:
97
+ llamafactory_ui = create_llamafactory_interface()
98
+ if llamafactory_ui:
99
+ # LlamaFactory UIを現在のタブに埋め込み
100
+ with gr.Group():
101
+ gr.Markdown("### 🔧 LlamaFactory コントロールパネル")
102
+ llamafactory_ui.render()
103
+ except Exception as e:
104
+ gr.Markdown(f"### ❌ LlamaFactory 読み込みエラー\n\n```\n{str(e)}\n```")
105
+
106
+ # 情報タブ
107
+ with gr.TabItem("ℹ️ システム情報"):
108
+ gr.Markdown("""
109
+ ## 📋 システム情報
110
+
111
+ ### 🔧 利用可能な機能:
112
+ - **LlamaFactory**: LLMファインチューニング
113
+ - **OpenInterpreter**: コード実行・解釈
114
+ - **AutoPrompt**: プロンプト自動最適化
115
+ - **BabyAGI**: 自律AIエージェント
116
+
117
+ ### 🚀 クイックスタート:
118
+ 1. 左側の「LlamaFactory WebUI」タブを選択
119
+ 2. データセットを準備・アップロード
120
+ 3. モデルとパラメータを設定
121
+ 4. 訓練を開始
122
+
123
+ ### 📞 サポート:
124
+ - 📖 ドキュメント: `/docs/` フォルダ
125
+ - 🐛 問題報告: GitHub Issues
126
+ """)
127
+
128
+ # システム状態表示
129
+ with gr.Row():
130
+ with gr.Column():
131
+ gr.Markdown("#### 🔍 システム状態")
132
+
133
+ # 動的にシステム情報を取得
134
+ def get_system_info():
135
+ llamafactory_path = '/workspaces/fastapi_django_main_live/LLaMA-Factory'
136
+ dataset_info_path = os.path.join(llamafactory_path, 'data', 'dataset_info.json')
137
+
138
+ return f"""
139
+ - **Python Version**: {sys.version.split()[0]}
140
+ - **Current Directory**: {os.getcwd()}
141
+ - **LlamaFactory Path**: {llamafactory_path}
142
+ - **Dataset Info Exists**: {"✅ Yes" if os.path.exists(dataset_info_path) else "❌ No"}
143
+ - **LlamaFactory Accessible**: {"✅ Yes" if os.path.exists(llamafactory_path) else "❌ No"}
144
+ """
145
+
146
+ system_status = get_system_info()
147
+ gr.Markdown(system_status)
148
+
149
+ # LlamaFactory セットアップボタン
150
+ with gr.Row():
151
+ setup_btn = gr.Button("🔧 LlamaFactory セットアップ確認", variant="secondary")
152
+
153
+ setup_output = gr.Textbox(
154
+ label="セットアップ結果",
155
+ lines=10,
156
+ interactive=False,
157
+ visible=False
158
+ )
159
+
160
+ def check_llamafactory_setup():
161
+ """LlamaFactoryのセットアップ状況をチェック"""
162
+ result = []
163
+ llamafactory_path = '/workspaces/fastapi_django_main_live/LLaMA-Factory'
164
+
165
+ # 1. ディレクトリ存在確認
166
+ if os.path.exists(llamafactory_path):
167
+ result.append("✅ LlamaFactoryディレクトリが存在します")
168
+ else:
169
+ result.append("❌ LlamaFactoryディレクトリが見つかりません")
170
+ return "\n".join(result), gr.update(visible=True)
171
+
172
+ # 2. dataset_info.json確認
173
+ dataset_info_path = os.path.join(llamafactory_path, 'data', 'dataset_info.json')
174
+ if os.path.exists(dataset_info_path):
175
+ result.append("✅ dataset_info.jsonが存在します")
176
+ else:
177
+ result.append("❌ dataset_info.jsonが見つかりません")
178
+
179
+ # 3. 必要なディレクトリ確認
180
+ required_dirs = ['src', 'data', 'examples']
181
+ for dir_name in required_dirs:
182
+ dir_path = os.path.join(llamafactory_path, dir_name)
183
+ if os.path.exists(dir_path):
184
+ result.append(f"✅ {dir_name}/ ディレクトリが存在します")
185
+ else:
186
+ result.append(f"❌ {dir_name}/ ディレクトリが見つかりません")
187
+
188
+ # 4. モジュールインポート確認
189
+ try:
190
+ sys.path.append(llamafactory_path)
191
+ import llamafactory
192
+ result.append("✅ LlamaFactoryモジュールのインポートが可能です")
193
+ except ImportError as e:
194
+ result.append(f"❌ LlamaFactoryモジュールのインポートに失敗: {e}")
195
+
196
+ return "\n".join(result), gr.update(visible=True)
197
+
198
+ setup_btn.click(
199
+ fn=check_llamafactory_setup,
200
+ outputs=[setup_output, setup_output]
201
+ )