openfree commited on
Commit
c225467
ยท
verified ยท
1 Parent(s): a010112

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +780 -782
app.py CHANGED
@@ -589,39 +589,39 @@ class WebSearchIntegration:
589
  return "\n".join(extracted)
590
 
591
  class ScreenplayGenerationSystem:
592
- """Professional screenplay generation system"""
593
- def __init__(self):
594
- self.token = FRIENDLI_TOKEN
595
- self.api_url = API_URL
596
- self.model_id = MODEL_ID
597
- self.screenplay_tracker = ScreenplayTracker()
598
- self.web_search = WebSearchIntegration()
599
- self.current_session_id = None
600
- ScreenplayDatabase.init_db()
601
-
602
- def create_headers(self):
603
- return {"Authorization": f"Bearer {self.token}", "Content-Type": "application/json"}
604
-
605
- # --- Prompt generation functions ---
606
- def create_producer_prompt(self, user_query: str, screenplay_type: str,
607
- genre: str, language: str) -> str:
608
- """Producer initial concept development"""
609
-
610
- # Web search for market trends if enabled
611
- search_results = ""
612
- if self.web_search.enabled:
613
- queries = [
614
- f"box office success {genre} films 2024 2025",
615
- f"popular {screenplay_type} {genre} trends",
616
- f"audience demographics {genre} movies"
617
- ]
618
- for q in queries[:2]:
619
- results = self.web_search.search(q, count=2, language=language)
620
- if results:
621
- search_results += self.web_search.extract_relevant_info(results) + "\n"
622
-
623
- lang_prompts = {
624
- "Korean": f"""๋‹น์‹ ์€ ํ• ๋ฆฌ์šฐ๋“œ ํ”„๋กœ๋“€์„œ์ž…๋‹ˆ๋‹ค. ์ƒ์—…์ ์œผ๋กœ ์„ฑ๊ณต ๊ฐ€๋Šฅํ•œ {screenplay_type} ์ปจ์…‰์„ ๊ฐœ๋ฐœํ•˜์„ธ์š”.
625
 
626
  **์š”์ฒญ์‚ฌํ•ญ:** {user_query}
627
  **ํƒ€์ž…:** {SCREENPLAY_LENGTHS[screenplay_type]['description']}
@@ -633,42 +633,42 @@ class ScreenplayGenerationSystem:
633
  **ํ•„์ˆ˜ ์ œ๊ณต ํ•ญ๋ชฉ:**
634
 
635
  1. **์ œ๋ชฉ (TITLE)**
636
- - ๊ธฐ์–ตํ•˜๊ธฐ ์‰ฝ๊ณ  ๋งˆ์ผ€ํŒ… ๊ฐ€๋Šฅํ•œ ์ œ๋ชฉ
637
- - ์žฅ๋ฅด์™€ ํ†ค์„ ์•”์‹œํ•˜๋Š” ์ œ๋ชฉ
638
 
639
  2. **๋กœ๊ทธ๋ผ์ธ (LOGLINE)**
640
- - 25๋‹จ์–ด ์ด๋‚ด ํ•œ ๋ฌธ์žฅ
641
- - ํ˜•์‹: "[์‚ฌ๊ฑด]์ด ์ผ์–ด๋‚ฌ์„ ๋•Œ, [์ฃผ์ธ๊ณต]์€ [๋ชฉํ‘œ]๋ฅผ ์ด๋ฃจ์–ด์•ผ ํ•œ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด [๊ฒฐ๊ณผ]"
642
- - ๊ฐˆ๋“ฑ๊ณผ stakes๊ฐ€ ๋ช…ํ™•ํ•ด์•ผ ํ•จ
643
 
644
  3. **์žฅ๋ฅด ๋ถ„์„**
645
- - ์ฃผ ์žฅ๋ฅด: {genre}
646
- - ์„œ๋ธŒ ์žฅ๋ฅด:
647
- - ํ†ค & ๋ถ„์œ„๊ธฐ:
648
 
649
  4. **ํƒ€๊ฒŸ ๊ด€๊ฐ**
650
- - ์ฃผ์š” ์—ฐ๋ น๋Œ€:
651
- - ์„ฑ๋ณ„ ๋ถ„ํฌ:
652
- - ๊ด€์‹ฌ์‚ฌ:
653
- - ์œ ์‚ฌ ์ž‘ํ’ˆ ํŒฌ์ธต:
654
 
655
  5. **๋น„๊ต ์ž‘ํ’ˆ (COMPS)**
656
- - 3๊ฐœ์˜ ์„ฑ๊ณตํ•œ ์œ ์‚ฌ ํ”„๋กœ์ ํŠธ
657
- - ๊ฐ๊ฐ์˜ ๋ฐ•์Šค์˜คํ”ผ์Šค/์‹œ์ฒญ๋ฅ  ์„ฑ๊ณผ
658
- - ์šฐ๋ฆฌ ํ”„๋กœ์ ํŠธ์™€์˜ ์ฐจ๋ณ„์ 
659
 
660
  6. **๊ณ ์œ  ํŒ๋งค ํฌ์ธํŠธ (USP)**
661
- - ์ด ์ด์•ผ๊ธฐ๋งŒ์˜ ๋…ํŠนํ•œ ์ 
662
- - ํ˜„์žฌ ์‹œ์žฅ์—์„œ์˜ ํ•„์š”์„ฑ
663
- - ์ œ์ž‘ ๊ฐ€๋Šฅ์„ฑ
664
 
665
  7. **๋น„์ฃผ์–ผ ์ปจ์…‰**
666
- - ํ•ต์‹ฌ ๋น„์ฃผ์–ผ ์ด๋ฏธ์ง€ 3๊ฐœ
667
- - ์ „์ฒด์ ์ธ ๋ฃฉ & ํ•„
668
 
669
  ๊ตฌ์ฒด์ ์ด๊ณ  ์‹œ์žฅ์„ฑ ์žˆ๋Š” ์ปจ์…‰์„ ์ œ์‹œํ•˜์„ธ์š”.""",
670
 
671
- "English": f"""You are a Hollywood producer. Develop a commercially viable {screenplay_type} concept.
672
 
673
  **Request:** {user_query}
674
  **Type:** {SCREENPLAY_LENGTHS[screenplay_type]['description']}
@@ -680,52 +680,52 @@ class ScreenplayGenerationSystem:
680
  **Required Elements:**
681
 
682
  1. **TITLE**
683
- - Memorable and marketable
684
- - Hints at genre and tone
685
 
686
  2. **LOGLINE**
687
- - One sentence, 25 words max
688
- - Format: "When [inciting incident], a [protagonist] must [objective] or else [stakes]"
689
- - Clear conflict and stakes
690
 
691
  3. **GENRE ANALYSIS**
692
- - Primary Genre: {genre}
693
- - Sub-genre:
694
- - Tone & Mood:
695
 
696
  4. **TARGET AUDIENCE**
697
- - Primary Age Range:
698
- - Gender Distribution:
699
- - Interests:
700
- - Similar Works Fanbase:
701
 
702
  5. **COMPARABLE FILMS (COMPS)**
703
- - 3 successful similar projects
704
- - Box office/viewership performance
705
- - How ours differs
706
 
707
  6. **UNIQUE SELLING POINT (USP)**
708
- - What makes this story unique
709
- - Why now in the market
710
- - Production feasibility
711
 
712
  7. **VISUAL CONCEPT**
713
- - 3 key visual images
714
- - Overall look & feel
715
 
716
  Provide specific, marketable concept."""
717
- }
718
-
719
- return lang_prompts.get(language, lang_prompts["English"])
720
 
721
- def create_story_developer_prompt(self, producer_concept: str, user_query: str,
722
- screenplay_type: str, genre: str, language: str) -> str:
723
- """Story developer for synopsis and structure"""
724
-
725
- genre_template = GENRE_TEMPLATES.get(genre, GENRE_TEMPLATES["drama"])
726
-
727
- lang_prompts = {
728
- "Korean": f"""๋‹น์‹ ์€ ์Šคํ† ๋ฆฌ ๊ฐœ๋ฐœ์ž์ž…๋‹ˆ๋‹ค. ํ”„๋กœ๋“€์„œ์˜ ์ปจ์…‰์„ ๋ฐ”ํƒ•์œผ๋กœ {screenplay_type}์˜ ์‹œ๋†‰์‹œ์Šค์™€ 3๋ง‰ ๊ตฌ์กฐ๋ฅผ ๊ฐœ๋ฐœํ•˜์„ธ์š”.
729
 
730
  **ํ”„๋กœ๋“€์„œ ์ปจ์…‰:**
731
  {producer_concept}
@@ -738,54 +738,54 @@ Provide specific, marketable concept."""
738
  **ํ•„์ˆ˜ ์ž‘์„ฑ ํ•ญ๋ชฉ:**
739
 
740
  1. **์‹œ๋†‰์‹œ์Šค (SYNOPSIS)**
741
- - 300-500๋‹จ์–ด
742
- - 3๋ง‰ ๊ตฌ์กฐ๊ฐ€ ๋ช…ํ™•ํžˆ ๋“œ๋Ÿฌ๋‚˜๋„๋ก
743
- - ์ฃผ์ธ๊ณต์˜ ๋ณ€ํ™” arc ํฌํ•จ
744
- - ์ฃผ์š” ์ „ํ™˜์  ๋ช…์‹œ
745
- - ๊ฒฐ๋ง ํฌํ•จ (์Šคํฌ์ผ๋Ÿฌ OK)
746
 
747
  2. **3๋ง‰ ๊ตฌ์กฐ (THREE-ACT STRUCTURE)**
748
-
749
- **์ œ1๋ง‰ - ์„ค์ • (Setup) [25%]**
750
- - ์ผ์ƒ ์„ธ๊ณ„ (Ordinary World):
751
- - ๊ทผ์นœ์ƒ๊ฐ„ ์‚ฌ๊ฑด (Inciting Incident):
752
- - ์ฃผ์ธ๊ณต ์†Œ๊ฐœ ๋ฐ ๊ฒฐํ•จ:
753
- - 1๋ง‰ ์ „ํ™˜์  (Plot Point 1):
754
-
755
- **์ œ2๋ง‰A - ์ƒ์Šน ์•ก์…˜ (Rising Action) [25%]**
756
- - ์ƒˆ๋กœ์šด ์„ธ๊ณ„ ์ง„์ž…:
757
- - ์žฌ๋ฏธ์™€ ๊ฒŒ์ž„ (Fun and Games):
758
- - B ์Šคํ† ๋ฆฌ (๊ด€๊ณ„/ํ…Œ๋งˆ):
759
- - ์ค‘๊ฐ„์  (Midpoint) - ๊ฐ€์งœ ์Šน๋ฆฌ/ํŒจ๋ฐฐ:
760
-
761
- **์ œ2๋ง‰B - ๋ณต์žกํ™” (Complications) [25%]**
762
- - ์•…๋‹น์˜ ๋ฐ˜๊ฒฉ:
763
- - ํŒ€ ํ•ด์ฒด/์œ„๊ธฐ:
764
- - ๋ชจ๋“  ๊ฒƒ์„ ์žƒ์Œ (All Is Lost):
765
- - ์˜ํ˜ผ์˜ ์–ด๋‘” ๋ฐค:
766
-
767
- **์ œ3๋ง‰ - ํ•ด๊ฒฐ (Resolution) [25%]**
768
- - 2๋ง‰ ์ „ํ™˜์  (Plot Point 2):
769
- - ์ตœ์ข… ์ „ํˆฌ ์ค€๋น„:
770
- - ํด๋ผ์ด๋งฅ์Šค:
771
- - ์ƒˆ๋กœ์šด ์ผ์ƒ:
772
 
773
  3. **Save the Cat ๋น„ํŠธ ์‹œํŠธ**
774
- 15๊ฐœ ๋น„ํŠธ๋ฅผ {SCREENPLAY_LENGTHS[screenplay_type]['pages']}ํŽ˜์ด์ง€์— ๋งž์ถฐ ๋ฐฐ์น˜
775
 
776
  4. **์ฃผ์ œ (THEME)**
777
- - ์ค‘์‹ฌ ์ฃผ์ œ:
778
- - ์ฃผ์ œ๊ฐ€ ๋“œ๋Ÿฌ๋‚˜๋Š” ์ˆœ๊ฐ„:
779
- - ์ฃผ์ œ์˜ ์‹œ๊ฐ์  ํ‘œํ˜„:
780
 
781
  5. **ํ†ค & ์Šคํƒ€์ผ**
782
- - ์ „์ฒด์ ์ธ ํ†ค:
783
- - ์œ ๋จธ ์‚ฌ์šฉ ์—ฌ๋ถ€:
784
- - ๋น„์ฃผ์–ผ ์Šคํƒ€์ผ:
785
 
786
  ๊ตฌ์ฒด์ ์ด๊ณ  ๊ฐ์ •์ ์œผ๋กœ ๊ณต๊ฐ๊ฐ€๋Š” ์Šคํ† ๋ฆฌ๋ฅผ ๋งŒ๋“œ์„ธ์š”.""",
787
 
788
- "English": f"""You are a story developer. Based on the producer's concept, develop the synopsis and three-act structure for this {screenplay_type}.
789
 
790
  **Producer Concept:**
791
  {producer_concept}
@@ -798,62 +798,62 @@ Provide specific, marketable concept."""
798
  **Required Elements:**
799
 
800
  1. **SYNOPSIS**
801
- - 300-500 words
802
- - Clear three-act structure
803
- - Protagonist's change arc
804
- - Major turning points
805
- - Include ending (spoilers OK)
806
 
807
  2. **THREE-ACT STRUCTURE**
808
-
809
- **ACT 1 - Setup [25%]**
810
- - Ordinary World:
811
- - Inciting Incident:
812
- - Protagonist Introduction & Flaw:
813
- - Plot Point 1:
814
-
815
- **ACT 2A - Rising Action [25%]**
816
- - Entering New World:
817
- - Fun and Games:
818
- - B Story (Relationship/Theme):
819
- - Midpoint - False Victory/Defeat:
820
-
821
- **ACT 2B - Complications [25%]**
822
- - Bad Guys Close In:
823
- - Team Breaks Down/Crisis:
824
- - All Is Lost:
825
- - Dark Night of the Soul:
826
-
827
- **ACT 3 - Resolution [25%]**
828
- - Plot Point 2:
829
- - Final Battle Preparation:
830
- - Climax:
831
- - New Normal:
832
 
833
  3. **SAVE THE CAT BEAT SHEET**
834
- Place 15 beats across {SCREENPLAY_LENGTHS[screenplay_type]['pages']} pages
835
 
836
  4. **THEME**
837
- - Central Theme:
838
- - Theme Stated Moment:
839
- - Visual Theme Expression:
840
 
841
  5. **TONE & STYLE**
842
- - Overall Tone:
843
- - Use of Humor:
844
- - Visual Style:
845
 
846
  Create specific, emotionally resonant story."""
847
- }
848
-
849
- return lang_prompts.get(language, lang_prompts["English"])
850
 
851
- def create_character_designer_prompt(self, producer_concept: str, story_structure: str,
852
- genre: str, language: str) -> str:
853
- """Character designer prompt"""
854
-
855
- lang_prompts = {
856
- "Korean": f"""๋‹น์‹ ์€ ์บ๋ฆญํ„ฐ ๋””์ž์ด๋„ˆ์ž…๋‹ˆ๋‹ค. ๋‹ค์ธต์ ์ด๊ณ  ๋งค๋ ฅ์ ์ธ ์บ๋ฆญํ„ฐ๋“ค์„ ์ฐฝ์กฐํ•˜์„ธ์š”.
857
 
858
  **ํ”„๋กœ๋“€์„œ ์ปจ์…‰:**
859
  {producer_concept}
@@ -864,53 +864,53 @@ Create specific, emotionally resonant story."""
864
  **ํ•„์ˆ˜ ์บ๋ฆญํ„ฐ ํ”„๋กœํ•„:**
865
 
866
  1. **์ฃผ์ธ๊ณต (PROTAGONIST)**
867
- - ์ด๋ฆ„ & ๋‚˜์ด:
868
- - ์ง์—…/์—ญํ• :
869
- - ์บ๋ฆญํ„ฐ ์•„ํฌํƒ€์ž…:
870
- - WANT (์™ธ์  ๋ชฉํ‘œ):
871
- - NEED (๋‚ด์  ํ•„์š”):
872
- - ์น˜๋ช…์  ๊ฒฐํ•จ (Fatal Flaw):
873
- - ๋ฐฑ์Šคํ† ๋ฆฌ (ํ•ต์‹ฌ ์ƒ์ฒ˜):
874
- - ์„ฑ๊ฒฉ ํŠน์„ฑ (3-5๊ฐœ):
875
- - ๋งํˆฌ & ์–ธ์–ด ํŒจํ„ด:
876
- - ์‹œ๊ฐ์  ํŠน์ง•:
877
- - ์บ๋ฆญํ„ฐ ์•„ํฌ (Aโ†’B):
878
 
879
  2. **์ ๋Œ€์ž (ANTAGONIST)**
880
- - ์ด๋ฆ„ & ๋‚˜์ด:
881
- - ์ง์—…/์—ญํ• :
882
- - ์•…์—ญ ์•„ํฌํƒ€์ž…:
883
- - ๋ชฉํ‘œ & ๋™๊ธฐ:
884
- - ์ฃผ์ธ๊ณต๊ณผ์˜ ์—ฐ๊ฒฐ์ :
885
- - ์ •๋‹น์„ฑ ์žˆ๋Š” ์ด์œ :
886
- - ์•ฝ์ :
887
- - ํŠน์ง•์  ํ–‰๋™:
888
 
889
  3. **์กฐ๋ ฅ์ž๋“ค (SUPPORTING CAST)**
890
- ์ตœ์†Œ 3๋ช…, ๊ฐ๊ฐ:
891
- - ์ด๋ฆ„ & ์—ญํ• :
892
- - ์ฃผ์ธ๊ณต๊ณผ์˜ ๊ด€๊ณ„:
893
- - ์Šคํ† ๋ฆฌ ๊ธฐ๋Šฅ:
894
- - ๋…ํŠนํ•œ ํŠน์„ฑ:
895
- - ๊ธฐ์—ฌํ•˜๋Š” ๋ฐ”:
896
 
897
  4. **์บ๋ฆญํ„ฐ ๊ด€๊ณ„๋„**
898
- - ์ฃผ์š” ๊ด€๊ณ„ ์—ญํ•™:
899
- - ๊ฐˆ๋“ฑ ๊ตฌ์กฐ:
900
- - ๊ฐ์ •์  ์—ฐ๊ฒฐ:
901
- - ํŒŒ์›Œ ๋‹ค์ด๋‚˜๋ฏน:
902
 
903
  5. **์บ์ŠคํŒ… ์ œ์•ˆ**
904
- - ๊ฐ ์ฃผ์š” ์บ๋ฆญํ„ฐ๋ณ„ ์ด์ƒ์ ์ธ ๋ฐฐ์šฐ ํƒ€์ž…
905
- - ์—ฐ๋ น๋Œ€, ์™ธ๋ชจ, ์—ฐ๊ธฐ ์Šคํƒ€์ผ
906
 
907
  6. **๋Œ€ํ™” ์ƒ˜ํ”Œ**
908
- - ๊ฐ ์ฃผ์š” ์บ๋ฆญํ„ฐ์˜ ์‹œ๊ทธ๋‹ˆ์ฒ˜ ๋Œ€์‚ฌ 2-3๊ฐœ
909
- - ์บ๋ฆญํ„ฐ์˜ ๋ณธ์งˆ์„ ๋“œ๋Ÿฌ๋‚ด๋Š” ๋Œ€ํ™”
910
 
911
  ๊ฐ ์บ๋ฆญํ„ฐ๊ฐ€ ํ…Œ๋งˆ๋ฅผ ๊ตฌํ˜„ํ•˜๊ณ  ์Šคํ† ๋ฆฌ๋ฅผ ์ถ”์ง„ํ•˜๋„๋ก ๋””์ž์ธํ•˜์„ธ์š”.""",
912
 
913
- "English": f"""You are a character designer. Create multi-dimensional, compelling characters.
914
 
915
  **Producer Concept:**
916
  {producer_concept}
@@ -921,63 +921,63 @@ Create specific, emotionally resonant story."""
921
  **Required Character Profiles:**
922
 
923
  1. **PROTAGONIST**
924
- - Name & Age:
925
- - Occupation/Role:
926
- - Character Archetype:
927
- - WANT (External Goal):
928
- - NEED (Internal Need):
929
- - Fatal Flaw:
930
- - Backstory (Core Wound):
931
- - Personality Traits (3-5):
932
- - Speech Pattern:
933
- - Visual Characteristics:
934
- - Character Arc (Aโ†’B):
935
 
936
  2. **ANTAGONIST**
937
- - Name & Age:
938
- - Occupation/Role:
939
- - Villain Archetype:
940
- - Goal & Motivation:
941
- - Connection to Protagonist:
942
- - Justifiable Reason:
943
- - Weakness:
944
- - Signature Behaviors:
945
 
946
  3. **SUPPORTING CAST**
947
- Minimum 3, each with:
948
- - Name & Role:
949
- - Relationship to Protagonist:
950
- - Story Function:
951
- - Unique Traits:
952
- - What They Contribute:
953
 
954
  4. **CHARACTER RELATIONSHIPS**
955
- - Key Relationship Dynamics:
956
- - Conflict Structure:
957
- - Emotional Connections:
958
- - Power Dynamics:
959
 
960
  5. **CASTING SUGGESTIONS**
961
- - Ideal actor type for each major character
962
- - Age range, appearance, acting style
963
 
964
  6. **DIALOGUE SAMPLES**
965
- - 2-3 signature lines per major character
966
- - Dialogue revealing character essence
967
 
968
  Design each character to embody theme and drive story."""
969
- }
970
-
971
- return lang_prompts.get(language, lang_prompts["English"])
972
 
973
- def create_scene_planner_prompt(self, story_structure: str, characters: str,
974
- screenplay_type: str, genre: str, language: str) -> str:
975
- """Scene breakdown planner"""
976
-
977
- total_pages = SCREENPLAY_LENGTHS[screenplay_type]['pages']
978
-
979
- lang_prompts = {
980
- "Korean": f"""๋‹น์‹ ์€ ์”ฌ ํ”Œ๋ž˜๋„ˆ์ž…๋‹ˆ๋‹ค. {total_pages}ํŽ˜์ด์ง€ {screenplay_type}์˜ ์ƒ์„ธํ•œ ์”ฌ ๋ธŒ๋ ˆ์ดํฌ๋‹ค์šด์„ ์ž‘์„ฑํ•˜์„ธ์š”.
981
 
982
  **์Šคํ† ๋ฆฌ ๊ตฌ์กฐ:**
983
  {story_structure}
@@ -1015,7 +1015,7 @@ Design each character to embody theme and drive story."""
1015
 
1016
  ๊ฐ ์”ฌ์ด ์Šคํ† ๋ฆฌ๋ฅผ ์ „์ง„์‹œํ‚ค๊ณ  ์บ๋ฆญํ„ฐ๋ฅผ ๋ฐœ์ „์‹œํ‚ค๋„๋ก ๊ณ„ํšํ•˜์„ธ์š”.""",
1017
 
1018
- "English": f"""You are a scene planner. Create detailed scene breakdown for {total_pages}-page {screenplay_type}.
1019
 
1020
  **Story Structure:**
1021
  {story_structure}
@@ -1052,19 +1052,19 @@ For each scene provide:
1052
  - DISSOLVE TO:
1053
 
1054
  Plan each scene to advance story and develop character."""
1055
- }
1056
-
1057
- return lang_prompts.get(language, lang_prompts["English"])
1058
 
1059
- def create_screenwriter_prompt(self, act: str, scene_breakdown: str,
1060
- characters: str, previous_acts: str,
1061
- screenplay_type: str, genre: str, language: str) -> str:
1062
- """Screenwriter prompt for actual screenplay pages"""
1063
-
1064
- act_pages = int(SCREENPLAY_LENGTHS[screenplay_type]['pages'] * 0.25)
1065
-
1066
- lang_prompts = {
1067
- "Korean": f"""๋‹น์‹ ์€ ํ”„๋กœ ์‹œ๋‚˜๋ฆฌ์˜ค ์ž‘๊ฐ€์ž…๋‹ˆ๋‹ค. {act}์„ ํ‘œ์ค€ ์‹œ๋‚˜๋ฆฌ์˜ค ํฌ๋งท์œผ๋กœ ์ž‘์„ฑํ•˜์„ธ์š”.
1068
 
1069
  **ํƒ€๊ฒŸ ๋ถ„๋Ÿ‰:** {act_pages}ํŽ˜์ด์ง€
1070
 
@@ -1080,29 +1080,29 @@ Plan each scene to advance story and develop character."""
1080
  **์‹œ๋‚˜๋ฆฌ์˜ค ํฌ๋งท ๊ทœ์น™:**
1081
 
1082
  1. **์”ฌ ํ—ค๋”ฉ**
1083
- INT. ์žฅ์†Œ - ์‹œ๊ฐ„
1084
- EXT. ์žฅ์†Œ - ์‹œ๊ฐ„
1085
 
1086
  2. **์•ก์…˜ ๋ผ์ธ**
1087
- - ํ˜„์žฌ ์‹œ์ œ ์‚ฌ์šฉ
1088
- - ์‹œ๊ฐ์ ์œผ๋กœ ๋ณด์ด๋Š” ๊ฒƒ๋งŒ ๋ฌ˜์‚ฌ
1089
- - 4์ค„ ์ดํ•˜๋กœ ์œ ์ง€
1090
- - ๊ฐ์ •์€ ํ–‰๋™์œผ๋กœ ํ‘œํ˜„
1091
 
1092
  3. **์บ๋ฆญํ„ฐ ์†Œ๊ฐœ**
1093
- ์ฒซ ๋“ฑ์žฅ์‹œ: ์ด๋ฆ„ (๋‚˜์ด) ๊ฐ„๋‹จํ•œ ๋ฌ˜์‚ฌ
1094
 
1095
  4. **๋Œ€ํ™”**
1096
- ์บ๋ฆญํ„ฐ๋ช…
1097
- (์ง€๋ฌธ)
1098
- ๋Œ€์‚ฌ
1099
 
1100
  5. **์ค‘์š” ์›์น™**
1101
- - Show, don't tell
1102
- - ์„œ๋ธŒํ…์ŠคํŠธ ํ™œ์šฉ
1103
- - ์ž์—ฐ์Šค๋Ÿฌ์šด ๋Œ€ํ™”
1104
- - ์‹œ๊ฐ์  ์Šคํ† ๋ฆฌํ…”๋ง
1105
- - ํŽ˜์ด์ง€๋‹น 1๋ถ„ ๊ทœ์น™
1106
 
1107
  **{genre} ์žฅ๋ฅด ํŠน์„ฑ:**
1108
  - ๋Œ€ํ™” ๋น„์œจ: {GENRE_TEMPLATES[genre]['dialogue_ratio']*100}%
@@ -1111,7 +1111,7 @@ Plan each scene to advance story and develop character."""
1111
 
1112
  ์ •ํ™•ํ•œ ํฌ๋งท๊ณผ ๋ชฐ์ž…๊ฐ ์žˆ๋Š” ์Šคํ† ๋ฆฌํ…”๋ง์œผ๋กœ ์ž‘์„ฑํ•˜์„ธ์š”.""",
1113
 
1114
- "English": f"""You are a professional screenwriter. Write {act} in standard screenplay format.
1115
 
1116
  **Target Length:** {act_pages} pages
1117
 
@@ -1127,29 +1127,29 @@ Plan each scene to advance story and develop character."""
1127
  **Screenplay Format Rules:**
1128
 
1129
  1. **Scene Headings**
1130
- INT. LOCATION - TIME
1131
- EXT. LOCATION - TIME
1132
 
1133
  2. **Action Lines**
1134
- - Present tense
1135
- - Only what's visually seen
1136
- - Keep under 4 lines
1137
- - Emotions through actions
1138
 
1139
  3. **Character Intros**
1140
- First appearance: NAME (age) brief description
1141
 
1142
  4. **Dialogue**
1143
- CHARACTER NAME
1144
- (parenthetical)
1145
- Dialogue
1146
 
1147
  5. **Key Principles**
1148
- - Show, don't tell
1149
- - Use subtext
1150
- - Natural dialogue
1151
- - Visual storytelling
1152
- - One page = one minute
1153
 
1154
  **{genre} Genre Characteristics:**
1155
  - Dialogue Ratio: {GENRE_TEMPLATES[genre]['dialogue_ratio']*100}%
@@ -1157,16 +1157,16 @@ Plan each scene to advance story and develop character."""
1157
  - Key Elements: {', '.join(GENRE_TEMPLATES[genre]['key_elements'][:2])}
1158
 
1159
  Write with proper format and engaging storytelling."""
1160
- }
1161
-
1162
- return lang_prompts.get(language, lang_prompts["English"])
1163
 
1164
- def create_script_doctor_prompt(self, act_content: str, act: str,
1165
- genre: str, language: str) -> str:
1166
- """Script doctor review and polish"""
1167
-
1168
- lang_prompts = {
1169
- "Korean": f"""๋‹น์‹ ์€ ์Šคํฌ๋ฆฝํŠธ ๋‹ฅํ„ฐ์ž…๋‹ˆ๋‹ค. {act}๋ฅผ ๊ฒ€ํ† ํ•˜๊ณ  ๊ฐœ์„  ์‚ฌํ•ญ์„ ์ œ์‹œํ•˜์„ธ์š”.
1170
 
1171
  **์ž‘์„ฑ๋œ ๋‚ด์šฉ:**
1172
  {act_content}
@@ -1174,37 +1174,37 @@ Write with proper format and engaging storytelling."""
1174
  **๊ฒ€ํ†  ํ•ญ๋ชฉ:**
1175
 
1176
  1. **ํฌ๋งท ์ •ํ™•์„ฑ**
1177
- - ์”ฌ ํ—ค๋”ฉ ํ˜•์‹
1178
- - ์•ก์…˜ ๋ผ์ธ ๊ธธ์ด
1179
- - ๋Œ€ํ™” ํฌ๋งท
1180
- - ์ „ํ™˜ ํ‘œ์‹œ
1181
 
1182
  2. **์Šคํ† ๋ฆฌํ…”๋ง**
1183
- - ์‹œ๊ฐ์  ๋ช…ํ™•์„ฑ
1184
- - ํŽ˜์ด์‹ฑ
1185
- - ๊ธด์žฅ๊ฐ ๊ตฌ์ถ•
1186
- - ์”ฌ ๋ชฉ์  ๋‹ฌ์„ฑ
1187
 
1188
  3. **๋Œ€ํ™” ํ’ˆ์งˆ**
1189
- - ์ž์—ฐ์Šค๋Ÿฌ์›€
1190
- - ์บ๋ฆญํ„ฐ ๊ณ ์œ ์„ฑ
1191
- - ์„œ๋ธŒํ…์ŠคํŠธ
1192
- - ๋ถˆํ•„์š”ํ•œ ์„ค๋ช… ์ œ๊ฑฐ
1193
 
1194
  4. **{genre} ์žฅ๋ฅด ์ ํ•ฉ์„ฑ**
1195
- - ์žฅ๋ฅด ๊ด€์Šต ์ค€์ˆ˜
1196
- - ํ†ค ์ผ๊ด€์„ฑ
1197
- - ๊ธฐ๋Œ€ ์ถฉ์กฑ
1198
 
1199
  5. **๊ธฐ์ˆ ์  ์ธก๋ฉด**
1200
- - ํŽ˜์ด์ง€ ์ˆ˜ ์ ์ •์„ฑ
1201
- - ์ œ์ž‘ ๊ฐ€๋Šฅ์„ฑ
1202
- - ์˜ˆ์‚ฐ ๊ณ ๋ ค์‚ฌํ•ญ
1203
 
1204
  **ํ•„์ˆ˜ ๊ฐœ์„ ์‚ฌํ•ญ:**
1205
  ๊ตฌ์ฒด์ ์ธ ์ˆ˜์ • ์ œ์•ˆ๊ณผ ๊ฐœ์„ ๋œ ์˜ˆ์‹œ๋ฅผ ์ œ๊ณตํ•˜์„ธ์š”.""",
1206
 
1207
- "English": f"""You are a script doctor. Review and provide improvements for {act}.
1208
 
1209
  **Written Content:**
1210
  {act_content}
@@ -1212,71 +1212,71 @@ Write with proper format and engaging storytelling."""
1212
  **Review Areas:**
1213
 
1214
  1. **Format Accuracy**
1215
- - Scene heading format
1216
- - Action line length
1217
- - Dialogue format
1218
- - Transitions
1219
 
1220
  2. **Storytelling**
1221
- - Visual clarity
1222
- - Pacing
1223
- - Tension building
1224
- - Scene purpose achievement
1225
 
1226
  3. **Dialogue Quality**
1227
- - Naturalness
1228
- - Character uniqueness
1229
- - Subtext
1230
- - Remove exposition
1231
 
1232
  4. **{genre} Genre Fit**
1233
- - Genre conventions
1234
- - Tone consistency
1235
- - Meeting expectations
1236
 
1237
  5. **Technical Aspects**
1238
- - Page count appropriateness
1239
- - Production feasibility
1240
- - Budget considerations
1241
 
1242
  **Required Improvements:**
1243
  Provide specific revision suggestions with improved examples."""
1244
- }
1245
-
1246
- return lang_prompts.get(language, lang_prompts["English"])
1247
 
1248
- def create_final_reviewer_prompt(self, complete_screenplay: str,
1249
- screenplay_type: str, genre: str, language: str) -> str:
1250
- """Final comprehensive review"""
1251
-
1252
- lang_prompts = {
1253
- "Korean": f"""๋‹น์‹ ์€ ์ตœ์ข… ๋ฆฌ๋ทฐ์–ด์ž…๋‹ˆ๋‹ค. ์™„์„ฑ๋œ {screenplay_type} ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ์ข…ํ•ฉ ํ‰๊ฐ€ํ•˜์„ธ์š”.
1254
 
1255
  **ํ‰๊ฐ€ ๊ธฐ์ค€:**
1256
 
1257
  1. **์ƒ์—…์„ฑ (25์ )**
1258
- - ์‹œ์žฅ์„ฑ
1259
- - ํƒ€๊ฒŸ ๊ด€๊ฐ ์–ดํ•„
1260
- - ์ œ์ž‘ ๊ฐ€๋Šฅ์„ฑ
1261
- - ๋ฐฐ๊ธ‰ ์ž ์žฌ๋ ฅ
1262
 
1263
  2. **์Šคํ† ๋ฆฌ (25์ )**
1264
- - 3๋ง‰ ๊ตฌ์กฐ ํšจ๊ณผ์„ฑ
1265
- - ์บ๋ฆญํ„ฐ ์•„ํฌ
1266
- - ํ”Œ๋กฏ ์ผ๊ด€์„ฑ
1267
- - ํ…Œ๋งˆ ์ „๋‹ฌ
1268
 
1269
  3. **๊ธฐ์ˆ ์  ์™„์„ฑ๋„ (25์ )**
1270
- - ํฌ๋งท ์ •ํ™•์„ฑ
1271
- - ํŽ˜์ด์ง€ ์ˆ˜ ์ ์ •์„ฑ
1272
- - ์”ฌ ๊ตฌ์„ฑ
1273
- - ์‹œ๊ฐ์  ์Šคํ† ๋ฆฌํ…”๋ง
1274
 
1275
  4. **๋Œ€ํ™” & ์บ๋ฆญํ„ฐ (25์ )**
1276
- - ๋Œ€ํ™” ์ž์—ฐ์Šค๋Ÿฌ์›€
1277
- - ์บ๋ฆญํ„ฐ ๊ณ ์œ ์„ฑ
1278
- - ๊ด€๊ณ„ ์—ญํ•™
1279
- - ๊ฐ์ •์  ์ง„์ •์„ฑ
1280
 
1281
  **์ข…ํ•ฉ ํ‰๊ฐ€:**
1282
  - ๊ฐ•์  (3-5๊ฐœ)
@@ -1288,33 +1288,33 @@ Provide specific revision suggestions with improved examples."""
1288
 
1289
  ๊ตฌ์ฒด์ ์ด๊ณ  ๊ฑด์„ค์ ์ธ ํ”ผ๋“œ๋ฐฑ์„ ์ œ๊ณตํ•˜์„ธ์š”.""",
1290
 
1291
- "English": f"""You are the final reviewer. Comprehensively evaluate the completed {screenplay_type} screenplay.
1292
 
1293
  **Evaluation Criteria:**
1294
 
1295
  1. **Commercial Viability (25 points)**
1296
- - Marketability
1297
- - Target audience appeal
1298
- - Production feasibility
1299
- - Distribution potential
1300
 
1301
  2. **Story (25 points)**
1302
- - Three-act structure effectiveness
1303
- - Character arcs
1304
- - Plot consistency
1305
- - Theme delivery
1306
 
1307
  3. **Technical Excellence (25 points)**
1308
- - Format accuracy
1309
- - Page count appropriateness
1310
- - Scene construction
1311
- - Visual storytelling
1312
 
1313
  4. **Dialogue & Character (25 points)**
1314
- - Dialogue naturalness
1315
- - Character uniqueness
1316
- - Relationship dynamics
1317
- - Emotional authenticity
1318
 
1319
  **Overall Assessment:**
1320
  - Strengths (3-5)
@@ -1325,218 +1325,307 @@ Provide specific revision suggestions with improved examples."""
1325
  **Grade:** A+ to F
1326
 
1327
  Provide specific, constructive feedback."""
1328
- }
1329
-
1330
- return lang_prompts.get(language, lang_prompts["English"])
1331
-
1332
- def _get_genre_scene_guidelines(self, genre: str, language: str) -> str:
1333
- """Get genre-specific scene guidelines"""
1334
- guidelines = {
1335
- "action": {
1336
- "Korean": "- ์งง๊ณ  ํŽ€์น˜๊ฐ ์žˆ๋Š” ์”ฌ\n- ์•ก์…˜ ์‹œํ€€์Šค ์ƒ์„ธ ๊ณ„ํš\n- ๊ธด์žฅ๊ฐ ์ง€์†",
1337
- "English": "- Short, punchy scenes\n- Detailed action sequences\n- Maintain tension"
1338
- },
1339
- "thriller": {
1340
- "Korean": "- ์„œ์ŠคํŽœ์Šค ๊ตฌ์ถ•\n- ์ •๋ณด ์ ์ง„์  ๊ณต๊ฐœ\n- ๋ฐ˜์ „ ๋ฐฐ์น˜",
1341
- "English": "- Build suspense\n- Gradual information reveal\n- Place twists"
1342
- },
1343
- "drama": {
1344
- "Korean": "- ๊ฐ์ •์  ๋น„ํŠธ ๊ฐ•์กฐ\n- ์บ๋ฆญํ„ฐ ์ค‘์‹ฌ ์”ฌ\n- ๋Œ€ํ™” ๊ณต๊ฐ„ ํ™•๋ณด",
1345
- "English": "- Emphasize emotional beats\n- Character-driven scenes\n- Allow dialogue space"
1346
- },
1347
- "comedy": {
1348
- "Korean": "- ์…‹์—…๊ณผ ํŽ˜์ด์˜คํ”„\n- ์ฝ”๋ฏน ํƒ€์ด๋ฐ\n- ์‹œ๊ฐ์  ๊ฐœ๊ทธ",
1349
- "English": "- Setup and payoff\n- Comic timing\n- Visual gags"
1350
- },
1351
- "horror": {
1352
- "Korean": "- ๋ถ„์œ„๊ธฐ ์กฐ์„ฑ\n- ์ ํ”„ ์Šค์ผ€์–ด ๋ฐฐ์น˜\n- ๊ธด์žฅ๊ณผ ์ด์™„",
1353
- "English": "- Atmosphere building\n- Jump scare placement\n- Tension and release"
1354
- },
1355
- "sci-fi": {
1356
- "Korean": "- ์„ธ๊ณ„๊ด€ ์„ค๋ช…\n- ์‹œ๊ฐ์  ์ŠคํŽ™ํ„ฐํด\n- ๊ฐœ๋… ์†Œ๊ฐœ",
1357
- "English": "- World building\n- Visual spectacle\n- Concept introduction"
1358
- },
1359
- "romance": {
1360
- "Korean": "- ๊ฐ์ •์  ์นœ๋ฐ€๊ฐ\n- ๊ด€๊ณ„ ๋ฐœ์ „\n- ๋กœ๋งจํ‹ฑ ๋น„ํŠธ",
1361
- "English": "- Emotional intimacy\n- Relationship progression\n- Romantic beats"
1362
- }
1363
- }
1364
-
1365
- return guidelines.get(genre, guidelines["drama"]).get(language, "")
1366
-
1367
- def _extract_act_scenes(self, scene_breakdown: str, act: str) -> str:
1368
- """Extract scenes for specific act"""
1369
- # This would parse the scene breakdown and return only scenes for the requested act
1370
- # For now, returning a placeholder
1371
- return f"Scenes for {act} from the breakdown"
1372
-
1373
- # --- LLM call functions ---
1374
- def call_llm_sync(self, messages: List[Dict[str, str]], role: str, language: str) -> str:
1375
- full_content = ""
1376
- for chunk in self.call_llm_streaming(messages, role, language):
1377
- full_content += chunk
1378
- if full_content.startswith("โŒ"):
1379
- raise Exception(f"LLM Call Failed: {full_content}")
1380
- return full_content
1381
-
1382
- def call_llm_streaming(self, messages: List[Dict[str, str]], role: str,
1383
- language: str) -> Generator[str, None, None]:
1384
- try:
1385
- system_prompts = self.get_system_prompts(language)
1386
- full_messages = [{"role": "system", "content": system_prompts.get(role, "")}, *messages]
1387
-
1388
- max_tokens = 15000 if role == "screenwriter" else 8000
1389
-
1390
- payload = {
1391
- "model": self.model_id,
1392
- "messages": full_messages,
1393
- "max_tokens": max_tokens,
1394
- "temperature": 0.7 if role in ["screenwriter", "script_doctor"] else 0.8,
1395
- "top_p": 0.9,
1396
- "presence_penalty": 0.3,
1397
- "frequency_penalty": 0.3,
1398
- "stream": True
1399
- }
1400
-
1401
- response = requests.post(
1402
- self.api_url,
1403
- headers=self.create_headers(),
1404
- json=payload,
1405
- stream=True,
1406
- timeout=180
1407
- )
1408
-
1409
- if response.status_code != 200:
1410
- yield f"โŒ API Error (Status Code: {response.status_code})"
1411
- return
1412
-
1413
- buffer = ""
1414
- for line in response.iter_lines():
1415
- if not line:
1416
- continue
1417
-
1418
- try:
1419
- line_str = line.decode('utf-8').strip()
1420
- if not line_str.startswith("data: "):
1421
- continue
1422
-
1423
- data_str = line_str[6:]
1424
- if data_str == "[DONE]":
1425
- break
1426
-
1427
- data = json.loads(data_str)
1428
- choices = data.get("choices", [])
1429
- if choices and choices[0].get("delta", {}).get("content"):
1430
- content = choices[0]["delta"]["content"]
1431
- buffer += content
1432
-
1433
- if len(buffer) >= 50 or '\n' in buffer:
1434
- yield buffer
1435
- buffer = ""
1436
- time.sleep(0.01)
1437
-
1438
- except Exception as e:
1439
- logger.error(f"Chunk processing error: {str(e)}")
1440
- continue
1441
-
1442
- if buffer:
1443
- yield buffer
1444
-
1445
- except Exception as e:
1446
- logger.error(f"Streaming error: {type(e).__name__}: {str(e)}")
1447
- yield f"โŒ Error occurred: {str(e)}"
1448
 
1449
- def get_system_prompts(self, language: str) -> Dict[str, str]:
1450
- """Role-specific system prompts"""
1451
-
1452
- base_prompts = {
1453
- "Korean": {
1454
- "producer": """๋‹น์‹ ์€ 20๋…„ ๊ฒฝ๋ ฅ์˜ ํ• ๋ฆฌ์šฐ๋“œ ํ”„๋กœ๋“€์„œ์ž…๋‹ˆ๋‹ค.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1455
  ์ƒ์—…์  ์„ฑ๊ณต๊ณผ ์˜ˆ์ˆ ์  ๊ฐ€์น˜๋ฅผ ๋ชจ๋‘ ์ถ”๊ตฌํ•ฉ๋‹ˆ๋‹ค.
1456
  ์‹œ์žฅ ํŠธ๋ Œ๋“œ์™€ ๊ด€๊ฐ ์‹ฌ๋ฆฌ๋ฅผ ์ •ํ™•ํžˆ ํŒŒ์•…ํ•ฉ๋‹ˆ๋‹ค.
1457
  ์‹คํ˜„ ๊ฐ€๋Šฅํ•˜๊ณ  ๋งค๋ ฅ์ ์ธ ํ”„๋กœ์ ํŠธ๋ฅผ ๊ฐœ๋ฐœํ•ฉ๋‹ˆ๋‹ค.""",
1458
-
1459
- "story_developer": """๋‹น์‹ ์€ ์ˆ˜์ƒ ๊ฒฝ๋ ฅ์ด ์žˆ๋Š” ์Šคํ† ๋ฆฌ ๊ฐœ๋ฐœ์ž์ž…๋‹ˆ๋‹ค.
1460
  ๊ฐ์ •์ ์œผ๋กœ ๊ณต๊ฐ๊ฐ€๊ณ  ๊ตฌ์กฐ์ ์œผ๋กœ ํƒ„ํƒ„ํ•œ ์ด์•ผ๊ธฐ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค.
1461
  ์บ๋ฆญํ„ฐ์˜ ๋‚ด์  ์—ฌ์ •๊ณผ ์™ธ์  ๏ฟฝ๏ฟฝ๏ฟฝ๋กฏ์„ ์กฐํ™”๋กญ๊ฒŒ ์—ฎ์Šต๋‹ˆ๋‹ค.
1462
  ๋ณดํŽธ์  ์ฃผ์ œ๋ฅผ ๋…ํŠนํ•œ ๋ฐฉ์‹์œผ๋กœ ํƒ๊ตฌํ•ฉ๋‹ˆ๋‹ค.""",
1463
-
1464
- "character_designer": """๋‹น์‹ ์€ ์‹ฌ๋ฆฌํ•™์„ ๊ณต๋ถ€ํ•œ ์บ๋ฆญํ„ฐ ๋””์ž์ด๋„ˆ์ž…๋‹ˆ๋‹ค.
1465
  ์ง„์งœ ๊ฐ™์€ ์ธ๋ฌผ๋“ค์„ ์ฐฝ์กฐํ•˜๋Š” ์ „๋ฌธ๊ฐ€์ž…๋‹ˆ๋‹ค.
1466
  ๊ฐ ์บ๋ฆญํ„ฐ์—๊ฒŒ ๊ณ ์œ ํ•œ ๋ชฉ์†Œ๋ฆฌ์™€ ๊ด€์ ์„ ๋ถ€์—ฌํ•ฉ๋‹ˆ๋‹ค.
1467
  ๋ณต์žกํ•˜๊ณ  ๋ชจ์ˆœ์ ์ธ ์ธ๊ฐ„์„ฑ์„ ํฌ์ฐฉํ•ฉ๋‹ˆ๋‹ค.""",
1468
-
1469
- "scene_planner": """๋‹น์‹ ์€ ์ •๋ฐ€ํ•œ ์”ฌ ๊ตฌ์„ฑ์˜ ๋Œ€๊ฐ€์ž…๋‹ˆ๋‹ค.
1470
  ๊ฐ ์”ฌ์ด ์Šคํ† ๋ฆฌ์™€ ์บ๋ฆญํ„ฐ๋ฅผ ์ „์ง„์‹œํ‚ค๋„๋ก ์„ค๊ณ„ํ•ฉ๋‹ˆ๋‹ค.
1471
  ๋ฆฌ๋“ฌ๊ณผ ํŽ˜์ด์‹ฑ์„ ์™„๋ฒฝํ•˜๊ฒŒ ์กฐ์ ˆํ•ฉ๋‹ˆ๋‹ค.
1472
  ์‹œ๊ฐ์  ์Šคํ† ๋ฆฌํ…”๋ง์„ ๊ทน๋Œ€ํ™”ํ•ฉ๋‹ˆ๋‹ค.""",
1473
-
1474
- "screenwriter": """๋‹น์‹ ์€ ๋‹ค์ž‘์˜ ์‹œ๋‚˜๋ฆฌ์˜ค ์ž‘๊ฐ€์ž…๋‹ˆ๋‹ค.
1475
  '๋ณด์—ฌ์ฃผ๊ธฐ'์˜ ๋Œ€๊ฐ€์ด๋ฉฐ ์„œ๋ธŒํ…์ŠคํŠธ๋ฅผ ๋Šฅ์ˆ™ํ•˜๊ฒŒ ๋‹ค๋ฃน๋‹ˆ๋‹ค.
1476
  ์ƒ์ƒํ•˜๊ณ  ์ž์—ฐ์Šค๋Ÿฌ์šด ๋Œ€ํ™”๋ฅผ ์“ฐ๋Š” ์ „๋ฌธ๊ฐ€์ž…๋‹ˆ๋‹ค.
1477
  ์ œ์ž‘ ํ˜„์‹ค์„ ๊ณ ๋ คํ•˜๋ฉด์„œ๋„ ์ฐฝ์˜์ ์ธ ํ•ด๊ฒฐ์ฑ…์„ ์ฐพ์Šต๋‹ˆ๋‹ค.""",
1478
-
1479
- "script_doctor": """๋‹น์‹ ์€ ๊นŒ๋‹ค๋กœ์šด ์Šคํฌ๋ฆฝํŠธ ๋‹ฅํ„ฐ์ž…๋‹ˆ๋‹ค.
1480
  ์ž‘์€ ๋””ํ…Œ์ผ๋„ ๋†“์น˜์ง€ ์•Š๋Š” ์™„๋ฒฝ์ฃผ์˜์ž์ž…๋‹ˆ๋‹ค.
1481
  ์Šคํ† ๋ฆฌ์˜ ์ž ์žฌ๋ ฅ์„ ์ตœ๋Œ€ํ•œ ๋Œ์–ด๋ƒ…๋‹ˆ๋‹ค.
1482
  ๊ฑด์„ค์ ์ด๊ณ  ๊ตฌ์ฒด์ ์ธ ๊ฐœ์„ ์•ˆ์„ ์ œ์‹œํ•ฉ๋‹ˆ๋‹ค.""",
1483
-
1484
- "critic_structure": """๋‹น์‹ ์€ ๊ตฌ์กฐ ๋ถ„์„ ์ „๋ฌธ๊ฐ€์ž…๋‹ˆ๋‹ค.
1485
  ์Šคํ† ๋ฆฌ์˜ ๋ผˆ๋Œ€์™€ ๊ทผ์œก์„ ๊ฟฐ๋šซ์–ด ๋ด…๋‹ˆ๋‹ค.
1486
  ๋…ผ๋ฆฌ์  ํ—ˆ์ ๊ณผ ๊ฐ์ •์  ๊ณต๋ฐฑ์„ ์ฐพ์•„๋ƒ…๋‹ˆ๋‹ค.
1487
  ๋” ๋‚˜์€ ๊ตฌ์กฐ๋ฅผ ์œ„ํ•œ ๊ตฌ์ฒด์  ์ œ์•ˆ์„ ํ•ฉ๋‹ˆ๋‹ค.""",
1488
-
1489
- "final_reviewer": """๋‹น์‹ ์€ ์—…๊ณ„ ๋ฒ ํ…Œ๋ž‘ ์ตœ์ข… ๋ฆฌ๋ทฐ์–ด์ž…๋‹ˆ๋‹ค.
1490
  ์ƒ์—…์„ฑ๊ณผ ์˜ˆ์ˆ ์„ฑ์„ ๊ท ํ˜•์žˆ๊ฒŒ ํ‰๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
1491
  ์ œ์ž‘์‚ฌ, ๋ฐฐ์šฐ, ๊ด€๊ฐ ๋ชจ๋“  ๊ด€์ ์„ ๊ณ ๋ คํ•ฉ๋‹ˆ๋‹ค.
1492
  ๋ƒ‰์ •ํ•˜์ง€๋งŒ ๊ฒฉ๋ คํ•˜๋Š” ํ”ผ๋“œ๋ฐฑ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค."""
1493
- },
1494
- "English": {
1495
- "producer": """You are a Hollywood producer with 20 years experience.
1496
  You pursue both commercial success and artistic value.
1497
  You accurately grasp market trends and audience psychology.
1498
  You develop feasible and attractive projects.""",
1499
-
1500
- "story_developer": """You are an award-winning story developer.
1501
  You create emotionally resonant and structurally sound stories.
1502
  You harmoniously weave internal journeys with external plots.
1503
  You explore universal themes in unique ways.""",
1504
-
1505
- "character_designer": """You are a character designer who studied psychology.
1506
  You're an expert at creating lifelike characters.
1507
  You give each character a unique voice and perspective.
1508
  You capture complex and contradictory humanity.""",
1509
-
1510
- "scene_planner": """You are a master of precise scene construction.
1511
  You design each scene to advance story and character.
1512
  You perfectly control rhythm and pacing.
1513
  You maximize visual storytelling.""",
1514
-
1515
- "screenwriter": """You are a prolific screenwriter.
1516
  You're a master of 'showing' and skilled with subtext.
1517
  You're an expert at writing vivid, natural dialogue.
1518
  You find creative solutions while considering production reality.""",
1519
-
1520
- "script_doctor": """You are a demanding script doctor.
1521
  You're a perfectionist who misses no small detail.
1522
  You maximize the story's potential.
1523
  You provide constructive and specific improvements.""",
1524
-
1525
- "critic_structure": """You are a structure analysis expert.
1526
  You see through the story's skeleton and muscles.
1527
  You find logical gaps and emotional voids.
1528
  You make specific suggestions for better structure.""",
1529
-
1530
- "final_reviewer": """You are an industry veteran final reviewer.
1531
  You evaluate commercial and artistic value in balance.
1532
  You consider all perspectives: producers, actors, audience.
1533
  You provide feedback that's critical yet encouraging."""
1534
- }
1535
- }
1536
-
1537
- return base_prompts.get(language, base_prompts["English"])
1538
 
1539
- # --- Main process ---
1540
  def process_screenplay_stream(self, query: str, screenplay_type: str, genre: str,
1541
  language: str, session_id: Optional[str] = None
1542
  ) -> Generator[Tuple[str, List[Dict[str, Any]], str], None, None]:
@@ -1629,266 +1718,175 @@ You provide feedback that's critical yet encouraging."""
1629
  logger.error(f"Screenplay generation error: {e}", exc_info=True)
1630
  yield f"โŒ Error occurred: {e}", stages if 'stages' in locals() else [], self.current_session_id
1631
 
1632
-
1633
-
1634
  def get_stage_prompt(self, stage_idx: int, role: str, query: str,
1635
- screenplay_type: str, genre: str, language: str,
1636
- stages: List[Dict]) -> str:
1637
- """Generate stage-specific prompt"""
1638
- if stage_idx == 0: # Producer
1639
- return self.create_producer_prompt(query, screenplay_type, genre, language)
1640
-
1641
- if stage_idx == 1: # Story Developer
1642
- return self.create_story_developer_prompt(
1643
- stages[0]["content"], query, screenplay_type, genre, language
1644
- )
1645
-
1646
- if stage_idx == 2: # Character Designer
1647
- return self.create_character_designer_prompt(
1648
- stages[0]["content"], stages[1]["content"], genre, language
1649
- )
1650
-
1651
- if stage_idx == 3: # Structure Critic
1652
- return self.create_critic_structure_prompt(
1653
- stages[1]["content"], stages[2]["content"], screenplay_type, genre, language
1654
- )
1655
-
1656
- if stage_idx == 4: # Scene Planner
1657
- return self.create_scene_planner_prompt(
1658
- stages[1]["content"], stages[2]["content"], screenplay_type, genre, language
1659
- )
1660
-
1661
- # Screenwriter acts
1662
- if role == "screenwriter":
1663
- act_mapping = {5: "Act 1", 7: "Act 2A", 9: "Act 2B", 11: "Act 3"}
1664
- if stage_idx in act_mapping:
1665
- act = act_mapping[stage_idx]
1666
- previous_acts = self._get_previous_acts(stages, stage_idx)
1667
- return self.create_screenwriter_prompt(
1668
- act, stages[4]["content"], stages[2]["content"],
1669
- previous_acts, screenplay_type, genre, language
1670
- )
1671
-
1672
- # Script doctor reviews
1673
- if role == "script_doctor":
1674
- act_mapping = {6: "Act 1", 8: "Act 2A", 10: "Act 2B"}
1675
- if stage_idx in act_mapping:
1676
- act = act_mapping[stage_idx]
1677
- act_content = stages[stage_idx-1]["content"]
1678
- return self.create_script_doctor_prompt(act_content, act, genre, language)
1679
-
1680
- # Final reviewer
1681
- if role == "final_reviewer":
1682
- complete_screenplay = ScreenplayDatabase.get_screenplay_content(self.current_session_id)
1683
- return self.create_final_reviewer_prompt(
1684
- complete_screenplay, screenplay_type, genre, language
1685
- )
1686
-
1687
- return ""
1688
-
1689
- def create_critic_structure_prompt(self, story_structure: str, characters: str,
1690
- screenplay_type: str, genre: str, language: str) -> str:
1691
- """Structure critic prompt"""
1692
- lang_prompts = {
1693
- "Korean": f"""๋‹น์‹ ์€ ๊ตฌ์กฐ ๋น„ํ‰๊ฐ€์ž…๋‹ˆ๋‹ค. ์Šคํ† ๋ฆฌ ๊ตฌ์กฐ์™€ ์บ๋ฆญํ„ฐ ์„ค์ •์„ ์‹ฌ์ธต ๋ถ„์„ํ•˜์„ธ์š”.
1694
-
1695
- **์Šคํ† ๋ฆฌ ๊ตฌ์กฐ:**
1696
- {story_structure}
1697
-
1698
- **์บ๋ฆญํ„ฐ ์„ค์ •:**
1699
- {characters}
1700
-
1701
- **๋ถ„์„ ํ•ญ๋ชฉ:**
1702
-
1703
- 1. **3๋ง‰ ๊ตฌ์กฐ ํšจ๊ณผ์„ฑ**
1704
- - ๊ฐ ๋ง‰์˜ ๊ท ํ˜•
1705
- - ์ „ํ™˜์ ์˜ ๊ฐ•๋„
1706
- - ํ”Œ๋กฏ ํฌ์ธํŠธ์˜ ๋ช…ํ™•์„ฑ
1707
- - ํด๋ผ์ด๋งฅ์Šค ์œ„์น˜
1708
-
1709
- 2. **์บ๋ฆญํ„ฐ ์•„ํฌ ํƒ€๋‹น์„ฑ**
1710
- - ๋ณ€ํ™”์˜ ์‹ ๋น™์„ฑ
1711
- - ๋™๊ธฐ์˜ ๋ช…ํ™•์„ฑ
1712
- - ๋‚ด์ /์™ธ์  ๋ชฉํ‘œ ์ผ์น˜
1713
- - ๊ด€๊ณ„ ์—ญํ•™
1714
-
1715
- 3. **ํ…Œ๋งˆ ํ†ตํ•ฉ**
1716
- - ํ…Œ๋งˆ์˜ ์ผ๊ด€์„ฑ
1717
- - ํ”Œ๋กฏ๊ณผ ํ…Œ๋งˆ ์—ฐ๊ฒฐ
1718
- - ์บ๋ฆญํ„ฐ์™€ ํ…Œ๋งˆ ์—ฐ๊ฒฐ
1719
- - ์‹œ๊ฐ์  ํ…Œ๋งˆ ํ‘œํ˜„
1720
-
1721
- 4. **์žฅ๋ฅด ๊ธฐ๋Œ€์น˜**
1722
- - {genre} ๊ด€์Šต ์ถฉ์กฑ
1723
- - ๋…์ฐฝ์„ฑ๊ณผ ์นœ์ˆ™ํ•จ ๊ท ํ˜•
1724
- - ํƒ€๊ฒŸ ๊ด€๊ฐ ๋งŒ์กฑ๋„
1725
-
1726
- 5. **์ œ์ž‘ ํ˜„์‹ค์„ฑ**
1727
- - ์˜ˆ์‚ฐ ๊ทœ๋ชจ ์ ์ •์„ฑ
1728
- - ๋กœ์ผ€์ด์…˜ ์‹คํ˜„ ๊ฐ€๋Šฅ์„ฑ
1729
- - ํŠน์ˆ˜ํšจ๊ณผ ์š”๊ตฌ์‚ฌํ•ญ
1730
-
1731
- **ํ•„์ˆ˜ ๊ฐœ์„  ์ œ์•ˆ:**
1732
- ๊ฐ ๋ฌธ์ œ์ ์— ๋Œ€ํ•œ ๊ตฌ์ฒด์  ํ•ด๊ฒฐ์ฑ…์„ ์ œ์‹œํ•˜์„ธ์š”.""",
1733
-
1734
- "English": f"""You are a structure critic. Deeply analyze story structure and character setup.
1735
-
1736
- **Story Structure:**
1737
- {story_structure}
1738
-
1739
- **Character Setup:**
1740
- {characters}
1741
-
1742
- **Analysis Items:**
1743
-
1744
- 1. **Three-Act Structure Effectiveness**
1745
- - Balance of each act
1746
- - Strength of transitions
1747
- - Clarity of plot points
1748
- - Climax positioning
1749
-
1750
- 2. **Character Arc Validity**
1751
- - Credibility of change
1752
- - Clarity of motivation
1753
- - Internal/external goal alignment
1754
- - Relationship dynamics
1755
-
1756
- 3. **Theme Integration**
1757
- - Theme consistency
1758
- - Plot-theme connection
1759
- - Character-theme connection
1760
- - Visual theme expression
1761
-
1762
- 4. **Genre Expectations**
1763
- - Meeting {genre} conventions
1764
- - Balance of originality and familiarity
1765
- - Target audience satisfaction
1766
-
1767
- 5. **Production Reality**
1768
- - Budget scale appropriateness
1769
- - Location feasibility
1770
- - Special effects requirements
1771
-
1772
- **Required Improvement Suggestions:**
1773
- Provide specific solutions for each issue."""
1774
- }
1775
-
1776
- return lang_prompts.get(language, lang_prompts["English"])
1777
 
1778
  def _get_previous_acts(self, stages: List[Dict], current_idx: int) -> str:
1779
- """Get previous acts content"""
1780
- previous = []
1781
- act_indices = {5: [], 7: [5], 9: [5, 7], 11: [5, 7, 9]}
1782
-
1783
- if current_idx in act_indices:
1784
- for idx in act_indices[current_idx]:
1785
- if idx < len(stages) and stages[idx]["content"]:
1786
- previous.append(stages[idx]["content"])
1787
-
1788
- return "\n\n---\n\n".join(previous) if previous else ""
1789
 
1790
  def _process_producer_content(self, content: str):
1791
- """Process producer output"""
1792
- # Extract title and logline
1793
- title_match = re.search(r'(?:TITLE|์ œ๋ชฉ):\s*(.+)', content)
1794
- logline_match = re.search(r'(?:LOGLINE|๋กœ๊ทธ๋ผ์ธ):\s*(.+)', content)
1795
-
1796
- if title_match:
1797
- self.screenplay_tracker.screenplay_bible.title = title_match.group(1).strip()
1798
- if logline_match:
1799
- self.screenplay_tracker.screenplay_bible.logline = logline_match.group(1).strip()
1800
-
1801
- # Save to database
1802
- ScreenplayDatabase.save_screenplay_bible(self.current_session_id,
1803
- self.screenplay_tracker.screenplay_bible)
1804
 
1805
  def _process_story_content(self, content: str):
1806
- """Process story developer output"""
1807
- # Extract three-act structure
1808
- self.screenplay_tracker.screenplay_bible.three_act_structure = {
1809
- "act1": self._extract_section(content, "ACT 1|์ œ1๋ง‰"),
1810
- "act2a": self._extract_section(content, "ACT 2A|์ œ2๋ง‰A"),
1811
- "act2b": self._extract_section(content, "ACT 2B|์ œ2๋ง‰B"),
1812
- "act3": self._extract_section(content, "ACT 3|์ œ3๋ง‰")
1813
- }
1814
-
1815
- ScreenplayDatabase.save_screenplay_bible(self.current_session_id,
1816
- self.screenplay_tracker.screenplay_bible)
1817
 
1818
  def _process_character_content(self, content: str):
1819
- """Process character designer output"""
1820
- # Extract protagonist
1821
- protagonist_section = self._extract_section(content, "PROTAGONIST|์ฃผ์ธ๊ณต")
1822
- if protagonist_section:
1823
- protagonist = self._parse_character_profile(protagonist_section, "protagonist")
1824
- self.screenplay_tracker.add_character(protagonist)
1825
- ScreenplayDatabase.save_character(self.current_session_id, protagonist)
1826
-
1827
- # Extract antagonist
1828
- antagonist_section = self._extract_section(content, "ANTAGONIST|์ ๋Œ€์ž")
1829
- if antagonist_section:
1830
- antagonist = self._parse_character_profile(antagonist_section, "antagonist")
1831
- self.screenplay_tracker.add_character(antagonist)
1832
- ScreenplayDatabase.save_character(self.current_session_id, antagonist)
1833
 
1834
  def _process_scene_content(self, content: str):
1835
- """Process scene planner output"""
1836
- # Parse scene breakdown
1837
- scene_pattern = r'(?:Scene|์”ฌ)\s*(\d+).*?(?:INT\.|EXT\.)\s*(.+?)\s*-\s*(\w+)'
1838
- scenes = re.finditer(scene_pattern, content, re.IGNORECASE | re.MULTILINE)
1839
-
1840
- for match in scenes:
1841
- scene_num = int(match.group(1))
1842
- location = match.group(2).strip()
1843
- time_of_day = match.group(3).strip()
1844
-
1845
- # Determine act based on scene number
1846
- act = 1 if scene_num <= 12 else 2 if scene_num <= 35 else 3
1847
-
1848
- scene = SceneBreakdown(
1849
- scene_number=scene_num,
1850
- act=act,
1851
- location=location,
1852
- time_of_day=time_of_day,
1853
- characters=[], # Would be extracted from content
1854
- purpose="", # Would be extracted from content
1855
- conflict="", # Would be extracted from content
1856
- page_count=1.5 # Default estimate
1857
- )
1858
-
1859
- self.screenplay_tracker.add_scene(scene)
1860
- ScreenplayDatabase.save_scene(self.current_session_id, scene)
1861
 
1862
  def _extract_section(self, content: str, section_pattern: str) -> str:
1863
- """Extract section from content"""
1864
- pattern = rf'(?:{section_pattern})[:\s]*(.+?)(?=\n(?:[A-Z]{{2,}}|[๊ฐ€-ํžฃ]{{2,}}):|\Z)'
1865
- match = re.search(pattern, content, re.IGNORECASE | re.DOTALL)
1866
- return match.group(1).strip() if match else ""
1867
 
1868
  def _parse_character_profile(self, content: str, role: str) -> CharacterProfile:
1869
- """Parse character profile from content"""
1870
- # Extract character details using regex or string parsing
1871
- name = self._extract_field(content, "Name|์ด๋ฆ„") or f"Character_{role}"
1872
- age = int(self._extract_field(content, "Age|๋‚˜์ด") or "30")
1873
-
1874
- return CharacterProfile(
1875
- name=name,
1876
- age=age,
1877
- role=role,
1878
- archetype=self._extract_field(content, "Archetype|์•„ํฌํƒ€์ž…") or "",
1879
- want=self._extract_field(content, "WANT|์™ธ์  ๋ชฉํ‘œ") or "",
1880
- need=self._extract_field(content, "NEED|๋‚ด์  ํ•„์š”") or "",
1881
- backstory=self._extract_field(content, "Backstory|๋ฐฑ์Šคํ† ๋ฆฌ") or "",
1882
- personality=[], # Would be parsed from content
1883
- speech_pattern=self._extract_field(content, "Speech|๋งํˆฌ") or "",
1884
- character_arc=self._extract_field(content, "Arc|์•„ํฌ") or ""
1885
- )
1886
 
1887
  def _extract_field(self, content: str, field_pattern: str) -> Optional[str]:
1888
- """Extract field value from content"""
1889
- pattern = rf'(?:{field_pattern})[:\s]*(.+?)(?=\n|$)'
1890
- match = re.search(pattern, content, re.IGNORECASE)
1891
- return match.group(1).strip() if match else None
1892
 
1893
  # --- Utility functions ---
1894
  def generate_random_screenplay_theme(screenplay_type: str, genre: str, language: str) -> str:
 
589
  return "\n".join(extracted)
590
 
591
  class ScreenplayGenerationSystem:
592
+ """Professional screenplay generation system"""
593
+ def __init__(self):
594
+ self.token = FRIENDLI_TOKEN
595
+ self.api_url = API_URL
596
+ self.model_id = MODEL_ID
597
+ self.screenplay_tracker = ScreenplayTracker()
598
+ self.web_search = WebSearchIntegration()
599
+ self.current_session_id = None
600
+ ScreenplayDatabase.init_db()
601
+
602
+ def create_headers(self):
603
+ return {"Authorization": f"Bearer {self.token}", "Content-Type": "application/json"}
604
+
605
+ # --- Prompt generation functions ---
606
+ def create_producer_prompt(self, user_query: str, screenplay_type: str,
607
+ genre: str, language: str) -> str:
608
+ """Producer initial concept development"""
609
+
610
+ # Web search for market trends if enabled
611
+ search_results = ""
612
+ if self.web_search.enabled:
613
+ queries = [
614
+ f"box office success {genre} films 2024 2025",
615
+ f"popular {screenplay_type} {genre} trends",
616
+ f"audience demographics {genre} movies"
617
+ ]
618
+ for q in queries[:2]:
619
+ results = self.web_search.search(q, count=2, language=language)
620
+ if results:
621
+ search_results += self.web_search.extract_relevant_info(results) + "\n"
622
+
623
+ lang_prompts = {
624
+ "Korean": f"""๋‹น์‹ ์€ ํ• ๋ฆฌ์šฐ๋“œ ํ”„๋กœ๋“€์„œ์ž…๋‹ˆ๋‹ค. ์ƒ์—…์ ์œผ๋กœ ์„ฑ๊ณต ๊ฐ€๋Šฅํ•œ {screenplay_type} ์ปจ์…‰์„ ๊ฐœ๋ฐœํ•˜์„ธ์š”.
625
 
626
  **์š”์ฒญ์‚ฌํ•ญ:** {user_query}
627
  **ํƒ€์ž…:** {SCREENPLAY_LENGTHS[screenplay_type]['description']}
 
633
  **ํ•„์ˆ˜ ์ œ๊ณต ํ•ญ๋ชฉ:**
634
 
635
  1. **์ œ๋ชฉ (TITLE)**
636
+ - ๊ธฐ์–ตํ•˜๊ธฐ ์‰ฝ๊ณ  ๋งˆ์ผ€ํŒ… ๊ฐ€๋Šฅํ•œ ์ œ๋ชฉ
637
+ - ์žฅ๋ฅด์™€ ํ†ค์„ ์•”์‹œํ•˜๋Š” ์ œ๋ชฉ
638
 
639
  2. **๋กœ๊ทธ๋ผ์ธ (LOGLINE)**
640
+ - 25๋‹จ์–ด ์ด๋‚ด ํ•œ ๋ฌธ์žฅ
641
+ - ํ˜•์‹: "[์‚ฌ๊ฑด]์ด ์ผ์–ด๋‚ฌ์„ ๋•Œ, [์ฃผ์ธ๊ณต]์€ [๋ชฉํ‘œ]๋ฅผ ์ด๋ฃจ์–ด์•ผ ํ•œ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด [๊ฒฐ๊ณผ]"
642
+ - ๊ฐˆ๋“ฑ๊ณผ stakes๊ฐ€ ๋ช…ํ™•ํ•ด์•ผ ํ•จ
643
 
644
  3. **์žฅ๋ฅด ๋ถ„์„**
645
+ - ์ฃผ ์žฅ๋ฅด: {genre}
646
+ - ์„œ๋ธŒ ์žฅ๋ฅด:
647
+ - ํ†ค & ๋ถ„์œ„๊ธฐ:
648
 
649
  4. **ํƒ€๊ฒŸ ๊ด€๊ฐ**
650
+ - ์ฃผ์š” ์—ฐ๋ น๋Œ€:
651
+ - ์„ฑ๋ณ„ ๋ถ„ํฌ:
652
+ - ๊ด€์‹ฌ์‚ฌ:
653
+ - ์œ ์‚ฌ ์ž‘ํ’ˆ ํŒฌ์ธต:
654
 
655
  5. **๋น„๊ต ์ž‘ํ’ˆ (COMPS)**
656
+ - 3๊ฐœ์˜ ์„ฑ๊ณตํ•œ ์œ ์‚ฌ ํ”„๋กœ์ ํŠธ
657
+ - ๊ฐ๊ฐ์˜ ๋ฐ•์Šค์˜คํ”ผ์Šค/์‹œ์ฒญ๋ฅ  ์„ฑ๊ณผ
658
+ - ์šฐ๋ฆฌ ํ”„๋กœ์ ํŠธ์™€์˜ ์ฐจ๋ณ„์ 
659
 
660
  6. **๊ณ ์œ  ํŒ๋งค ํฌ์ธํŠธ (USP)**
661
+ - ์ด ์ด์•ผ๊ธฐ๋งŒ์˜ ๋…ํŠนํ•œ ์ 
662
+ - ํ˜„์žฌ ์‹œ์žฅ์—์„œ์˜ ํ•„์š”์„ฑ
663
+ - ์ œ์ž‘ ๊ฐ€๋Šฅ์„ฑ
664
 
665
  7. **๋น„์ฃผ์–ผ ์ปจ์…‰**
666
+ - ํ•ต์‹ฌ ๋น„์ฃผ์–ผ ์ด๋ฏธ์ง€ 3๊ฐœ
667
+ - ์ „์ฒด์ ์ธ ๋ฃฉ & ํ•„
668
 
669
  ๊ตฌ์ฒด์ ์ด๊ณ  ์‹œ์žฅ์„ฑ ์žˆ๋Š” ์ปจ์…‰์„ ์ œ์‹œํ•˜์„ธ์š”.""",
670
 
671
+ "English": f"""You are a Hollywood producer. Develop a commercially viable {screenplay_type} concept.
672
 
673
  **Request:** {user_query}
674
  **Type:** {SCREENPLAY_LENGTHS[screenplay_type]['description']}
 
680
  **Required Elements:**
681
 
682
  1. **TITLE**
683
+ - Memorable and marketable
684
+ - Hints at genre and tone
685
 
686
  2. **LOGLINE**
687
+ - One sentence, 25 words max
688
+ - Format: "When [inciting incident], a [protagonist] must [objective] or else [stakes]"
689
+ - Clear conflict and stakes
690
 
691
  3. **GENRE ANALYSIS**
692
+ - Primary Genre: {genre}
693
+ - Sub-genre:
694
+ - Tone & Mood:
695
 
696
  4. **TARGET AUDIENCE**
697
+ - Primary Age Range:
698
+ - Gender Distribution:
699
+ - Interests:
700
+ - Similar Works Fanbase:
701
 
702
  5. **COMPARABLE FILMS (COMPS)**
703
+ - 3 successful similar projects
704
+ - Box office/viewership performance
705
+ - How ours differs
706
 
707
  6. **UNIQUE SELLING POINT (USP)**
708
+ - What makes this story unique
709
+ - Why now in the market
710
+ - Production feasibility
711
 
712
  7. **VISUAL CONCEPT**
713
+ - 3 key visual images
714
+ - Overall look & feel
715
 
716
  Provide specific, marketable concept."""
717
+ }
718
+
719
+ return lang_prompts.get(language, lang_prompts["English"])
720
 
721
+ def create_story_developer_prompt(self, producer_concept: str, user_query: str,
722
+ screenplay_type: str, genre: str, language: str) -> str:
723
+ """Story developer for synopsis and structure"""
724
+
725
+ genre_template = GENRE_TEMPLATES.get(genre, GENRE_TEMPLATES["drama"])
726
+
727
+ lang_prompts = {
728
+ "Korean": f"""๋‹น์‹ ์€ ์Šคํ† ๋ฆฌ ๊ฐœ๋ฐœ์ž์ž…๋‹ˆ๋‹ค. ํ”„๋กœ๋“€์„œ์˜ ์ปจ์…‰์„ ๋ฐ”ํƒ•์œผ๋กœ {screenplay_type}์˜ ์‹œ๋†‰์‹œ์Šค์™€ 3๋ง‰ ๊ตฌ์กฐ๋ฅผ ๊ฐœ๋ฐœํ•˜์„ธ์š”.
729
 
730
  **ํ”„๋กœ๋“€์„œ ์ปจ์…‰:**
731
  {producer_concept}
 
738
  **ํ•„์ˆ˜ ์ž‘์„ฑ ํ•ญ๋ชฉ:**
739
 
740
  1. **์‹œ๋†‰์‹œ์Šค (SYNOPSIS)**
741
+ - 300-500๋‹จ์–ด
742
+ - 3๋ง‰ ๊ตฌ์กฐ๊ฐ€ ๋ช…ํ™•ํžˆ ๋“œ๋Ÿฌ๋‚˜๋„๋ก
743
+ - ์ฃผ์ธ๊ณต์˜ ๋ณ€ํ™” arc ํฌํ•จ
744
+ - ์ฃผ์š” ์ „ํ™˜์  ๋ช…์‹œ
745
+ - ๊ฒฐ๋ง ํฌํ•จ (์Šคํฌ์ผ๋Ÿฌ OK)
746
 
747
  2. **3๋ง‰ ๊ตฌ์กฐ (THREE-ACT STRUCTURE)**
748
+
749
+ **์ œ1๋ง‰ - ์„ค์ • (Setup) [25%]**
750
+ - ์ผ์ƒ ์„ธ๊ณ„ (Ordinary World):
751
+ - ๊ทผ์นœ์ƒ๊ฐ„ ์‚ฌ๊ฑด (Inciting Incident):
752
+ - ์ฃผ์ธ๊ณต ์†Œ๊ฐœ ๋ฐ ๊ฒฐํ•จ:
753
+ - 1๋ง‰ ์ „ํ™˜์  (Plot Point 1):
754
+
755
+ **์ œ2๋ง‰A - ์ƒ์Šน ์•ก์…˜ (Rising Action) [25%]**
756
+ - ์ƒˆ๋กœ์šด ์„ธ๊ณ„ ์ง„์ž…:
757
+ - ์žฌ๋ฏธ์™€ ๊ฒŒ์ž„ (Fun and Games):
758
+ - B ์Šคํ† ๋ฆฌ (๊ด€๊ณ„/ํ…Œ๋งˆ):
759
+ - ์ค‘๊ฐ„์  (Midpoint) - ๊ฐ€์งœ ์Šน๋ฆฌ/ํŒจ๋ฐฐ:
760
+
761
+ **์ œ2๋ง‰B - ๋ณต์žกํ™” (Complications) [25%]**
762
+ - ์•…๋‹น์˜ ๋ฐ˜๊ฒฉ:
763
+ - ํŒ€ ํ•ด์ฒด/์œ„๊ธฐ:
764
+ - ๋ชจ๋“  ๊ฒƒ์„ ์žƒ์Œ (All Is Lost):
765
+ - ์˜ํ˜ผ์˜ ์–ด๋‘” ๋ฐค:
766
+
767
+ **์ œ3๋ง‰ - ํ•ด๊ฒฐ (Resolution) [25%]**
768
+ - 2๋ง‰ ์ „ํ™˜์  (Plot Point 2):
769
+ - ์ตœ์ข… ์ „ํˆฌ ์ค€๋น„:
770
+ - ํด๋ผ์ด๋งฅ์Šค:
771
+ - ์ƒˆ๋กœ์šด ์ผ์ƒ:
772
 
773
  3. **Save the Cat ๋น„ํŠธ ์‹œํŠธ**
774
+ 15๊ฐœ ๋น„ํŠธ๋ฅผ {SCREENPLAY_LENGTHS[screenplay_type]['pages']}ํŽ˜์ด์ง€์— ๋งž์ถฐ ๋ฐฐ์น˜
775
 
776
  4. **์ฃผ์ œ (THEME)**
777
+ - ์ค‘์‹ฌ ์ฃผ์ œ:
778
+ - ์ฃผ์ œ๊ฐ€ ๋“œ๋Ÿฌ๋‚˜๋Š” ์ˆœ๊ฐ„:
779
+ - ์ฃผ์ œ์˜ ์‹œ๊ฐ์  ํ‘œํ˜„:
780
 
781
  5. **ํ†ค & ์Šคํƒ€์ผ**
782
+ - ์ „์ฒด์ ์ธ ํ†ค:
783
+ - ์œ ๋จธ ์‚ฌ์šฉ ์—ฌ๋ถ€:
784
+ - ๋น„์ฃผ์–ผ ์Šคํƒ€์ผ:
785
 
786
  ๊ตฌ์ฒด์ ์ด๊ณ  ๊ฐ์ •์ ์œผ๋กœ ๊ณต๊ฐ๊ฐ€๋Š” ์Šคํ† ๋ฆฌ๋ฅผ ๋งŒ๋“œ์„ธ์š”.""",
787
 
788
+ "English": f"""You are a story developer. Based on the producer's concept, develop the synopsis and three-act structure for this {screenplay_type}.
789
 
790
  **Producer Concept:**
791
  {producer_concept}
 
798
  **Required Elements:**
799
 
800
  1. **SYNOPSIS**
801
+ - 300-500 words
802
+ - Clear three-act structure
803
+ - Protagonist's change arc
804
+ - Major turning points
805
+ - Include ending (spoilers OK)
806
 
807
  2. **THREE-ACT STRUCTURE**
808
+
809
+ **ACT 1 - Setup [25%]**
810
+ - Ordinary World:
811
+ - Inciting Incident:
812
+ - Protagonist Introduction & Flaw:
813
+ - Plot Point 1:
814
+
815
+ **ACT 2A - Rising Action [25%]**
816
+ - Entering New World:
817
+ - Fun and Games:
818
+ - B Story (Relationship/Theme):
819
+ - Midpoint - False Victory/Defeat:
820
+
821
+ **ACT 2B - Complications [25%]**
822
+ - Bad Guys Close In:
823
+ - Team Breaks Down/Crisis:
824
+ - All Is Lost:
825
+ - Dark Night of the Soul:
826
+
827
+ **ACT 3 - Resolution [25%]**
828
+ - Plot Point 2:
829
+ - Final Battle Preparation:
830
+ - Climax:
831
+ - New Normal:
832
 
833
  3. **SAVE THE CAT BEAT SHEET**
834
+ Place 15 beats across {SCREENPLAY_LENGTHS[screenplay_type]['pages']} pages
835
 
836
  4. **THEME**
837
+ - Central Theme:
838
+ - Theme Stated Moment:
839
+ - Visual Theme Expression:
840
 
841
  5. **TONE & STYLE**
842
+ - Overall Tone:
843
+ - Use of Humor:
844
+ - Visual Style:
845
 
846
  Create specific, emotionally resonant story."""
847
+ }
848
+
849
+ return lang_prompts.get(language, lang_prompts["English"])
850
 
851
+ def create_character_designer_prompt(self, producer_concept: str, story_structure: str,
852
+ genre: str, language: str) -> str:
853
+ """Character designer prompt"""
854
+
855
+ lang_prompts = {
856
+ "Korean": f"""๋‹น์‹ ์€ ์บ๋ฆญํ„ฐ ๋””์ž์ด๋„ˆ์ž…๋‹ˆ๋‹ค. ๋‹ค์ธต์ ์ด๊ณ  ๋งค๋ ฅ์ ์ธ ์บ๋ฆญํ„ฐ๋“ค์„ ์ฐฝ์กฐํ•˜์„ธ์š”.
857
 
858
  **ํ”„๋กœ๋“€์„œ ์ปจ์…‰:**
859
  {producer_concept}
 
864
  **ํ•„์ˆ˜ ์บ๋ฆญํ„ฐ ํ”„๋กœํ•„:**
865
 
866
  1. **์ฃผ์ธ๊ณต (PROTAGONIST)**
867
+ - ์ด๋ฆ„ & ๋‚˜์ด:
868
+ - ์ง์—…/์—ญํ• :
869
+ - ์บ๋ฆญํ„ฐ ์•„ํฌํƒ€์ž…:
870
+ - WANT (์™ธ์  ๋ชฉํ‘œ):
871
+ - NEED (๋‚ด์  ํ•„์š”):
872
+ - ์น˜๋ช…์  ๊ฒฐํ•จ (Fatal Flaw):
873
+ - ๋ฐฑ์Šคํ† ๋ฆฌ (ํ•ต์‹ฌ ์ƒ์ฒ˜):
874
+ - ์„ฑ๊ฒฉ ํŠน์„ฑ (3-5๊ฐœ):
875
+ - ๋งํˆฌ & ์–ธ์–ด ํŒจํ„ด:
876
+ - ์‹œ๊ฐ์  ํŠน์ง•:
877
+ - ์บ๋ฆญํ„ฐ ์•„ํฌ (Aโ†’B):
878
 
879
  2. **์ ๋Œ€์ž (ANTAGONIST)**
880
+ - ์ด๋ฆ„ & ๋‚˜์ด:
881
+ - ์ง์—…/์—ญํ• :
882
+ - ์•…์—ญ ์•„ํฌํƒ€์ž…:
883
+ - ๋ชฉํ‘œ & ๋™๊ธฐ:
884
+ - ์ฃผ์ธ๊ณต๊ณผ์˜ ์—ฐ๊ฒฐ์ :
885
+ - ์ •๋‹น์„ฑ ์žˆ๋Š” ์ด์œ :
886
+ - ์•ฝ์ :
887
+ - ํŠน์ง•์  ํ–‰๋™:
888
 
889
  3. **์กฐ๋ ฅ์ž๋“ค (SUPPORTING CAST)**
890
+ ์ตœ์†Œ 3๋ช…, ๊ฐ๊ฐ:
891
+ - ์ด๋ฆ„ & ์—ญํ• :
892
+ - ์ฃผ์ธ๊ณต๊ณผ์˜ ๊ด€๊ณ„:
893
+ - ์Šคํ† ๋ฆฌ ๊ธฐ๋Šฅ:
894
+ - ๋…ํŠนํ•œ ํŠน์„ฑ:
895
+ - ๊ธฐ์—ฌํ•˜๋Š” ๋ฐ”:
896
 
897
  4. **์บ๋ฆญํ„ฐ ๊ด€๊ณ„๋„**
898
+ - ์ฃผ์š” ๊ด€๊ณ„ ์—ญํ•™:
899
+ - ๊ฐˆ๋“ฑ ๊ตฌ์กฐ:
900
+ - ๊ฐ์ •์  ์—ฐ๊ฒฐ:
901
+ - ํŒŒ์›Œ ๋‹ค์ด๋‚˜๋ฏน:
902
 
903
  5. **์บ์ŠคํŒ… ์ œ์•ˆ**
904
+ - ๊ฐ ์ฃผ์š” ์บ๋ฆญํ„ฐ๋ณ„ ์ด์ƒ์ ์ธ ๋ฐฐ์šฐ ํƒ€์ž…
905
+ - ์—ฐ๋ น๋Œ€, ์™ธ๋ชจ, ์—ฐ๊ธฐ ์Šคํƒ€์ผ
906
 
907
  6. **๋Œ€ํ™” ์ƒ˜ํ”Œ**
908
+ - ๊ฐ ์ฃผ์š” ์บ๋ฆญํ„ฐ์˜ ์‹œ๊ทธ๋‹ˆ์ฒ˜ ๋Œ€์‚ฌ 2-3๊ฐœ
909
+ - ์บ๋ฆญํ„ฐ์˜ ๋ณธ์งˆ์„ ๋“œ๋Ÿฌ๋‚ด๋Š” ๋Œ€ํ™”
910
 
911
  ๊ฐ ์บ๋ฆญํ„ฐ๊ฐ€ ํ…Œ๋งˆ๋ฅผ ๊ตฌํ˜„ํ•˜๊ณ  ์Šคํ† ๋ฆฌ๋ฅผ ์ถ”์ง„ํ•˜๋„๋ก ๋””์ž์ธํ•˜์„ธ์š”.""",
912
 
913
+ "English": f"""You are a character designer. Create multi-dimensional, compelling characters.
914
 
915
  **Producer Concept:**
916
  {producer_concept}
 
921
  **Required Character Profiles:**
922
 
923
  1. **PROTAGONIST**
924
+ - Name & Age:
925
+ - Occupation/Role:
926
+ - Character Archetype:
927
+ - WANT (External Goal):
928
+ - NEED (Internal Need):
929
+ - Fatal Flaw:
930
+ - Backstory (Core Wound):
931
+ - Personality Traits (3-5):
932
+ - Speech Pattern:
933
+ - Visual Characteristics:
934
+ - Character Arc (Aโ†’B):
935
 
936
  2. **ANTAGONIST**
937
+ - Name & Age:
938
+ - Occupation/Role:
939
+ - Villain Archetype:
940
+ - Goal & Motivation:
941
+ - Connection to Protagonist:
942
+ - Justifiable Reason:
943
+ - Weakness:
944
+ - Signature Behaviors:
945
 
946
  3. **SUPPORTING CAST**
947
+ Minimum 3, each with:
948
+ - Name & Role:
949
+ - Relationship to Protagonist:
950
+ - Story Function:
951
+ - Unique Traits:
952
+ - What They Contribute:
953
 
954
  4. **CHARACTER RELATIONSHIPS**
955
+ - Key Relationship Dynamics:
956
+ - Conflict Structure:
957
+ - Emotional Connections:
958
+ - Power Dynamics:
959
 
960
  5. **CASTING SUGGESTIONS**
961
+ - Ideal actor type for each major character
962
+ - Age range, appearance, acting style
963
 
964
  6. **DIALOGUE SAMPLES**
965
+ - 2-3 signature lines per major character
966
+ - Dialogue revealing character essence
967
 
968
  Design each character to embody theme and drive story."""
969
+ }
970
+
971
+ return lang_prompts.get(language, lang_prompts["English"])
972
 
973
+ def create_scene_planner_prompt(self, story_structure: str, characters: str,
974
+ screenplay_type: str, genre: str, language: str) -> str:
975
+ """Scene breakdown planner"""
976
+
977
+ total_pages = SCREENPLAY_LENGTHS[screenplay_type]['pages']
978
+
979
+ lang_prompts = {
980
+ "Korean": f"""๋‹น์‹ ์€ ์”ฌ ํ”Œ๋ž˜๋„ˆ์ž…๋‹ˆ๋‹ค. {total_pages}ํŽ˜์ด์ง€ {screenplay_type}์˜ ์ƒ์„ธํ•œ ์”ฌ ๋ธŒ๋ ˆ์ดํฌ๋‹ค์šด์„ ์ž‘์„ฑํ•˜์„ธ์š”.
981
 
982
  **์Šคํ† ๋ฆฌ ๊ตฌ์กฐ:**
983
  {story_structure}
 
1015
 
1016
  ๊ฐ ์”ฌ์ด ์Šคํ† ๋ฆฌ๋ฅผ ์ „์ง„์‹œํ‚ค๊ณ  ์บ๋ฆญํ„ฐ๋ฅผ ๋ฐœ์ „์‹œํ‚ค๋„๋ก ๊ณ„ํšํ•˜์„ธ์š”.""",
1017
 
1018
+ "English": f"""You are a scene planner. Create detailed scene breakdown for {total_pages}-page {screenplay_type}.
1019
 
1020
  **Story Structure:**
1021
  {story_structure}
 
1052
  - DISSOLVE TO:
1053
 
1054
  Plan each scene to advance story and develop character."""
1055
+ }
1056
+
1057
+ return lang_prompts.get(language, lang_prompts["English"])
1058
 
1059
+ def create_screenwriter_prompt(self, act: str, scene_breakdown: str,
1060
+ characters: str, previous_acts: str,
1061
+ screenplay_type: str, genre: str, language: str) -> str:
1062
+ """Screenwriter prompt for actual screenplay pages"""
1063
+
1064
+ act_pages = int(SCREENPLAY_LENGTHS[screenplay_type]['pages'] * 0.25)
1065
+
1066
+ lang_prompts = {
1067
+ "Korean": f"""๋‹น์‹ ์€ ํ”„๋กœ ์‹œ๋‚˜๋ฆฌ์˜ค ์ž‘๊ฐ€์ž…๋‹ˆ๋‹ค. {act}์„ ํ‘œ์ค€ ์‹œ๋‚˜๋ฆฌ์˜ค ํฌ๋งท์œผ๋กœ ์ž‘์„ฑํ•˜์„ธ์š”.
1068
 
1069
  **ํƒ€๊ฒŸ ๋ถ„๋Ÿ‰:** {act_pages}ํŽ˜์ด์ง€
1070
 
 
1080
  **์‹œ๋‚˜๋ฆฌ์˜ค ํฌ๋งท ๊ทœ์น™:**
1081
 
1082
  1. **์”ฌ ํ—ค๋”ฉ**
1083
+ INT. ์žฅ์†Œ - ์‹œ๊ฐ„
1084
+ EXT. ์žฅ์†Œ - ์‹œ๊ฐ„
1085
 
1086
  2. **์•ก์…˜ ๋ผ์ธ**
1087
+ - ํ˜„์žฌ ์‹œ์ œ ์‚ฌ์šฉ
1088
+ - ์‹œ๊ฐ์ ์œผ๋กœ ๋ณด์ด๋Š” ๊ฒƒ๋งŒ ๋ฌ˜์‚ฌ
1089
+ - 4์ค„ ์ดํ•˜๋กœ ์œ ์ง€
1090
+ - ๊ฐ์ •์€ ํ–‰๋™์œผ๋กœ ํ‘œํ˜„
1091
 
1092
  3. **์บ๋ฆญํ„ฐ ์†Œ๊ฐœ**
1093
+ ์ฒซ ๋“ฑ์žฅ์‹œ: ์ด๋ฆ„ (๋‚˜์ด) ๊ฐ„๋‹จํ•œ ๋ฌ˜์‚ฌ
1094
 
1095
  4. **๋Œ€ํ™”**
1096
+ ์บ๋ฆญํ„ฐ๋ช…
1097
+ (์ง€๋ฌธ)
1098
+ ๋Œ€์‚ฌ
1099
 
1100
  5. **์ค‘์š” ์›์น™**
1101
+ - Show, don't tell
1102
+ - ์„œ๋ธŒํ…์ŠคํŠธ ํ™œ์šฉ
1103
+ - ์ž์—ฐ์Šค๋Ÿฌ์šด ๋Œ€ํ™”
1104
+ - ์‹œ๊ฐ์  ์Šคํ† ๋ฆฌํ…”๋ง
1105
+ - ํŽ˜์ด์ง€๋‹น 1๋ถ„ ๊ทœ์น™
1106
 
1107
  **{genre} ์žฅ๋ฅด ํŠน์„ฑ:**
1108
  - ๋Œ€ํ™” ๋น„์œจ: {GENRE_TEMPLATES[genre]['dialogue_ratio']*100}%
 
1111
 
1112
  ์ •ํ™•ํ•œ ํฌ๋งท๊ณผ ๋ชฐ์ž…๊ฐ ์žˆ๋Š” ์Šคํ† ๋ฆฌํ…”๋ง์œผ๋กœ ์ž‘์„ฑํ•˜์„ธ์š”.""",
1113
 
1114
+ "English": f"""You are a professional screenwriter. Write {act} in standard screenplay format.
1115
 
1116
  **Target Length:** {act_pages} pages
1117
 
 
1127
  **Screenplay Format Rules:**
1128
 
1129
  1. **Scene Headings**
1130
+ INT. LOCATION - TIME
1131
+ EXT. LOCATION - TIME
1132
 
1133
  2. **Action Lines**
1134
+ - Present tense
1135
+ - Only what's visually seen
1136
+ - Keep under 4 lines
1137
+ - Emotions through actions
1138
 
1139
  3. **Character Intros**
1140
+ First appearance: NAME (age) brief description
1141
 
1142
  4. **Dialogue**
1143
+ CHARACTER NAME
1144
+ (parenthetical)
1145
+ Dialogue
1146
 
1147
  5. **Key Principles**
1148
+ - Show, don't tell
1149
+ - Use subtext
1150
+ - Natural dialogue
1151
+ - Visual storytelling
1152
+ - One page = one minute
1153
 
1154
  **{genre} Genre Characteristics:**
1155
  - Dialogue Ratio: {GENRE_TEMPLATES[genre]['dialogue_ratio']*100}%
 
1157
  - Key Elements: {', '.join(GENRE_TEMPLATES[genre]['key_elements'][:2])}
1158
 
1159
  Write with proper format and engaging storytelling."""
1160
+ }
1161
+
1162
+ return lang_prompts.get(language, lang_prompts["English"])
1163
 
1164
+ def create_script_doctor_prompt(self, act_content: str, act: str,
1165
+ genre: str, language: str) -> str:
1166
+ """Script doctor review and polish"""
1167
+
1168
+ lang_prompts = {
1169
+ "Korean": f"""๋‹น์‹ ์€ ์Šคํฌ๋ฆฝํŠธ ๋‹ฅํ„ฐ์ž…๋‹ˆ๋‹ค. {act}๋ฅผ ๊ฒ€ํ† ํ•˜๊ณ  ๊ฐœ์„  ์‚ฌํ•ญ์„ ์ œ์‹œํ•˜์„ธ์š”.
1170
 
1171
  **์ž‘์„ฑ๋œ ๋‚ด์šฉ:**
1172
  {act_content}
 
1174
  **๊ฒ€ํ†  ํ•ญ๋ชฉ:**
1175
 
1176
  1. **ํฌ๋งท ์ •ํ™•์„ฑ**
1177
+ - ์”ฌ ํ—ค๋”ฉ ํ˜•์‹
1178
+ - ์•ก์…˜ ๋ผ์ธ ๊ธธ์ด
1179
+ - ๋Œ€ํ™” ํฌ๋งท
1180
+ - ์ „ํ™˜ ํ‘œ์‹œ
1181
 
1182
  2. **์Šคํ† ๋ฆฌํ…”๋ง**
1183
+ - ์‹œ๊ฐ์  ๋ช…ํ™•์„ฑ
1184
+ - ํŽ˜์ด์‹ฑ
1185
+ - ๊ธด์žฅ๊ฐ ๊ตฌ์ถ•
1186
+ - ์”ฌ ๋ชฉ์  ๋‹ฌ์„ฑ
1187
 
1188
  3. **๋Œ€ํ™” ํ’ˆ์งˆ**
1189
+ - ์ž์—ฐ์Šค๋Ÿฌ์›€
1190
+ - ์บ๋ฆญํ„ฐ ๊ณ ์œ ์„ฑ
1191
+ - ์„œ๋ธŒํ…์ŠคํŠธ
1192
+ - ๋ถˆํ•„์š”ํ•œ ์„ค๋ช… ์ œ๊ฑฐ
1193
 
1194
  4. **{genre} ์žฅ๋ฅด ์ ํ•ฉ์„ฑ**
1195
+ - ์žฅ๋ฅด ๊ด€์Šต ์ค€์ˆ˜
1196
+ - ํ†ค ์ผ๊ด€์„ฑ
1197
+ - ๊ธฐ๋Œ€ ์ถฉ์กฑ
1198
 
1199
  5. **๊ธฐ์ˆ ์  ์ธก๋ฉด**
1200
+ - ํŽ˜์ด์ง€ ์ˆ˜ ์ ์ •์„ฑ
1201
+ - ์ œ์ž‘ ๊ฐ€๋Šฅ์„ฑ
1202
+ - ์˜ˆ์‚ฐ ๊ณ ๋ ค์‚ฌํ•ญ
1203
 
1204
  **ํ•„์ˆ˜ ๊ฐœ์„ ์‚ฌํ•ญ:**
1205
  ๊ตฌ์ฒด์ ์ธ ์ˆ˜์ • ์ œ์•ˆ๊ณผ ๊ฐœ์„ ๋œ ์˜ˆ์‹œ๋ฅผ ์ œ๊ณตํ•˜์„ธ์š”.""",
1206
 
1207
+ "English": f"""You are a script doctor. Review and provide improvements for {act}.
1208
 
1209
  **Written Content:**
1210
  {act_content}
 
1212
  **Review Areas:**
1213
 
1214
  1. **Format Accuracy**
1215
+ - Scene heading format
1216
+ - Action line length
1217
+ - Dialogue format
1218
+ - Transitions
1219
 
1220
  2. **Storytelling**
1221
+ - Visual clarity
1222
+ - Pacing
1223
+ - Tension building
1224
+ - Scene purpose achievement
1225
 
1226
  3. **Dialogue Quality**
1227
+ - Naturalness
1228
+ - Character uniqueness
1229
+ - Subtext
1230
+ - Remove exposition
1231
 
1232
  4. **{genre} Genre Fit**
1233
+ - Genre conventions
1234
+ - Tone consistency
1235
+ - Meeting expectations
1236
 
1237
  5. **Technical Aspects**
1238
+ - Page count appropriateness
1239
+ - Production feasibility
1240
+ - Budget considerations
1241
 
1242
  **Required Improvements:**
1243
  Provide specific revision suggestions with improved examples."""
1244
+ }
1245
+
1246
+ return lang_prompts.get(language, lang_prompts["English"])
1247
 
1248
+ def create_final_reviewer_prompt(self, complete_screenplay: str,
1249
+ screenplay_type: str, genre: str, language: str) -> str:
1250
+ """Final comprehensive review"""
1251
+
1252
+ lang_prompts = {
1253
+ "Korean": f"""๋‹น์‹ ์€ ์ตœ์ข… ๋ฆฌ๋ทฐ์–ด์ž…๋‹ˆ๋‹ค. ์™„์„ฑ๋œ {screenplay_type} ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ์ข…ํ•ฉ ํ‰๊ฐ€ํ•˜์„ธ์š”.
1254
 
1255
  **ํ‰๊ฐ€ ๊ธฐ์ค€:**
1256
 
1257
  1. **์ƒ์—…์„ฑ (25์ )**
1258
+ - ์‹œ์žฅ์„ฑ
1259
+ - ํƒ€๊ฒŸ ๊ด€๊ฐ ์–ดํ•„
1260
+ - ์ œ์ž‘ ๊ฐ€๋Šฅ์„ฑ
1261
+ - ๋ฐฐ๊ธ‰ ์ž ์žฌ๋ ฅ
1262
 
1263
  2. **์Šคํ† ๋ฆฌ (25์ )**
1264
+ - 3๋ง‰ ๊ตฌ์กฐ ํšจ๊ณผ์„ฑ
1265
+ - ์บ๋ฆญํ„ฐ ์•„ํฌ
1266
+ - ํ”Œ๋กฏ ์ผ๊ด€์„ฑ
1267
+ - ํ…Œ๋งˆ ์ „๋‹ฌ
1268
 
1269
  3. **๊ธฐ์ˆ ์  ์™„์„ฑ๋„ (25์ )**
1270
+ - ํฌ๋งท ์ •ํ™•์„ฑ
1271
+ - ํŽ˜์ด์ง€ ์ˆ˜ ์ ์ •์„ฑ
1272
+ - ์”ฌ ๊ตฌ์„ฑ
1273
+ - ์‹œ๊ฐ์  ์Šคํ† ๋ฆฌํ…”๋ง
1274
 
1275
  4. **๋Œ€ํ™” & ์บ๋ฆญํ„ฐ (25์ )**
1276
+ - ๋Œ€ํ™” ์ž์—ฐ์Šค๋Ÿฌ์›€
1277
+ - ์บ๋ฆญํ„ฐ ๊ณ ์œ ์„ฑ
1278
+ - ๊ด€๊ณ„ ์—ญํ•™
1279
+ - ๊ฐ์ •์  ์ง„์ •์„ฑ
1280
 
1281
  **์ข…ํ•ฉ ํ‰๊ฐ€:**
1282
  - ๊ฐ•์  (3-5๊ฐœ)
 
1288
 
1289
  ๊ตฌ์ฒด์ ์ด๊ณ  ๊ฑด์„ค์ ์ธ ํ”ผ๋“œ๋ฐฑ์„ ์ œ๊ณตํ•˜์„ธ์š”.""",
1290
 
1291
+ "English": f"""You are the final reviewer. Comprehensively evaluate the completed {screenplay_type} screenplay.
1292
 
1293
  **Evaluation Criteria:**
1294
 
1295
  1. **Commercial Viability (25 points)**
1296
+ - Marketability
1297
+ - Target audience appeal
1298
+ - Production feasibility
1299
+ - Distribution potential
1300
 
1301
  2. **Story (25 points)**
1302
+ - Three-act structure effectiveness
1303
+ - Character arcs
1304
+ - Plot consistency
1305
+ - Theme delivery
1306
 
1307
  3. **Technical Excellence (25 points)**
1308
+ - Format accuracy
1309
+ - Page count appropriateness
1310
+ - Scene construction
1311
+ - Visual storytelling
1312
 
1313
  4. **Dialogue & Character (25 points)**
1314
+ - Dialogue naturalness
1315
+ - Character uniqueness
1316
+ - Relationship dynamics
1317
+ - Emotional authenticity
1318
 
1319
  **Overall Assessment:**
1320
  - Strengths (3-5)
 
1325
  **Grade:** A+ to F
1326
 
1327
  Provide specific, constructive feedback."""
1328
+ }
1329
+
1330
+ return lang_prompts.get(language, lang_prompts["English"])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1331
 
1332
+ def create_critic_structure_prompt(self, story_structure: str, characters: str,
1333
+ screenplay_type: str, genre: str, language: str) -> str:
1334
+ """Structure critic prompt"""
1335
+ lang_prompts = {
1336
+ "Korean": f"""๋‹น์‹ ์€ ๊ตฌ์กฐ ๋น„ํ‰๊ฐ€์ž…๋‹ˆ๋‹ค. ์Šคํ† ๋ฆฌ ๊ตฌ์กฐ์™€ ์บ๋ฆญํ„ฐ ์„ค์ •์„ ์‹ฌ์ธต ๋ถ„์„ํ•˜์„ธ์š”.
1337
+
1338
+ **์Šคํ† ๋ฆฌ ๊ตฌ์กฐ:**
1339
+ {story_structure}
1340
+
1341
+ **์บ๋ฆญํ„ฐ ์„ค์ •:**
1342
+ {characters}
1343
+
1344
+ **๋ถ„์„ ํ•ญ๋ชฉ:**
1345
+
1346
+ 1. **3๋ง‰ ๊ตฌ์กฐ ํšจ๊ณผ์„ฑ**
1347
+ - ๊ฐ ๋ง‰์˜ ๊ท ํ˜•
1348
+ - ์ „ํ™˜์ ์˜ ๊ฐ•๋„
1349
+ - ํ”Œ๋กฏ ํฌ์ธํŠธ์˜ ๋ช…ํ™•์„ฑ
1350
+ - ํด๋ผ์ด๋งฅ์Šค ์œ„์น˜
1351
+
1352
+ 2. **์บ๋ฆญํ„ฐ ์•„ํฌ ํƒ€๋‹น์„ฑ**
1353
+ - ๋ณ€ํ™”์˜ ์‹ ๋น™์„ฑ
1354
+ - ๋™๊ธฐ์˜ ๋ช…ํ™•์„ฑ
1355
+ - ๋‚ด์ /์™ธ์  ๋ชฉํ‘œ ์ผ์น˜
1356
+ - ๊ด€๊ณ„ ์—ญํ•™
1357
+
1358
+ 3. **ํ…Œ๋งˆ ํ†ตํ•ฉ**
1359
+ - ํ…Œ๋งˆ์˜ ์ผ๊ด€์„ฑ
1360
+ - ํ”Œ๋กฏ๊ณผ ํ…Œ๋งˆ ์—ฐ๊ฒฐ
1361
+ - ์บ๋ฆญํ„ฐ์™€ ํ…Œ๋งˆ ์—ฐ๊ฒฐ
1362
+ - ์‹œ๊ฐ์  ํ…Œ๋งˆ ํ‘œํ˜„
1363
+
1364
+ 4. **์žฅ๋ฅด ๊ธฐ๋Œ€์น˜**
1365
+ - {genre} ๊ด€์Šต ์ถฉ์กฑ
1366
+ - ๋…์ฐฝ์„ฑ๊ณผ ์นœ์ˆ™ํ•จ ๊ท ํ˜•
1367
+ - ํƒ€๊ฒŸ ๊ด€๊ฐ ๋งŒ์กฑ๋„
1368
+
1369
+ 5. **์ œ์ž‘ ํ˜„์‹ค์„ฑ**
1370
+ - ์˜ˆ์‚ฐ ๊ทœ๋ชจ ์ ์ •์„ฑ
1371
+ - ๋กœ์ผ€์ด์…˜ ์‹คํ˜„ ๊ฐ€๋Šฅ์„ฑ
1372
+ - ํŠน์ˆ˜ํšจ๊ณผ ์š”๊ตฌ์‚ฌํ•ญ
1373
+
1374
+ **ํ•„์ˆ˜ ๊ฐœ์„  ์ œ์•ˆ:**
1375
+ ๊ฐ ๋ฌธ์ œ์ ์— ๋Œ€ํ•œ ๊ตฌ์ฒด์  ํ•ด๊ฒฐ์ฑ…์„ ์ œ์‹œํ•˜์„ธ์š”.""",
1376
+
1377
+ "English": f"""You are a structure critic. Deeply analyze story structure and character setup.
1378
+
1379
+ **Story Structure:**
1380
+ {story_structure}
1381
+
1382
+ **Character Setup:**
1383
+ {characters}
1384
+
1385
+ **Analysis Items:**
1386
+
1387
+ 1. **Three-Act Structure Effectiveness**
1388
+ - Balance of each act
1389
+ - Strength of transitions
1390
+ - Clarity of plot points
1391
+ - Climax positioning
1392
+
1393
+ 2. **Character Arc Validity**
1394
+ - Credibility of change
1395
+ - Clarity of motivation
1396
+ - Internal/external goal alignment
1397
+ - Relationship dynamics
1398
+
1399
+ 3. **Theme Integration**
1400
+ - Theme consistency
1401
+ - Plot-theme connection
1402
+ - Character-theme connection
1403
+ - Visual theme expression
1404
+
1405
+ 4. **Genre Expectations**
1406
+ - Meeting {genre} conventions
1407
+ - Balance of originality and familiarity
1408
+ - Target audience satisfaction
1409
+
1410
+ 5. **Production Reality**
1411
+ - Budget scale appropriateness
1412
+ - Location feasibility
1413
+ - Special effects requirements
1414
+
1415
+ **Required Improvement Suggestions:**
1416
+ Provide specific solutions for each issue."""
1417
+ }
1418
+
1419
+ return lang_prompts.get(language, lang_prompts["English"])
1420
+
1421
+ def _get_genre_scene_guidelines(self, genre: str, language: str) -> str:
1422
+ """Get genre-specific scene guidelines"""
1423
+ guidelines = {
1424
+ "action": {
1425
+ "Korean": "- ์งง๊ณ  ํŽ€์น˜๊ฐ ์žˆ๋Š” ์”ฌ\n- ์•ก์…˜ ์‹œํ€€์Šค ์ƒ์„ธ ๊ณ„ํš\n- ๊ธด์žฅ๊ฐ ์ง€์†",
1426
+ "English": "- Short, punchy scenes\n- Detailed action sequences\n- Maintain tension"
1427
+ },
1428
+ "thriller": {
1429
+ "Korean": "- ์„œ์ŠคํŽœ์Šค ๊ตฌ์ถ•\n- ์ •๋ณด ์ ์ง„์  ๊ณต๊ฐœ\n- ๋ฐ˜์ „ ๋ฐฐ์น˜",
1430
+ "English": "- Build suspense\n- Gradual information reveal\n- Place twists"
1431
+ },
1432
+ "drama": {
1433
+ "Korean": "- ๊ฐ์ •์  ๋น„ํŠธ ๊ฐ•์กฐ\n- ์บ๋ฆญํ„ฐ ์ค‘์‹ฌ ์”ฌ\n- ๋Œ€ํ™” ๊ณต๊ฐ„ ํ™•๋ณด",
1434
+ "English": "- Emphasize emotional beats\n- Character-driven scenes\n- Allow dialogue space"
1435
+ },
1436
+ "comedy": {
1437
+ "Korean": "- ์…‹์—…๊ณผ ํŽ˜์ด์˜คํ”„\n- ์ฝ”๋ฏน ํƒ€์ด๋ฐ\n- ์‹œ๊ฐ์  ๊ฐœ๊ทธ",
1438
+ "English": "- Setup and payoff\n- Comic timing\n- Visual gags"
1439
+ },
1440
+ "horror": {
1441
+ "Korean": "- ๋ถ„์œ„๊ธฐ ์กฐ์„ฑ\n- ์ ํ”„ ์Šค์ผ€์–ด ๋ฐฐ์น˜\n- ๊ธด์žฅ๊ณผ ์ด์™„",
1442
+ "English": "- Atmosphere building\n- Jump scare placement\n- Tension and release"
1443
+ },
1444
+ "sci-fi": {
1445
+ "Korean": "- ์„ธ๊ณ„๊ด€ ์„ค๋ช…\n- ์‹œ๊ฐ์  ์ŠคํŽ™ํ„ฐํด\n- ๊ฐœ๋… ์†Œ๊ฐœ",
1446
+ "English": "- World building\n- Visual spectacle\n- Concept introduction"
1447
+ },
1448
+ "romance": {
1449
+ "Korean": "- ๊ฐ์ •์  ์นœ๋ฐ€๊ฐ\n- ๊ด€๊ณ„ ๋ฐœ์ „\n- ๋กœ๋งจํ‹ฑ ๋น„ํŠธ",
1450
+ "English": "- Emotional intimacy\n- Relationship progression\n- Romantic beats"
1451
+ }
1452
+ }
1453
+
1454
+ return guidelines.get(genre, guidelines["drama"]).get(language, "")
1455
+
1456
+ def _extract_act_scenes(self, scene_breakdown: str, act: str) -> str:
1457
+ """Extract scenes for specific act"""
1458
+ # This would parse the scene breakdown and return only scenes for the requested act
1459
+ # For now, returning a placeholder
1460
+ return f"Scenes for {act} from the breakdown"
1461
+
1462
+ # --- LLM call functions ---
1463
+ def call_llm_sync(self, messages: List[Dict[str, str]], role: str, language: str) -> str:
1464
+ full_content = ""
1465
+ for chunk in self.call_llm_streaming(messages, role, language):
1466
+ full_content += chunk
1467
+ if full_content.startswith("โŒ"):
1468
+ raise Exception(f"LLM Call Failed: {full_content}")
1469
+ return full_content
1470
+
1471
+ def call_llm_streaming(self, messages: List[Dict[str, str]], role: str,
1472
+ language: str) -> Generator[str, None, None]:
1473
+ try:
1474
+ system_prompts = self.get_system_prompts(language)
1475
+ full_messages = [{"role": "system", "content": system_prompts.get(role, "")}, *messages]
1476
+
1477
+ max_tokens = 15000 if role == "screenwriter" else 8000
1478
+
1479
+ payload = {
1480
+ "model": self.model_id,
1481
+ "messages": full_messages,
1482
+ "max_tokens": max_tokens,
1483
+ "temperature": 0.7 if role in ["screenwriter", "script_doctor"] else 0.8,
1484
+ "top_p": 0.9,
1485
+ "presence_penalty": 0.3,
1486
+ "frequency_penalty": 0.3,
1487
+ "stream": True
1488
+ }
1489
+
1490
+ response = requests.post(
1491
+ self.api_url,
1492
+ headers=self.create_headers(),
1493
+ json=payload,
1494
+ stream=True,
1495
+ timeout=180
1496
+ )
1497
+
1498
+ if response.status_code != 200:
1499
+ yield f"โŒ API Error (Status Code: {response.status_code})"
1500
+ return
1501
+
1502
+ buffer = ""
1503
+ for line in response.iter_lines():
1504
+ if not line:
1505
+ continue
1506
+
1507
+ try:
1508
+ line_str = line.decode('utf-8').strip()
1509
+ if not line_str.startswith("data: "):
1510
+ continue
1511
+
1512
+ data_str = line_str[6:]
1513
+ if data_str == "[DONE]":
1514
+ break
1515
+
1516
+ data = json.loads(data_str)
1517
+ choices = data.get("choices", [])
1518
+ if choices and choices[0].get("delta", {}).get("content"):
1519
+ content = choices[0]["delta"]["content"]
1520
+ buffer += content
1521
+
1522
+ if len(buffer) >= 50 or '\n' in buffer:
1523
+ yield buffer
1524
+ buffer = ""
1525
+ time.sleep(0.01)
1526
+
1527
+ except Exception as e:
1528
+ logger.error(f"Chunk processing error: {str(e)}")
1529
+ continue
1530
+
1531
+ if buffer:
1532
+ yield buffer
1533
+
1534
+ except Exception as e:
1535
+ logger.error(f"Streaming error: {type(e).__name__}: {str(e)}")
1536
+ yield f"โŒ Error occurred: {str(e)}"
1537
+
1538
+ def get_system_prompts(self, language: str) -> Dict[str, str]:
1539
+ """Role-specific system prompts"""
1540
+
1541
+ base_prompts = {
1542
+ "Korean": {
1543
+ "producer": """๋‹น์‹ ์€ 20๋…„ ๊ฒฝ๋ ฅ์˜ ํ• ๋ฆฌ์šฐ๋“œ ํ”„๋กœ๋“€์„œ์ž…๋‹ˆ๋‹ค.
1544
  ์ƒ์—…์  ์„ฑ๊ณต๊ณผ ์˜ˆ์ˆ ์  ๊ฐ€์น˜๋ฅผ ๋ชจ๋‘ ์ถ”๊ตฌํ•ฉ๋‹ˆ๋‹ค.
1545
  ์‹œ์žฅ ํŠธ๋ Œ๋“œ์™€ ๊ด€๊ฐ ์‹ฌ๋ฆฌ๋ฅผ ์ •ํ™•ํžˆ ํŒŒ์•…ํ•ฉ๋‹ˆ๋‹ค.
1546
  ์‹คํ˜„ ๊ฐ€๋Šฅํ•˜๊ณ  ๋งค๋ ฅ์ ์ธ ํ”„๋กœ์ ํŠธ๋ฅผ ๊ฐœ๋ฐœํ•ฉ๋‹ˆ๋‹ค.""",
1547
+
1548
+ "story_developer": """๋‹น์‹ ์€ ์ˆ˜์ƒ ๊ฒฝ๋ ฅ์ด ์žˆ๋Š” ์Šคํ† ๋ฆฌ ๊ฐœ๋ฐœ์ž์ž…๋‹ˆ๋‹ค.
1549
  ๊ฐ์ •์ ์œผ๋กœ ๊ณต๊ฐ๊ฐ€๊ณ  ๊ตฌ์กฐ์ ์œผ๋กœ ํƒ„ํƒ„ํ•œ ์ด์•ผ๊ธฐ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค.
1550
  ์บ๋ฆญํ„ฐ์˜ ๋‚ด์  ์—ฌ์ •๊ณผ ์™ธ์  ๏ฟฝ๏ฟฝ๏ฟฝ๋กฏ์„ ์กฐํ™”๋กญ๊ฒŒ ์—ฎ์Šต๋‹ˆ๋‹ค.
1551
  ๋ณดํŽธ์  ์ฃผ์ œ๋ฅผ ๋…ํŠนํ•œ ๋ฐฉ์‹์œผ๋กœ ํƒ๊ตฌํ•ฉ๋‹ˆ๋‹ค.""",
1552
+
1553
+ "character_designer": """๋‹น์‹ ์€ ์‹ฌ๋ฆฌํ•™์„ ๊ณต๋ถ€ํ•œ ์บ๋ฆญํ„ฐ ๋””์ž์ด๋„ˆ์ž…๋‹ˆ๋‹ค.
1554
  ์ง„์งœ ๊ฐ™์€ ์ธ๋ฌผ๋“ค์„ ์ฐฝ์กฐํ•˜๋Š” ์ „๋ฌธ๊ฐ€์ž…๋‹ˆ๋‹ค.
1555
  ๊ฐ ์บ๋ฆญํ„ฐ์—๊ฒŒ ๊ณ ์œ ํ•œ ๋ชฉ์†Œ๋ฆฌ์™€ ๊ด€์ ์„ ๋ถ€์—ฌํ•ฉ๋‹ˆ๋‹ค.
1556
  ๋ณต์žกํ•˜๊ณ  ๋ชจ์ˆœ์ ์ธ ์ธ๊ฐ„์„ฑ์„ ํฌ์ฐฉํ•ฉ๋‹ˆ๋‹ค.""",
1557
+
1558
+ "scene_planner": """๋‹น์‹ ์€ ์ •๋ฐ€ํ•œ ์”ฌ ๊ตฌ์„ฑ์˜ ๋Œ€๊ฐ€์ž…๋‹ˆ๋‹ค.
1559
  ๊ฐ ์”ฌ์ด ์Šคํ† ๋ฆฌ์™€ ์บ๋ฆญํ„ฐ๋ฅผ ์ „์ง„์‹œํ‚ค๋„๋ก ์„ค๊ณ„ํ•ฉ๋‹ˆ๋‹ค.
1560
  ๋ฆฌ๋“ฌ๊ณผ ํŽ˜์ด์‹ฑ์„ ์™„๋ฒฝํ•˜๊ฒŒ ์กฐ์ ˆํ•ฉ๋‹ˆ๋‹ค.
1561
  ์‹œ๊ฐ์  ์Šคํ† ๋ฆฌํ…”๋ง์„ ๊ทน๋Œ€ํ™”ํ•ฉ๋‹ˆ๋‹ค.""",
1562
+
1563
+ "screenwriter": """๋‹น์‹ ์€ ๋‹ค์ž‘์˜ ์‹œ๋‚˜๋ฆฌ์˜ค ์ž‘๊ฐ€์ž…๋‹ˆ๋‹ค.
1564
  '๋ณด์—ฌ์ฃผ๊ธฐ'์˜ ๋Œ€๊ฐ€์ด๋ฉฐ ์„œ๋ธŒํ…์ŠคํŠธ๋ฅผ ๋Šฅ์ˆ™ํ•˜๊ฒŒ ๋‹ค๋ฃน๋‹ˆ๋‹ค.
1565
  ์ƒ์ƒํ•˜๊ณ  ์ž์—ฐ์Šค๋Ÿฌ์šด ๋Œ€ํ™”๋ฅผ ์“ฐ๋Š” ์ „๋ฌธ๊ฐ€์ž…๋‹ˆ๋‹ค.
1566
  ์ œ์ž‘ ํ˜„์‹ค์„ ๊ณ ๋ คํ•˜๋ฉด์„œ๋„ ์ฐฝ์˜์ ์ธ ํ•ด๊ฒฐ์ฑ…์„ ์ฐพ์Šต๋‹ˆ๋‹ค.""",
1567
+
1568
+ "script_doctor": """๋‹น์‹ ์€ ๊นŒ๋‹ค๋กœ์šด ์Šคํฌ๋ฆฝํŠธ ๋‹ฅํ„ฐ์ž…๋‹ˆ๋‹ค.
1569
  ์ž‘์€ ๋””ํ…Œ์ผ๋„ ๋†“์น˜์ง€ ์•Š๋Š” ์™„๋ฒฝ์ฃผ์˜์ž์ž…๋‹ˆ๋‹ค.
1570
  ์Šคํ† ๋ฆฌ์˜ ์ž ์žฌ๋ ฅ์„ ์ตœ๋Œ€ํ•œ ๋Œ์–ด๋ƒ…๋‹ˆ๋‹ค.
1571
  ๊ฑด์„ค์ ์ด๊ณ  ๊ตฌ์ฒด์ ์ธ ๊ฐœ์„ ์•ˆ์„ ์ œ์‹œํ•ฉ๋‹ˆ๋‹ค.""",
1572
+
1573
+ "critic_structure": """๋‹น์‹ ์€ ๊ตฌ์กฐ ๋ถ„์„ ์ „๋ฌธ๊ฐ€์ž…๋‹ˆ๋‹ค.
1574
  ์Šคํ† ๋ฆฌ์˜ ๋ผˆ๋Œ€์™€ ๊ทผ์œก์„ ๊ฟฐ๋šซ์–ด ๋ด…๋‹ˆ๋‹ค.
1575
  ๋…ผ๋ฆฌ์  ํ—ˆ์ ๊ณผ ๊ฐ์ •์  ๊ณต๋ฐฑ์„ ์ฐพ์•„๋ƒ…๋‹ˆ๋‹ค.
1576
  ๋” ๋‚˜์€ ๊ตฌ์กฐ๋ฅผ ์œ„ํ•œ ๊ตฌ์ฒด์  ์ œ์•ˆ์„ ํ•ฉ๋‹ˆ๋‹ค.""",
1577
+
1578
+ "final_reviewer": """๋‹น์‹ ์€ ์—…๊ณ„ ๋ฒ ํ…Œ๋ž‘ ์ตœ์ข… ๋ฆฌ๋ทฐ์–ด์ž…๋‹ˆ๋‹ค.
1579
  ์ƒ์—…์„ฑ๊ณผ ์˜ˆ์ˆ ์„ฑ์„ ๊ท ํ˜•์žˆ๊ฒŒ ํ‰๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
1580
  ์ œ์ž‘์‚ฌ, ๋ฐฐ์šฐ, ๊ด€๊ฐ ๋ชจ๋“  ๊ด€์ ์„ ๊ณ ๋ คํ•ฉ๋‹ˆ๋‹ค.
1581
  ๋ƒ‰์ •ํ•˜์ง€๋งŒ ๊ฒฉ๋ คํ•˜๋Š” ํ”ผ๋“œ๋ฐฑ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค."""
1582
+ },
1583
+ "English": {
1584
+ "producer": """You are a Hollywood producer with 20 years experience.
1585
  You pursue both commercial success and artistic value.
1586
  You accurately grasp market trends and audience psychology.
1587
  You develop feasible and attractive projects.""",
1588
+
1589
+ "story_developer": """You are an award-winning story developer.
1590
  You create emotionally resonant and structurally sound stories.
1591
  You harmoniously weave internal journeys with external plots.
1592
  You explore universal themes in unique ways.""",
1593
+
1594
+ "character_designer": """You are a character designer who studied psychology.
1595
  You're an expert at creating lifelike characters.
1596
  You give each character a unique voice and perspective.
1597
  You capture complex and contradictory humanity.""",
1598
+
1599
+ "scene_planner": """You are a master of precise scene construction.
1600
  You design each scene to advance story and character.
1601
  You perfectly control rhythm and pacing.
1602
  You maximize visual storytelling.""",
1603
+
1604
+ "screenwriter": """You are a prolific screenwriter.
1605
  You're a master of 'showing' and skilled with subtext.
1606
  You're an expert at writing vivid, natural dialogue.
1607
  You find creative solutions while considering production reality.""",
1608
+
1609
+ "script_doctor": """You are a demanding script doctor.
1610
  You're a perfectionist who misses no small detail.
1611
  You maximize the story's potential.
1612
  You provide constructive and specific improvements.""",
1613
+
1614
+ "critic_structure": """You are a structure analysis expert.
1615
  You see through the story's skeleton and muscles.
1616
  You find logical gaps and emotional voids.
1617
  You make specific suggestions for better structure.""",
1618
+
1619
+ "final_reviewer": """You are an industry veteran final reviewer.
1620
  You evaluate commercial and artistic value in balance.
1621
  You consider all perspectives: producers, actors, audience.
1622
  You provide feedback that's critical yet encouraging."""
1623
+ }
1624
+ }
1625
+
1626
+ return base_prompts.get(language, base_prompts["English"])
1627
 
1628
+ # --- Main process ---
1629
  def process_screenplay_stream(self, query: str, screenplay_type: str, genre: str,
1630
  language: str, session_id: Optional[str] = None
1631
  ) -> Generator[Tuple[str, List[Dict[str, Any]], str], None, None]:
 
1718
  logger.error(f"Screenplay generation error: {e}", exc_info=True)
1719
  yield f"โŒ Error occurred: {e}", stages if 'stages' in locals() else [], self.current_session_id
1720
 
 
 
1721
  def get_stage_prompt(self, stage_idx: int, role: str, query: str,
1722
+ screenplay_type: str, genre: str, language: str,
1723
+ stages: List[Dict]) -> str:
1724
+ """Generate stage-specific prompt"""
1725
+ if stage_idx == 0: # Producer
1726
+ return self.create_producer_prompt(query, screenplay_type, genre, language)
1727
+
1728
+ if stage_idx == 1: # Story Developer
1729
+ return self.create_story_developer_prompt(
1730
+ stages[0]["content"], query, screenplay_type, genre, language
1731
+ )
1732
+
1733
+ if stage_idx == 2: # Character Designer
1734
+ return self.create_character_designer_prompt(
1735
+ stages[0]["content"], stages[1]["content"], genre, language
1736
+ )
1737
+
1738
+ if stage_idx == 3: # Structure Critic
1739
+ return self.create_critic_structure_prompt(
1740
+ stages[1]["content"], stages[2]["content"], screenplay_type, genre, language
1741
+ )
1742
+
1743
+ if stage_idx == 4: # Scene Planner
1744
+ return self.create_scene_planner_prompt(
1745
+ stages[1]["content"], stages[2]["content"], screenplay_type, genre, language
1746
+ )
1747
+
1748
+ # Screenwriter acts
1749
+ if role == "screenwriter":
1750
+ act_mapping = {5: "Act 1", 7: "Act 2A", 9: "Act 2B", 11: "Act 3"}
1751
+ if stage_idx in act_mapping:
1752
+ act = act_mapping[stage_idx]
1753
+ previous_acts = self._get_previous_acts(stages, stage_idx)
1754
+ return self.create_screenwriter_prompt(
1755
+ act, stages[4]["content"], stages[2]["content"],
1756
+ previous_acts, screenplay_type, genre, language
1757
+ )
1758
+
1759
+ # Script doctor reviews
1760
+ if role == "script_doctor":
1761
+ act_mapping = {6: "Act 1", 8: "Act 2A", 10: "Act 2B"}
1762
+ if stage_idx in act_mapping:
1763
+ act = act_mapping[stage_idx]
1764
+ act_content = stages[stage_idx-1]["content"]
1765
+ return self.create_script_doctor_prompt(act_content, act, genre, language)
1766
+
1767
+ # Final reviewer
1768
+ if role == "final_reviewer":
1769
+ complete_screenplay = ScreenplayDatabase.get_screenplay_content(self.current_session_id)
1770
+ return self.create_final_reviewer_prompt(
1771
+ complete_screenplay, screenplay_type, genre, language
1772
+ )
1773
+
1774
+ return ""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1775
 
1776
  def _get_previous_acts(self, stages: List[Dict], current_idx: int) -> str:
1777
+ """Get previous acts content"""
1778
+ previous = []
1779
+ act_indices = {5: [], 7: [5], 9: [5, 7], 11: [5, 7, 9]}
1780
+
1781
+ if current_idx in act_indices:
1782
+ for idx in act_indices[current_idx]:
1783
+ if idx < len(stages) and stages[idx]["content"]:
1784
+ previous.append(stages[idx]["content"])
1785
+
1786
+ return "\n\n---\n\n".join(previous) if previous else ""
1787
 
1788
  def _process_producer_content(self, content: str):
1789
+ """Process producer output"""
1790
+ # Extract title and logline
1791
+ title_match = re.search(r'(?:TITLE|์ œ๋ชฉ):\s*(.+)', content)
1792
+ logline_match = re.search(r'(?:LOGLINE|๋กœ๊ทธ๋ผ์ธ):\s*(.+)', content)
1793
+
1794
+ if title_match:
1795
+ self.screenplay_tracker.screenplay_bible.title = title_match.group(1).strip()
1796
+ if logline_match:
1797
+ self.screenplay_tracker.screenplay_bible.logline = logline_match.group(1).strip()
1798
+
1799
+ # Save to database
1800
+ ScreenplayDatabase.save_screenplay_bible(self.current_session_id,
1801
+ self.screenplay_tracker.screenplay_bible)
1802
 
1803
  def _process_story_content(self, content: str):
1804
+ """Process story developer output"""
1805
+ # Extract three-act structure
1806
+ self.screenplay_tracker.screenplay_bible.three_act_structure = {
1807
+ "act1": self._extract_section(content, "ACT 1|์ œ1๋ง‰"),
1808
+ "act2a": self._extract_section(content, "ACT 2A|์ œ2๋ง‰A"),
1809
+ "act2b": self._extract_section(content, "ACT 2B|์ œ2๋ง‰B"),
1810
+ "act3": self._extract_section(content, "ACT 3|์ œ3๋ง‰")
1811
+ }
1812
+
1813
+ ScreenplayDatabase.save_screenplay_bible(self.current_session_id,
1814
+ self.screenplay_tracker.screenplay_bible)
1815
 
1816
  def _process_character_content(self, content: str):
1817
+ """Process character designer output"""
1818
+ # Extract protagonist
1819
+ protagonist_section = self._extract_section(content, "PROTAGONIST|์ฃผ์ธ๊ณต")
1820
+ if protagonist_section:
1821
+ protagonist = self._parse_character_profile(protagonist_section, "protagonist")
1822
+ self.screenplay_tracker.add_character(protagonist)
1823
+ ScreenplayDatabase.save_character(self.current_session_id, protagonist)
1824
+
1825
+ # Extract antagonist
1826
+ antagonist_section = self._extract_section(content, "ANTAGONIST|์ ๋Œ€์ž")
1827
+ if antagonist_section:
1828
+ antagonist = self._parse_character_profile(antagonist_section, "antagonist")
1829
+ self.screenplay_tracker.add_character(antagonist)
1830
+ ScreenplayDatabase.save_character(self.current_session_id, antagonist)
1831
 
1832
  def _process_scene_content(self, content: str):
1833
+ """Process scene planner output"""
1834
+ # Parse scene breakdown
1835
+ scene_pattern = r'(?:Scene|์”ฌ)\s*(\d+).*?(?:INT\.|EXT\.)\s*(.+?)\s*-\s*(\w+)'
1836
+ scenes = re.finditer(scene_pattern, content, re.IGNORECASE | re.MULTILINE)
1837
+
1838
+ for match in scenes:
1839
+ scene_num = int(match.group(1))
1840
+ location = match.group(2).strip()
1841
+ time_of_day = match.group(3).strip()
1842
+
1843
+ # Determine act based on scene number
1844
+ act = 1 if scene_num <= 12 else 2 if scene_num <= 35 else 3
1845
+
1846
+ scene = SceneBreakdown(
1847
+ scene_number=scene_num,
1848
+ act=act,
1849
+ location=location,
1850
+ time_of_day=time_of_day,
1851
+ characters=[], # Would be extracted from content
1852
+ purpose="", # Would be extracted from content
1853
+ conflict="", # Would be extracted from content
1854
+ page_count=1.5 # Default estimate
1855
+ )
1856
+
1857
+ self.screenplay_tracker.add_scene(scene)
1858
+ ScreenplayDatabase.save_scene(self.current_session_id, scene)
1859
 
1860
  def _extract_section(self, content: str, section_pattern: str) -> str:
1861
+ """Extract section from content"""
1862
+ pattern = rf'(?:{section_pattern})[:\s]*(.+?)(?=\n(?:[A-Z]{{2,}}|[๊ฐ€-ํžฃ]{{2,}}):|\Z)'
1863
+ match = re.search(pattern, content, re.IGNORECASE | re.DOTALL)
1864
+ return match.group(1).strip() if match else ""
1865
 
1866
  def _parse_character_profile(self, content: str, role: str) -> CharacterProfile:
1867
+ """Parse character profile from content"""
1868
+ # Extract character details using regex or string parsing
1869
+ name = self._extract_field(content, "Name|์ด๋ฆ„") or f"Character_{role}"
1870
+ age = int(self._extract_field(content, "Age|๋‚˜์ด") or "30")
1871
+
1872
+ return CharacterProfile(
1873
+ name=name,
1874
+ age=age,
1875
+ role=role,
1876
+ archetype=self._extract_field(content, "Archetype|์•„ํฌํƒ€์ž…") or "",
1877
+ want=self._extract_field(content, "WANT|์™ธ์  ๋ชฉํ‘œ") or "",
1878
+ need=self._extract_field(content, "NEED|๋‚ด์  ํ•„์š”") or "",
1879
+ backstory=self._extract_field(content, "Backstory|๋ฐฑ์Šคํ† ๋ฆฌ") or "",
1880
+ personality=[], # Would be parsed from content
1881
+ speech_pattern=self._extract_field(content, "Speech|๋งํˆฌ") or "",
1882
+ character_arc=self._extract_field(content, "Arc|์•„ํฌ") or ""
1883
+ )
1884
 
1885
  def _extract_field(self, content: str, field_pattern: str) -> Optional[str]:
1886
+ """Extract field value from content"""
1887
+ pattern = rf'(?:{field_pattern})[:\s]*(.+?)(?=\n|$)'
1888
+ match = re.search(pattern, content, re.IGNORECASE)
1889
+ return match.group(1).strip() if match else None
1890
 
1891
  # --- Utility functions ---
1892
  def generate_random_screenplay_theme(screenplay_type: str, genre: str, language: str) -> str: