openfree commited on
Commit
d10d76d
ยท
verified ยท
1 Parent(s): 8ae8099

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +203 -31
app.py CHANGED
@@ -1235,6 +1235,34 @@ def create_interface():
1235
  box-shadow: 0 10px 30px rgba(0,0,0,0.3);
1236
  }
1237
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1238
  .act-button {
1239
  min-height: 80px;
1240
  font-size: 1.1rem;
@@ -1258,7 +1286,7 @@ def create_interface():
1258
  margin: 15px 0;
1259
  }
1260
  """
1261
-
1262
  with gr.Blocks(theme=gr.themes.Soft(), css=css, title="AI ์‹œ๋‚˜๋ฆฌ์˜ค ์ž‘๊ฐ€") as interface:
1263
  gr.HTML("""
1264
  <div class="main-header">
@@ -1402,6 +1430,7 @@ def create_interface():
1402
  session_id = system.current_session_id
1403
  yield progress, status, formatted, planning_data, session_id
1404
 
 
1405
  def handle_act_writing(act_name, session_id, planning_data, previous_acts):
1406
  """๋ง‰๋ณ„ ์‹œ๋‚˜๋ฆฌ์˜ค ์ž‘์„ฑ - generator ๋ž˜ํผ"""
1407
  if not session_id or not planning_data:
@@ -1410,6 +1439,7 @@ def create_interface():
1410
 
1411
  try:
1412
  system = ScreenplayGenerationSystem()
 
1413
 
1414
  # Generator๋ฅผ ์ˆœํšŒํ•˜๋ฉฐ yield
1415
  for act_progress, status_msg in system.generate_act(
@@ -1417,46 +1447,179 @@ def create_interface():
1417
  ):
1418
  progress_html = create_act_progress_display(act_progress)
1419
  screenplay_display = format_screenplay_display(act_progress.content)
 
1420
 
1421
  yield progress_html, status_msg, screenplay_display
 
 
 
 
1422
 
1423
  except Exception as e:
1424
  logger.error(f"Act writing error: {e}")
1425
  yield f"<div>โŒ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}</div>", f"์˜ค๋ฅ˜: {str(e)}", ""
1426
-
1427
  def format_screenplay_display(content):
 
1428
  if not content:
1429
  return "*์ž‘์„ฑ ์ค‘...*"
1430
-
1431
- # ์‹œ๋‚˜๋ฆฌ์˜ค ํฌ๋งทํŒ…
1432
- formatted = content.replace("INT.", "**INT.**").replace("EXT.", "**EXT.**")
1433
- # ์บ๋ฆญํ„ฐ๋ช… ๊ฐ•์กฐ (๋Œ€๋ฌธ์ž๋กœ ๋œ ์ค„)
1434
- lines = formatted.split('\n')
1435
  result = []
 
 
1436
  for line in lines:
1437
- if line.strip() and line.strip().isupper() and len(line.strip().split()) <= 3:
1438
- result.append(f"**{line.strip()}**")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1439
  else:
1440
  result.append(line)
1441
- return '\n'.join(result)
1442
-
1443
- def combine_all_acts(act1, act2a, act2b, act3):
1444
- """๋ชจ๋“  ๋ง‰ ํ•ฉ์น˜๊ธฐ"""
 
 
 
 
 
 
 
 
 
1445
  full = "# ๐ŸŽฌ ์ „์ฒด ์‹œ๋‚˜๋ฆฌ์˜ค\n\n"
1446
 
1447
- if act1 and act1 != "*1๋ง‰์ด ์—ฌ๊ธฐ์— ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค...*":
1448
- full += "## ์ œ1๋ง‰ - ์„ค์ •\n\n" + act1 + "\n\n---\n\n"
1449
- if act2a and act2a != "*2๋ง‰A๊ฐ€ ์—ฌ๊ธฐ์— ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค...*":
1450
- full += "## ์ œ2๋ง‰A - ์ƒ์Šน\n\n" + act2a + "\n\n---\n\n"
1451
- if act2b and act2b != "*2๋ง‰B๊ฐ€ ์—ฌ๊ธฐ์— ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค...*":
1452
- full += "## ์ œ2๋ง‰B - ๋ณต์žกํ™”\n\n" + act2b + "\n\n---\n\n"
1453
- if act3 and act3 != "*3๋ง‰์ด ์—ฌ๊ธฐ์— ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค...*":
1454
- full += "## ์ œ3๋ง‰ - ํ•ด๊ฒฐ\n\n" + act3 + "\n\n"
1455
 
1456
- return full if full != "# ๐ŸŽฌ ์ „์ฒด ์‹œ๋‚˜๋ฆฌ์˜ค\n\n" else "*์ „์ฒด ์‹œ๋‚˜๋ฆฌ์˜ค๊ฐ€ ์™„์„ฑ๋˜๋ฉด ์—ฌ๊ธฐ์— ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค...*"
1457
-
1458
- def save_to_file(full_screenplay):
1459
- """์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ํŒŒ์ผ๋กœ ์ €์žฅ"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1460
  if not full_screenplay or full_screenplay == "*์ „์ฒด ์‹œ๋‚˜๋ฆฌ์˜ค๊ฐ€ ์™„์„ฑ๋˜๋ฉด ์—ฌ๊ธฐ์— ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค...*":
1461
  return None
1462
 
@@ -1464,8 +1627,16 @@ def create_interface():
1464
  filename = f"screenplay_{timestamp}.txt"
1465
 
1466
  with open(filename, 'w', encoding='utf-8') as f:
1467
- # ๋งˆํฌ๋‹ค์šด ์ œ๊ฑฐ
1468
- clean_text = full_screenplay.replace("**", "").replace("#", "")
 
 
 
 
 
 
 
 
1469
  f.write(clean_text)
1470
 
1471
  return filename
@@ -1562,15 +1733,16 @@ def create_interface():
1562
 
1563
  # ๋‹ค์šด๋กœ๋“œ
1564
  download_btn.click(
1565
- fn=save_to_file,
1566
- inputs=[full_output],
1567
  outputs=[download_file]
1568
  ).then(
1569
- lambda x: gr.update(visible=True) if x else gr.update(visible=False),
1570
  inputs=[download_file],
1571
  outputs=[download_file]
1572
  )
1573
-
 
1574
  return interface
1575
 
1576
  # ๋ฉ”์ธ ์‹คํ–‰
 
1235
  box-shadow: 0 10px 30px rgba(0,0,0,0.3);
1236
  }
1237
 
1238
+ /* ์‹œ๋‚˜๋ฆฌ์˜ค ์ถœ๋ ฅ ์Šคํƒ€์ผ */
1239
+ .screenplay-output {
1240
+ font-family: 'Courier New', monospace;
1241
+ font-size: 14px;
1242
+ line-height: 1.6;
1243
+ white-space: pre-wrap;
1244
+ background: #f8f9fa;
1245
+ padding: 20px;
1246
+ border-radius: 8px;
1247
+ }
1248
+
1249
+ .screenplay-output h3 {
1250
+ color: #2c3e50;
1251
+ margin: 20px 0 10px 0;
1252
+ font-size: 16px;
1253
+ font-weight: bold;
1254
+ }
1255
+
1256
+ .screenplay-output strong {
1257
+ color: #34495e;
1258
+ font-weight: bold;
1259
+ }
1260
+
1261
+ .screenplay-output em {
1262
+ font-style: italic;
1263
+ color: #7f8c8d;
1264
+ }
1265
+
1266
  .act-button {
1267
  min-height: 80px;
1268
  font-size: 1.1rem;
 
1286
  margin: 15px 0;
1287
  }
1288
  """
1289
+
1290
  with gr.Blocks(theme=gr.themes.Soft(), css=css, title="AI ์‹œ๋‚˜๋ฆฌ์˜ค ์ž‘๊ฐ€") as interface:
1291
  gr.HTML("""
1292
  <div class="main-header">
 
1430
  session_id = system.current_session_id
1431
  yield progress, status, formatted, planning_data, session_id
1432
 
1433
+ # 4. ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ ์ˆ˜์ • - act ๋‚ด์šฉ ์ €์žฅ ๊ฐœ์„ 
1434
  def handle_act_writing(act_name, session_id, planning_data, previous_acts):
1435
  """๋ง‰๋ณ„ ์‹œ๋‚˜๋ฆฌ์˜ค ์ž‘์„ฑ - generator ๋ž˜ํผ"""
1436
  if not session_id or not planning_data:
 
1439
 
1440
  try:
1441
  system = ScreenplayGenerationSystem()
1442
+ final_content = "" # ์ตœ์ข… ์ฝ˜ํ…์ธ  ์ €์žฅ
1443
 
1444
  # Generator๋ฅผ ์ˆœํšŒํ•˜๋ฉฐ yield
1445
  for act_progress, status_msg in system.generate_act(
 
1447
  ):
1448
  progress_html = create_act_progress_display(act_progress)
1449
  screenplay_display = format_screenplay_display(act_progress.content)
1450
+ final_content = act_progress.content # ์›๋ณธ ์ฝ˜ํ…์ธ  ์ €์žฅ
1451
 
1452
  yield progress_html, status_msg, screenplay_display
1453
+
1454
+ # ์™„๋ฃŒ ํ›„ ์›๋ณธ ์ฝ˜ํ…์ธ  ๋ฐ˜ํ™˜
1455
+ if final_content:
1456
+ yield progress_html, f"โœ… {act_name} ์™„์„ฑ ๋ฐ ์ €์žฅ๋จ", screenplay_display
1457
 
1458
  except Exception as e:
1459
  logger.error(f"Act writing error: {e}")
1460
  yield f"<div>โŒ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}</div>", f"์˜ค๋ฅ˜: {str(e)}", ""
1461
+
1462
  def format_screenplay_display(content):
1463
+ """์‹œ๋‚˜๋ฆฌ์˜ค ํ‘œ์‹œ ํฌ๋งทํŒ… - ๊ฐœ์„ ๋œ ๋ฒ„์ „"""
1464
  if not content:
1465
  return "*์ž‘์„ฑ ์ค‘...*"
1466
+
1467
+ lines = content.split('\n')
 
 
 
1468
  result = []
1469
+ scene_number = 0
1470
+
1471
  for line in lines:
1472
+ stripped = line.strip()
1473
+
1474
+ # ๋นˆ ์ค„ ์œ ์ง€
1475
+ if not stripped:
1476
+ result.append("")
1477
+ continue
1478
+
1479
+ # ์”ฌ ํ—ค๋” ๊ฐ์ง€ ๋ฐ ํฌ๋งทํŒ… (INT. ๋˜๋Š” EXT.๋กœ ์‹œ์ž‘)
1480
+ if stripped.startswith(('INT.', 'EXT.', 'INT ', 'EXT ')):
1481
+ scene_number += 1
1482
+ # ์”ฌ ๊ตฌ๋ถ„์„  ์ถ”๊ฐ€
1483
+ result.append("\n" + "="*80)
1484
+ result.append(f"### ์”ฌ {scene_number}")
1485
+ result.append(f"**{stripped}**")
1486
+ result.append("-"*40)
1487
+ # ์บ๋ฆญํ„ฐ๋ช… ๊ฐ์ง€ (๋Œ€๋ฌธ์ž๋กœ๋งŒ ๋œ ์งง์€ ์ค„)
1488
+ elif stripped.isupper() and len(stripped.split()) <= 3 and not any(c.isdigit() for c in stripped):
1489
+ # ์บ๋ฆญํ„ฐ๋ช… ๊ฐ•์กฐ
1490
+ result.append(f"\n**{stripped}**")
1491
+ # ๊ด„ํ˜ธ๋กœ ๋œ ์ง€์‹œ๋ฌธ (์—ฐ๊ธฐ ์ง€์‹œ)
1492
+ elif stripped.startswith('(') and stripped.endswith(')'):
1493
+ result.append(f"*{stripped}*")
1494
+ # ํŠธ๋žœ์ง€์…˜ (CUT TO:, FADE IN: ๋“ฑ)
1495
+ elif any(trans in stripped.upper() for trans in ['CUT TO:', 'FADE IN:', 'FADE OUT:', 'DISSOLVE TO:']):
1496
+ result.append(f"\n_{stripped}_\n")
1497
+ # ์ผ๋ฐ˜ ํ…์ŠคํŠธ
1498
  else:
1499
  result.append(line)
1500
+
1501
+ # ์ตœ์ข… ์ •๋ฆฌ
1502
+ formatted = '\n'.join(result)
1503
+
1504
+ # ์—ฐ์†๋œ ๋นˆ ์ค„ ์ œ๊ฑฐ
1505
+ while '\n\n\n' in formatted:
1506
+ formatted = formatted.replace('\n\n\n', '\n\n')
1507
+
1508
+ return formatted
1509
+
1510
+ # 2. combine_all_acts ํ•จ์ˆ˜ ์ˆ˜์ • - State ๊ฐ’ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ฒ˜๋ฆฌ
1511
+ def combine_all_acts(act1_state, act2a_state, act2b_state, act3_state):
1512
+ """๋ชจ๋“  ๋ง‰ ํ•ฉ์น˜๊ธฐ - State ๊ฐ’ ์ฒ˜๋ฆฌ ๊ฐœ์„ """
1513
  full = "# ๐ŸŽฌ ์ „์ฒด ์‹œ๋‚˜๋ฆฌ์˜ค\n\n"
1514
 
1515
+ # State ๊ฐ์ฒด์ธ ๊ฒฝ์šฐ value ์†์„ฑ ์ ‘๊ทผ
1516
+ act1 = act1_state.value if hasattr(act1_state, 'value') else act1_state
1517
+ act2a = act2a_state.value if hasattr(act2a_state, 'value') else act2a_state
1518
+ act2b = act2b_state.value if hasattr(act2b_state, 'value') else act2b_state
1519
+ act3 = act3_state.value if hasattr(act3_state, 'value') else act3_state
 
 
 
1520
 
1521
+ # ์‹ค์ œ ์ฝ˜ํ…์ธ ๊ฐ€ ์žˆ๋Š”์ง€ ํ™•์ธ
1522
+ has_content = False
1523
+
1524
+ if act1 and act1 != "*1๋ง‰์ด ์—ฌ๊ธฐ์— ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค...*" and act1 != "":
1525
+ # ๋งˆํฌ๋‹ค์šด ์ œ๊ฑฐํ•œ ์›๋ณธ ํ…์ŠคํŠธ ์ถ”์ถœ
1526
+ clean_act1 = act1.replace("**", "").replace("###", "").replace("="*80, "").replace("-"*40, "")
1527
+ full += "## ์ œ1๋ง‰ - ์„ค์ •\n\n" + clean_act1 + "\n\n" + "="*80 + "\n\n"
1528
+ has_content = True
1529
+
1530
+ if act2a and act2a != "*2๋ง‰A๊ฐ€ ์—ฌ๊ธฐ์— ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค...*" and act2a != "":
1531
+ clean_act2a = act2a.replace("**", "").replace("###", "").replace("="*80, "").replace("-"*40, "")
1532
+ full += "## ์ œ2๋ง‰A - ์ƒ์Šน\n\n" + clean_act2a + "\n\n" + "="*80 + "\n\n"
1533
+ has_content = True
1534
+
1535
+ if act2b and act2b != "*2๋ง‰B๊ฐ€ ์—ฌ๊ธฐ์— ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค...*" and act2b != "":
1536
+ clean_act2b = act2b.replace("**", "").replace("###", "").replace("="*80, "").replace("-"*40, "")
1537
+ full += "## ์ œ2๋ง‰B - ๋ณต์žกํ™”\n\n" + clean_act2b + "\n\n" + "="*80 + "\n\n"
1538
+ has_content = True
1539
+
1540
+ if act3 and act3 != "*3๋ง‰์ด ์—ฌ๊ธฐ์— ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค...*" and act3 != "":
1541
+ clean_act3 = act3.replace("**", "").replace("###", "").replace("="*80, "").replace("-"*40, "")
1542
+ full += "## ์ œ3๋ง‰ - ํ•ด๊ฒฐ\n\n" + clean_act3 + "\n\n"
1543
+ has_content = True
1544
+
1545
+ if not has_content:
1546
+ return "*์ „์ฒด ์‹œ๋‚˜๋ฆฌ์˜ค๊ฐ€ ์™„์„ฑ๋˜๋ฉด ์—ฌ๊ธฐ์— ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค...*"
1547
+
1548
+ return full
1549
+
1550
+ # 3. save_to_file ํ•จ์ˆ˜ ์ˆ˜์ • - ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ์ง์ ‘ ๊ฐ€์ ธ์˜ค๊ธฐ
1551
+ def save_to_file(full_screenplay, session_id):
1552
+ """์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ํŒŒ์ผ๋กœ ์ €์žฅ - ๊ฐœ์„ ๋œ ๋ฒ„์ „"""
1553
+
1554
+ # ์„ธ์…˜ ID๊ฐ€ ์žˆ์œผ๋ฉด DB์—์„œ ์ง์ ‘ ๊ฐ€์ ธ์˜ค๊ธฐ
1555
+ if session_id:
1556
+ try:
1557
+ with ScreenplayDatabase.get_db() as conn:
1558
+ cursor = conn.cursor()
1559
+ row = cursor.execute(
1560
+ '''SELECT user_query, title, logline, genre, screenplay_type,
1561
+ act1_content, act2a_content, act2b_content, act3_content
1562
+ FROM screenplay_sessions WHERE session_id = ?''',
1563
+ (session_id,)
1564
+ ).fetchone()
1565
+
1566
+ if row:
1567
+ # ํŒŒ์ผ ๋‚ด์šฉ ๊ตฌ์„ฑ
1568
+ timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
1569
+ filename = f"screenplay_{timestamp}.txt"
1570
+
1571
+ with open(filename, 'w', encoding='utf-8') as f:
1572
+ # ํ—ค๋” ์ •๋ณด
1573
+ f.write("="*80 + "\n")
1574
+ f.write("์‹œ๋‚˜๋ฆฌ์˜ค\n")
1575
+ f.write("="*80 + "\n\n")
1576
+
1577
+ if row['title']:
1578
+ f.write(f"์ œ๋ชฉ: {row['title']}\n")
1579
+ if row['genre']:
1580
+ f.write(f"์žฅ๋ฅด: {row['genre']}\n")
1581
+ if row['screenplay_type']:
1582
+ f.write(f"ํ˜•์‹: {row['screenplay_type']}\n")
1583
+ if row['logline']:
1584
+ f.write(f"๋กœ๊ทธ๋ผ์ธ: {row['logline']}\n")
1585
+
1586
+ f.write("\n" + "="*80 + "\n\n")
1587
+
1588
+ # ๊ฐ ๋ง‰ ๋‚ด์šฉ ์ถ”๊ฐ€
1589
+ if row['act1_content']:
1590
+ f.write("์ œ1๋ง‰ - ์„ค์ •\n")
1591
+ f.write("="*80 + "\n\n")
1592
+ f.write(row['act1_content'])
1593
+ f.write("\n\n" + "="*80 + "\n\n")
1594
+
1595
+ if row['act2a_content']:
1596
+ f.write("์ œ2๋ง‰A - ์ƒ์Šน\n")
1597
+ f.write("="*80 + "\n\n")
1598
+ f.write(row['act2a_content'])
1599
+ f.write("\n\n" + "="*80 + "\n\n")
1600
+
1601
+ if row['act2b_content']:
1602
+ f.write("์ œ2๋ง‰B - ๋ณต์žกํ™”\n")
1603
+ f.write("="*80 + "\n\n")
1604
+ f.write(row['act2b_content'])
1605
+ f.write("\n\n" + "="*80 + "\n\n")
1606
+
1607
+ if row['act3_content']:
1608
+ f.write("์ œ3๋ง‰ - ํ•ด๊ฒฐ\n")
1609
+ f.write("="*80 + "\n\n")
1610
+ f.write(row['act3_content'])
1611
+ f.write("\n\n")
1612
+
1613
+ # ์ž‘์„ฑ ์ •๋ณด
1614
+ f.write("\n" + "="*80 + "\n")
1615
+ f.write(f"์ž‘์„ฑ์ผ: {datetime.now().strftime('%Y๋…„ %m์›” %d์ผ %H:%M')}\n")
1616
+ f.write("="*80 + "\n")
1617
+
1618
+ return filename
1619
+ except Exception as e:
1620
+ logger.error(f"DB์—์„œ ํŒŒ์ผ ์ €์žฅ ์ค‘ ์˜ค๋ฅ˜: {e}")
1621
+
1622
+ # DB ์ ‘๊ทผ ์‹คํŒจ์‹œ ์ „๋‹ฌ๋ฐ›์€ ๋‚ด์šฉ์œผ๋กœ ์ €์žฅ
1623
  if not full_screenplay or full_screenplay == "*์ „์ฒด ์‹œ๋‚˜๋ฆฌ์˜ค๊ฐ€ ์™„์„ฑ๋˜๋ฉด ์—ฌ๊ธฐ์— ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค...*":
1624
  return None
1625
 
 
1627
  filename = f"screenplay_{timestamp}.txt"
1628
 
1629
  with open(filename, 'w', encoding='utf-8') as f:
1630
+ # ๋ชจ๋“  ๋งˆํฌ๋‹ค์šด ๋ฐ ํฌ๋งทํŒ… ์ œ๊ฑฐ
1631
+ clean_text = full_screenplay
1632
+ clean_text = clean_text.replace("**", "")
1633
+ clean_text = clean_text.replace("###", "")
1634
+ clean_text = clean_text.replace("#", "")
1635
+ clean_text = clean_text.replace("="*80, "-"*80)
1636
+ clean_text = clean_text.replace("-"*40, "")
1637
+ clean_text = clean_text.replace("_", "")
1638
+ clean_text = clean_text.replace("*", "")
1639
+
1640
  f.write(clean_text)
1641
 
1642
  return filename
 
1733
 
1734
  # ๋‹ค์šด๋กœ๋“œ
1735
  download_btn.click(
1736
+ fn=lambda full, sid: save_to_file(full, sid),
1737
+ inputs=[full_output, current_session_id], # session_id ์ถ”๊ฐ€
1738
  outputs=[download_file]
1739
  ).then(
1740
+ lambda x: gr.update(visible=True, value=x) if x else gr.update(visible=False),
1741
  inputs=[download_file],
1742
  outputs=[download_file]
1743
  )
1744
+
1745
+
1746
  return interface
1747
 
1748
  # ๋ฉ”์ธ ์‹คํ–‰