Spaces:
Sleeping
Sleeping
| import os | |
| import re | |
| import json | |
| import gradio as gr | |
| from typing import Dict, List, Optional | |
| from openai import OpenAI | |
| # إعداد العميل - يمكنك استخدام أي نموذج متوافق مع OpenAI API | |
| API_KEY = os.getenv("API_KEY", "") | |
| BASE_URL = os.getenv("BASE_URL", "https://api.openai.com/v1") | |
| client = OpenAI(api_key=API_KEY, base_url=BASE_URL) if API_KEY else None | |
| CSS = """ | |
| :root { direction: rtl; } | |
| * { font-family: "Tajawal", system-ui, -apple-system, sans-serif; } | |
| .gradio-container { direction: rtl; } | |
| .app-header { text-align: center; margin: 20px 0; } | |
| .app-title { font-size: 24px; font-weight: bold; color: #2D3748; } | |
| .app-sub { color: #718096; margin-bottom: 30px; } | |
| .result-area { direction: ltr; } | |
| """ | |
| SYSTEM_PROMPT = """أنت مساعد متخصص في تحويل أوامر Docker إلى قوالب نشر Ghaymah. | |
| قم بتحليل أوامر Docker Run أو Docker Compose وأنشئ قالب Ghaymah المناسب. | |
| هيكل قالب Ghaymah: | |
| { | |
| "category": "development|automation|database|etc", | |
| "description": "وصف التطبيق", | |
| "icon": "IconName", | |
| "id": "app-id", | |
| "name": "App Name", | |
| "resources": [ | |
| { | |
| "type": "volume", | |
| "values": { | |
| "name": "data-volume", | |
| "size": "{{volumeSize}}", | |
| "userId": "{{userId}}" | |
| } | |
| }, | |
| { | |
| "type": "app", | |
| "values": { | |
| "container": { | |
| "image": "image:tag" | |
| }, | |
| "env": { | |
| "VARIABLE": "value" | |
| }, | |
| "name": "app-name", | |
| "ports": [{"expose": true, "number": 8080}], | |
| "projectId": "{{projectId}}", | |
| "publicAccess": { | |
| "baseDomain": "hosted.ghaymah.systems", | |
| "domain": "auto", | |
| "enabled": true | |
| }, | |
| "resourceTier": "{{resourceTier}}", | |
| "storage": { | |
| "volumes": [ | |
| { | |
| "mountPath": "/data", | |
| "name": "{{resources[0].uniqueName}}" | |
| } | |
| ] | |
| } | |
| } | |
| } | |
| ], | |
| "variables": { | |
| "resourceTier": { | |
| "default": "t3", | |
| "description": "Instance size", | |
| "options": ["t1", "t2", "t3", "t4", "t5", "t6", "t7"], | |
| "type": "dropdown" | |
| }, | |
| "volumeSize": { | |
| "default": "1Gi", | |
| "description": "Volume size", | |
| "options": ["512Mi", "1Gi", "2Gi", "5Gi", "10Gi"], | |
| "type": "dropdown" | |
| } | |
| } | |
| } | |
| Examples | |
| { | |
| "category": "automation", | |
| "description": "n8n workflow automation", | |
| "icon": "Zap", | |
| "id": "n8n", | |
| "name": "n8n", | |
| "resources": [ | |
| { | |
| "type": "volume", | |
| "values": { | |
| "name": "n8n-data", | |
| "size": "{{volumeSize}}", | |
| "userId": "{{userId}}" | |
| } | |
| }, | |
| { | |
| "type": "app", | |
| "values": { | |
| "container": { | |
| "image": "docker.n8n.io/n8nio/n8n" | |
| }, | |
| "env": { | |
| "EXECUTIONS_DATA_MAX_AGE": "336", | |
| "EXECUTIONS_DATA_PRUNE": "true", | |
| "N8N_EDITOR_BASE_URL": "https://{{resources[1].uniqueName}}.hosted.ghaymah.systems", | |
| "N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS": false, | |
| "N8N_HIRING_BANNER_ENABLED": false, | |
| "N8N_HOST": "{{resources[1].uniqueName}}.hosted.ghaymah.systems", | |
| "N8N_PORT": "5678", | |
| "N8N_PROTOCOL": "https", | |
| "N8N_PROXY_HOPS": 1, | |
| "N8N_TEMPLATES_ENABLED": true, | |
| "WEBHOOK_URL": "https://{{resources[1].uniqueName}}.hosted.ghaymah.systems" | |
| }, | |
| "fsGroup": 1000, | |
| "name": "n8n", | |
| "ports": [ | |
| { | |
| "expose": true, | |
| "number": 5678 | |
| } | |
| ], | |
| "projectId": "{{projectId}}", | |
| "publicAccess": { | |
| "baseDomain": "hosted.ghaymah.systems", | |
| "domain": "auto", | |
| "enabled": true | |
| }, | |
| "resourceTier": "{{resourceTier}}", | |
| "storage": { | |
| "volumes": [ | |
| { | |
| "mountPath": "/home/node", | |
| "name": "{{resources[0].uniqueName}}" | |
| } | |
| ] | |
| } | |
| } | |
| } | |
| ], | |
| "variables": { | |
| "resourceTier": { | |
| "default": "t4", | |
| "description": "Instance size", | |
| "options": [ | |
| "t1", | |
| "t2", | |
| "t3", | |
| "t4", | |
| "t5", | |
| "t6", | |
| "t7" | |
| ], | |
| "type": "dropdown" | |
| }, | |
| "volumeSize": { | |
| "default": "1Gi", | |
| "description": "Volume size", | |
| "options": [ | |
| "512Mi", | |
| "1Gi", | |
| "2Gi", | |
| "5Gi", | |
| "10Gi" | |
| ], | |
| "type": "dropdown" | |
| } | |
| } | |
| } | |
| Example 2 | |
| { | |
| "category": "development", | |
| "description": "DocuSeal is an open-source document signing platform", | |
| "icon": "Box", | |
| "id": "docuseal", | |
| "name": "DocuSeal", | |
| "resources": [ | |
| { | |
| "type": "volume", | |
| "values": { | |
| "name": "docuseal-data", | |
| "size": "{{volumeSize}}", | |
| "userId": "{{userId}}" | |
| } | |
| }, | |
| { | |
| "type": "volume", | |
| "values": { | |
| "name": "postgres-data", | |
| "size": "{{pgVolumeSize}}", | |
| "userId": "{{userId}}" | |
| } | |
| }, | |
| { | |
| "type": "app", | |
| "values": { | |
| "container": { | |
| "image": "docuseal/docuseal:latest" | |
| }, | |
| "env": { | |
| "DATABASE_URL": "postgresql://postgres:postgres@{{resources[1].uniqueName}}:5432/docuseal", | |
| "FORCE_SSL": "{{host}}" | |
| }, | |
| "name": "docuseal", | |
| "ports": [ | |
| { | |
| "expose": true, | |
| "number": 3000 | |
| } | |
| ], | |
| "projectId": "{{projectId}}", | |
| "publicAccess": { | |
| "baseDomain": "hosted.ghaymah.systems", | |
| "domain": "auto", | |
| "enabled": true | |
| }, | |
| "resourceTier": "{{resourceTier}}", | |
| "storage": { | |
| "volumes": [ | |
| { | |
| "mountPath": "/data/docuseal", | |
| "name": "{{resources[0].uniqueName}}" | |
| } | |
| ] | |
| } | |
| } | |
| }, | |
| { | |
| "type": "app", | |
| "values": { | |
| "container": { | |
| "image": "postgres:16" | |
| }, | |
| "env": { | |
| "PGDATA": "/var/lib/postgresql/data/pgdata", | |
| "POSTGRES_DB": "docuseal", | |
| "POSTGRES_PASSWORD": "postgres", | |
| "POSTGRES_USER": "postgres" | |
| }, | |
| "healthCheck": { | |
| "command": [ | |
| "CMD-SHELL", | |
| "pg_isready -U postgres" | |
| ], | |
| "interval": 5, | |
| "retries": 5, | |
| "timeout": 5 | |
| }, | |
| "name": "postgres", | |
| "ports": [ | |
| { | |
| "expose": false, | |
| "number": 5432 | |
| } | |
| ], | |
| "projectId": "{{projectId}}", | |
| "publicAccess": { | |
| "enabled": false | |
| }, | |
| "resourceTier": "{{resourceTier}}", | |
| "storage": { | |
| "volumes": [ | |
| { | |
| "mountPath": "/var/lib/postgresql/data", | |
| "name": "{{resources[1].uniqueName}}" | |
| } | |
| ] | |
| } | |
| } | |
| } | |
| ], | |
| "variables": { | |
| "host": { | |
| "default": "", | |
| "description": "Host domain for SSL (leave empty if not using SSL)", | |
| "type": "text" | |
| }, | |
| "pgVolumeSize": { | |
| "default": "1Gi", | |
| "description": "PostgreSQL data volume size", | |
| "options": [ | |
| "512Mi", | |
| "1Gi", | |
| "2Gi", | |
| "5Gi", | |
| "10Gi" | |
| ], | |
| "type": "dropdown" | |
| }, | |
| "resourceTier": { | |
| "default": "t3", | |
| "description": "Instance size", | |
| "options": [ | |
| "t1", | |
| "t2", | |
| "t3", | |
| "t4", | |
| "t5", | |
| "t6", | |
| "t7" | |
| ], | |
| "type": "dropdown" | |
| }, | |
| "volumeSize": { | |
| "default": "2Gi", | |
| "description": "DocuSeal data volume size", | |
| "options": [ | |
| "512Mi", | |
| "1Gi", | |
| "2Gi", | |
| "5Gi", | |
| "10Gi" | |
| ], | |
| "type": "dropdown" | |
| } | |
| } | |
| } | |
| Example 3 | |
| { | |
| "category": "database", | |
| "description": "PostgreSQL database server with Hasura GraphQL Engine", | |
| "icon": "Database", | |
| "id": "postgres-hasura", | |
| "name": "Hasura GraphQL", | |
| "resources": [ | |
| { | |
| "type": "volume", | |
| "values": { | |
| "name": "postgres-data", | |
| "size": "{{volumeSize}}", | |
| "userId": "{{userId}}" | |
| } | |
| }, | |
| { | |
| "type": "app", | |
| "values": { | |
| "container": { | |
| "image": "postgres:{{version}}" | |
| }, | |
| "env": { | |
| "PGDATA": "/var/lib/postgresql/data/pgdata", | |
| "POSTGRES_DB": "graphql", | |
| "POSTGRES_HOST_AUTH_METHOD": "scram-sha-256", | |
| "POSTGRES_INITDB_ARGS": "--auth-host=scram-sha-256 --auth-local=scram-sha-256", | |
| "POSTGRES_PASSWORD": "postgres", | |
| "POSTGRES_USER": "postgres" | |
| }, | |
| "fsGroup": 999, | |
| "name": "postgres", | |
| "ports": [ | |
| { | |
| "expose": false, | |
| "number": 5432 | |
| } | |
| ], | |
| "projectId": "{{projectId}}", | |
| "publicAccess": { | |
| "enabled": false | |
| }, | |
| "resourceTier": "{{resourceTier}}", | |
| "storage": { | |
| "volumes": [ | |
| { | |
| "mountPath": "/var/lib/postgresql/data", | |
| "name": "{{resources[0].uniqueName}}" | |
| } | |
| ] | |
| } | |
| } | |
| }, | |
| { | |
| "type": "app", | |
| "values": { | |
| "container": { | |
| "image": "hasura/graphql-engine:latest" | |
| }, | |
| "env": { | |
| "HASURA_GRAPHQL_ADMIN_SECRET": "{{adminSecret}}", | |
| "HASURA_GRAPHQL_DATABASE_URL": "postgres://postgres:postgres@{{resources[1].uniqueName}}:5432/graphql", | |
| "HASURA_GRAPHQL_DEV_MODE": "true", | |
| "HASURA_GRAPHQL_ENABLED_LOG_TYPES": "startup, http-log, webhook-log, websocket-log, query-log", | |
| "HASURA_GRAPHQL_ENABLE_CONSOLE": "true" | |
| }, | |
| "name": "hasura", | |
| "ports": [ | |
| { | |
| "expose": true, | |
| "number": 8080 | |
| } | |
| ], | |
| "projectId": "{{projectId}}", | |
| "publicAccess": { | |
| "baseDomain": "hosted.ghaymah.systems", | |
| "domain": "auto", | |
| "enabled": true | |
| }, | |
| "resourceTier": "{{hasuraResourceTier}}" | |
| } | |
| } | |
| ], | |
| "variables": { | |
| "adminSecret": { | |
| "default": "test-secret", | |
| "description": "Hasura admin secret", | |
| "type": "password" | |
| }, | |
| "hasuraResourceTier": { | |
| "default": "t3", | |
| "description": "Hasura instance size", | |
| "options": [ | |
| "t1", | |
| "t2", | |
| "t3", | |
| "t4", | |
| "t5", | |
| "t6", | |
| "t7" | |
| ], | |
| "type": "dropdown" | |
| }, | |
| "resourceTier": { | |
| "default": "t3", | |
| "description": "PostgreSQL instance size", | |
| "options": [ | |
| "t1", | |
| "t2", | |
| "t3", | |
| "t4", | |
| "t5", | |
| "t6", | |
| "t7" | |
| ], | |
| "type": "dropdown" | |
| }, | |
| "version": { | |
| "default": "15", | |
| "description": "PostgreSQL version (compatible with Hasura)", | |
| "options": [ | |
| "12", | |
| "13", | |
| "14", | |
| "15", | |
| "16" | |
| ], | |
| "type": "dropdown" | |
| }, | |
| "volumeSize": { | |
| "default": "200Mi", | |
| "description": "Volume size for database storage", | |
| "options": [ | |
| "200Mi", | |
| "500Mi", | |
| "1Gi", | |
| "2Gi", | |
| "5Gi", | |
| "10Gi" | |
| ], | |
| "type": "dropdown" | |
| } | |
| } | |
| } | |
| أرجع JSON صالح فقط بدون أي نص إضافي.""" | |
| def analyze_docker_command(command: str) -> str: | |
| """تحليل أمر Docker باستخدام النموذج اللغوي""" | |
| if not client: | |
| return json.dumps({ | |
| "error": "⚠️ لم يتم تكوين API_KEY. الرجاء إضافة المفتاح في متغيرات البيئة." | |
| }, indent=2, ensure_ascii=False) | |
| try: | |
| response = client.chat.completions.create( | |
| model="DeepSeek-Coder", | |
| messages=[ | |
| {"role": "system", "content": SYSTEM_PROMPT}, | |
| {"role": "user", "content": f"""حول أمر Docker التالي إلى قالب Ghaymah: | |
| {command} | |
| ملاحظات: | |
| - استخدم المنافذ المناسبة | |
| - أضف المتغيرات البيئية اللازمة | |
| - حدد الفئة المناسبة (development, automation, database, etc) | |
| - اختر أيقونة مناسبة من: Box, Database, Server, Code, Zap, Search | |
| - تأكد من أن القالب يعمل بشكل صحيح على منصة Ghaymah"""} | |
| ], | |
| temperature=0.1, | |
| max_tokens=2000 | |
| ) | |
| result = response.choices[0].message.content | |
| # محاولة استخراج JSON من الرد | |
| json_match = re.search(r'\{.*\}', result, re.DOTALL) | |
| if json_match: | |
| return json_match.group() | |
| else: | |
| return result | |
| except Exception as e: | |
| return json.dumps({ | |
| "error": f"فشل في التحليل: {str(e)}" | |
| }, indent=2, ensure_ascii=False) | |
| def validate_and_format_json(json_str: str) -> str: | |
| """التحقق من صحة JSON وتنسيقه""" | |
| try: | |
| parsed = json.loads(json_str) | |
| return json.dumps(parsed, indent=2, ensure_ascii=False) | |
| except json.JSONDecodeError: | |
| # إذا لم يكن JSON صالحاً، إرجاعه كما هو مع رسالة خطأ | |
| return f"⚠️ الناتج ليس JSON صالح:\n\n{json_str}" | |
| def process_docker_input(docker_input: str, input_type: str) -> dict: | |
| """معالجة إدخال Docker وإرجاع قالب Ghaymah""" | |
| if not docker_input.strip(): | |
| return {"error": "الرجاء إدخال أمر Docker أو تكوين Docker Compose"} | |
| try: | |
| if input_type == "docker_run": | |
| result = analyze_docker_command(docker_input) | |
| else: # docker_compose | |
| result = analyze_docker_command(f"docker-compose:\n{docker_input}") | |
| # محاولة تحويل الناتج إلى قاموس | |
| try: | |
| if isinstance(result, str): | |
| return json.loads(result) | |
| return result | |
| except: | |
| return {"raw_output": result} | |
| except Exception as e: | |
| return {"error": f"حدث خطأ: {str(e)}"} | |
| # أمثلة للاستخدام | |
| DOCKER_RUN_EXAMPLES = [ | |
| "docker run -d --name nginx -p 8080:80 nginx:latest", | |
| "docker run -it --rm -p 7700:7700 -v $(pwd)/meili_data:/meili_data getmeili/meilisearch:v1.16", | |
| "docker run -d --name postgres -p 5432:5432 -e POSTGRES_PASSWORD=mysecretpassword -v pg_data:/var/lib/postgresql/data postgres:15", | |
| "docker run -d --name redis -p 6379:6379 -v redis_data:/data redis:7-alpine" | |
| ] | |
| DOCKER_COMPOSE_EXAMPLES = [ | |
| """version: '3.8' | |
| services: | |
| web: | |
| image: nginx:latest | |
| ports: | |
| - "8080:80" | |
| volumes: | |
| - ./html:/usr/share/nginx/html | |
| db: | |
| image: postgres:15 | |
| environment: | |
| POSTGRES_PASSWORD: mysecretpassword | |
| volumes: | |
| - pg_data:/var/lib/postgresql/data | |
| volumes: | |
| pg_data:""", | |
| """version: '3' | |
| services: | |
| app: | |
| image: node:18 | |
| ports: | |
| - "3000:3000" | |
| environment: | |
| - NODE_ENV=production | |
| volumes: | |
| - app_data:/app/data | |
| volumes: | |
| app_data:""" | |
| ] | |
| # واجهة Gradio | |
| with gr.Blocks(title="محول Docker إلى Ghaymah", css=CSS, theme=gr.themes.Soft()) as demo: | |
| gr.HTML(""" | |
| <div class="app-header"> | |
| <div class="app-title">🔄 محول Docker إلى Ghaymah</div> | |
| <div class="app-sub">حوّل أوامر Docker Run و Docker Compose إلى قوالب نشر Ghaymah تلقائياً</div> | |
| </div> | |
| """) | |
| with gr.Row(): | |
| with gr.Column(scale=1): | |
| input_type = gr.Radio( | |
| choices=["docker_run", "docker_compose"], | |
| value="docker_run", | |
| label="نوع الإدخال", | |
| info="اختر نوع أمر Docker الذي تريد تحويله" | |
| ) | |
| gr.Markdown("### أمثلة جاهزة") | |
| with gr.Tab("Docker Run"): | |
| docker_run_examples = gr.Dataset( | |
| components=[gr.Textbox(visible=False)], | |
| samples=[[ex] for ex in DOCKER_RUN_EXAMPLES], | |
| label="اختر مثالاً" | |
| ) | |
| with gr.Tab("Docker Compose"): | |
| docker_compose_examples = gr.Dataset( | |
| components=[gr.Textbox(visible=False)], | |
| samples=[[ex] for ex in DOCKER_COMPOSE_EXAMPLES], | |
| label="اختر مثالاً" | |
| ) | |
| gr.Markdown(""" | |
| ### 💡 نصائح للاستخدام: | |
| - أدخل أمر `docker run` كاملاً أو تكوين `docker-compose.yml` | |
| - سيقوم النموذج اللغوي بتحليل الأوامر وإنشاء القالب المناسب | |
| - يمكنك تعديل القالب الناتج حسب احتياجاتك | |
| """) | |
| with gr.Column(scale=2): | |
| docker_input = gr.Textbox( | |
| label="أمر Docker أو تكوين Docker Compose", | |
| placeholder="أدخل أمر docker run هنا... أو تكوين docker-compose...", | |
| lines=8, | |
| max_lines=15 | |
| ) | |
| convert_btn = gr.Button("تحويل إلى قالب Ghaymah 🚀", variant="primary") | |
| output = gr.JSON( | |
| label="قالب Ghaymah الناتج" | |
| ) | |
| # معالجة الأمثلة | |
| def load_example(example): | |
| return example[0] | |
| docker_run_examples.click(load_example, docker_run_examples, docker_input) | |
| docker_compose_examples.click(load_example, docker_compose_examples, docker_input) | |
| # زر التحويل | |
| convert_btn.click( | |
| fn=process_docker_input, | |
| inputs=[docker_input, input_type], | |
| outputs=output | |
| ) | |
| # أيضًا السماح بالإدخال باستخدام Enter | |
| docker_input.submit( | |
| fn=process_docker_input, | |
| inputs=[docker_input, input_type], | |
| outputs=output | |
| ) | |
| if __name__ == "__main__": | |
| demo.launch(share=True) |