ndmhung6 commited on
Commit
753ef6d
·
1 Parent(s): b9d06f7

feat: migrate batch generator backend to SQL Server with auto-provisioned tables

Browse files
Files changed (2) hide show
  1. app.py +147 -50
  2. requirements.txt +1 -0
app.py CHANGED
@@ -2622,14 +2622,56 @@ def api_content_planner_generate():
2622
  return jsonify({'error': f"Lỗi lập kế hoạch nội dung: {_err_msg(str(e))}"}), 500
2623
 
2624
  # ==============================================
2625
- # TOOL: AI BATCH GENERATOR
2626
  # ==============================================
2627
  import uuid
2628
  import threading
 
 
 
 
 
 
 
 
 
 
2629
 
2630
- BATCH_JOBS = {}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2631
 
2632
- def run_batch_replicate(batch_id, prompts, mode, replicate_token):
 
 
 
2633
  # Model configuration
2634
  if mode == 'video':
2635
  model_version = "748dae3f714ccf25a72064119d854203f1917b2b8c56fa769f3e498c0d9c491f"
@@ -2641,10 +2683,31 @@ def run_batch_replicate(batch_id, prompts, mode, replicate_token):
2641
  'Content-Type': 'application/json'
2642
  }
2643
 
2644
- for idx, prompt_item in enumerate(prompts):
2645
- prompt_text = prompt_item['prompt']
2646
- prompt_item['status'] = 'processing'
2647
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2648
  # Prepare payload
2649
  payload = {
2650
  "version": model_version,
@@ -2655,7 +2718,7 @@ def run_batch_replicate(batch_id, prompts, mode, replicate_token):
2655
  payload["input"]["guidance_scale"] = 1.0
2656
 
2657
  try:
2658
- # 1. Create prediction request
2659
  req = urllib.request.Request(
2660
  "https://api.replicate.com/v1/predictions",
2661
  data=json.dumps(payload).encode('utf-8'),
@@ -2669,7 +2732,7 @@ def run_batch_replicate(batch_id, prompts, mode, replicate_token):
2669
  if not prediction_id:
2670
  raise Exception("Không nhận được prediction_id từ Replicate")
2671
 
2672
- # 2. Polling loop
2673
  poll_url = f"https://api.replicate.com/v1/predictions/{prediction_id}"
2674
  success = False
2675
  for _ in range(30): # max 60 seconds polling (30 * 2)
@@ -2682,33 +2745,60 @@ def run_batch_replicate(batch_id, prompts, mode, replicate_token):
2682
  pred_status = status_data.get('status')
2683
  if pred_status == 'succeeded':
2684
  output = status_data.get('output')
 
2685
  if isinstance(output, list) and len(output) > 0:
2686
- prompt_item['output_url'] = output[0]
2687
  elif isinstance(output, str):
2688
- prompt_item['output_url'] = output
2689
  else:
2690
- prompt_item['output_url'] = str(output)
2691
 
2692
- prompt_item['status'] = 'done'
 
 
 
 
 
2693
  success = True
2694
  break
2695
  elif pred_status in ['failed', 'canceled']:
2696
- prompt_item['status'] = 'failed'
2697
- prompt_item['error'] = status_data.get('error') or "Đã bị hủy hoặc lỗi"
 
 
 
 
 
2698
  success = True
2699
  break
2700
 
2701
  if not success:
2702
- prompt_item['status'] = 'failed'
2703
- prompt_item['error'] = "Quá thời gian chờ phản hồi (Timeout)"
 
 
 
2704
 
2705
  except Exception as e:
2706
- prompt_item['status'] = 'failed'
2707
- prompt_item['error'] = str(e)
 
 
 
 
 
 
 
2708
 
2709
  # Mark batch job as completed
2710
- if batch_id in BATCH_JOBS:
2711
- BATCH_JOBS[batch_id]['status'] = 'completed'
 
 
 
 
 
 
2712
 
2713
 
2714
  @app.route('/batch-generator')
@@ -2729,33 +2819,28 @@ def api_batch_generator_start():
2729
  if not raw_prompts or not isinstance(raw_prompts, list):
2730
  return jsonify({'error': 'Danh sách prompt không hợp lệ'}), 400
2731
 
2732
- # Build prompts structure
2733
- prompts_list = []
2734
- for p in raw_prompts:
2735
- p_str = str(p).strip()
2736
- if p_str:
2737
- prompts_list.append({
2738
- 'prompt': p_str,
2739
- 'status': 'queued',
2740
- 'output_url': None,
2741
- 'error': None
2742
- })
2743
-
2744
  if not prompts_list:
2745
  return jsonify({'error': 'Không tìm thấy prompt hợp lệ nào'}), 400
2746
 
2747
  batch_id = str(uuid.uuid4())
2748
- BATCH_JOBS[batch_id] = {
2749
- 'id': batch_id,
2750
- 'mode': mode,
2751
- 'status': 'running',
2752
- 'prompts': prompts_list
2753
- }
 
 
 
 
 
 
2754
 
2755
  # Start processing thread
2756
  thread = threading.Thread(
2757
- target=run_batch_replicate,
2758
- args=(batch_id, prompts_list, mode, replicate_token)
2759
  )
2760
  thread.daemon = True
2761
  thread.start()
@@ -2769,15 +2854,27 @@ def api_batch_generator_start():
2769
 
2770
  @app.route('/api/batch-generator/status/<batch_id>')
2771
  def api_batch_generator_status(batch_id):
2772
- job = BATCH_JOBS.get(batch_id)
2773
- if not job:
2774
- return jsonify({'error': 'Không tìm thấy mã Batch'}), 404
2775
- return jsonify({
2776
- 'success': True,
2777
- 'status': job['status'],
2778
- 'mode': job['mode'],
2779
- 'prompts': job['prompts']
2780
- })
 
 
 
 
 
 
 
 
 
 
 
 
2781
 
2782
  if __name__ == '__main__':
2783
  app.run(debug=True, port=5000)
 
2622
  return jsonify({'error': f"Lỗi lập kế hoạch nội dung: {_err_msg(str(e))}"}), 500
2623
 
2624
  # ==============================================
2625
+ # TOOL: AI BATCH GENERATOR (SQL SERVER CONNECTED)
2626
  # ==============================================
2627
  import uuid
2628
  import threading
2629
+ import pymssql
2630
+
2631
+ def get_db_connection():
2632
+ return pymssql.connect(
2633
+ server='db57971.public.databaseasp.net',
2634
+ user='db57971',
2635
+ password='Qn4@3F#p!9fD',
2636
+ database='db57971',
2637
+ charset='utf8'
2638
+ )
2639
 
2640
+ def init_db():
2641
+ try:
2642
+ conn = get_db_connection()
2643
+ cursor = conn.cursor()
2644
+ cursor.execute("""
2645
+ IF NOT EXISTS (SELECT * FROM sysobjects WHERE name='batch_jobs' AND xtype='U')
2646
+ CREATE TABLE batch_jobs (
2647
+ id VARCHAR(50) PRIMARY KEY,
2648
+ mode VARCHAR(10) NOT NULL,
2649
+ status VARCHAR(20) NOT NULL,
2650
+ created_at DATETIME DEFAULT GETDATE()
2651
+ )
2652
+ """)
2653
+ cursor.execute("""
2654
+ IF NOT EXISTS (SELECT * FROM sysobjects WHERE name='batch_prompts' AND xtype='U')
2655
+ CREATE TABLE batch_prompts (
2656
+ id INT IDENTITY(1,1) PRIMARY KEY,
2657
+ batch_id VARCHAR(50) FOREIGN KEY REFERENCES batch_jobs(id) ON DELETE CASCADE,
2658
+ prompt_text NVARCHAR(MAX) NOT NULL,
2659
+ status VARCHAR(20) NOT NULL,
2660
+ output_url VARCHAR(2083) NULL,
2661
+ error_message NVARCHAR(MAX) NULL,
2662
+ created_at DATETIME DEFAULT GETDATE()
2663
+ )
2664
+ """)
2665
+ conn.commit()
2666
+ conn.close()
2667
+ print("SQL Server initialized and tables verified successfully.")
2668
+ except Exception as e:
2669
+ print(f"Error initializing SQL Server database: {e}")
2670
 
2671
+ # Run database setup on startup
2672
+ init_db()
2673
+
2674
+ def run_batch_replicate_db(batch_id, mode, replicate_token):
2675
  # Model configuration
2676
  if mode == 'video':
2677
  model_version = "748dae3f714ccf25a72064119d854203f1917b2b8c56fa769f3e498c0d9c491f"
 
2683
  'Content-Type': 'application/json'
2684
  }
2685
 
2686
+ try:
2687
+ # Fetch all prompts to process
2688
+ conn = get_db_connection()
2689
+ cursor = conn.cursor(as_dict=True)
2690
+ cursor.execute("SELECT id, prompt_text FROM batch_prompts WHERE batch_id = %s", (batch_id,))
2691
+ prompts = cursor.fetchall()
2692
+ conn.close()
2693
+ except Exception as e:
2694
+ print(f"Error fetching prompts from DB: {e}")
2695
+ return
2696
+
2697
+ for prompt_item in prompts:
2698
+ prompt_id = prompt_item['id']
2699
+ prompt_text = prompt_item['prompt_text']
2700
+
2701
+ # 1. Update status to 'processing'
2702
+ try:
2703
+ conn = get_db_connection()
2704
+ cursor = conn.cursor()
2705
+ cursor.execute("UPDATE batch_prompts SET status = 'processing' WHERE id = %d", (prompt_id,))
2706
+ conn.commit()
2707
+ conn.close()
2708
+ except Exception as e:
2709
+ print(f"Error updating status to processing: {e}")
2710
+
2711
  # Prepare payload
2712
  payload = {
2713
  "version": model_version,
 
2718
  payload["input"]["guidance_scale"] = 1.0
2719
 
2720
  try:
2721
+ # Create prediction request
2722
  req = urllib.request.Request(
2723
  "https://api.replicate.com/v1/predictions",
2724
  data=json.dumps(payload).encode('utf-8'),
 
2732
  if not prediction_id:
2733
  raise Exception("Không nhận được prediction_id từ Replicate")
2734
 
2735
+ # Polling loop
2736
  poll_url = f"https://api.replicate.com/v1/predictions/{prediction_id}"
2737
  success = False
2738
  for _ in range(30): # max 60 seconds polling (30 * 2)
 
2745
  pred_status = status_data.get('status')
2746
  if pred_status == 'succeeded':
2747
  output = status_data.get('output')
2748
+ output_url = None
2749
  if isinstance(output, list) and len(output) > 0:
2750
+ output_url = output[0]
2751
  elif isinstance(output, str):
2752
+ output_url = output
2753
  else:
2754
+ output_url = str(output)
2755
 
2756
+ # Update status to 'done' in DB
2757
+ conn = get_db_connection()
2758
+ cursor = conn.cursor()
2759
+ cursor.execute("UPDATE batch_prompts SET status = 'done', output_url = %s WHERE id = %d", (output_url, prompt_id))
2760
+ conn.commit()
2761
+ conn.close()
2762
  success = True
2763
  break
2764
  elif pred_status in ['failed', 'canceled']:
2765
+ error_msg = status_data.get('error') or "Đã bị hủy hoặc lỗi"
2766
+ # Update status to 'failed' in DB
2767
+ conn = get_db_connection()
2768
+ cursor = conn.cursor()
2769
+ cursor.execute("UPDATE batch_prompts SET status = 'failed', error_message = %s WHERE id = %d", (error_msg, prompt_id))
2770
+ conn.commit()
2771
+ conn.close()
2772
  success = True
2773
  break
2774
 
2775
  if not success:
2776
+ conn = get_db_connection()
2777
+ cursor = conn.cursor()
2778
+ cursor.execute("UPDATE batch_prompts SET status = 'failed', error_message = 'Quá thời gian chờ phản hồi (Timeout)' WHERE id = %d", (prompt_id,))
2779
+ conn.commit()
2780
+ conn.close()
2781
 
2782
  except Exception as e:
2783
+ # Update status to 'failed' in DB
2784
+ try:
2785
+ conn = get_db_connection()
2786
+ cursor = conn.cursor()
2787
+ cursor.execute("UPDATE batch_prompts SET status = 'failed', error_message = %s WHERE id = %d", (str(e), prompt_id))
2788
+ conn.commit()
2789
+ conn.close()
2790
+ except Exception as dbe:
2791
+ print(f"Error updating failure in DB: {dbe}")
2792
 
2793
  # Mark batch job as completed
2794
+ try:
2795
+ conn = get_db_connection()
2796
+ cursor = conn.cursor()
2797
+ cursor.execute("UPDATE batch_jobs SET status = 'completed' WHERE id = %s", (batch_id,))
2798
+ conn.commit()
2799
+ conn.close()
2800
+ except Exception as e:
2801
+ print(f"Error updating batch job completion: {e}")
2802
 
2803
 
2804
  @app.route('/batch-generator')
 
2819
  if not raw_prompts or not isinstance(raw_prompts, list):
2820
  return jsonify({'error': 'Danh sách prompt không hợp lệ'}), 400
2821
 
2822
+ prompts_list = [str(p).strip() for p in raw_prompts if str(p).strip()]
 
 
 
 
 
 
 
 
 
 
 
2823
  if not prompts_list:
2824
  return jsonify({'error': 'Không tìm thấy prompt hợp lệ nào'}), 400
2825
 
2826
  batch_id = str(uuid.uuid4())
2827
+
2828
+ try:
2829
+ # Insert batch job and prompts in database
2830
+ conn = get_db_connection()
2831
+ cursor = conn.cursor()
2832
+ cursor.execute("INSERT INTO batch_jobs (id, mode, status) VALUES (%s, %s, %s)", (batch_id, mode, 'running'))
2833
+ for prompt_text in prompts_list:
2834
+ cursor.execute("INSERT INTO batch_prompts (batch_id, prompt_text, status) VALUES (%s, %s, %s)", (batch_id, prompt_text, 'queued'))
2835
+ conn.commit()
2836
+ conn.close()
2837
+ except Exception as e:
2838
+ return jsonify({'error': f'Lỗi lưu thông tin vào CSDL SQL Server: {e}'}), 500
2839
 
2840
  # Start processing thread
2841
  thread = threading.Thread(
2842
+ target=run_batch_replicate_db,
2843
+ args=(batch_id, mode, replicate_token)
2844
  )
2845
  thread.daemon = True
2846
  thread.start()
 
2854
 
2855
  @app.route('/api/batch-generator/status/<batch_id>')
2856
  def api_batch_generator_status(batch_id):
2857
+ try:
2858
+ conn = get_db_connection()
2859
+ cursor = conn.cursor(as_dict=True)
2860
+ cursor.execute("SELECT status, mode FROM batch_jobs WHERE id = %s", (batch_id,))
2861
+ job = cursor.fetchone()
2862
+ if not job:
2863
+ conn.close()
2864
+ return jsonify({'error': 'Không tìm thấy mã Batch'}), 404
2865
+
2866
+ cursor.execute("SELECT prompt_text AS prompt, status, output_url, error_message AS error FROM batch_prompts WHERE batch_id = %s ORDER BY id ASC", (batch_id,))
2867
+ prompts = cursor.fetchall()
2868
+ conn.close()
2869
+
2870
+ return jsonify({
2871
+ 'success': True,
2872
+ 'status': job['status'],
2873
+ 'mode': job['mode'],
2874
+ 'prompts': prompts
2875
+ })
2876
+ except Exception as e:
2877
+ return jsonify({'error': f'Lỗi truy vấn CSDL SQL Server: {e}'}), 500
2878
 
2879
  if __name__ == '__main__':
2880
  app.run(debug=True, port=5000)
requirements.txt CHANGED
@@ -14,3 +14,4 @@ vieneu
14
  moviepy
15
  replicate
16
  gradio-client
 
 
14
  moviepy
15
  replicate
16
  gradio-client
17
+ pymssql